vis: rewrite for new agent-core protocol#34
Conversation
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad04343aac
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| <div className="flex flex-1 items-center justify-center p-6 font-mono text-[12px] text-fg-3"> | ||
| <div className="text-center"> | ||
| <div>session detail UI rewrite in progress</div> | ||
| <div className="mt-2 text-fg-3"> |
There was a problem hiding this comment.
Restore session detail UI instead of placeholder message
This replaces the /sessions/:sessionId body with a static “rewrite in progress” placeholder, so users can no longer access Wire/Context/Subagents/State from the main detail route at all. That breaks the primary inspection flow for every session and makes the new protocol data effectively unreachable unless users manually guess deep links.
Useful? React with 👍 / 👎.
| export function WireTab({ sessionId, initialAgentId = 'main' }: WireTabProps) { | ||
| const [agentId, setAgentId] = useState<string>(initialAgentId); | ||
| const { data: detail } = useSession(sessionId); | ||
| const { data: wire, isLoading, error } = useWire(sessionId, agentId); |
There was a problem hiding this comment.
Sync WireTab agent state with route-driven prop changes
The selected agent is initialized from initialAgentId only once and then stored in local state, so navigating between /sessions/:sessionId/agents/:agentId URLs while the component remains mounted can leave the dropdown/data on the previous agent. In that case the URL and rendered wire timeline disagree, which can lead users to inspect the wrong agent data.
Useful? React with 👍 / 👎.
| return { | ||
| sessionId, | ||
| sessionDir, | ||
| workDir: '', // filled in by caller via session_index lookup | ||
| title: state.title ?? null, |
There was a problem hiding this comment.
Populate workDir instead of returning empty workspace for all sessions
Session summaries hardcode workDir to an empty string, and the list route returns these values directly. As a result, the UI cannot show or filter by actual workspace and every session appears as “(no workspace)”, which is a functional regression for identifying sessions across projects.
Useful? React with 👍 / 👎.
| {active === 'context' ? ( | ||
| contextQ.isLoading ? ( | ||
| <Centered>loading context…</Centered> | ||
| ) : contextQ.error ? ( | ||
| <ErrorView msg={(contextQ.error).message} /> | ||
| ) : contextQ.data ? ( | ||
| <ContextTab | ||
| sessionId={sessionId} | ||
| messages={contextQ.data.annotated_messages} | ||
| projectedState={contextQ.data.projected_state} | ||
| /> | ||
| ) : null | ||
| <Centered>context tab pending</Centered> | ||
| ) : null} |
There was a problem hiding this comment.
Implement subagent context tab instead of pending placeholder
The subagent detail page still exposes a Context tab, but selecting it only renders a “context tab pending” stub and never fetches or displays context data. This is a direct feature regression from the previous behavior and blocks core debugging workflows for subagent runs.
Useful? React with 👍 / 👎.
| const info = await scanWire(mainWirePath); | ||
| mainCount = info.count; |
There was a problem hiding this comment.
Handle wire read failures per session during listing
Session listing now calls scanWire without guarding read-stream failures, so a single unreadable/corrupt wire.jsonl can reject listSessions and fail the entire /api/sessions response instead of marking just that session unhealthy. The previous code path tolerated per-session wire read failures, so this reduces robustness when any session data is partially broken.
Useful? React with 👍 / 👎.
| files_read: [archivePath], | ||
| health: result.health, | ||
| warnings: [...result.warnings], | ||
| const result = await readAgentWire(join(agent.homedir, 'wire.jsonl')); |
There was a problem hiding this comment.
Read wire from canonical agent path instead of state.homedir
This route verifies wire existence using the canonical session path during inventory, but then reads from join(agent.homedir, 'wire.jsonl') taken from mutable state.json metadata. If homedir is stale or inconsistent, requests can fail with READ_ERROR (or read the wrong file) even though wireExists was true, causing incorrect or unavailable wire/context views.
Useful? React with 👍 / 👎.
| for (const [id, meta] of Object.entries(state.agents ?? {})) { | ||
| const wirePath = join(sessionDir, 'agents', id, 'wire.jsonl'); |
There was a problem hiding this comment.
Fallback to main agent when state.agents is absent
Agent inventory is built only from state.agents, so sessions with a valid agents/main/wire.jsonl but missing/partial state.agents produce an empty agent list. In that case /api/sessions/:id/wire and /context return agent-not-found even though the main wire file exists, which regresses debuggability for partially written or migrated state files.
Useful? React with 👍 / 👎.
Summary
Rewrite the
apps/visdebug visualization tool to consume the currentAgentRecordwire protocol. The old code targeted a now-defunct protocol with record types liketurn_begin / step_begin / content_part / tool_call / tool_result / notification / subagent_*; none of those types exist anymore. No backward compatibility is preserved.What changed
Single-source types.
visnow importsAgentRecord,ContextMessage,PromptOrigin,LoopRecordedEvent,TokenUsage, etc. directly from@moonshot-ai/agent-coreand@moonshot-ai/kosong. The 700-LOC local type mirror is gone — drift that caused this collapse cannot recur.New storage layout. Session lister reads
~/.kimi-code/sessions/<wd_key>/<session_id>/state.json(camelCase, ISO timestamps) andagents/<id>/wire.jsonlper agent. Sessions withstate.custom.imported_from_kimi_cli === trueare filtered out.New record union. All 24 new record types (
metadata,config.update,turn.{prompt,steer,cancel},context.*,tools.*,permission.*,plan_mode.*,full_compaction.*,usage.record,background.stop) are exhaustively rendered with badges, headlines, and detail views. Loop-level granularity (step.begin / step.end / content.part / tool.call / tool.result) is preserved by expandingcontext.append_loop_eventrecords on demand.Per-agent timelines. Each agent has its own
wire.jsonl; the Wire and Context tabs include an agent dropdown (defaults tomain). The Subagents tab builds its tree fromstate.json.agentsinstead of synthesized spawn/complete events.Context projection. A new
context-projectorderives the conversation timeline, token usage totals (by scope and by model), config snapshot, permission mode, and plan-mode state from raw wire records.API redesigned. All response payloads are camelCase with epoch-ms timestamps. Endpoints:
GET /api/sessions,GET /api/sessions/:id,GET /api/sessions/:id/wire?agent=<id>,GET /api/sessions/:id/context?agent=<id>,GET /api/sessions/:id/agents,DELETE /api/sessions/:id. The legacy/tool-results/*route is gone — tool outputs are inline incontext.append_messagerecords.agent-core export surface. Added wire-record type re-exports from
@moonshot-ai/agent-coreroot so in-monorepo consumers don't need deep imports.Verification
pnpm --filter @moonshot-ai/vis-server build— passespnpm --filter @moonshot-ai/vis-server test— 13/13 across 4 test files (session-store, wire-reader, context-projector, agent-tree)pnpm --filter @moonshot-ai/vis-web build— passesmain + agent-0 + agent-1Known issue
pnpm --filter @moonshot-ai/vis-web typecheckreports 22 errors fromagent-core's*.mdraw imports and one pre-existingkosongUint8Array typing. These are upstream packaging issues unrelated to this PR — vite build succeeds. Tracking separately.Test plan
state.jsonis rendered alongside highlight cards