What Is the ModelAdapter in Maka? Architecture and Responsibilities

The ModelAdapter serves as the central bridge between Maka's runtime and underlying AI-SDK providers, normalizing streaming interfaces, translating raw provider chunks into Maka-native events, and managing provider-specific configurations including error classification, tool name remapping, and token budgets.

The ModelAdapter is a foundational abstraction in the Apache Maka project that unifies interactions with large language model providers such as OpenAI and Anthropic. Located in packages/runtime/src/model-adapter.ts, this class encapsulates provider-specific complexity while exposing a consistent streaming interface for text generation. Understanding the ModelAdapter's architecture is essential for developers extending Maka's runtime capabilities or debugging provider integrations.

Bridging Maka and AI-SDK Providers

Resolving the Provider Runtime

The adapter creates a ResolvedModelRuntime based on the connection and model ID through the resolveModel method. It evaluates runtimeEventReplaySupport to determine if the current configuration supports event replay functionality. This resolution step ensures that Maka's backend receives a standardized runtime object regardless of whether the underlying provider is OpenAI, Anthropic, or another supported SDK.

Building Provider-Specific Language Models

Using a ModelFactory, the adapter constructs provider-specific language models while injecting runtime-specific state. For example, when interfacing with OpenAI, it configures the chat reasoning transport or the OpenAI-Responses transport as needed. This factory pattern allows Maka to support provider-specific features—such as OpenAI's reasoning models—without leaking implementation details into the core runtime.

Streaming Normalization and Event Translation

Normalizing Stream Contracts

The startStream method wraps the provider's native streamText call, tracking stream activity through callbacks and enforcing a consistent streaming contract across all providers. This normalization ensures that consumer code receives uniform events whether streaming from GPT-4, Claude, or other models.

Translating Raw Chunks to Maka Events

Raw AI-SDK chunks are converted into Maka-owned ModelStreamEvent types via the translateChunk method. This translation layer ensures that only Maka-native types are exposed to the backend, isolating the system from provider-specific payload structures. The protocol definitions for these events are maintained in packages/runtime/src/model-protocol.ts.

Error Handling and Provider Normalization

Error Classification and Failure Normalization

When providers return errors, the adapter invokes normalizeProviderFailure and classifyError to transform provider-specific exceptions into standardized ModelFailure objects. This classification system, implemented in packages/runtime/src/provider-error-classification.ts, enables consistent retry logic and error reporting across heterogeneous provider implementations.

Mapping Finish Reasons and Tool Names

Provider-specific finish reasons are mapped to Maka's internal stop-reason enum through mapFinishReason. Additionally, when using the OpenAI-Responses adapter, the adapter handles tool name remapping via remapModelMessageToolNames and remapProviderToolNamesInText to ensure that Maka's persisted tool names remain consistent regardless of provider-side naming conventions.

Token Management and Continuation Control

Token Budget Calculation

The adapter computes the maximum output tokens allowed for a request through selectedModelMaxOutputTokens, enforcing budget constraints before dispatching requests to the provider. This prevents runtime failures due to context window exceeded errors.

Continuation Lanes and Replay Support

For providers like OpenAI-Responses that support lane-based continuation, the adapter manages semantic request/response pairs and exposes replay-capability flags through runtimeEventReplaySupport. This functionality enables sophisticated conversation patterns where previous turns can be replayed or continued with modified parameters.

Lifecycle Management

The adapter exposes explicit lifecycle methods to manage continuation state: endContinuation, recordContinuationResponse, clearContinuation, and dispose. These methods ensure proper cleanup of resources and state when streaming operations complete or when the adapter is destroyed.

Implementation Reference

The ModelAdapter implementation spans several key files in the apache/maka repository:

Usage Examples

Creating and using a Model Adapter

import { ModelAdapter } from './model-adapter.js';
import { resolveModelRuntime } from './model-runtime.js';

// Input needed to construct the adapter
const adapterInput = {
  sessionId: 'sess-01',
  connection: myRuntimeConnection,
  apiKey: process.env.OPENAI_API_KEY,
  modelId: 'gpt-4o-mini',
  modelFactory: myModelFactory,
  newId: () => crypto.randomUUID(),
  now: () => Date.now(),
};

// Build the adapter
const adapter = new ModelAdapter(adapterInput);

// Prepare stream input
const streamInput = {
  model: await adapter.resolveModel(),
  messages: [{ role: 'user', content: [{ type: 'text', text: 'Hello' }] }],
  tools: myToolSet,
  activeTools: [],
  onStreamActivity: () => console.log('stream activity'),
  abortSignal: new AbortController().signal,
  repairToolCall: async ({ toolCall, error }) => null,
};

// Start streaming
const result = await adapter.startStream(streamInput);

// Iterate over events
for await (const ev of result.events) {
  console.log('event:', ev);
}

// Get the final outcome
const outcome = await result.outcome;
console.log('outcome:', outcome);

Handling a streamed error

adapter.startStream(streamInput).then(({ events, outcome }) => {
  (async () => {
    for await (const ev of events) {
      if (ev.kind === 'error') {
        console.error('Stream error:', ev.failure);
      }
    }
    const final = await outcome;
    if (final.kind !== 'completed') {
      console.warn('Step failed:', final);
    }
  })();
});

Summary

  • The ModelAdapter acts as the primary abstraction layer between Maka's runtime and AI-SDK providers, handling OpenAI, Anthropic, and other implementations.
  • It normalizes streaming through startStream and translateChunk, converting provider-specific outputs into standardized ModelStreamEvent types.
  • Error handling is unified via normalizeProviderFailure and classifyError, producing consistent ModelFailure objects for all providers.
  • The adapter manages provider-specific metadata including finish reason mapping, tool name remapping, and token budget calculations via selectedModelMaxOutputTokens.
  • Continuation and replay capabilities are supported through lane-based state management and runtimeEventReplaySupport flags.
  • All implementation resides in packages/runtime/src/model-adapter.ts with supporting protocols in packages/runtime/src/model-protocol.ts.

Frequently Asked Questions

What is the primary role of the ModelAdapter in Maka?

The ModelAdapter serves as the central integration point that bridges Maka's runtime with underlying AI-SDK providers like OpenAI and Anthropic. It resolves provider runtimes, builds language models, normalizes streaming interfaces, and translates raw provider outputs into Maka-native events, ensuring a uniform interface regardless of the specific AI provider being used.

How does ModelAdapter handle streaming errors?

The adapter catches errors from the provider's streamText implementation and processes them through normalizeProviderFailure and classifyError to create standardized ModelFailure objects. These failures are then emitted as ModelStreamEvent objects with kind 'error', allowing consumer code to handle retries or logging consistently across different providers.

What is the difference between ModelAdapter and ModelFactory?

The ModelFactory creates provider-specific language model instances (such as OpenAI chat or reasoning transports), while the ModelAdapter orchestrates these instances, manages their lifecycle, and normalizes their outputs. The factory handles construction; the adapter handles integration, streaming, error translation, and state management.

How does ModelAdapter support conversation replay functionality?

Through the runtimeEventReplaySupport flag and continuation lane methods (endContinuation, recordContinuationResponse, clearContinuation), the adapter records semantic request/response pairs for compatible providers like OpenAI-Responses. This enables the runtime to replay previous conversation turns or continue lanes with modified parameters while maintaining accurate state tracking.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →