Skip to main content
GlassKit Eval supports in-process Python adapters and language-neutral command adapters. Both expose the same individual or batch evaluation behavior to the runner. Use a Python adapter when the app logic is importable by Python, or --adapter-command when the adapter should run in its own process, such as a JavaScript or TypeScript backend.

Python adapters

By default, glasskit eval seed and glasskit eval run load <eval-dir>/adapter.py:create_evaluator. With the default eval directory, that is eval/adapter.py:create_evaluator. Use --adapter <module-or-file>:<callable> to choose another adapter target. The module side can be an import path such as my_app.eval_adapter or a file path such as eval/adapter.py. The callable side can name a function, class, or nested attribute such as create_evaluator or EvalAdapters.step_checker. Keep the adapter thin by reusing as much of the app’s runtime logic as practical and adding only the wrappers needed for recorded-video evaluation. The recommended adapter shape is a factory that accepts one config argument and returns an evaluator object:
Adapter factories may be synchronous or asynchronous. No-argument factories are supported, but they do not receive the factory config object. If the factory needs --adapter-config, --artifacts-dir, --verbose, or the eval directory, define it with one required argument.

Individual and batch evaluation

An evaluator chooses one of two execution strategies by implementing evaluate or evaluate_many. Both methods may be synchronous or asynchronous. Implement at least one strategy. If an evaluator implements both methods, evaluate_many takes precedence. Batch evaluation must return exactly one JSON-like observation per input sample in the same order. A batch adapter owns any chunking or internal concurrency it needs; --concurrency does not fan out calls inside evaluate_many. Samples with an ignore reason are omitted before either strategy runs. They are not decoded and are not present in the samples list passed to evaluate_many. GlassKit Eval schedules the remaining samples in case-file declaration order and passes batch samples in that order. During seed and resumed runs, only samples that still need work are passed, so a batch adapter must not assume it always receives a target’s complete sample set. Prefer evaluate when the work consists of independent calls, even if those calls should overlap. GlassKit Eval bounds synchronous and asynchronous calls by --concurrency and restores deterministic sample order after calls finish. With --keep-going, an individual call failure becomes an error only for that sample. Use evaluate_many only for actual batch behavior. If a batch call fails, GlassKit Eval cannot attribute the failure to one input, so --keep-going records an error for every sample in that target batch. The optional close() method is called after the run or adapter validation check and may also be synchronous or asynchronous. With --repeat, GlassKit Eval creates fresh evaluator instances sequentially and closes each trial before calling the evaluator factory for the next one. Simple function adapters are also supported when the first two positional argument names are either image, target_id or sample, target:
Factory config fields: Sample fields passed to the evaluator: Frame sampling is timestamp-based. sample.timestamp_s is always the requested eval time, not the actual media timestamp of the selected frame. sample.image is the decoded frame whose timestamp is closest to that requested time, with ties choosing the earlier frame. GlassKit applies the source video’s display rotation and reflection before handing the frame to an adapter, so its pixels and dimensions match normal video playback. For variable-frame-rate videos, glasskit eval uses each frame’s media timestamp when available; if a video lacks frame timestamps, it estimates them from the frame index and average frame rate. sample.image is closed when the evaluate call returns. Call sample.image.copy() if the adapter needs to keep the frame afterward. Target fields passed to the evaluator: Adapter return values must be JSON-like: None, boolean, finite number, string, array, or object with string keys.

Command adapters

Use --adapter-command when the app is easier to call from its own runtime, such as a JavaScript or TypeScript backend:
GlassKit Eval parses the command into an argument list, then starts it directly without a shell. Pipes, redirects, variable expansion, and command substitution are therefore unavailable. The command inherits the current working directory and environment, so it can import the app normally and read the same secrets and configuration. Start from the complete JavaScript file below. Its editable application section passes a factory to runGlassKitAdapter; the protocol function handles communication with GlassKit Eval. Stdout belongs to that function, so write application and dependency logs to stderr with console.error(). GlassKit Eval mirrors adapter stderr to its own stderr and quotes the most recent output in error messages. The factory runs once per eval trial and receives this context: Return an object with at least one evaluation method: The individual and batch scheduling behavior is the same as described above. Multiple evaluate calls can be active at once according to --concurrency, so shared app clients and mutable state must support that. Pass the provided AbortSignal through to backend calls when possible. Throw an error to report a failed call; otherwise return a JSON-compatible observation. Command-adapter samples contain the same information as Python samples, using lower camel case for field names: Targets use the id, index, label, and config fields described above. GlassKit-owned fields use lower camel case; keys inside the user-provided factory and target config objects are preserved unchanged. glasskit eval validate --adapter-command ... constructs and closes the adapter without evaluating samples. After answering the final close request, the adapter process must exit promptly with status 0; GlassKit Eval waits about five seconds before terminating the process and its children. Protocol messages are limited to 256 MiB in each direction, which bounds how many PNG frames one evaluateMany batch can carry. In this eval/adapter.js, replace createAppClient and its methods with thin calls into the app, then keep the marked protocol function unchanged. Application clients stay in the factory’s closure, and supported methods are detected automatically. The example uses an ECMAScript module; use .mjs or set "type": "module" in the app’s package.json when needed. For adapters in other languages, use the JavaScript implementation below as an executable protocol reference.