Address review: the gate module docstring now states the actual evaluation contexts (config after injections against the plugin context, disabled at every mount decision against the loader context); metadataExpressionErrors rejects expressions nested below disabled and syntax-checks the disabled expression itself so an unparseable gate fails at the gate instead of the boot. The tutorial's !!js claims follow, and the loader note moves to implemented/architecture with its inbound links retargeted.
4.8 KiB
Agent Note: Code Mode UI foundation — run_code description and native-parity dispatch logging
Status: implemented
English | 中文
Scope: the host-side contract changes that let a UI render a Code Mode turn with the same fidelity as native tool calls — the foundation the other Code Mode UI notes build on. The Code Mode foundation owns the transport design; this note owns the model-visible
descriptionparameter, the full-contenttool/code-dispatchpayload, and the temporaryDSH_TOOLS_MODEenablement switch for thedshconfig tree.
Problem
A run_code turn was opaque in every product surface. The call card's title was the raw program text — unreadable at row width, and unlike bash (whose required description labels the card while the command rides the expanded input) there was no model-authored label at all. The tool/code-dispatch event carried only a 200-char, cwd-normalized resultSummary of each sub-call, so no UI could ever show what a sub-call actually returned: the web conversation view (chat sub-call rows) renders sub-calls through the exact components that render native tool/result cards, and a bounded summary cannot feed a native-parity card. And the dsh web composition had no way to enable Code Mode at all — the tools row pinned the schema default and the runtime was absent from the tree.
Decision
Three changes, one per obstacle:
run_codegains a requireddescriptionparameter (bash's exact contract: active voice, 5-10 words, shown in the UI; whitespace-only rejected at execute).presentCallnow titles the card with the description and moves the program torawInput. The prompt-side cost is a few tokens per call; the return is that every surface — TUI card, ACP title, web row — gets a human-readable label without parsing TypeScript.tool/code-dispatchlogs the sub-call's complete model-facing outcome —content: ContentBlock[]+isError, thetool/resultvocabulary — replacingresultSummaryand deleting the summarize/cwd-normalization machinery outright. A UI renders a sub-call through the identical code path as a native result, including error text and non-text blocks. The event stays log-only (deriveMessages()ignores it): nothing about model context changes.DSH_TOOLS_MODEenv var on thedshconfig tree (native|code|both; unset keeps the schema default): thetoolsrow reads it via!!js, and the worker code runtime is mounted unconditionally (Loader metadata was static when this shipped — no conditional row existed; the laterdisabledinterpolation decision makes one possible but changes nothing here — a native boot only registers the service, workers spawn per run). This is an explicitly temporary configuration hook: per-session tool-mode selection owned by the web UI is the design goal, and the env var dies when that lands.
Alternatives considered
Keep a bounded summary (raised cap, or a cap + truncated flag). Rejected: the stack's settled requirement is that sub-call rows and details render identically to native calls; any cap forces a second, degraded render path plus truncation UI. The cost accepted instead: a program that reads a large file logs the rendered content verbatim on the dispatch event — uncapped, outside spill policy, growing the session log by the same bytes. Spill integration for the logged copy shipped as code-dispatch log spill.
A --tools-mode CLI flag or profile key. Deferred, not rejected: the flag grammar suggests permanence, and the profile json is user config — both would harden a seam the per-session design intends to remove. An env var reads as the workaround it is.
Log the canonical value instead of rendered content. Rejected: tool/result persists content, not values (the canonical output contract), and native parity means matching that exactly; values remain execution-local everywhere.
Consequences
Session format keeps SESSION_FORMAT_VERSION 0 (pre-release churn does not bump; old logs with resultSummary simply carry an extra unread field and lack content — v0 makes no compatibility promise). Existing code-mode snapshot fixtures were re-recorded. Model-visible surface grew: the run_code schema (one required parameter) and every code-mode system prompt/tool-schema snapshot changed. The web UI work builds directly on the new event payload; live per-sub-call running state reshaped this event into a dispatch start/end pair (live parallel dispatch).