4.2 KiB
Details Edit Protocol
This document describes the WebSocket message protocol for reading and editing the details field of category items (indicators, strategies, research scripts) from the web client.
Background
Every category item stored in the sandbox has a details field: a full markdown description of the implementation with enough detail that another coding agent could reproduce the code from it alone. The web client can display this field, allow the user to edit it in plain text, and submit the revised version — the gateway then diffs the old vs new details and instructs the appropriate subagent to update the Python code accordingly.
The details field is intentionally filtered out of the workspace _types stores (see mcp-tool-wrapper.ts:filterTypeStoreState) because it can be several kilobytes of markdown. The read/update protocol below provides direct, on-demand access.
Message Flow
1. Read Details
Client → Server
{
"type": "read_details",
"category": "indicator" | "strategy" | "research",
"name": "My Indicator Name"
}
Server → Client (success)
{
"type": "details_data",
"category": "indicator",
"name": "My Indicator Name",
"details": "## My Indicator\n\nFull markdown description..."
}
Server → Client (error)
{
"type": "details_error",
"category": "indicator",
"name": "My Indicator Name",
"error": "Item not found or has no details"
}
2. Submit Updated Details
Client → Server
{
"type": "update_details",
"category": "indicator" | "strategy" | "research",
"name": "My Indicator Name",
"details": "## My Indicator\n\nRevised full markdown description..."
}
The gateway will:
- Read the current
detailsfrom the sandbox viapython_read - Compute a unified diff between the old and new text
- If no changes are detected, reply immediately with
details_updated(success) - Otherwise, invoke the appropriate subagent (indicator / strategy / research) with instructions to update the Python code according to the diff, and also persist the new
detailstext
While the subagent is running, the server streams progress events using the same event types as normal agent interactions:
{ "type": "subagent_chunk", "agentName": "indicator", "content": "Reading current implementation..." }
{ "type": "subagent_tool_call", "agentName": "indicator", "toolName": "python_read", "label": "python_read" }
{ "type": "subagent_tool_call", "agentName": "indicator", "toolName": "python_edit", "label": "python_edit" }
{ "type": "subagent_chunk", "agentName": "indicator", "content": "Applied patch. Validation passed." }
Server → Client (completion)
{
"type": "details_updated",
"category": "indicator",
"name": "My Indicator Name",
"success": true
}
or on failure:
{
"type": "details_updated",
"category": "indicator",
"name": "My Indicator Name",
"success": false,
"error": "Failed to update details"
}
Workspace Sync After Update
When the subagent calls python_edit, the sandbox returns a _workspace_sync payload in the MCP response. The gateway automatically applies this to the {category}_types workspace store and sends a WebSocket patch message to the client (the normal workspace sync path). The client should listen for these patches to refresh any UI that displays list metadata (name, description).
The details field itself is not in the workspace store — the client must call read_details again if it needs the refreshed details text after an update.
Implementation Notes
| Component | File | Responsibility |
|---|---|---|
| WebSocket routing | src/channels/websocket-handler.ts |
Parse read_details / update_details, stream subagent events, send details_data / details_updated |
| Harness methods | src/harness/agent-harness.ts |
readDetails(), streamDetailsUpdate() |
| Diff utility | src/harness/agent-harness.ts |
buildUnifiedDiff(), computeLCS() (module-level helpers) |
| Instruction builder | src/harness/agent-harness.ts |
buildDetailsUpdateInstruction() |
| Details filter | src/tools/mcp/mcp-tool-wrapper.ts |
filterTypeStoreState() — strips details before workspace sync |