源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,681 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
# Runtime v2 Architecture Evolution
|
||||
|
||||
> Archived on 2026-07-13. This proposal records the route to the current runtime; it is not current architecture authority. Start with `ARCHITECTURE.md`.
|
||||
|
||||
This document proposes a long-term evolution path for Maka's agent runtime. It
|
||||
is written for developers who need to understand why the runtime needs another
|
||||
architecture pass, what should stay stable, and how the codebase can move there
|
||||
without a big-bang rewrite.
|
||||
|
||||
The goal is not to replace the Vercel AI SDK. The goal is to make Maka own its
|
||||
runtime semantics while continuing to use the AI SDK as the main model/tool
|
||||
stepping engine.
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Maka already has a working local coding agent runtime:
|
||||
|
||||
- Electron desktop entry points
|
||||
- session JSONL storage
|
||||
- model streaming through the AI SDK
|
||||
- tool execution and permission prompts
|
||||
- abort handling
|
||||
- bot and OpenGateway entry points
|
||||
- tool artifacts and usage telemetry
|
||||
- an internal `AgentRun` ledger
|
||||
|
||||
The current architecture is better than the original monolithic path, but the
|
||||
runtime still lacks one stable center of gravity. The same run is currently
|
||||
represented through several related but separate structures:
|
||||
|
||||
- `StoredMessage` in the session JSONL
|
||||
- renderer-facing `SessionEvent`
|
||||
- `AgentRunEvent` in the run ledger
|
||||
- best-effort `RunTraceEvent`
|
||||
- telemetry records
|
||||
|
||||
That split makes the system hard to evolve. It also makes important questions
|
||||
harder than they should be:
|
||||
|
||||
- Which facts are the real runtime truth?
|
||||
- Which objects are only UI projections?
|
||||
- Which events should be replayed into the next model request?
|
||||
- Which events are diagnostic-only?
|
||||
- Where should permission, tool, recovery, and telemetry semantics live?
|
||||
|
||||
Runtime v2 should introduce a canonical invocation/event spine:
|
||||
|
||||
```text
|
||||
RuntimeRunner
|
||||
-> InvocationContext
|
||||
-> AgentFlow
|
||||
-> AiSdkFlow
|
||||
-> AI SDK streamText
|
||||
-> ToolRuntime
|
||||
-> RuntimeEvent ledger
|
||||
-> projections
|
||||
```
|
||||
|
||||
The key shift is:
|
||||
|
||||
```text
|
||||
Today:
|
||||
SessionManager + StoredMessage/SessionEvent are close to the runtime center.
|
||||
|
||||
Target:
|
||||
Invocation + RuntimeEvent + AgentFlow are the runtime center.
|
||||
StoredMessage, renderer SessionEvent, AgentRunStore, RunTrace, and telemetry
|
||||
become projections or ledgers derived from canonical runtime facts.
|
||||
```
|
||||
|
||||
## Design Inputs
|
||||
|
||||
This proposal is based on the current Maka implementation and on the runtime
|
||||
structure documented in the Google ADK Go reading materials. The useful lesson
|
||||
from ADK is not to copy type names directly. The useful lesson is the layering:
|
||||
|
||||
```text
|
||||
Runner -> Agent -> Flow -> Model/Tool -> Event -> Session
|
||||
```
|
||||
|
||||
In that model:
|
||||
|
||||
- `Runner` owns the invocation shell and persistence boundary.
|
||||
- `Agent` owns lifecycle and routing.
|
||||
- `Flow` owns the model/tool loop.
|
||||
- `Event` is the shared runtime fact language.
|
||||
- `Session` stores durable history and scoped state.
|
||||
- tool, callback, plugin, instruction, workflow, entrypoint, and telemetry
|
||||
layers attach around that axis without becoming the axis themselves.
|
||||
|
||||
Maka has different product constraints, so the evolution should be adapted:
|
||||
|
||||
- keep the AI SDK as the long-term main flow implementation;
|
||||
- preserve Electron and existing user-visible session behavior;
|
||||
- preserve existing JSONL compatibility;
|
||||
- reuse `ToolRuntime`, `AgentRunStore`, and `RunTrace`;
|
||||
- avoid a flag day where all storage and UI projections change at once.
|
||||
|
||||
## Current Runtime Path
|
||||
|
||||
Today, one user turn approximately flows like this:
|
||||
|
||||
```text
|
||||
renderer / bot / gateway
|
||||
-> desktop main / entrypoint code
|
||||
-> ensureSessionCanSend(...)
|
||||
-> SessionManager.sendMessage(sessionId, input)
|
||||
-> new AgentRun(...)
|
||||
-> AgentRun.execute()
|
||||
-> append user StoredMessage
|
||||
-> append turn_state=running
|
||||
-> lock connection snapshot
|
||||
-> ensureActive() / build AiSdkBackend
|
||||
-> register active run
|
||||
-> AiSdkBackend.send()
|
||||
-> PermissionEngine.beginTurn()
|
||||
-> RunTrace
|
||||
-> ModelAdapter.resolveModel()
|
||||
-> build AI SDK tool map
|
||||
-> materialize prior StoredMessage[] into AI SDK messages
|
||||
-> AI SDK streamText({ tools, stopWhen: stepCountIs(maxSteps) })
|
||||
-> AI SDK owns model -> tool -> model stepping
|
||||
-> tool.execute(...) calls ToolRuntime
|
||||
-> pump fullStream into SessionEvent queue
|
||||
-> append assistant StoredMessage
|
||||
-> append token_usage StoredMessage
|
||||
-> queue complete/error/abort
|
||||
-> AgentRun updates SessionHeader / turn_state / AgentRunStore
|
||||
-> cleanup active run
|
||||
```
|
||||
|
||||
This split has some good properties:
|
||||
|
||||
- `SessionManager.sendMessage()` no longer owns the whole hot path.
|
||||
- `AgentRun` gives a durable run lifecycle record.
|
||||
- `ToolRuntime` is a real boundary for tool permission, execution, artifacts,
|
||||
and tool telemetry.
|
||||
- `ModelAdapter` isolates provider/AI SDK stream and error normalization.
|
||||
|
||||
But it also has structural limits:
|
||||
|
||||
- Maka does not have its own explicit `Flow.Run`; the model/tool loop is
|
||||
implicit inside `AiSdkBackend.send()` plus the AI SDK.
|
||||
- Cross-turn model history is built from selected `StoredMessage` types, not
|
||||
from a canonical runtime event history.
|
||||
- tool calls and tool results are persisted for UI/history, but their role in
|
||||
future model context is an implicit policy inside `materializePriorMessages()`.
|
||||
- permission and tool events are represented across `StoredMessage`,
|
||||
`SessionEvent`, `RunTraceEvent`, and telemetry rather than one canonical fact.
|
||||
- entrypoints still own some runtime readiness semantics, such as connection
|
||||
readiness/rebind checks.
|
||||
|
||||
## Target Architecture
|
||||
|
||||
The target architecture keeps the AI SDK as the primary model/tool stepping
|
||||
engine, but wraps it in Maka-owned invocation and event semantics.
|
||||
|
||||
```text
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ Entrypoint Adapters │
|
||||
│ │
|
||||
│ Desktop IPC Bot Gateway OpenGateway │
|
||||
│ - parse input - parse input - parse HTTP │
|
||||
│ - validate shape - auth/rate limit - SSE/JSON │
|
||||
│ - broadcast output - send bot reply - gateway output │
|
||||
│ │
|
||||
│ Entrypoints are protocol adapters. They do not own runtime loop, │
|
||||
│ readiness, recovery, or model/tool policy. │
|
||||
└──────────────────────────────┬─────────────────────────────────────┘
|
||||
│ RuntimeRequest
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ RuntimeRunner │
|
||||
│ │
|
||||
│ - RuntimeGate preflight │
|
||||
│ - create invocation/run context │
|
||||
│ - append user RuntimeEvent │
|
||||
│ - resolve active agent/flow policy │
|
||||
│ - run AgentFlow │
|
||||
│ - persist canonical events │
|
||||
│ - drive projections │
|
||||
└──────────────────────────────┬─────────────────────────────────────┘
|
||||
│ InvocationContext
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ AgentFlow Interface │
|
||||
│ │
|
||||
│ interface AgentFlow { │
|
||||
│ run(ctx, input): AsyncIterable<RuntimeEvent> │
|
||||
│ } │
|
||||
│ │
|
||||
│ AiSdkFlow is the default long-term implementation: │
|
||||
│ │
|
||||
│ - build AI SDK messages from runtime history projection │
|
||||
│ - build AI SDK tool map │
|
||||
│ - call streamText({ tools, stopWhen: stepCountIs(...) }) │
|
||||
│ - map text/thinking/tool/usage/finish/error to RuntimeEvent │
|
||||
│ - delegate tool execution to ToolRuntime │
|
||||
└──────────────────────────────┬─────────────────────────────────────┘
|
||||
│ tool.execute seam
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ ToolRuntime │
|
||||
│ │
|
||||
│ - declaration/schema/registry │
|
||||
│ - permission evaluation and parked decisions │
|
||||
│ - tool implementation execution │
|
||||
│ - output deltas and artifacts │
|
||||
│ - tool telemetry │
|
||||
│ - RuntimeEvent(tool_call/tool_result/permission/artifact) │
|
||||
│ - returns result to AI SDK so streamText can continue stepping │
|
||||
└────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Shared services sit beside this path:
|
||||
|
||||
```text
|
||||
RuntimeEventLedger
|
||||
canonical invocation facts
|
||||
|
||||
ProjectionManager
|
||||
RuntimeEvent -> StoredMessage JSONL
|
||||
RuntimeEvent -> renderer SessionEvent stream
|
||||
RuntimeEvent -> TurnRecord / SessionHeader
|
||||
RuntimeEvent -> AgentRunStore / RunTrace
|
||||
RuntimeEvent -> TelemetryRepo
|
||||
|
||||
SessionService
|
||||
event history + scoped state
|
||||
legacy JSONL compatibility
|
||||
|
||||
RuntimeGate
|
||||
readiness / rebind / blocked/running/waiting guards
|
||||
|
||||
Plugin / Callback / Instruction
|
||||
prompt injection / audit / retry-reflect / telemetry hooks
|
||||
```
|
||||
|
||||
## Canonical RuntimeEvent
|
||||
|
||||
Runtime v2 needs a single internal fact model. A sketch:
|
||||
|
||||
```ts
|
||||
type RuntimeEvent = {
|
||||
id: string;
|
||||
invocationId: string;
|
||||
runId: string;
|
||||
sessionId: string;
|
||||
turnId: string;
|
||||
ts: number;
|
||||
|
||||
author: 'user' | 'agent' | 'tool' | 'system';
|
||||
role: 'user' | 'model' | 'tool' | 'system';
|
||||
branch?: string;
|
||||
partial: boolean;
|
||||
|
||||
content?: {
|
||||
text?: string;
|
||||
thinking?: string;
|
||||
functionCall?: {
|
||||
id: string;
|
||||
name: string;
|
||||
args: unknown;
|
||||
};
|
||||
functionResponse?: {
|
||||
id: string;
|
||||
name: string;
|
||||
result: unknown;
|
||||
isError?: boolean;
|
||||
};
|
||||
error?: {
|
||||
code?: string;
|
||||
reason?: string;
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
actions?: {
|
||||
stateDelta?: Record<string, unknown>;
|
||||
artifactDelta?: Record<string, string | number>;
|
||||
permissionRequest?: PermissionRequest;
|
||||
permissionDecision?: PermissionDecision;
|
||||
transferToAgent?: string;
|
||||
endInvocation?: boolean;
|
||||
tokenUsage?: TokenUsage;
|
||||
};
|
||||
|
||||
refs?: {
|
||||
storedMessageId?: string;
|
||||
traceEventId?: string;
|
||||
toolCallId?: string;
|
||||
providerEventId?: string;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
This event is not a UI event and not a trace event. It is the internal runtime
|
||||
fact. Other records should either be written from it or be explicitly linked to
|
||||
it.
|
||||
|
||||
## Consumption Paths
|
||||
|
||||
### Desktop User Message
|
||||
|
||||
```text
|
||||
Renderer
|
||||
-> preload IPC
|
||||
-> main IPC handler
|
||||
-> normalize input
|
||||
-> validate attachment shape
|
||||
-> RuntimeRunner.run({ source: 'desktop', sessionId, text, attachments })
|
||||
-> RuntimeGate.preflight()
|
||||
-> create invocation
|
||||
-> append RuntimeEvent(user)
|
||||
-> ProjectionManager writes user StoredMessage and renderer append event
|
||||
-> AiSdkFlow.run(ctx)
|
||||
-> build AI SDK messages from runtime history projection
|
||||
-> streamText(...)
|
||||
-> partial model chunks -> RuntimeEvent(partial model text)
|
||||
-> final model output -> RuntimeEvent(final model text)
|
||||
-> tool calls go through ToolRuntime
|
||||
-> ProjectionManager writes:
|
||||
-> assistant StoredMessage
|
||||
-> TurnRecord
|
||||
-> SessionHeader
|
||||
-> AgentRun ledger status
|
||||
-> telemetry usage/tool records
|
||||
-> main process streams projected SessionEvents back to renderer
|
||||
```
|
||||
|
||||
The renderer consumes a projection stream. It does not consume the runtime core
|
||||
directly.
|
||||
|
||||
### Tool Call and Permission
|
||||
|
||||
```text
|
||||
AiSdkFlow
|
||||
-> AI SDK asks tool.execute({ args, toolCallId })
|
||||
-> ToolRuntime.executeTool()
|
||||
-> RuntimeEvent(tool_call)
|
||||
-> StoredMessage tool_call
|
||||
-> renderer tool_start
|
||||
-> PermissionEngine.evaluate()
|
||||
├─ allow
|
||||
│ -> run tool.impl
|
||||
│ -> RuntimeEvent(tool_result)
|
||||
│ -> return result to AI SDK
|
||||
│
|
||||
├─ block
|
||||
│ -> RuntimeEvent(tool_result isError synthetic)
|
||||
│ -> return synthetic error result to AI SDK
|
||||
│
|
||||
└─ prompt
|
||||
-> RuntimeEvent(permission_request)
|
||||
-> renderer permission modal
|
||||
-> session waiting_for_user projection
|
||||
-> park tool execution
|
||||
-> respondPermission(...)
|
||||
-> RuntimeEvent(permission_decision)
|
||||
-> allow/deny branch
|
||||
```
|
||||
|
||||
Permission is a runtime action, not just a UI event. It should be represented in
|
||||
`RuntimeEvent.actions`.
|
||||
|
||||
### Model History Construction
|
||||
|
||||
Today, model history is built from stored messages and skips several runtime
|
||||
message types. Runtime v2 should make this an explicit projection:
|
||||
|
||||
```text
|
||||
RuntimeEvent history
|
||||
-> ModelHistoryProjector
|
||||
include:
|
||||
user text events
|
||||
model final text events
|
||||
selected system/instruction events
|
||||
function call events when required by the provider protocol
|
||||
tool function response events
|
||||
exclude:
|
||||
partial chunks
|
||||
token usage
|
||||
trace diagnostics
|
||||
UI-only system notes
|
||||
permission ack unless deliberately exposed to the model
|
||||
-> AI SDK messages
|
||||
```
|
||||
|
||||
This makes the "what does the next model call see?" policy reviewable and
|
||||
testable.
|
||||
|
||||
### Startup Recovery
|
||||
|
||||
```text
|
||||
App startup
|
||||
-> RuntimeRecovery.scan()
|
||||
-> read invocation/run ledger
|
||||
-> classify non-terminal invocations by latest RuntimeEvent:
|
||||
- model stream started with no terminal event -> failed app_restarted
|
||||
- tool started with no result -> failed interrupted_tool
|
||||
- permission_request pending -> waiting_for_user or failed by policy
|
||||
- final model event persisted but run header not completed -> complete it
|
||||
-> append recovery RuntimeEvent
|
||||
-> ProjectionManager repairs:
|
||||
- TurnRecord
|
||||
- SessionHeader
|
||||
- StoredMessage system note if needed
|
||||
- AgentRun terminal status
|
||||
```
|
||||
|
||||
Recovery should reason from canonical invocation facts first and then repair
|
||||
projections. It should not independently guess from multiple stores unless it is
|
||||
handling legacy data.
|
||||
|
||||
### Bot and OpenGateway
|
||||
|
||||
```text
|
||||
Bot / OpenGateway
|
||||
-> normalize external protocol
|
||||
-> RuntimeRunner.run({ source: 'bot' | 'gateway', ... })
|
||||
-> same RuntimeGate
|
||||
-> same AiSdkFlow
|
||||
-> same ToolRuntime
|
||||
-> projected output:
|
||||
bot: collect final response and send bot reply
|
||||
gateway: format JSON/SSE response
|
||||
desktop: optional fan-out when the same session is visible
|
||||
```
|
||||
|
||||
The runtime should not have three subtly different send paths for desktop, bot,
|
||||
and gateway.
|
||||
|
||||
## Source of Truth Boundaries
|
||||
|
||||
The intended boundary is:
|
||||
|
||||
```text
|
||||
RuntimeEventLedger
|
||||
runtime fact
|
||||
|
||||
StoredMessage JSONL
|
||||
user-visible conversation projection and legacy read model
|
||||
|
||||
renderer SessionEvent
|
||||
transport projection for UI streaming
|
||||
|
||||
AgentRunStore
|
||||
invocation/run lifecycle ledger, eventually closely linked with RuntimeEvent
|
||||
|
||||
RunTrace
|
||||
diagnostic-only projection; failures must not affect execution
|
||||
|
||||
TelemetryRepo
|
||||
economic and operational projection
|
||||
```
|
||||
|
||||
This boundary is the main reason to do the work. Without it, adding more
|
||||
features will keep increasing the number of places that need to agree about the
|
||||
same run.
|
||||
|
||||
## Proposed Module Shape
|
||||
|
||||
One possible file layout:
|
||||
|
||||
```text
|
||||
packages/runtime/src/
|
||||
runtime-event.ts
|
||||
runtime-event-projection.ts
|
||||
invocation-context.ts
|
||||
runtime-runner.ts
|
||||
runtime-gate.ts
|
||||
runtime-recovery.ts
|
||||
|
||||
flows/
|
||||
agent-flow.ts
|
||||
ai-sdk-flow.ts
|
||||
|
||||
model/
|
||||
model-adapter.ts
|
||||
model-history.ts
|
||||
|
||||
tools/
|
||||
tool-runtime.ts
|
||||
tool-registry.ts
|
||||
permission-events.ts
|
||||
|
||||
projections/
|
||||
stored-message-projection.ts
|
||||
session-event-projection.ts
|
||||
turn-record-projection.ts
|
||||
telemetry-projection.ts
|
||||
|
||||
session-manager.ts
|
||||
```
|
||||
|
||||
This is not a required final file layout. The important part is the direction:
|
||||
`SessionManager` becomes a facade and session CRUD owner, not the runtime brain.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: RuntimeEvent RFC and Adapters
|
||||
|
||||
Add the canonical event types and adapters without changing the run path.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `RuntimeEvent` and `RuntimeEventActions`
|
||||
- mapping tests for current `StoredMessage`, `SessionEvent`, `AgentRunEvent`,
|
||||
and `RunTraceEvent`
|
||||
- documentation of which events are facts and which are projections
|
||||
|
||||
Reason:
|
||||
|
||||
This gives the team a shared language before changing control flow.
|
||||
|
||||
### Phase 2: RuntimeRunner Shell
|
||||
|
||||
Introduce `RuntimeRunner.run()` and make `SessionManager.sendMessage()` delegate
|
||||
to it while still using current `AgentRun.execute()`.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `RuntimeRunner`
|
||||
- `InvocationContext`
|
||||
- `RuntimeGate` placeholder for readiness policy
|
||||
- backward-compatible `SessionManager` facade
|
||||
- tests proving current UI-visible behavior remains stable
|
||||
|
||||
Reason:
|
||||
|
||||
This moves invocation ownership out of `SessionManager` without changing the
|
||||
AI SDK or storage path all at once.
|
||||
|
||||
### Phase 3: AgentRunStore to Invocation Ledger
|
||||
|
||||
Upgrade the run ledger to carry invocation/event linkage.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- run headers linked to `invocationId`
|
||||
- run events linked to canonical runtime event ids where possible
|
||||
- recovery tests that reason from invocation facts and repair projections
|
||||
|
||||
Reason:
|
||||
|
||||
The current run ledger is already useful. It should become part of the runtime
|
||||
spine instead of a parallel diagnostic store.
|
||||
|
||||
### Phase 4: AiSdkFlow Formalization
|
||||
|
||||
Extract/formalize the current `AiSdkBackend.send()` loop into `AiSdkFlow`.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `AgentFlow` interface
|
||||
- `AiSdkFlow` implementation
|
||||
- `ModelHistoryProjector`
|
||||
- `AiSdkFlow` emits canonical `RuntimeEvent`s
|
||||
- `AiSdkBackend` becomes configuration/factory shell rather than the runtime
|
||||
loop owner
|
||||
|
||||
Reason:
|
||||
|
||||
The AI SDK remains the main engine, but Maka gains explicit flow input/output
|
||||
semantics.
|
||||
|
||||
### Phase 5: ToolRuntime Event Actions
|
||||
|
||||
Make tool calls, tool results, permission requests, permission decisions, state
|
||||
deltas, and artifact deltas first-class runtime event actions.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `tool_call` / `tool_result` runtime events
|
||||
- permission request/decision runtime actions
|
||||
- artifact delta linkage
|
||||
- tests for allow/block/prompt/deny/abort paths through canonical events
|
||||
|
||||
Reason:
|
||||
|
||||
Tools are where model intent becomes local side effects. That boundary must be
|
||||
auditable and replayable.
|
||||
|
||||
### Phase 6: Entrypoint Cleanup
|
||||
|
||||
Move readiness and rebind policy out of desktop main and into runtime gates.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- `RuntimeGate` owns connection readiness/rebind/session blocked/running guards
|
||||
- desktop/bot/gateway entrypoints call the same runner APIs
|
||||
- contract tests proving the same session state behaves the same across
|
||||
desktop, bot, and gateway paths
|
||||
|
||||
Reason:
|
||||
|
||||
Entry points should translate protocols; they should not own runtime policy.
|
||||
|
||||
### Phase 7: Model History Correctness
|
||||
|
||||
Build future model prompts from runtime event history projection.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- explicit policy for which runtime events enter model history
|
||||
- tests for tool-result replay into the next model call
|
||||
- tests excluding partial chunks, telemetry, trace, and UI-only notes
|
||||
- provider compatibility tests around AI SDK message shapes
|
||||
|
||||
Reason:
|
||||
|
||||
The next model call must see the right history for the right reason. This
|
||||
should be a tested runtime policy, not incidental stored-message filtering.
|
||||
|
||||
## What Not To Do
|
||||
|
||||
Avoid these failure modes:
|
||||
|
||||
- Do not rewrite all provider streaming logic from scratch.
|
||||
- Do not remove the AI SDK as the main flow engine.
|
||||
- Do not delete session JSONL compatibility.
|
||||
- Do not move UI concerns into `RuntimeEvent`.
|
||||
- Do not let `RunTrace` become a success/failure source of truth.
|
||||
- Do not let desktop main remain the owner of readiness/rebind runtime policy.
|
||||
- Do not introduce a second tool runtime beside the current `ToolRuntime`;
|
||||
evolve it into the event/action model.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Runtime v2 is working when these statements are true:
|
||||
|
||||
- A developer can answer "what happened in this turn?" by reading one
|
||||
invocation/event ledger.
|
||||
- UI messages, turn records, run records, trace rows, and telemetry can be
|
||||
traced back to canonical runtime event ids.
|
||||
- desktop, bot, and gateway entry points share the same runtime readiness and
|
||||
execution semantics.
|
||||
- model history construction is an explicit tested projection from runtime
|
||||
events.
|
||||
- tool permission and tool result behavior is visible as runtime actions, not
|
||||
scattered side effects.
|
||||
- `SessionManager` is mostly session CRUD plus backward-compatible facade
|
||||
methods.
|
||||
- the AI SDK remains a supported first-class flow implementation through
|
||||
`AiSdkFlow`.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Should canonical `RuntimeEvent` be stored as a separate JSONL immediately, or
|
||||
first mirrored into `AgentRunStore` events?
|
||||
- Should `StoredMessage` projection be synchronous with event append, or should
|
||||
projection failures be recoverable/replayable?
|
||||
- How much of current `RunTrace` should be folded into `RuntimeEvent` refs
|
||||
versus left as diagnostic-only rows?
|
||||
- Should permission prompts be model-visible events, UI-only events, or
|
||||
configurable by flow policy?
|
||||
- How should branch/agent transfer be represented before Maka has a full
|
||||
multi-agent tree?
|
||||
- What is the compatibility strategy for old sessions that have no runtime
|
||||
event ledger?
|
||||
|
||||
These should be answered in the RFC before implementation starts.
|
||||
Reference in New Issue
Block a user