ModLens VisionProvider Interface: Methods, Types, and Implementation Patterns
The VisionProvider interface in src/providers/index.ts defines the common contract that all ModLens vision providers must satisfy, exposing both subprocess-based and in-process API execution patterns through optional methods like buildInvocation, execute, and parseOutput.
The ModLens repository (liustack/modlens) provides a unified framework for integrating vision language models through a single, extensible provider interface. The VisionProvider interface establishes the mandatory properties and optional methods that every provider—from CLI wrappers like antigravity-cli to direct API clients like gemini-api—must implement to participate in the analysis pipeline.
Core VisionProvider Interface Structure
The VisionProvider interface is defined in [src/providers/index.ts](https://github.com/liustack/modlens/blob/main/src/providers/index.ts) and serves as the central abstraction for all vision providers. It accommodates two distinct execution models: subprocess providers that spawn external CLI tools, and in-process providers that make direct API calls.
export interface VisionProvider {
/** Human‑readable identifier (e.g. “antigravity-cli”). */
name: string;
/** Default model name used when the caller does not specify one. */
defaultModel: string;
/** Sub‑process providers: construct a child‑process command line. */
buildInvocation?: (options: BuildProviderInvocationOptions) => ProviderInvocation;
/** Sub‑process providers: turn raw stdout into structured output. */
parseOutput?: (stdout: string) => ProviderParsedOutput;
/** In‑process API providers: directly perform the request. */
execute?: (options: BuildProviderInvocationOptions) => Promise<ProviderParsedOutput>;
/** Turn a non‑zero exit or error into a friendly message. */
describeFailure?: (context: ProviderFailureContext) => string | Error | null;
/** Does the provider enforce its own timeout? (e.g. agy’s `--print-timeout`) */
hasInternalTimeout?: boolean;
/** Should the analyzer run the provider in an isolated work‑dir? */
isolateWorkdir?: boolean;
/** Optional warning shown when a route is reused from another harness. */
reuseNote?: string;
}
Required Properties
Every VisionProvider implementation must define two core properties:
name: A human-readable string identifier (e.g.,"antigravity-cli","gemini-api") used for provider resolution and logging.defaultModel: The default model name invoked when the caller does not explicitly specify one inBuildProviderInvocationOptions.
These properties appear at the top of every provider export, such as antigravityCliProvider in [src/providers/antigravity.ts](https://github.com/liustack/modlens/blob/main/src/providers/antigravity.ts).
Execution Patterns: Subprocess vs. In-Process
The interface supports two mutually exclusive execution strategies. Providers implement one pattern based on their underlying architecture.
Subprocess Providers
Subprocess providers wrap external CLI executables and must implement:
buildInvocation: A function acceptingBuildProviderInvocationOptionsand returning aProviderInvocationobject containing thecommand,args,cwd, and optionalenvfor the child process.parseOutput: A function that transforms raw stdout strings into structuredProviderParsedOutputobjects according to the ModLens schema.
This pattern is used by providers like antigravity-cli, kimi-cli, and claude-cli, which shell out to local binaries.
In-Process API Providers
In-process API providers make direct HTTP calls or SDK invocations within the Node.js process and must implement:
execute: An async function acceptingBuildProviderInvocationOptionsand returning aPromise<ProviderParsedOutput>directly, bypassing subprocess management.
This pattern appears in [src/providers/geminiApi.ts](https://github.com/liustack/modlens/blob/main/src/providers/geminiApi.ts) and [src/providers/anthropicApi.ts](https://github.com/liustack/modlens/blob/main/src/providers/anthropicApi.ts), where the provider directly interfaces with cloud APIs.
Utility and Configuration Methods
The VisionProvider interface includes optional configuration flags and error handling utilities:
describeFailure: Transforms subprocess exit codes, stderr, or API errors into user-friendly messages. Accepts aProviderFailureContextobject containingstdout,stderr,code, andstartedAt.hasInternalTimeout: A boolean flag indicating whether the provider manages its own timeout logic (e.g., Antigravity's--print-timeoutflag).isolateWorkdir: Whentrue, instructs the analyzer to execute the provider in an isolated temporary directory.reuseNote: An optional warning string displayed when a test route is reused from another harness.
Supporting Types for Type Safety
The interface relies on several supporting types defined in the same [src/providers/index.ts](https://github.com/liustack/modlens/blob/main/src/providers/index.ts) file:
ProviderInvocation(lines 9‑15): Describes the child process configuration withcommand,args,cwd, and optionalenv.BuildProviderInvocationOptions(lines 17‑28): Input parameters passed to bothbuildInvocationandexecute, includingimageSource,imageKind,timeoutMs,model, andextraPrompt.ProviderParsedOutput(lines 30‑37): The normalized return structure containing theresultstring and optional metadata.ProviderFailureContext(lines 40‑46): Context object for error handling withstdout,stderr,code, andstartedAttimestamp.
Implementation Examples
Resolving a Provider by Name
Use the resolveProvider utility to retrieve a VisionProvider implementation by its string identifier:
import { resolveProvider } from './providers/index.ts';
const provider = resolveProvider('gemini-api');
console.log(provider.name); // "gemini-api"
console.log(provider.defaultModel); // Default model for Gemini
Building Subprocess Commands
For CLI-based providers like antigravity-cli, construct the invocation using buildInvocation:
import { resolveProvider } from './providers/index.ts';
import type { BuildProviderInvocationOptions } from './providers/index.ts';
const options: BuildProviderInvocationOptions = {
imageSource: '/tmp/screenshot.png',
imageKind: 'local',
timeoutMs: 30_000,
};
const provider = resolveProvider('antigravity-cli');
if (provider.buildInvocation) {
const invocation = provider.buildInvocation(options);
// Returns: { command: 'agy', args: ['--image', '/tmp/screenshot.png'], cwd: '/tmp' }
}
Executing Direct API Calls
For API providers like gemini-api, use the execute method for in-process requests:
import { resolveProvider } from './providers/index.ts';
const opts = {
imageSource: 'https://example.com/image.jpg',
imageKind: 'remote',
timeoutMs: 20_000,
model: 'gemini-1.5-flash',
};
const provider = resolveProvider('gemini-api');
if (provider.execute) {
const result = await provider.execute(opts);
console.log(result.result); // Structured vision analysis
}
Handling Provider Failures
Implement graceful error handling using describeFailure:
import { resolveProvider } from './providers/index.ts';
import type { ProviderFailureContext } from './providers/index.ts';
const provider = resolveProvider('antigravity-cli');
if (provider.describeFailure) {
const context: ProviderFailureContext = {
stdout: '',
stderr: 'quota exceeded',
code: 1,
startedAt: Date.now() - 5000,
};
const message = provider.describeFailure(context);
console.warn(message); // User-friendly error description
}
Concrete Provider Implementations
The ModLens repository includes several reference implementations conforming to VisionProvider:
src/providers/antigravity.ts: Implements subprocess pattern withbuildInvocation,parseOutput, anddescribeFailure.src/providers/geminiApi.ts: Implements in-process pattern using theexecutemethod for Google Gemini API.src/providers/openaiCompat.ts: Wraps OpenAI-compatible endpoints as aVisionProvider.src/providers/anthropicApi.ts: Implements forced tool-call style interactions with Anthropic's API.src/providers/kimi-cli.tsandclaude-cli.ts: Additional subprocess-based providers for local CLI tools.
Summary
- The
VisionProviderinterface insrc/providers/index.tsis the common contract all ModLens providers must implement. - Required properties are
nameanddefaultModel; all execution methods are optional but providers must implement either the subprocess pair (buildInvocation/parseOutput) or the in-process method (execute). - Supporting types like
ProviderInvocation,BuildProviderInvocationOptions, andProviderFailureContextensure type safety across the provider boundary. - Concrete implementations demonstrate both CLI-wrapping (antigravity-cli) and native API (gemini-api) patterns.
- Optional flags like
hasInternalTimeoutandisolateWorkdirallow providers to signal specific runtime requirements to the analyzer.
Frequently Asked Questions
What is the difference between buildInvocation and execute in the ModLens VisionProvider interface?
buildInvocation is used by subprocess providers to construct a shell command (returning command, args, and cwd), while execute is used by in-process API providers to perform direct SDK or HTTP calls and return a Promise<ProviderParsedOutput>. A provider should implement one pattern or the other, never both.
How does the describeFailure method improve error handling in ModLens providers?
The describeFailure method receives a ProviderFailureContext object containing stdout, stderr, code, and startedAt, allowing providers to translate cryptic exit codes or API errors into actionable, user-friendly strings. If not implemented, the analyzer falls back to generic error messages.
Which providers in the ModLens repository implement the VisionProvider interface?
All concrete providers export an object conforming to VisionProvider, including antigravity-cli (src/providers/antigravity.ts), gemini-api (src/providers/geminiApi.ts), openai-compat (src/providers/openaiCompat.ts), anthropic-api (src/providers/anthropicApi.ts), kimi-cli, and claude-cli.
When should a provider set isolateWorkdir to true?
Set isolateWorkdir to true when the provider creates temporary files, modifies the filesystem, or requires a clean state between runs. This flag instructs the ModLens analyzer to execute the provider in a temporary directory that is cleaned up after execution, preventing state pollution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →