feat(kap-server): stream raw xstate inspection events over /api/v1/debug/ws - #3687
Conversation
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f13cec2940
ℹ️ 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".
| actorSessionId: event.actorRef.sessionId, | ||
| actorId: scalar(actorRef.id), | ||
| logicId: scalar(logic?.id), |
There was a problem hiding this comment.
Include runtime ownership in inspection envelopes
When multiple Kimi sessions or agents are active, these fields cannot associate an inspected actor with its owning runtime: createMachineEngine creates each root actor without an application session/agent ID, while nested actors reuse IDs such as turn and tool. Because the projection also discards XState's source/parent relationship, consumers cannot reconstruct which child belongs to which root, so concurrent state-machine views will mix unrelated actors. Include an owning session/agent identifier and parent/source actor session ID in the envelope.
Useful? React with 👍 / 👎.
| private onEnvelope(envelope: XstateInspectionEnvelope): void { | ||
| if (this.closed) return; | ||
| if (this.socket.bufferedAmount > this.highWaterMarkBytes) return; | ||
| this.outbound.push(envelope); | ||
| this.scheduleFlush(); |
There was a problem hiding this comment.
Bound the queued and flushed inspection data
With a slow or non-reading debug client and a synchronous burst of inspection events, bufferedAmount may remain below the limit while an arbitrarily large outbound array accumulates; the subsequent flush then sends the entire captured batch without rechecking the high-water mark. This defeats the advertised backpressure limit and can grow both process memory and the WebSocket send buffer far beyond 1 MiB. Track queued bytes or cap the queue, and stop/batch the flush once bufferedAmount reaches the limit.
Useful? React with 👍 / 👎.
Related Issue
Internal observability work (kimi-code-harness state-machine inspection); no linked issue.
Problem
External observers of the agent runtime (e.g. the kimi-code-harness inspection UI) can only consume the twice-projected event stream on
/api/v1/ws: human-machine emitted events are first consolidated intoMachineEngineEvent, then projected onto Event2 domain events, then mapped onto WS envelopes. Nested xstate states (e.g. agentidle{ready,waiting}/running{active,aborting}) are lost in projection, so a faithful, real-time state-machine view cannot be built from that stream. The existing/api/v1/debug/*RPC surface is request/response only and has no push channel.What changed
xstateInspectionCollectorsingleton that serializes xstate inspection events into compact envelopes ({type, timestamp, actorSessionId, actorId?, logicId?, eventType?, stateValue?}) and never includes machine context. ThecreateActorwrapper inhuman/xstate2.tsnow publishes every root actor system's inspection events to the collector, covering the whole human stack (agent/turn/llm/tool subtree plus interaction/usage/provider-catalog/watch);AgentActorServiceswitches itscreateActorimport to the same wrapper so the feature actors (cron/goal/reminder/todo/notifyUserNudge/dateChange) are included too./api/v1/debug/ws, registered only under the existingdebugEndpointsgate (loopback bind +--debug-endpoints), sharing the upgrade pipeline's host/origin/bearer checks with/api/v1/ws. Connections use a lightweight outbound queue with high-watermark drop for this volatile stream and a 10s heartbeat — no journal, seq/epoch, or resync. Server shutdown now terminates debug clients beforeapp.close()to avoid a deadlock where the HTTP server waits for upgraded sockets.Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.