Skip to content

feat(kap-server): add flat entity message protocol (v3 WS + history API) - #3532

Open
sailist wants to merge 3 commits into
MoonshotAI:mainfrom
sailist:feat-148-09-03-message-api-v3
Open

feat(kap-server): add flat entity message protocol (v3 WS + history API)#3532
sailist wants to merge 3 commits into
MoonshotAI:mainfrom
sailist:feat-148-09-03-message-api-v3

Conversation

@sailist

@sailist sailist commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

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:

  • Contract (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 ./protocol subpath for clients to import directly.
  • Projection (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.
  • WS /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 dedicated WS_SLOW_CONSUMER disconnect; protocol-level ping/pong.
  • REST 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), with before_turn/after_step cursors and an in_flight marker.
  • kimi-inspect: consumes the new protocol natively (upsert by id / delta append / authoritative overwrite / system(undo,clear) truncation); dependency on @moonshot-ai/transcript removed.

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

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (N/A — internal redesign).
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset. (No changeset: internal server protocol surface + kimi-inspect; not user-perceivable.)
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ff5795b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@ff5795b
npx https://pkg.pr.new/@moonshot-ai/kimi-code@ff5795b

commit: ff5795b

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +520 to +521
for (const item of materializer.materialize(op)) {
target.send(this.buildV3Envelope(state, v3ItemFrame(item, seq)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

@sailist
sailist force-pushed the feat-148-09-03-message-api-v3 branch from ed38e86 to 319e6e4 Compare September 5, 2026 01:36
@sailist sailist changed the title feat(kap-server): add v3 message streaming and transcript APIs feat(kap-server): add flat entity message protocol (v3 WS + history API) Sep 5, 2026
@sailist
sailist force-pushed the feat-148-09-03-message-api-v3 branch from cddaab9 to ff5795b Compare September 5, 2026 08:48
Sign up for free to 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.

1 participant