Skip to content

refactor(runtime): contain the AI SDK protocol in ModelAdapter (#1381 slice 1) - #1390

Merged
Astro-Han merged 6 commits into
apache:mainfrom
sunheyi6:refactor/model-adapter-boundary-types-1381
Jul 23, 2026
Merged

refactor(runtime): contain the AI SDK protocol in ModelAdapter (#1381 slice 1)#1390
Astro-Han merged 6 commits into
apache:mainfrom
sunheyi6:refactor/model-adapter-boundary-types-1381

Conversation

@sunheyi6

@sunheyi6sunheyi6 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Complete #1381 Slice 1 by making the main-agent ModelAdapter boundary Maka-owned end to end.

  • Define independent Maka contracts for JSON/model messages, provider-facing tool definitions, stream events, typed failures, usage, finish reasons, and final request-message metadata.
  • Keep raw AI SDK chunks, failure classification, request lowering, and response normalization inside ModelAdapter; AiSdkBackend consumes only the Maka event/result surface.
  • Preserve the existing SDK-owned multi-step loop and executable-tool behavior for this slice. Tool settlement and loop ownership remain the later refactor(runtime): make a single provider step the ModelAdapter primitive #1381 slices.
  • Keep provider request-body capture with the existing ProviderRequestTracker owner instead of retaining large request bodies a second time in the stream result.
  • Guard both source and emitted declarations against reintroducing ai / @ai-sdk/* protocol dependencies outside the adapter.

Refs #1381.

Verification

  • npm --workspace @maka/runtime test — 2,396 passed, 7 skipped, 0 failed.
  • npm --workspace @maka/runtime run typecheck — passed.
  • npm run lint — passed.
  • npm run format:check — passed.
  • Repository-wide npm run typecheck reaches the unrelated desktop baseline failure at apps/desktop/src/renderer/app-shell.tsx:1630 (onSetSkillPinned); the same failure reproduces on current main.

Review focus

This is a boundary relocation, not a provider rewrite. The production path remains singular: the AI SDK still owns the current multi-step loop, while all protocol types crossing into Runtime are now Maka-owned.

@sunheyi6
sunheyi6force-pushed the refactor/model-adapter-boundary-types-1381 branch from 9dd6fde to 9ec190cCompareJuly 23, 2026 11:06
apache#1381)
First increment of apache#1381 slice 1: establish a Maka-owned provider-boundary
type seam so AI SDK message/value types no longer cross the ModelAdapter
boundary into runtime consumers.
Add packages/runtime/src/model-protocol.ts as the single module that imports
ModelMessage / JSONValue from 'ai'. Re-point 11 runtime source consumers
(history projection, compaction, context budget, request shape, tool-output,
the adapter itself) plus 4 tests and the cli runtime bootstrap to import the
Maka-owned types instead of importing 'ai' directly. Export the boundary
types from the @maka/runtime barrel for cross-package consumers.
This is a behavior-preserving type-only seam: ModelMessage and JSONValue are
re-exported as type aliases, so the existing SDK-owned multi-step loop and
executable-tool behavior remain unchanged (one production path). Per the RFC,
schema helpers (jsonSchema/zodSchema) and SDK value imports (generateText,
RetryError, ...) stay local or are deferred to follow-up; the stream-event
and completion contracts are handled in a later slice-1 increment.
Refs apache#1381
@Astro-Han

Astro-Han commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Thanks for taking this on. The type-only import redirection is behavior-preserving and CI is green, but I don't think this is ready to merge as #1381 Slice 1 yet.

P1 — Define an actual Maka-owned protocol instead of forwarding AI SDK types

packages/runtime/src/model-protocol.ts currently defines:

exporttypeModelMessage=AiModelMessage;exporttypeJSONValue=AiJsonValue;

These aliases remain the AI SDK types. The generated declaration still imports ai, AI SDK union changes still propagate directly into runtime/CLI consumers, and @maka/runtime now publishes those aliases through its supported public barrel. This changes the import path without transferring protocol ownership.

Please define independent Maka-owned message, JSON, tool-definition, stream-event, completion, usage, finish-reason, request-metadata, and typed-failure contracts. Lower requests to AI SDK types and normalize responses back to Maka types only inside ModelAdapter.

P2 — Lock the boundary with characterization and contract tests

The changed tests only redirect imports. Slice 1 requires the existing text, signed-thinking, tool-call, usage, finish-reason, error, request-capture, and provider-matrix behavior to be characterized through the new Maka-owned contract.

Please add or adapt verification so that:

  • emitted Maka protocol declarations do not import ai or @ai-sdk/*;
  • production code outside ModelAdapter cannot consume SDK protocol types or parse raw SDK chunk names;
  • text, signed thinking, tool calls, usage, finish reasons, typed failures, request capture, and provider-matrix behavior exercise the Maka-owned adapter surface;
  • a cheap source-contract guard fails if direct SDK protocol imports are reintroduced outside the adapter boundary.

Once these points are addressed, Slice 1 should have a stable, independently useful seam while leaving the current loop behavior unchanged.

…-imports (apache#1381 slice 1)
Add a source-contract guard (mirroring containment-guard-contract) that
fails if any runtime/CLI source outside model-protocol.ts / model-adapter.ts
imports ModelMessage or JSONValue from 'ai' / '@ai-sdk/*'. This is the cheap
re-introduction guard requested in the apache#1390 review for apache#1381 slice 1, and
keeps the type-seam property established by cfeed61 enforceable as the
codebase evolves.
Verified: tsc emits with no new errors (remaining errors are pre-existing and
unrelated); node --test dist/__tests__/model-protocol-boundary-contract.test.js
passes 2/2; negative check (injecting an offending import) correctly fails.
…pache#1381 slice 1)
Complete apache#1381 slice 1 so no AI SDK type crosses the ModelAdapter boundary:
P1 — Maka-owned message/value contracts (no longer ai aliases):
model-protocol.ts now defines ModelMessage / JSONValue and every content
part type independently (structurally equivalent to @ai-sdk/provider-utils,
but owned by Maka). The emitted declaration imports nothing from ai or
@ai-sdk/* (verified).
P2 — relocate raw SDK chunk / usage / finish-reason interpretation into the
adapter; expose a Maka-owned event/result contract to the backend:
- New Maka-owned contracts in model-protocol.ts: NormalizedUsage,
RawUsageFields, ModelFinishReason, ModelStreamEvent (discriminated),
ModelStreamResult.
- ModelAdapter.startStream now returns ModelStreamResult: a lazy
async iterable of ModelStreamEvent (translated from raw SDK chunks by the
new adapter-internal translateChunk), plus normalized and
finishReason promises. handleStreamChunk / ModelAdapterStreamCallbacks /
the exported StreamTextResult / AiSdkStreamChunk types are retired
(AiSdkStreamChunk stays adapter-internal).
- AiSdkBackend now iterates result.events and switches on event.kind; it no
longer parses raw SDK chunk names, calls normalizeAiSdkUsage/
rawFinishReasonString, or touches raw usage. text/thinking SessionEvent
deltas and step accounting are driven by Maka events.
P2 — lock the boundary with a source-contract guard and characterization:
- model-protocol-boundary-contract.test.ts fails if any source outside
model-protocol.ts / model-adapter.ts re-imports the protocol symbols from
ai / @ai-sdk/*.
- model-adapter.test.ts now characterizes translateChunk through the
Maka-owned ModelStreamEvent output (text/thinking/signature/step-finish/
error); the ai-sdk-backend capped-stream fixture drives the backend
through the new event contract.
Behavior-preserving relocation: the SDK-owned multi-step loop, executable-tool
behavior, and single production path are unchanged (slice 3 work). Schema
helpers (jsonSchema/zodSchema) and RetryError/generateText/LanguageModel value
imports remain local (RFC apache#1381 follow-up Q2/Q4).
Verified: tsc error count unchanged (178 -> 178, all pre-existing); dist tests
green — model-adapter 19/19, ai-sdk-backend 158/158, active-tool-result-prune
13/13, active-full-compact 22/22, semantic-compact 18/18, boundary guard 2/2,
deferred-tools + onerror pass. provider-contract-matrix 111/113 is unchanged
from baseline (2 pre-existing failures).
Refs apache#1381
@Astro-Han

Copy link
Copy Markdown
Contributor
English

The latest changes fix the central aliasing problem: ModelMessage / JSONValue are now Maka-owned, and raw stream chunks are translated inside ModelAdapter. The previous review is only partially resolved, though.

P1 — CI is still failing

The test job has two failures in tool-runtime-extraction-contract.test.ts. The contract still requires handleStreamChunk(), although the new event-based boundary intentionally removed it.

Please update the extraction contract to assert the new ownership:

  • AiSdkBackend consumes result.events;
  • raw chunk interpretation remains in ModelAdapter;
  • the removed handleStreamChunk() path is not restored.

P2 — The boundary guard permits the original regression

model-protocol-boundary-contract.test.ts includes both model-protocol.ts and model-adapter.ts in ALLOWED_HOMES. Consequently, model-protocol.ts could return to importing and aliasing ModelMessage / JSONValue from ai, and the guard would still pass.

Only the adapter should be allowed to depend on SDK protocol types. Please also assert that the emitted model-protocol.d.ts has no ai or @ai-sdk/* imports.

P2 — The Slice 1 owned contract remains incomplete

Several contracts requested by #1381 and the previous review are still missing:

  • ModelAdapterStreamInput.tools remains Record<string, unknown> instead of a Maka-owned tool-definition contract;
  • ModelStreamEvent carries error: unknown instead of a typed Maka failure;
  • the stream result exposes no Maka-owned request metadata.

Please complete these contracts before treating this PR as Slice 1’s finished boundary.

P3 — The PR description is stale

It still describes model-protocol.ts as an AI SDK alias module and says stream/result conversion is out of scope, although the latest commit now implements both.

Once CI is green and these boundary gaps are closed, this should be ready for another review.

简体中文

最新改动已经修正了核心的类型别名问题:ModelMessage / JSONValue 现在是 Maka 自己拥有的类型,原始 stream chunk 也已经在 ModelAdapter 内转换。不过,上一次 review 目前只解决了一部分。

P1 — CI 仍然失败

当前 test job 在 tool-runtime-extraction-contract.test.ts 中有两个失败。契约测试仍然要求存在 handleStreamChunk(),但新的 event-based boundary 已经有意删除了这条路径。

请更新 extraction contract,使其验证新的 ownership:

  • AiSdkBackend 消费 result.events
  • 原始 chunk 的解释只留在 ModelAdapter
  • 不要恢复已经删除的 handleStreamChunk() 路径。

P2 — 边界 guard 允许原问题回归

model-protocol-boundary-contract.test.tsmodel-protocol.tsmodel-adapter.ts 都放进了 ALLOWED_HOMES。因此,即使 model-protocol.ts 重新从 ai 导入并给 ModelMessage / JSONValue 建别名,这个 guard 仍然会通过。

只有 adapter 应被允许依赖 SDK protocol 类型。同时请验证生成的 model-protocol.d.ts 不包含任何 ai@ai-sdk/* import。

P2 — Slice 1 的 owned contract 仍不完整

#1381 和上一次 review 要求的几个 contract 仍然缺失:

  • ModelAdapterStreamInput.tools 仍是 Record<string, unknown>,还不是 Maka-owned tool-definition contract;
  • ModelStreamEvent 仍携带 error: unknown,还不是 typed Maka failure;
  • stream result 没有暴露 Maka-owned request metadata。

在把这个 PR 视为 Slice 1 的完整边界之前,请补齐这些 contract。

P3 — PR 正文已经过时

正文仍把 model-protocol.ts 描述为 AI SDK 类型别名模块,并称 stream/result conversion 不在范围内,但最新 commit 已经实现了这两项。

等 CI 恢复绿色并补齐这些边界缺口后,就可以再次 review。

sunheyi6and others added 3 commits July 23, 2026 20:49
…wned event surface (apache#1381 slice 1)
tool-runtime-extraction-contract regexed the retired adapter shape
(handleStreamChunk on the backend, normalizeAiSdkUsage(await result.usage, ...),
result.stream). Re-point it at the new boundary: the backend iterates
result.events and switches on event.kind (never parses raw SDK chunk names or
calls normalizeAiSdkUsage); the adapter owns translateChunk (the chunk->event
lowering) plus makeErrorEvent/mapFinishReason/normalizeAiSdkUsage. Add
doesNotMatch guards for handleStreamChunk / normalizeAiSdkUsage(await result.usage
/ result.stream on the backend.
Verified: tool-runtime-extraction-contract 8/8; full streaming suite green
(model-adapter 19/19, ai-sdk-backend 158/158, boundary guard 2/2, plus
active-tool-result-prune / active-full-compact / semantic-compact /
deferred-tools / onerror / computer-use-model-loop / mid-turn-capacity /
overflow-reactive-recovery all pass).
@Astro-HanAstro-Han changed the title refactor(runtime): own ModelMessage/JSONValue behind ModelAdapter seam (#1381 slice 1)refactor(runtime): contain the AI SDK protocol in ModelAdapter (#1381 slice 1)Jul 23, 2026
@Astro-Han
Astro-Han merged commit 3249f2a into apache:mainJul 23, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@sunheyi6@Astro-Han