# ModLens VisionProvider Interface: Methods, Types, and Implementation Patterns

> Explore the ModLens VisionProvider interface, its key methods like buildInvocation and execute, and understand how it unifies subprocess and in-process API execution patterns.

- Repository: [liustack/modlens](https://github.com/liustack/modlens)
- Tags: api-reference
- Published: 2026-08-25

---

**The `VisionProvider` interface in [`src/providers/index.ts`](https://github.com/liustack/modlens/blob/main/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)](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.

```typescript
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 in `BuildProviderInvocationOptions`.

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)](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 accepting `BuildProviderInvocationOptions` and returning a `ProviderInvocation` object containing the `command`, `args`, `cwd`, and optional `env` for the child process.
- **`parseOutput`**: A function that transforms raw stdout strings into structured `ProviderParsedOutput` objects 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 accepting `BuildProviderInvocationOptions` and returning a `Promise<ProviderParsedOutput>` directly, bypassing subprocess management.

This pattern appears in **[[`src/providers/geminiApi.ts`](https://github.com/liustack/modlens/blob/main/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)](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 a `ProviderFailureContext` object containing `stdout`, `stderr`, `code`, and `startedAt`.
- **`hasInternalTimeout`**: A boolean flag indicating whether the provider manages its own timeout logic (e.g., Antigravity's `--print-timeout` flag).
- **`isolateWorkdir`**: When `true`, 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 with `command`, `args`, `cwd`, and optional `env`.
- **`BuildProviderInvocationOptions`** (lines 17‑28): Input parameters passed to both `buildInvocation` and `execute`, including `imageSource`, `imageKind`, `timeoutMs`, `model`, and `extraPrompt`.
- **`ProviderParsedOutput`** (lines 30‑37): The normalized return structure containing the `result` string and optional metadata.
- **`ProviderFailureContext`** (lines 40‑46): Context object for error handling with `stdout`, `stderr`, `code`, and `startedAt` timestamp.

## Implementation Examples

### Resolving a Provider by Name

Use the `resolveProvider` utility to retrieve a `VisionProvider` implementation by its string identifier:

```typescript
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`:

```typescript
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:

```typescript
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`:

```typescript
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`](https://github.com/liustack/modlens/blob/main/src/providers/antigravity.ts)**: Implements subprocess pattern with `buildInvocation`, `parseOutput`, and `describeFailure`.
- **[`src/providers/geminiApi.ts`](https://github.com/liustack/modlens/blob/main/src/providers/geminiApi.ts)**: Implements in-process pattern using the `execute` method for Google Gemini API.
- **[`src/providers/openaiCompat.ts`](https://github.com/liustack/modlens/blob/main/src/providers/openaiCompat.ts)**: Wraps OpenAI-compatible endpoints as a `VisionProvider`.
- **[`src/providers/anthropicApi.ts`](https://github.com/liustack/modlens/blob/main/src/providers/anthropicApi.ts)**: Implements forced tool-call style interactions with Anthropic's API.
- **[`src/providers/kimi-cli.ts`](https://github.com/liustack/modlens/blob/main/src/providers/kimi-cli.ts)** and **[`claude-cli.ts`](https://github.com/liustack/modlens/blob/main/claude-cli.ts)**: Additional subprocess-based providers for local CLI tools.

## Summary

- The `VisionProvider` interface in [`src/providers/index.ts`](https://github.com/liustack/modlens/blob/main/src/providers/index.ts) is the common contract all ModLens providers must implement.
- Required properties are `name` and `defaultModel`; 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`, and `ProviderFailureContext` ensure type safety across the provider boundary.
- Concrete implementations demonstrate both CLI-wrapping (antigravity-cli) and native API (gemini-api) patterns.
- Optional flags like `hasInternalTimeout` and `isolateWorkdir` allow 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`](https://github.com/liustack/modlens/blob/main/src/providers/antigravity.ts)), **gemini-api** ([`src/providers/geminiApi.ts`](https://github.com/liustack/modlens/blob/main/src/providers/geminiApi.ts)), **openai-compat** ([`src/providers/openaiCompat.ts`](https://github.com/liustack/modlens/blob/main/src/providers/openaiCompat.ts)), **anthropic-api** ([`src/providers/anthropicApi.ts`](https://github.com/liustack/modlens/blob/main/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.