feat(kap-server): add flat entity message protocol (v3 WS + history API) - #3532
feat(kap-server): add flat entity message protocol (v3 WS + history API)#3532sailist wants to merge 3 commits into
Conversation
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e28327a85d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| for (const item of materializer.materialize(op)) { | ||
| target.send(this.buildV3Envelope(state, v3ItemFrame(item, seq))); |
There was a problem hiding this comment.
Preserve op-batch atomicity in v3 catch-up
When one transcript op batch materializes into multiple items, this sends each as a separate frame carrying the same seq. If the connection drops after the client receives and persists that sequence from an early frame, reconnecting with transcript_since skips the entire batch, permanently losing the remaining messages; the client also has no marker indicating which frame is last. Send the materialized batch atomically or add an item index/count or completion marker so the watermark can be committed safely.
AGENTS.md reference: AGENTS.md:L28-L28
Useful? React with 👍 / 👎.
| id: `remove.${this.removeCounter}`, | ||
| session_id: env.sessionId, | ||
| agent_id: env.agentId, | ||
| ids: [...op.ids], |
There was a problem hiding this comment.
Remove child messages when undoing a turn
When context.undone removes a turn that has already streamed steps and frames, onContextUndone puts only top-level item IDs and anchored interaction IDs in op.ids, and this forwards that list unchanged. Because v3 exposes each step and frame as an independent message, applying this removal deletes the turn message but leaves its step_*, text, thinking, and tool messages orphaned, diverging from the REST snapshot where the whole turn subtree is gone. Include every flattened descendant ID in the removal.
Useful? React with 👍 / 👎.
ed38e86 to
319e6e4
Compare
cddaab9 to
ff5795b
Compare
Related Issue
N/A — internal protocol redesign per the "New API draft" design doc (flat, self-contained message union to replace the dual-track event/transcript streams).
Problem
kap-server currently ships two divergent delivery pipelines: 51 agent frame types + 19
event.*frame types (legacy lane) and transcript reset/ops (v2 lane). The same fact is projected twice, kept consistent by a hand-maintained suppression table; transcript's store/ops/granularity concepts force every consumer through an apply/store middle layer before WS data becomes usable; approvals, tasks, busy and other state domains have 2–3 competing sources of truth; and the declared schema has systematically drifted from what the server actually emits.What changed
Implements the next-generation protocol as a pure addition — v1/v2 lanes, legacy REST, and the transcript package are untouched, so existing clients keep working:
packages/kap-server/src/protocol/messages/): the zod single source for a flat union of 22 entity messages + 4 control messages (snake_case, no envelope, no seq/epoch/volatile/offset). Browser-safe; exported via the./protocolsubpath for clients to import directly.services/projection/): a single direct projector mapping agent-core-v2 event-bus events + service emitters + queryable services to entity messages, with zero dependency on the transcript package. Holds in-flight turn/step accumulation and current state entities; heals against wire.jsonl at turn end; validates every outbound message against the schema./api/v3/ws:hello → subscribe → ack → recovery payload → live. Recovery in three sentences: persisted state comes from REST, in-flight steps replay, state entities resend in full — no cursors, no journal, no seq/epoch. Per-session ordered sequence (recovery and live queued atomically); bounded outbound queue with a dedicatedWS_SLOW_CONSUMERdisconnect; protocol-level ping/pong.GET /api/v1/sessions/{id}/history: cold rebuild from wire.jsonl into the same flat entity messages (same schema, same id rules as the live projection), withbefore_turn/after_stepcursors and anin_flightmarker.system(undo,clear)truncation); dependency on@moonshot-ai/transcriptremoved.Zero changes to
agent-core-v2, to the v1/v2 lanes, to legacy REST, or to the transcript package.Verification: kap-server/kimi-inspect typecheck green; 67 contract + 24 projection + 20 WS + 27 history + 116 kimi-inspect tests green; 39/39 end-to-end smoke checks against a real server (handshake, live streaming, approvals, todo, subagent modes A/B/C, undo/clear, all three recovery scenarios, REST↔WS convergence); full repo suite green except pre-existing agent-core-v2 zip environment failures.
Checklist
gen-changesetsskill, or this PR needs no changeset. (No changeset: internal server protocol surface + kimi-inspect; not user-perceivable.)gen-docsskill, or this PR needs no doc update.