OpenProgram · Design · Runtime / UI

Nested LLM node content: ordered chat blocks

Expanding an LLM node shows all displayable content in execution order: Markdown, reasoning summaries, function references, parallel groups and retry boundaries. Reuse chat components. Remove fixed LLM Reply / Reasoning sections while retaining distinct underlying content types. This page defines the current protocol, persistence and UI semantics.

Authoritative design Extend execution_stream.v1 instead of creating another chat protocol Streaming, DAG and persistence share one identity Reference: agentic-llm-streaming.zh.html

0. Current implementation (checked against current code)

CapabilityImplementation boundaryRequired invariant
execution_stream.v1Each nested LLM node maintains attempts and ordered blocks, including types such as text, reasoning_summary, tool_ref, tool_arguments, refusal.All deltas and snapshots use the same block_id, block_index; the frontend does not reorder by WS arrival time.
DAG / tool identityTool-node metadata stores the original tool_call_id and qualified tool_call_occurrence_id; tool_ref stores only the referenced ref_node_id, name and occurrence.One occurrence corresponds to exactly one tool row. If the provider reuses a raw call ID, a round/message-qualified occurrence creates a new row. Arguments, progress, results and errors come from that DAG node; streams must not duplicate terminal data.
Attempt semanticsA model request after normal tool results remains in the current attempt. Only actual recovery, such as transport or structured-output failure, creates a new attempt.turn_end means only that one provider round ended; it does not automatically create an attempt boundary. New attempts require an explicit failure reason.
Persistencecheckpoint, metadata.stream, live snapshots and terminal snapshots contain complete displayable attempts/blocks subject to retention policy; legacy previews may still be truncated.After the owner disappears or the worker restarts, historical reads restore ordering, references and terminal states solely from persistent snapshots, without calling the model again. Live snapshots must not silently drop Markdown prefixes.
Tool reference identity: do not retransmit complete tool arguments/results. When execution creates or discovers a DAG tool node, it records the original tool_call_id and qualified occurrence, then the stream publishes a reference through occurrence_id → ref_node_id. If the mapping is not yet visible, publish a placeholder with a stable occurrence, then use the same block_id to fill in ref_node_id; do not create a second row or fabricate completion.
Existing tool_arguments blocks suit transient previews while arguments are being generated. Terminal display uses the tree node to avoid two sources of truth.

1. Expanded layout

2. Execution tree and node-content responsibilities

ViewPurpose
Execution treeCall relationships, parallel branches, execution status, duration and failure location
Node contentOrdered text / reasoning / function references within the LLM node

3. Model calls inside functions

4. Parallel functions

5. Ordered block protocol (execution_stream.v1 extension)

Each LLM node_id maintains, within each attempt, ordered blocks[]. Execution determines ordering; the frontend must not infer it from WS arrival time.

Block kindRequired fieldsDescription
textblock_id, content, statusMarkdown text with streaming deltas
reasoning_summaryblock_id, content, status, retentionDisplayable reasoning; persistence may be omitted by policy
tool_refblock_id, tool_call_id, occurrence_id, node_id, optional group_idReference to a tree node without complete inline results. Missing occurrence is supported only for legacy records.
tool_arguments(may remain)Streaming argument preview; the tree determines terminal state
parallel_groupgroup_id, ordered tool_ref idsParallel container with an execution-generated group ID and references in invocation order. Do not create one without an explicit concurrent batch.
attempt_boundaryattempt_id, reason, statusFailure-retry boundary; older attempts remain collapsed
refusal / unsupportedExistingRetained

Continuation vs. failure retry

{
  "type": "execution_stream",
  "schema_version": 1,
  "op": "block_started",
  "node_id": "call_9f3e",
  "attempt_id": "att_2",
  "block_id": "blk_tool_7",
  "block_index": 4,
  "kind": "tool_ref",
  "tool_call_id": "call_abc",
  "occurrence_id": "occ_7e4c",
  "ref_node_id": "exec_read_file_01",
  "group_id": "par_1"
}

6. Markdown streaming and scrolling

7. Disconnect / refresh / failure

8. Implementation order

  1. Ordered protocol and persistence: extend kinds, tool_ref and parallel_group; persist complete attempt.blocks in metadata and checkpoints.
  2. Unified content component LlmNodeContent: reuse chat Markdown, collapsible reasoning and function rows that read the tree only.
  3. Connect node details: remove Reply/Reasoning sections and verify sequence, refresh and recovery.
  4. Reuse the same component for expanded cards.
  5. Parallelism, recursion, retry boundaries and scrolling acceptance.
No stage may reduce this to concatenating two strings first and adding features later; that would violate ordering.

9. Required acceptance scenarios

The model emits Markdown, calls two functions in parallel, one function calls an inner model with read_file, and the outer model continues. Disconnect and refresh during execution. After recovery, block order, function states and hierarchy must match the earlier live state.

Implementation status

ScopeStatusEvidence boundary
Protocol and state mergingImplementedCallStreamState, the execution-stream reducer and protocol tests cover ordered blocks, tool_ref, attempts and version recovery.
Unified node-content componentImplementedExpanded cards and right-side details use LlmNodeContent; Markdown, collapsible reasoning, tool references and earlier attempts share one rendering path.
Authority boundaries, expansion state and recursive detailsImplementedHidden nodes are discarded before projection; io/llm shows permitted descendants only. Node/attempt/block expansion persists; content beyond eight recursive levels offers a details action.
Tool identity, normal continuation and parallel-event consistencyRepaired in this taskAcceptance uses real DAG-node mappings, continuation within one attempt and explicit concurrent batches.
Complete recovery after owner loss / worker restartRepaired in this taskUse persistent snapshots and observable historical-read results as evidence; long real-model tasks still require live acceptance.
Real-model and default-App acceptanceAwaiting live executionRun deterministic nested-tool scenarios in the default profile, port 18100, and existing App. Unit tests are not live acceptance evidence for this page.

Interaction example