@linxiraos/pi-tui 1.1.26 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -491
- package/README.md +13 -7
- package/dist/types/active-terminal.d.ts +30 -0
- package/dist/types/app-keybindings.d.ts +7 -2
- package/dist/types/apps/cleanse-board.d.ts +1 -1
- package/dist/types/apps/debug/log-viewer.d.ts +4 -0
- package/dist/types/apps/debug/raw-sse-buffer.d.ts +2 -0
- package/dist/types/apps/git/git-tui.d.ts +5 -4
- package/dist/types/apps/git/help.d.ts +3 -1
- package/dist/types/apps/if-bench-board.d.ts +2 -2
- package/dist/types/apps/setup-model-picker.d.ts +1 -1
- package/dist/types/autocomplete.d.ts +5 -2
- package/dist/types/charts/chart-plan.d.ts +674 -0
- package/dist/types/charts/chart-svg.d.ts +59 -0
- package/dist/types/charts/table-data.d.ts +175 -0
- package/dist/types/chat/assistant-message.d.ts +11 -1
- package/dist/types/chat/chat-transcript-builder.d.ts +3 -0
- package/dist/types/chat/compaction-summary-message.d.ts +1 -0
- package/dist/types/chat/execution-shared.d.ts +6 -5
- package/dist/types/chat/fence-figure.d.ts +42 -0
- package/dist/types/chat/figure-markdown.d.ts +42 -0
- package/dist/types/chat/messages.d.ts +1 -1
- package/dist/types/chat/svg-figure.d.ts +33 -0
- package/dist/types/chat/svg-source.d.ts +49 -0
- package/dist/types/chat/table-chart.d.ts +89 -0
- package/dist/types/chat/tool-execution.d.ts +2 -0
- package/dist/types/chat/user-message.d.ts +17 -4
- package/dist/types/chrome/shared.d.ts +9 -0
- package/dist/types/chrome/status-notice.d.ts +15 -3
- package/dist/types/chrome/transcript-container.d.ts +6 -0
- package/dist/types/components/box.d.ts +1 -0
- package/dist/types/components/disclosure.d.ts +1 -0
- package/dist/types/components/editor.d.ts +23 -5
- package/dist/types/components/form.d.ts +1 -0
- package/dist/types/components/image.d.ts +26 -44
- package/dist/types/components/input.d.ts +2 -1
- package/dist/types/components/key-value-list.d.ts +1 -0
- package/dist/types/components/layout/row.d.ts +1 -0
- package/dist/types/components/layout/stack.d.ts +1 -0
- package/dist/types/components/loader.d.ts +5 -6
- package/dist/types/components/markdown.d.ts +47 -5
- package/dist/types/components/scroll-view.d.ts +1 -0
- package/dist/types/components/section.d.ts +1 -0
- package/dist/types/components/table.d.ts +1 -0
- package/dist/types/components/text.d.ts +1 -0
- package/dist/types/components/tree-view.d.ts +7 -0
- package/dist/types/components/truncated-text.d.ts +1 -0
- package/dist/types/fuzzy.d.ts +29 -1
- package/dist/types/key-hint-format.d.ts +9 -1
- package/dist/types/keybinding-matchers.d.ts +3 -0
- package/dist/types/keybindings.d.ts +1 -1
- package/dist/types/kitty-graphics.d.ts +2 -2
- package/dist/types/loop-watchdog.d.ts +8 -7
- package/dist/types/multiplexers/cmux.d.ts +16 -0
- package/dist/types/multiplexers/herdr.d.ts +26 -0
- package/dist/types/multiplexers/notify.d.ts +13 -0
- package/dist/types/multiplexers/orca.d.ts +12 -0
- package/dist/types/multiplexers/screen.d.ts +9 -0
- package/dist/types/multiplexers/tmux.d.ts +29 -0
- package/dist/types/multiplexers/types.d.ts +100 -0
- package/dist/types/multiplexers/wmux.d.ts +12 -0
- package/dist/types/multiplexers/zellij.d.ts +12 -0
- package/dist/types/native/apply.d.ts +4 -3
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +7 -3
- package/dist/types/native/encode.d.ts +8 -6
- package/dist/types/native/node.d.ts +36 -5
- package/dist/types/native/overlay.d.ts +8 -3
- package/dist/types/native/settle.d.ts +4 -3
- package/dist/types/overlays/agent-hub-projection.d.ts +6 -5
- package/dist/types/overlays/agent-hub-types.d.ts +9 -0
- package/dist/types/overlays/agent-hub.d.ts +3 -0
- package/dist/types/overlays/agent-transcript-viewer.d.ts +12 -2
- package/dist/types/overlays/agents-hub.d.ts +9 -0
- package/dist/types/overlays/annotation-overlay.d.ts +19 -2
- package/dist/types/overlays/annotation-types.d.ts +2 -0
- package/dist/types/overlays/ask-dialog.d.ts +5 -2
- package/dist/types/overlays/btw-history-panel.d.ts +13 -1
- package/dist/types/overlays/copy-selector.d.ts +1 -0
- package/dist/types/overlays/history-search.d.ts +10 -0
- package/dist/types/overlays/hook-selector.d.ts +9 -4
- package/dist/types/overlays/hub-frame.d.ts +4 -1
- package/dist/types/overlays/jobs-panel.d.ts +1 -7
- package/dist/types/overlays/model-browser.d.ts +54 -7
- package/dist/types/overlays/model-hub.d.ts +37 -0
- package/dist/types/overlays/oauth-selector.d.ts +0 -1
- package/dist/types/overlays/plan-review-overlay.d.ts +3 -2
- package/dist/types/overlays/report-panel.d.ts +68 -0
- package/dist/types/overlays/rewind-selector.d.ts +1 -0
- package/dist/types/overlays/session-observer-registry.d.ts +2 -0
- package/dist/types/overlays/session-selector.d.ts +6 -2
- package/dist/types/overlays/settings-defs.d.ts +1 -0
- package/dist/types/overlays/thinking-selector.d.ts +2 -2
- package/dist/types/overlays/usage-dashboard.d.ts +12 -8
- package/dist/types/overlays/usage-display.d.ts +3 -1
- package/dist/types/prompt/composer-cache.d.ts +0 -16
- package/dist/types/prompt/composer.d.ts +18 -3
- package/dist/types/prompt/custom-editor.d.ts +25 -13
- package/dist/types/prompt/image-source.d.ts +2 -1
- package/dist/types/prompt/interactive-context-helpers.d.ts +5 -1
- package/dist/types/prompt/model-mention-autocomplete.d.ts +1 -1
- package/dist/types/prompt/welcome.d.ts +7 -2
- package/dist/types/render/composite.d.ts +2 -0
- package/dist/types/render/output-pane.d.ts +1 -0
- package/dist/types/render/render-utils.d.ts +1 -0
- package/dist/types/render/tool-card.d.ts +6 -0
- package/dist/types/render/width-aware-text.d.ts +2 -0
- package/dist/types/setup/scenes/types.d.ts +1 -0
- package/dist/types/space-hold.d.ts +40 -25
- package/dist/types/status-line/component.d.ts +3 -0
- package/dist/types/status-line/context-usage.d.ts +7 -5
- package/dist/types/status-line/host.d.ts +4 -1
- package/dist/types/status-line/segments.d.ts +2 -0
- package/dist/types/status-line/types.d.ts +14 -3
- package/dist/types/terminal-capabilities.d.ts +41 -36
- package/dist/types/terminal-multiplexer.d.ts +127 -14
- package/dist/types/terminal.d.ts +23 -16
- package/dist/types/theme/active-symbols.d.ts +1 -1
- package/dist/types/theme/schema.d.ts +11 -2
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme-class.d.ts +7 -0
- package/dist/types/theme/theme.d.ts +1 -1
- package/dist/types/theme/tui-adapters.d.ts +3 -0
- package/dist/types/thinking.d.ts +1 -1
- package/dist/types/tmux.d.ts +11 -4
- package/dist/types/tools/bash.d.ts +7 -2
- package/dist/types/tools/daemon.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +22 -3
- package/dist/types/tools/glob.d.ts +4 -0
- package/dist/types/tools/native-view.d.ts +47 -0
- package/dist/types/tools/output-meta.d.ts +11 -1
- package/dist/types/tools/renderer.d.ts +37 -2
- package/dist/types/tools/streaming-output.d.ts +20 -1
- package/dist/types/tools/task.d.ts +2 -3
- package/dist/types/tools/write.d.ts +9 -2
- package/dist/types/tools/yield.d.ts +22 -0
- package/dist/types/tui.d.ts +36 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/vim.d.ts +19 -5
- package/dist/types/windows-input-mode.d.ts +33 -1
- package/package.json +13 -9
- package/src/active-terminal.d.ts +30 -0
- package/src/active-terminal.ts +80 -0
- package/src/app-keybindings.d.ts +7 -2
- package/src/app-keybindings.ts +7 -2
- package/src/apps/autoresearch-dashboard.ts +7 -3
- package/src/apps/cleanse-board.ts +2 -2
- package/src/apps/cleanse-picker.ts +1 -1
- package/src/apps/debug/log-viewer.ts +188 -72
- package/src/apps/debug/raw-sse-buffer.ts +8 -0
- package/src/apps/debug/raw-sse.ts +39 -5
- package/src/apps/git/diff-pane.ts +96 -23
- package/src/apps/git/git-tui.ts +23 -16
- package/src/apps/git/help.ts +29 -20
- package/src/apps/git/sidebar.ts +8 -3
- package/src/apps/if-bench-board.ts +2 -2
- package/src/apps/ps-top.ts +2 -2
- package/src/apps/setup-model-picker.ts +1 -1
- package/src/autocomplete.d.ts +5 -2
- package/src/autocomplete.ts +67 -43
- package/src/bracketed-paste.ts +10 -3
- package/src/charts/chart-plan.d.ts +674 -0
- package/src/charts/chart-plan.ts +5081 -0
- package/src/charts/chart-svg.d.ts +59 -0
- package/src/charts/chart-svg.ts +4657 -0
- package/src/charts/table-data.d.ts +175 -0
- package/src/charts/table-data.ts +1478 -0
- package/src/chat/advisor-message.ts +11 -0
- package/src/chat/assistant-message.d.ts +11 -1
- package/src/chat/assistant-message.ts +245 -54
- package/src/chat/chat-transcript-builder.d.ts +3 -0
- package/src/chat/chat-transcript-builder.ts +9 -3
- package/src/chat/compaction-summary-message.d.ts +1 -0
- package/src/chat/compaction-summary-message.ts +8 -0
- package/src/chat/execution-shared.d.ts +6 -5
- package/src/chat/execution-shared.ts +42 -25
- package/src/chat/fence-figure.d.ts +42 -0
- package/src/chat/fence-figure.ts +80 -0
- package/src/chat/figure-markdown.d.ts +42 -0
- package/src/chat/figure-markdown.ts +174 -0
- package/src/chat/messages.d.ts +1 -1
- package/src/chat/messages.ts +1 -1
- package/src/chat/read-tool-group.ts +6 -4
- package/src/chat/skill-message.ts +6 -0
- package/src/chat/svg-figure.d.ts +33 -0
- package/src/chat/svg-figure.ts +399 -0
- package/src/chat/svg-source.d.ts +49 -0
- package/src/chat/svg-source.ts +188 -0
- package/src/chat/table-chart.d.ts +89 -0
- package/src/chat/table-chart.ts +294 -0
- package/src/chat/tool-execution.d.ts +2 -0
- package/src/chat/tool-execution.ts +86 -7
- package/src/chat/user-message.d.ts +17 -4
- package/src/chat/user-message.ts +71 -8
- package/src/chrome/shared.ts +53 -0
- package/src/chrome/status-notice.ts +25 -7
- package/src/chrome/transcript-container.d.ts +6 -0
- package/src/chrome/transcript-container.ts +162 -19
- package/src/components/box.d.ts +1 -0
- package/src/components/box.ts +5 -0
- package/src/components/disclosure.d.ts +1 -0
- package/src/components/disclosure.ts +8 -0
- package/src/components/editor.d.ts +23 -5
- package/src/components/editor.ts +316 -47
- package/src/components/form.d.ts +1 -0
- package/src/components/form.ts +8 -0
- package/src/components/image.d.ts +26 -44
- package/src/components/image.ts +115 -152
- package/src/components/input.d.ts +2 -1
- package/src/components/input.ts +17 -7
- package/src/components/key-value-list.d.ts +1 -0
- package/src/components/key-value-list.ts +4 -0
- package/src/components/layout/row.d.ts +1 -0
- package/src/components/layout/row.ts +7 -0
- package/src/components/layout/stack.d.ts +1 -0
- package/src/components/layout/stack.ts +7 -0
- package/src/components/loader.d.ts +5 -6
- package/src/components/loader.ts +10 -17
- package/src/components/markdown.d.ts +47 -5
- package/src/components/markdown.ts +786 -303
- package/src/components/scroll-view.d.ts +1 -0
- package/src/components/scroll-view.ts +5 -0
- package/src/components/section.d.ts +1 -0
- package/src/components/section.ts +5 -0
- package/src/components/settings-list.ts +2 -0
- package/src/components/table.d.ts +1 -0
- package/src/components/table.ts +4 -0
- package/src/components/text.d.ts +1 -0
- package/src/components/text.ts +7 -0
- package/src/components/tree-view.d.ts +7 -0
- package/src/components/tree-view.ts +38 -8
- package/src/components/truncated-text.d.ts +1 -0
- package/src/components/truncated-text.ts +5 -0
- package/src/desktop-notify.ts +3 -2
- package/src/fuzzy.d.ts +29 -1
- package/src/fuzzy.ts +115 -30
- package/src/hotkeys-markdown.ts +9 -2
- package/src/key-hint-format.d.ts +9 -1
- package/src/key-hint-format.ts +26 -11
- package/src/keybinding-matchers.d.ts +3 -0
- package/src/keybinding-matchers.ts +6 -2
- package/src/keybindings.d.ts +1 -1
- package/src/keybindings.ts +1 -1
- package/src/kitty-graphics.d.ts +2 -2
- package/src/kitty-graphics.ts +11 -5
- package/src/loop-watchdog.d.ts +8 -7
- package/src/loop-watchdog.ts +18 -13
- package/src/multiplexers/cmux.d.ts +16 -0
- package/src/multiplexers/cmux.ts +29 -0
- package/src/multiplexers/herdr.d.ts +26 -0
- package/src/multiplexers/herdr.ts +64 -0
- package/src/multiplexers/notify.d.ts +13 -0
- package/src/multiplexers/notify.ts +24 -0
- package/src/multiplexers/orca.d.ts +12 -0
- package/src/multiplexers/orca.ts +16 -0
- package/src/multiplexers/screen.d.ts +9 -0
- package/src/multiplexers/screen.ts +15 -0
- package/src/multiplexers/tmux.d.ts +29 -0
- package/src/multiplexers/tmux.ts +40 -0
- package/src/multiplexers/types.d.ts +100 -0
- package/src/multiplexers/types.ts +110 -0
- package/src/multiplexers/wmux.d.ts +12 -0
- package/src/multiplexers/wmux.ts +16 -0
- package/src/multiplexers/zellij.d.ts +12 -0
- package/src/multiplexers/zellij.ts +24 -0
- package/src/native/apply.d.ts +4 -3
- package/src/native/apply.ts +4 -3
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +199 -22
- package/src/native/blobs.d.ts +7 -3
- package/src/native/blobs.ts +47 -12
- package/src/native/encode.d.ts +8 -6
- package/src/native/encode.ts +76 -34
- package/src/native/node.d.ts +36 -5
- package/src/native/node.ts +31 -5
- package/src/native/overlay.d.ts +8 -3
- package/src/native/overlay.ts +17 -4
- package/src/native/reconcile.ts +16 -4
- package/src/native/settle.d.ts +4 -3
- package/src/native/settle.ts +4 -3
- package/src/overlays/agent-hub-projection.d.ts +6 -5
- package/src/overlays/agent-hub-projection.ts +124 -13
- package/src/overlays/agent-hub-types.d.ts +9 -0
- package/src/overlays/agent-hub-types.ts +6 -0
- package/src/overlays/agent-hub.ts +48 -29
- package/src/overlays/agent-transcript-viewer.ts +93 -23
- package/src/overlays/agents-hub.ts +28 -8
- package/src/overlays/annotation-overlay.ts +293 -90
- package/src/overlays/annotation-types.ts +2 -0
- package/src/overlays/ask-dialog.ts +10 -17
- package/src/overlays/btw-history-panel.ts +136 -39
- package/src/overlays/copy-selector.d.ts +1 -0
- package/src/overlays/copy-selector.ts +32 -8
- package/src/overlays/extensions/extension-dashboard.ts +4 -4
- package/src/overlays/extensions/state-manager.ts +52 -12
- package/src/overlays/history-search.ts +100 -7
- package/src/overlays/hook-selector.ts +12 -5
- package/src/overlays/hub-frame.ts +19 -1
- package/src/overlays/jobs-panel.ts +33 -52
- package/src/overlays/model-browser.ts +367 -122
- package/src/overlays/model-hub.ts +435 -59
- package/src/overlays/move-overlay.ts +28 -14
- package/src/overlays/oauth-selector.ts +54 -70
- package/src/overlays/pause-screen.ts +2 -2
- package/src/overlays/plan-review-overlay.ts +208 -70
- package/src/overlays/plugin-settings.ts +3 -3
- package/src/overlays/report-panel.ts +191 -0
- package/src/overlays/rewind-selector.ts +88 -17
- package/src/overlays/session-observer-registry.d.ts +2 -0
- package/src/overlays/session-observer-registry.ts +10 -2
- package/src/overlays/session-selector.ts +64 -26
- package/src/overlays/settings-defs.ts +5 -4
- package/src/overlays/settings-selector.ts +33 -8
- package/src/overlays/snapcompact-shape-preview.ts +2 -3
- package/src/overlays/stats-notice.ts +1 -1
- package/src/overlays/thinking-selector.ts +11 -10
- package/src/overlays/tree-selector.ts +41 -20
- package/src/overlays/usage-dashboard.ts +117 -58
- package/src/overlays/usage-display.ts +10 -4
- package/src/overlays/usage-row.ts +22 -8
- package/src/prompt/attachment-chips.ts +15 -11
- package/src/prompt/composer-attachments.ts +6 -4
- package/src/prompt/composer-cache.ts +7 -86
- package/src/prompt/composer.ts +37 -26
- package/src/prompt/custom-editor.ts +282 -105
- package/src/prompt/image-source.ts +2 -1
- package/src/prompt/interactive-context-helpers.ts +32 -18
- package/src/prompt/macos-spelling.ts +7 -0
- package/src/prompt/magic-keywords.ts +11 -2
- package/src/prompt/model-mention-autocomplete.ts +14 -14
- package/src/prompt/queued-messages.ts +6 -4
- package/src/prompt/tips.txt +13 -9
- package/src/prompt/welcome.ts +64 -46
- package/src/prompt/word-completion.ts +38 -5
- package/src/render/composite.d.ts +2 -0
- package/src/render/composite.ts +64 -0
- package/src/render/output-pane.d.ts +1 -0
- package/src/render/output-pane.ts +6 -0
- package/src/render/render-utils.d.ts +1 -0
- package/src/render/render-utils.ts +16 -1
- package/src/render/tool-card.d.ts +6 -0
- package/src/render/tool-card.ts +15 -0
- package/src/render/width-aware-text.d.ts +2 -0
- package/src/render/width-aware-text.ts +5 -0
- package/src/setup/scenes/model.ts +2 -1
- package/src/setup/scenes/types.ts +1 -0
- package/src/space-hold.d.ts +40 -25
- package/src/space-hold.ts +156 -52
- package/src/status-line/component.ts +292 -78
- package/src/status-line/context-usage.ts +21 -46
- package/src/status-line/host.ts +4 -1
- package/src/status-line/segments.ts +40 -22
- package/src/status-line/types.ts +15 -3
- package/src/terminal-capabilities.d.ts +41 -36
- package/src/terminal-capabilities.ts +137 -213
- package/src/terminal-multiplexer.d.ts +127 -14
- package/src/terminal-multiplexer.ts +112 -33
- package/src/terminal.d.ts +23 -16
- package/src/terminal.ts +203 -99
- package/src/theme/active-symbols.d.ts +1 -1
- package/src/theme/active-symbols.ts +1 -1
- package/src/theme/schema-validation.ts +1 -0
- package/src/theme/schema.d.ts +11 -2
- package/src/theme/schema.ts +14 -1
- package/src/theme/session-color.ts +1 -7
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +11 -4
- package/src/theme/theme-class.d.ts +7 -0
- package/src/theme/theme-class.ts +26 -1
- package/src/theme/theme-schema.json +5 -1
- package/src/theme/theme.d.ts +1 -1
- package/src/theme/theme.ts +8 -4
- package/src/theme/tui-adapters.d.ts +3 -0
- package/src/theme/tui-adapters.ts +68 -0
- package/src/thinking.d.ts +1 -1
- package/src/thinking.ts +1 -1
- package/src/tmux.d.ts +11 -4
- package/src/tmux.ts +47 -11
- package/src/tools/ast-edit.ts +59 -35
- package/src/tools/ast-grep.ts +35 -16
- package/src/tools/bash.d.ts +7 -2
- package/src/tools/bash.ts +116 -47
- package/src/tools/daemon.d.ts +1 -1
- package/src/tools/daemon.ts +1 -1
- package/src/tools/default-renderer.ts +35 -19
- package/src/tools/edit.ts +142 -120
- package/src/tools/eval-format/index.ts +28 -2
- package/src/tools/eval-format/javascript.ts +7 -5
- package/src/tools/eval.d.ts +22 -3
- package/src/tools/eval.ts +364 -208
- package/src/tools/fetch.ts +5 -6
- package/src/tools/glob.d.ts +4 -0
- package/src/tools/glob.ts +33 -65
- package/src/tools/grep.ts +81 -48
- package/src/tools/index.ts +2 -0
- package/src/tools/lsp.ts +81 -59
- package/src/tools/mcp.ts +111 -68
- package/src/tools/native-view.d.ts +47 -0
- package/src/tools/native-view.ts +102 -1
- package/src/tools/output-meta.d.ts +11 -1
- package/src/tools/output-meta.ts +23 -3
- package/src/tools/read.ts +7 -5
- package/src/tools/renderer.d.ts +37 -2
- package/src/tools/renderer.ts +42 -2
- package/src/tools/streaming-output.d.ts +20 -1
- package/src/tools/streaming-output.ts +154 -50
- package/src/tools/task.d.ts +2 -3
- package/src/tools/task.ts +115 -62
- package/src/tools/todo.ts +119 -30
- package/src/tools/wait.ts +34 -24
- package/src/tools/web-search.ts +1 -1
- package/src/tools/write.d.ts +9 -2
- package/src/tools/write.ts +147 -95
- package/src/tools/yield.d.ts +22 -0
- package/src/tools/yield.ts +225 -0
- package/src/tui.d.ts +36 -0
- package/src/tui.ts +666 -217
- package/src/utils.d.ts +6 -0
- package/src/utils.ts +19 -0
- package/src/vim.d.ts +19 -5
- package/src/vim.ts +333 -18
- package/src/windows-input-mode.d.ts +33 -1
- package/src/windows-input-mode.ts +212 -6
package/src/tools/eval.ts
CHANGED
|
@@ -9,14 +9,19 @@ import type {
|
|
|
9
9
|
ToolRenderer,
|
|
10
10
|
} from "./renderer";
|
|
11
11
|
import type { TspSpan } from "@linxiraos/pi-wire";
|
|
12
|
-
import {
|
|
12
|
+
import { compact, keyed, md, node, span, text } from "../native/describe";
|
|
13
13
|
import type { NativeChild, NativeNode } from "../native/node";
|
|
14
14
|
import { plainText } from "../native/spans";
|
|
15
|
-
import {
|
|
15
|
+
import { resultText, runBox, runFoot, type RunFootInput, runInput, runOutput, type RunState } from "./native-view";
|
|
16
16
|
import { renderAgentTreeRow } from "./agent-tree";
|
|
17
17
|
import { truncateToVisualLines } from "../chrome/visual-truncate";
|
|
18
18
|
import { getMarkdownTheme, type Theme } from "../theme/theme";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
type CodeCellOptions,
|
|
21
|
+
markFramedBlockComponent,
|
|
22
|
+
outputBlockContentWidth,
|
|
23
|
+
renderCodeCell,
|
|
24
|
+
} from "../render/index";
|
|
20
25
|
import { formatOutputPaneLines } from "../render/output-pane";
|
|
21
26
|
import { formatEvalCodeForDisplay } from "./eval-format/index";
|
|
22
27
|
import {
|
|
@@ -66,6 +71,8 @@ export interface EvalCellResult {
|
|
|
66
71
|
durationMs?: number;
|
|
67
72
|
exitCode?: number;
|
|
68
73
|
statusEvents?: EvalStatusEvent[];
|
|
74
|
+
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
75
|
+
statusEventsElided?: number;
|
|
69
76
|
hasMarkdown?: boolean;
|
|
70
77
|
}
|
|
71
78
|
|
|
@@ -75,6 +82,8 @@ export interface EvalToolDetails {
|
|
|
75
82
|
jsonOutputs?: unknown[];
|
|
76
83
|
images?: ImageContent[];
|
|
77
84
|
statusEvents?: EvalStatusEvent[];
|
|
85
|
+
/** Discrete events dropped from the front of `statusEvents` (see {@link recordStatusEvent}). */
|
|
86
|
+
statusEventsElided?: number;
|
|
78
87
|
isError?: boolean;
|
|
79
88
|
meta?: OutputMeta;
|
|
80
89
|
/** First backend that produced cells. Kept for transcript compatibility. */
|
|
@@ -144,6 +153,37 @@ function getRenderCells(args: EvalRenderArgs | undefined): EvalRenderCell[] {
|
|
|
144
153
|
return out;
|
|
145
154
|
}
|
|
146
155
|
|
|
156
|
+
/**
|
|
157
|
+
* A rendered {@link renderCodeCell} box. Its first row is the header bar, the
|
|
158
|
+
* only row that depends on `spinnerFrame`; the code and output rows below it
|
|
159
|
+
* are reused across spinner ticks.
|
|
160
|
+
*/
|
|
161
|
+
interface RenderedCodeCell {
|
|
162
|
+
readonly options: CodeCellOptions;
|
|
163
|
+
readonly lines: readonly string[];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Append `cell` for `spinnerFrame`. Only a running header animates, so only it
|
|
168
|
+
* is redrawn for a new frame: `renderOutputBlock` lays the header bar out from
|
|
169
|
+
* the header fields and width alone, so rendering an empty cell with the same
|
|
170
|
+
* header yields the identical bar row.
|
|
171
|
+
*/
|
|
172
|
+
function pushCodeCellLines(
|
|
173
|
+
out: string[],
|
|
174
|
+
cell: RenderedCodeCell,
|
|
175
|
+
spinnerFrame: number | undefined,
|
|
176
|
+
theme: Theme,
|
|
177
|
+
): void {
|
|
178
|
+
const { options, lines } = cell;
|
|
179
|
+
const header =
|
|
180
|
+
options.status === "running" && options.spinnerFrame !== spinnerFrame
|
|
181
|
+
? renderCodeCell({ ...options, code: "", output: undefined, spinnerFrame }, theme)[0]!
|
|
182
|
+
: lines[0]!;
|
|
183
|
+
out.push(header);
|
|
184
|
+
for (let i = 1; i < lines.length; i++) out.push(lines[i]!);
|
|
185
|
+
}
|
|
186
|
+
|
|
147
187
|
type AgentEventStatus = "pending" | "running" | "completed" | "failed" | "aborted";
|
|
148
188
|
|
|
149
189
|
/**
|
|
@@ -159,11 +199,20 @@ export function statusEventKey(event: { op: string; [key: string]: unknown }): s
|
|
|
159
199
|
return undefined;
|
|
160
200
|
}
|
|
161
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Discrete status events a log keeps. A cell polling a helper in a loop emits
|
|
204
|
+
* one event per call (hundreds of thousands), and every live update and the
|
|
205
|
+
* persisted tool result would otherwise carry them all.
|
|
206
|
+
*/
|
|
207
|
+
export const MAX_STATUS_EVENTS = 200;
|
|
208
|
+
|
|
209
|
+
/** A status event list plus the count of discrete events dropped from its front. */
|
|
210
|
+
export type StatusEventLog = Pick<EvalCellResult, "statusEvents" | "statusEventsElided">;
|
|
211
|
+
|
|
162
212
|
/**
|
|
163
213
|
* Append or replace a status event. Progress snapshots (see
|
|
164
214
|
* {@link statusEventKey}) coalesce in place, preserving first-seen order; every
|
|
165
|
-
* other op is a discrete action and simply appends.
|
|
166
|
-
* list bounded even when a subagent or batch emits hundreds of progress ticks.
|
|
215
|
+
* other op is a discrete action and simply appends.
|
|
167
216
|
*/
|
|
168
217
|
export function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEvent): void {
|
|
169
218
|
const key = statusEventKey(event);
|
|
@@ -177,6 +226,24 @@ export function upsertStatusEvent(events: EvalStatusEvent[], event: EvalStatusEv
|
|
|
177
226
|
events.push(event);
|
|
178
227
|
}
|
|
179
228
|
|
|
229
|
+
/**
|
|
230
|
+
* {@link upsertStatusEvent} into a bounded log. Past {@link MAX_STATUS_EVENTS},
|
|
231
|
+
* the oldest discrete event is dropped and counted. Snapshots stay, since agent
|
|
232
|
+
* cards read them, and so does the newest committed `todo` result, which the
|
|
233
|
+
* session todo panel refreshes from. Renderers already show only the newest
|
|
234
|
+
* events behind an "… N earlier" row.
|
|
235
|
+
*/
|
|
236
|
+
export function recordStatusEvent(log: StatusEventLog, event: EvalStatusEvent): void {
|
|
237
|
+
const events = (log.statusEvents ??= []);
|
|
238
|
+
upsertStatusEvent(events, event);
|
|
239
|
+
if (events.length <= MAX_STATUS_EVENTS) return;
|
|
240
|
+
const keep = events.findLastIndex(e => e.op === "todo" && e.committed === true);
|
|
241
|
+
const oldest = events.findIndex((e, i) => i !== keep && statusEventKey(e) === undefined);
|
|
242
|
+
if (oldest < 0) return;
|
|
243
|
+
events.splice(oldest, 1);
|
|
244
|
+
log.statusEventsElided = (log.statusEventsElided ?? 0) + 1;
|
|
245
|
+
}
|
|
246
|
+
|
|
180
247
|
function eventString(value: unknown): string | undefined {
|
|
181
248
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
182
249
|
}
|
|
@@ -475,17 +542,20 @@ function formatStatusEventExpanded(event: EvalStatusEvent, theme: Theme): string
|
|
|
475
542
|
* the live edge for `log()` progress loops) behind an "… N earlier" marker,
|
|
476
543
|
* matching the code/output tail-window convention. Collapsed keeps a small
|
|
477
544
|
* fixed window; expanded widens to the viewport-sized preview window.
|
|
545
|
+
* `elided` counts events already dropped from the log's front.
|
|
478
546
|
*/
|
|
479
|
-
function renderStatusEvents(events: EvalStatusEvent[], theme: Theme, expanded: boolean): string[] {
|
|
480
|
-
if (events.length === 0) return [];
|
|
547
|
+
function renderStatusEvents(events: EvalStatusEvent[], theme: Theme, expanded: boolean, elided = 0): string[] {
|
|
548
|
+
if (events.length === 0 && elided === 0) return [];
|
|
481
549
|
|
|
482
550
|
const max = expanded ? Math.max(10, previewWindowRows()) : 3;
|
|
483
|
-
const
|
|
484
|
-
const
|
|
551
|
+
const shownFrom = Math.max(0, events.length - max);
|
|
552
|
+
const hidden = shownFrom + elided;
|
|
553
|
+
const visible = shownFrom > 0 ? events.slice(shownFrom) : events;
|
|
485
554
|
|
|
486
555
|
const lines: string[] = [];
|
|
487
556
|
if (hidden > 0) {
|
|
488
|
-
|
|
557
|
+
const glyph = visible.length > 0 ? theme.tree.branch : theme.tree.last;
|
|
558
|
+
lines.push(`${theme.fg("dim", glyph)} ${theme.fg("dim", `… ${hidden} earlier`)}`);
|
|
489
559
|
}
|
|
490
560
|
for (let i = 0; i < visible.length; i++) {
|
|
491
561
|
const isLast = i === visible.length - 1;
|
|
@@ -658,89 +728,112 @@ function splitConsoleTables(output: string): EvalOutputPart[] {
|
|
|
658
728
|
return parts;
|
|
659
729
|
}
|
|
660
730
|
|
|
661
|
-
/**
|
|
662
|
-
|
|
731
|
+
/**
|
|
732
|
+
* One cell's outputs: markdown, else terminal text (following its tail,
|
|
733
|
+
* clamped to the last `previewLines` while folded) with any `console.table`
|
|
734
|
+
* blocks as tables.
|
|
735
|
+
*/
|
|
736
|
+
function evalOutputNodes(output: string, markdown: boolean, previewLines: number): NativeNode[] {
|
|
663
737
|
if (output.trim().length === 0) return [];
|
|
664
|
-
if (markdown
|
|
665
|
-
|
|
666
|
-
return splitConsoleTables(output).map(part =>
|
|
738
|
+
if (markdown) return [keyed(md(output), "output")];
|
|
739
|
+
return splitConsoleTables(output).map((part, i) =>
|
|
667
740
|
part.kind === "text"
|
|
668
|
-
?
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
741
|
+
? runOutput(part.text, {
|
|
742
|
+
role: "zeta.tool.eval.output",
|
|
743
|
+
previewLines,
|
|
744
|
+
key: i === 0 ? "output" : `output-${i}`,
|
|
745
|
+
})
|
|
746
|
+
: node(
|
|
747
|
+
"table",
|
|
748
|
+
{
|
|
749
|
+
// Node's index column header is noise in a real table.
|
|
750
|
+
cols: part.head.map((head, c) => ({ id: `c${c}`, head: head === "(index)" ? "" : head })),
|
|
751
|
+
rows: part.rows.map((cells, r) => ({
|
|
752
|
+
id: `r${r}`,
|
|
753
|
+
cells: Object.fromEntries(cells.map((cell, c) => [`c${c}`, cell])),
|
|
754
|
+
})),
|
|
755
|
+
role: "zeta.tool.eval.table",
|
|
756
|
+
},
|
|
757
|
+
undefined,
|
|
758
|
+
`table-${i}`,
|
|
759
|
+
),
|
|
678
760
|
);
|
|
679
761
|
}
|
|
680
762
|
|
|
681
|
-
/**
|
|
682
|
-
|
|
763
|
+
/** Status lines a folded cell keeps: the newest ones. */
|
|
764
|
+
const RUN_STATUS_TAIL = 8;
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* A status log's events (`zeta.run.status`): all kept ones when expanded, else
|
|
768
|
+
* the newest {@link RUN_STATUS_TAIL}, after a muted `N earlier` line that also
|
|
769
|
+
* counts events already dropped from the log's front.
|
|
770
|
+
*/
|
|
771
|
+
function evalStatusSection(log: StatusEventLog, expanded: boolean): NativeNode | undefined {
|
|
772
|
+
const events = log.statusEvents ?? [];
|
|
773
|
+
const elided = log.statusEventsElided ?? 0;
|
|
774
|
+
if (events.length === 0 && elided === 0) return undefined;
|
|
775
|
+
const shownFrom = expanded ? 0 : Math.max(0, events.length - RUN_STATUS_TAIL);
|
|
776
|
+
const hidden = shownFrom + elided;
|
|
777
|
+
const lines = events.slice(shownFrom).map((event, i) => keyed(describeStatusEvent(event), `s${hidden + i}`));
|
|
778
|
+
return node(
|
|
779
|
+
"col",
|
|
780
|
+
{ role: "zeta.run.status", gap: "none" },
|
|
781
|
+
compact<NativeNode>([hidden > 0 && keyed(text([span(`${hidden} earlier`, "muted")]), "earlier"), ...lines]),
|
|
782
|
+
"status",
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/** The foot state of a cell, or undefined while it has not started. */
|
|
787
|
+
function evalCellState(status: EvalCellResult["status"], cancelled: boolean): RunState | undefined {
|
|
788
|
+
switch (status) {
|
|
789
|
+
case "pending":
|
|
790
|
+
return undefined;
|
|
791
|
+
case "running":
|
|
792
|
+
return cancelled ? "cancelled" : "running";
|
|
793
|
+
case "complete":
|
|
794
|
+
return "done";
|
|
795
|
+
case "error":
|
|
796
|
+
return "failed";
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/** Inputs of one eval cell box. */
|
|
801
|
+
interface EvalCellRun {
|
|
683
802
|
readonly language: EvalLanguage;
|
|
684
803
|
readonly code: string;
|
|
685
804
|
readonly title?: string;
|
|
686
|
-
readonly
|
|
687
|
-
readonly
|
|
688
|
-
|
|
805
|
+
readonly outputs?: readonly NativeChild[];
|
|
806
|
+
readonly status?: NativeNode;
|
|
807
|
+
/** Omitted while the cell has not started. */
|
|
808
|
+
readonly foot?: RunFootInput;
|
|
689
809
|
}
|
|
690
810
|
|
|
691
811
|
/**
|
|
692
|
-
* A notebook cell
|
|
693
|
-
*
|
|
694
|
-
* Only multi-cell calls repeat titles; marks never invent execution counts.
|
|
812
|
+
* A notebook cell as one run box: the caption (multi-cell calls only), the
|
|
813
|
+
* source, its outputs, status lines and foot. A failed cell tints its box.
|
|
695
814
|
*/
|
|
696
|
-
function
|
|
697
|
-
let
|
|
815
|
+
function evalCellBox(cell: EvalCellRun, index: number, total: number): NativeNode {
|
|
816
|
+
let caption: NativeNode | undefined;
|
|
698
817
|
if (total > 1) {
|
|
699
|
-
|
|
818
|
+
const spans: TspSpan[] = [span(`${index + 1}/${total}`, "muted")];
|
|
700
819
|
const title = plainText(cell.title ?? "").trim();
|
|
701
|
-
if (title)
|
|
702
|
-
|
|
703
|
-
if (cell.durationMs !== undefined) head.push(span(` · ${(cell.durationMs / 1000).toFixed(2)}s`, "muted"));
|
|
820
|
+
if (title) spans.push(span(` ${title}`, "toolTitle"));
|
|
821
|
+
caption = keyed(text(spans, { role: "zeta.run.caption" }), "caption");
|
|
704
822
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
role: "zeta.tool.eval.
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
})
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
},
|
|
720
|
-
compact<NativeChild>([
|
|
721
|
-
head ? text(head, { role: "zeta.tool.eval.caption" }) : undefined,
|
|
722
|
-
node(
|
|
723
|
-
"row",
|
|
724
|
-
{ role: "zeta.tool.eval.input", align: "start" },
|
|
725
|
-
[
|
|
726
|
-
inputMark,
|
|
727
|
-
keyed(codeNode(cell.code, { lang: languageForHighlighter(cell.language), numbers: false }), "code"),
|
|
728
|
-
],
|
|
729
|
-
"input",
|
|
730
|
-
),
|
|
731
|
-
cell.output?.length
|
|
732
|
-
? node(
|
|
733
|
-
"row",
|
|
734
|
-
{ role: "zeta.tool.eval.result", align: "start" },
|
|
735
|
-
[
|
|
736
|
-
node("icon", { name: "arrow-right", role: "zeta.tool.eval.prompt", aria: "Output" }),
|
|
737
|
-
node("col", { role: "zeta.tool.eval.outputs" }, cell.output),
|
|
738
|
-
],
|
|
739
|
-
"output",
|
|
740
|
-
)
|
|
741
|
-
: undefined,
|
|
742
|
-
]),
|
|
743
|
-
`cell-${index}`,
|
|
823
|
+
return runBox(
|
|
824
|
+
[
|
|
825
|
+
caption,
|
|
826
|
+
cell.code.trim().length > 0 &&
|
|
827
|
+
runInput(cell.code, {
|
|
828
|
+
role: "zeta.tool.eval.input",
|
|
829
|
+
lang: languageForHighlighter(cell.language),
|
|
830
|
+
wrap: false,
|
|
831
|
+
}),
|
|
832
|
+
...(cell.outputs ?? []),
|
|
833
|
+
cell.status,
|
|
834
|
+
cell.foot && runFoot(cell.foot),
|
|
835
|
+
],
|
|
836
|
+
{ key: `cell-${index}`, tone: cell.foot?.state === "failed" ? "error" : undefined },
|
|
744
837
|
);
|
|
745
838
|
}
|
|
746
839
|
|
|
@@ -757,47 +850,59 @@ export const evalToolRenderer = {
|
|
|
757
850
|
return new Text(text, 0, 0);
|
|
758
851
|
}
|
|
759
852
|
|
|
760
|
-
|
|
853
|
+
// Cell bodies depend on width, expansion, the viewport window and whether
|
|
854
|
+
// the call is live; a spinner tick only redraws the running header rows.
|
|
855
|
+
let bodies: { key: string; cells: RenderedCodeCell[] } | undefined;
|
|
856
|
+
let cached: { key: string; result: string[] } | undefined;
|
|
761
857
|
|
|
762
858
|
return markFramedBlockComponent({
|
|
763
859
|
render: (width: number): readonly string[] => {
|
|
764
|
-
const
|
|
765
|
-
|
|
860
|
+
const spinnerFrame = options.spinnerFrame;
|
|
861
|
+
const windowRows = previewWindowRows();
|
|
862
|
+
const bodyKey = `${width}|${options.expanded ? 1 : 0}|${windowRows}|${spinnerFrame === undefined ? 0 : 1}`;
|
|
863
|
+
const key = `${bodyKey}|${spinnerFrame ?? "-"}`;
|
|
864
|
+
if (cached?.key === key) {
|
|
766
865
|
return cached.result;
|
|
767
866
|
}
|
|
768
867
|
|
|
868
|
+
if (bodies?.key !== bodyKey) {
|
|
869
|
+
bodies = {
|
|
870
|
+
key: bodyKey,
|
|
871
|
+
cells: cells.map((cell, i) => {
|
|
872
|
+
const cellOptions: CodeCellOptions = {
|
|
873
|
+
code: cell.code,
|
|
874
|
+
language: languageForHighlighter(cell.language),
|
|
875
|
+
showLanguage: true,
|
|
876
|
+
index: i,
|
|
877
|
+
total: cells.length,
|
|
878
|
+
title: cell.title,
|
|
879
|
+
status: spinnerFrame !== undefined ? "running" : "pending",
|
|
880
|
+
spinnerFrame,
|
|
881
|
+
width,
|
|
882
|
+
// Viewport-sized tail window following the newest streamed code
|
|
883
|
+
// line; renderResult keeps the same cap so the cell never snaps
|
|
884
|
+
// open on completion. Only ctrl+o uncaps.
|
|
885
|
+
codeTail: true,
|
|
886
|
+
codeMaxLines: windowRows,
|
|
887
|
+
expanded: options.expanded,
|
|
888
|
+
};
|
|
889
|
+
return { options: cellOptions, lines: renderCodeCell(cellOptions, uiTheme) };
|
|
890
|
+
}),
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
|
|
769
894
|
const lines: string[] = [];
|
|
770
|
-
for (let i = 0; i < cells.length; i++) {
|
|
771
|
-
|
|
772
|
-
const cellLines = renderCodeCell(
|
|
773
|
-
{
|
|
774
|
-
code: cell.code,
|
|
775
|
-
language: languageForHighlighter(cell.language),
|
|
776
|
-
showLanguage: true,
|
|
777
|
-
index: i,
|
|
778
|
-
total: cells.length,
|
|
779
|
-
title: cell.title,
|
|
780
|
-
status: options.spinnerFrame !== undefined ? "running" : "pending",
|
|
781
|
-
spinnerFrame: options.spinnerFrame,
|
|
782
|
-
width,
|
|
783
|
-
// Viewport-sized tail window following the newest streamed code
|
|
784
|
-
// line; renderResult keeps the same cap so the cell never snaps
|
|
785
|
-
// open on completion. Only ctrl+o uncaps.
|
|
786
|
-
codeTail: true,
|
|
787
|
-
codeMaxLines: previewWindowRows(),
|
|
788
|
-
expanded: options.expanded,
|
|
789
|
-
},
|
|
790
|
-
uiTheme,
|
|
791
|
-
);
|
|
792
|
-
lines.push(...cellLines);
|
|
895
|
+
for (let i = 0; i < bodies.cells.length; i++) {
|
|
896
|
+
pushCodeCellLines(lines, bodies.cells[i]!, spinnerFrame, uiTheme);
|
|
793
897
|
if (i < cells.length - 1) {
|
|
794
898
|
lines.push("");
|
|
795
899
|
}
|
|
796
900
|
}
|
|
797
|
-
cached = { key,
|
|
901
|
+
cached = { key, result: lines };
|
|
798
902
|
return lines;
|
|
799
903
|
},
|
|
800
904
|
invalidate: () => {
|
|
905
|
+
bodies = undefined;
|
|
801
906
|
cached = undefined;
|
|
802
907
|
},
|
|
803
908
|
});
|
|
@@ -848,69 +953,106 @@ export const evalToolRenderer = {
|
|
|
848
953
|
if (cellResults && cellResults.length > 0) {
|
|
849
954
|
const displayCells = cellResults.map(cell => {
|
|
850
955
|
const language = cell.language ?? details?.language ?? "python";
|
|
851
|
-
|
|
956
|
+
const allEvents = cell.statusEvents ?? [];
|
|
957
|
+
const agentEvents = allEvents.filter(e => e.op === "agent");
|
|
958
|
+
return {
|
|
959
|
+
cell,
|
|
960
|
+
code: formatEvalCodeForDisplay(cell.code, language),
|
|
961
|
+
language,
|
|
962
|
+
agentEvents,
|
|
963
|
+
otherEvents: agentEvents.length > 0 ? allEvents.filter(e => e.op !== "agent") : allEvents,
|
|
964
|
+
// Running agent rows carry the spinner; settled ones are frame-independent.
|
|
965
|
+
agentLive: agentEvents.some(e => agentEventStatus(e.status) === "running"),
|
|
966
|
+
};
|
|
852
967
|
});
|
|
853
|
-
|
|
968
|
+
// Per-cell rows keyed by everything but the spinner frame: a tick only
|
|
969
|
+
// redraws running headers and running agent rows.
|
|
970
|
+
let bodies:
|
|
971
|
+
| {
|
|
972
|
+
key: string;
|
|
973
|
+
cells: { codeCell: RenderedCodeCell; agentLines: string[]; agentFrame: number | undefined }[];
|
|
974
|
+
}
|
|
975
|
+
| undefined;
|
|
976
|
+
let cached: { key: string; result: string[] } | undefined;
|
|
854
977
|
|
|
855
978
|
return markFramedBlockComponent({
|
|
856
979
|
render: (width: number): readonly string[] => {
|
|
980
|
+
const spinnerFrame = options.spinnerFrame;
|
|
857
981
|
const expanded = options.renderContext?.expanded ?? options.expanded;
|
|
982
|
+
const windowRows = previewWindowRows();
|
|
858
983
|
const previewLines = Math.min(
|
|
859
984
|
options.renderContext?.previewLines ?? EVAL_DEFAULT_PREVIEW_LINES,
|
|
860
|
-
|
|
985
|
+
windowRows,
|
|
861
986
|
);
|
|
862
|
-
const
|
|
863
|
-
|
|
987
|
+
const bodyKey = `${width}|${expanded}|${previewLines}|${windowRows}`;
|
|
988
|
+
const key = `${bodyKey}|${spinnerFrame}`;
|
|
989
|
+
if (cached?.key === key) {
|
|
864
990
|
return cached.result;
|
|
865
991
|
}
|
|
866
992
|
|
|
993
|
+
if (bodies?.key !== bodyKey) {
|
|
994
|
+
bodies = {
|
|
995
|
+
key: bodyKey,
|
|
996
|
+
cells: displayCells.map(({ cell, code, language, agentEvents, otherEvents }, i) => {
|
|
997
|
+
const statusLines = renderStatusEvents(otherEvents, uiTheme, expanded, cell.statusEventsElided);
|
|
998
|
+
const outputContent = formatCellOutputLines(cell, expanded, previewLines, uiTheme, width);
|
|
999
|
+
const outputLines = [...outputContent.lines];
|
|
1000
|
+
if (!expanded && outputContent.hiddenCount > 0) {
|
|
1001
|
+
outputLines.push(
|
|
1002
|
+
uiTheme.fg(
|
|
1003
|
+
"dim",
|
|
1004
|
+
`… ${outputContent.hiddenCount} more lines (${expandKeyHint()} to expand)`,
|
|
1005
|
+
),
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
if (statusLines.length > 0) {
|
|
1009
|
+
if (outputLines.length > 0) {
|
|
1010
|
+
outputLines.push(uiTheme.fg("dim", "Status"));
|
|
1011
|
+
}
|
|
1012
|
+
outputLines.push(...statusLines);
|
|
1013
|
+
}
|
|
1014
|
+
const cellOptions: CodeCellOptions = {
|
|
1015
|
+
code,
|
|
1016
|
+
language: languageForHighlighter(language),
|
|
1017
|
+
showLanguage: true,
|
|
1018
|
+
index: i,
|
|
1019
|
+
total: cellResults.length,
|
|
1020
|
+
title: cell.title,
|
|
1021
|
+
status: cell.status,
|
|
1022
|
+
spinnerFrame,
|
|
1023
|
+
duration: cell.durationMs,
|
|
1024
|
+
output: outputLines.length > 0 ? outputLines.join("\n") : undefined,
|
|
1025
|
+
outputMaxLines: outputLines.length,
|
|
1026
|
+
// Same viewport-sized tail window as the pending preview so the
|
|
1027
|
+
// cell never snaps open on completion; only ctrl+o uncaps.
|
|
1028
|
+
// `output` keeps its own preview cap from above.
|
|
1029
|
+
codeTail: true,
|
|
1030
|
+
codeMaxLines: windowRows,
|
|
1031
|
+
expanded,
|
|
1032
|
+
width,
|
|
1033
|
+
};
|
|
1034
|
+
return {
|
|
1035
|
+
codeCell: { options: cellOptions, lines: renderCodeCell(cellOptions, uiTheme) },
|
|
1036
|
+
agentLines:
|
|
1037
|
+
agentEvents.length > 0
|
|
1038
|
+
? renderAgentProgressEvents(agentEvents, uiTheme, width, spinnerFrame)
|
|
1039
|
+
: [],
|
|
1040
|
+
agentFrame: spinnerFrame,
|
|
1041
|
+
};
|
|
1042
|
+
}),
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
867
1046
|
const lines: string[] = [];
|
|
868
1047
|
for (let i = 0; i < displayCells.length; i++) {
|
|
869
|
-
const {
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
const outputLines = [...outputContent.lines];
|
|
876
|
-
if (!expanded && outputContent.hiddenCount > 0) {
|
|
877
|
-
outputLines.push(
|
|
878
|
-
uiTheme.fg("dim", `… ${outputContent.hiddenCount} more lines (${expandKeyHint()} to expand)`),
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
if (statusLines.length > 0) {
|
|
882
|
-
if (outputLines.length > 0) {
|
|
883
|
-
outputLines.push(uiTheme.fg("dim", "Status"));
|
|
884
|
-
}
|
|
885
|
-
outputLines.push(...statusLines);
|
|
886
|
-
}
|
|
887
|
-
const cellLines = renderCodeCell(
|
|
888
|
-
{
|
|
889
|
-
code,
|
|
890
|
-
language: languageForHighlighter(language),
|
|
891
|
-
showLanguage: true,
|
|
892
|
-
index: i,
|
|
893
|
-
total: cellResults.length,
|
|
894
|
-
title: cell.title,
|
|
895
|
-
status: cell.status,
|
|
896
|
-
spinnerFrame: options.spinnerFrame,
|
|
897
|
-
duration: cell.durationMs,
|
|
898
|
-
output: outputLines.length > 0 ? outputLines.join("\n") : undefined,
|
|
899
|
-
outputMaxLines: outputLines.length,
|
|
900
|
-
// Same viewport-sized tail window as the pending preview so the
|
|
901
|
-
// cell never snaps open on completion; only ctrl+o uncaps.
|
|
902
|
-
// `output` keeps its own preview cap from above.
|
|
903
|
-
codeTail: true,
|
|
904
|
-
codeMaxLines: previewWindowRows(),
|
|
905
|
-
expanded,
|
|
906
|
-
width,
|
|
907
|
-
},
|
|
908
|
-
uiTheme,
|
|
909
|
-
);
|
|
910
|
-
lines.push(...cellLines);
|
|
911
|
-
if (agentEvents.length > 0) {
|
|
912
|
-
lines.push(...renderAgentProgressEvents(agentEvents, uiTheme, width, options.spinnerFrame));
|
|
1048
|
+
const { agentEvents, agentLive } = displayCells[i]!;
|
|
1049
|
+
const body = bodies.cells[i]!;
|
|
1050
|
+
pushCodeCellLines(lines, body.codeCell, spinnerFrame, uiTheme);
|
|
1051
|
+
if (agentLive && body.agentFrame !== spinnerFrame) {
|
|
1052
|
+
body.agentLines = renderAgentProgressEvents(agentEvents, uiTheme, width, spinnerFrame);
|
|
1053
|
+
body.agentFrame = spinnerFrame;
|
|
913
1054
|
}
|
|
1055
|
+
lines.push(...body.agentLines);
|
|
914
1056
|
if (i < cellResults.length - 1) {
|
|
915
1057
|
lines.push("");
|
|
916
1058
|
}
|
|
@@ -928,10 +1070,11 @@ export const evalToolRenderer = {
|
|
|
928
1070
|
if (warningLine) {
|
|
929
1071
|
lines.push(warningLine);
|
|
930
1072
|
}
|
|
931
|
-
cached = { key,
|
|
1073
|
+
cached = { key, result: lines };
|
|
932
1074
|
return lines;
|
|
933
1075
|
},
|
|
934
1076
|
invalidate: () => {
|
|
1077
|
+
bodies = undefined;
|
|
935
1078
|
cached = undefined;
|
|
936
1079
|
},
|
|
937
1080
|
});
|
|
@@ -945,6 +1088,7 @@ export const evalToolRenderer = {
|
|
|
945
1088
|
statusEvents,
|
|
946
1089
|
uiTheme,
|
|
947
1090
|
options.renderContext?.expanded ?? options.expanded,
|
|
1091
|
+
details?.statusEventsElided,
|
|
948
1092
|
);
|
|
949
1093
|
|
|
950
1094
|
if (!combinedOutput && statusLines.length === 0) {
|
|
@@ -1043,16 +1187,20 @@ export const evalToolRenderer = {
|
|
|
1043
1187
|
};
|
|
1044
1188
|
},
|
|
1045
1189
|
|
|
1046
|
-
describeCall(args: EvalRenderArgs,
|
|
1190
|
+
describeCall(args: EvalRenderArgs, options: RenderResultOptions): NativeToolView {
|
|
1047
1191
|
const cells = getRenderCells(args);
|
|
1192
|
+
// No foot until the call starts; then the first cell runs (before any result names it).
|
|
1193
|
+
const startFoot: RunFootInput | undefined = options.executionStarted
|
|
1194
|
+
? { state: options.cancelled ? "cancelled" : "running", elapsedMs: options.elapsedMs }
|
|
1195
|
+
: undefined;
|
|
1048
1196
|
return {
|
|
1049
1197
|
tool: evalToolHead(
|
|
1050
1198
|
cells[0]?.title,
|
|
1051
1199
|
cells.map(cell => cell.language),
|
|
1052
1200
|
cells.length,
|
|
1053
1201
|
),
|
|
1054
|
-
body: cells.map((cell, i) =>
|
|
1055
|
-
preview:
|
|
1202
|
+
body: cells.map((cell, i) => evalCellBox({ ...cell, foot: i === 0 ? startFoot : undefined }, i, cells.length)),
|
|
1203
|
+
preview: "children",
|
|
1056
1204
|
};
|
|
1057
1205
|
},
|
|
1058
1206
|
|
|
@@ -1063,82 +1211,90 @@ export const evalToolRenderer = {
|
|
|
1063
1211
|
): NativeToolView {
|
|
1064
1212
|
const details = result.details;
|
|
1065
1213
|
const isPartial = options.isPartial === true;
|
|
1214
|
+
const cancelled = options.cancelled === true;
|
|
1215
|
+
const expanded = options.renderContext?.expanded ?? options.expanded;
|
|
1066
1216
|
const previewLines = options.renderContext?.previewLines ?? EVAL_DEFAULT_PREVIEW_LINES;
|
|
1067
1217
|
const jsonNodes = (details?.jsonOutputs ?? []).map((value, index) =>
|
|
1068
1218
|
keyed(describeJsonTree(value, { hiddenRootKeys: [] }), `display-${index}`),
|
|
1069
1219
|
);
|
|
1070
|
-
//
|
|
1071
|
-
const
|
|
1220
|
+
// The call's notice and truncation join the last run's foot facts (a background job is a head badge).
|
|
1221
|
+
const callFacts = { facts: compact([details?.notice]), meta: details?.meta };
|
|
1072
1222
|
const cellResults = details?.cells;
|
|
1073
|
-
let cells: NativeNode[];
|
|
1074
|
-
let head: NativeToolHead;
|
|
1075
1223
|
if (cellResults && cellResults.length > 0) {
|
|
1076
1224
|
const languages = cellResults.map(cell => cell.language ?? details?.language ?? "python");
|
|
1077
|
-
|
|
1078
|
-
|
|
1225
|
+
const states = cellResults.map(cell => evalCellState(cell.status, cancelled));
|
|
1226
|
+
// A cell that never started has no foot to carry the call's facts: the last one that ran does.
|
|
1227
|
+
const factsIndex = states.findLastIndex(state => state !== undefined);
|
|
1228
|
+
let earlierMs = 0;
|
|
1229
|
+
const cells = cellResults.map((cell, i) => {
|
|
1079
1230
|
const language = languages[i]!;
|
|
1080
|
-
|
|
1231
|
+
const state = states[i];
|
|
1232
|
+
// A running cell's clock is the call's minus the cells that finished before it.
|
|
1233
|
+
const elapsedMs =
|
|
1234
|
+
state === "running" || state === "cancelled"
|
|
1235
|
+
? options.elapsedMs === undefined
|
|
1236
|
+
? undefined
|
|
1237
|
+
: Math.max(0, options.elapsedMs - earlierMs)
|
|
1238
|
+
: cell.durationMs;
|
|
1239
|
+
earlierMs += cell.durationMs ?? 0;
|
|
1240
|
+
return evalCellBox(
|
|
1081
1241
|
{
|
|
1082
1242
|
language,
|
|
1083
1243
|
code: formatEvalCodeForDisplay(cell.code, language),
|
|
1084
1244
|
title: cell.title,
|
|
1085
|
-
|
|
1086
|
-
durationMs: cell.durationMs,
|
|
1087
|
-
output: [
|
|
1245
|
+
outputs: [
|
|
1088
1246
|
...evalOutputNodes(
|
|
1089
1247
|
cell.output,
|
|
1090
|
-
cell.hasMarkdown === true,
|
|
1091
|
-
|
|
1092
|
-
cell.status === "error",
|
|
1248
|
+
cell.hasMarkdown === true && cell.status !== "error",
|
|
1249
|
+
previewLines,
|
|
1093
1250
|
),
|
|
1094
|
-
|
|
1251
|
+
|
|
1095
1252
|
...(i === cellResults.length - 1 ? jsonNodes : []),
|
|
1096
1253
|
],
|
|
1254
|
+
status: evalStatusSection(cell, expanded),
|
|
1255
|
+
foot: state && {
|
|
1256
|
+
state,
|
|
1257
|
+
exitCode: cell.exitCode,
|
|
1258
|
+
elapsedMs,
|
|
1259
|
+
...(i === factsIndex ? callFacts : {}),
|
|
1260
|
+
},
|
|
1097
1261
|
},
|
|
1098
1262
|
i,
|
|
1099
1263
|
cellResults.length,
|
|
1100
1264
|
);
|
|
1101
1265
|
});
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1266
|
+
return {
|
|
1267
|
+
tool: evalToolHead(cellResults[0]!.title, languages, cellResults.length, details),
|
|
1268
|
+
body: cells,
|
|
1269
|
+
preview: "children",
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
// No per-cell results (older details): the call's cells, the whole output and foot under the last.
|
|
1273
|
+
const argCells = getRenderCells(args);
|
|
1274
|
+
const languages = details?.languages ?? (details?.language ? [details.language] : []);
|
|
1275
|
+
const rawOutput = options.renderContext?.output ?? resultText(result).trimEnd();
|
|
1276
|
+
const state: RunState = cancelled ? "cancelled" : isPartial ? "running" : result.isError ? "failed" : "done";
|
|
1277
|
+
const last: Omit<EvalCellRun, "language" | "code" | "title"> = {
|
|
1278
|
+
outputs: [
|
|
1279
|
+
...evalOutputNodes(stripOutputNotice(rawOutput, details?.meta).trimEnd(), false, previewLines),
|
|
1280
|
+
...jsonNodes,
|
|
1281
|
+
],
|
|
1282
|
+
status: evalStatusSection(details ?? {}, expanded),
|
|
1283
|
+
foot: { state, elapsedMs: options.elapsedMs, ...callFacts },
|
|
1284
|
+
};
|
|
1285
|
+
const runs: EvalCellRun[] =
|
|
1286
|
+
argCells.length > 0
|
|
1287
|
+
? argCells.map((cell, i) => (i === argCells.length - 1 ? { ...cell, ...last } : cell))
|
|
1288
|
+
: [{ language: languages[0] ?? "python", code: "", ...last }];
|
|
1289
|
+
return {
|
|
1290
|
+
tool: evalToolHead(
|
|
1107
1291
|
argCells[0]?.title,
|
|
1108
1292
|
argCells.length > 0 ? argCells.map(cell => cell.language) : languages,
|
|
1109
1293
|
argCells.length,
|
|
1110
1294
|
details,
|
|
1111
|
-
)
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
...evalOutputNodes(
|
|
1115
|
-
stripOutputNotice(rawOutput, details?.meta).trimEnd(),
|
|
1116
|
-
false,
|
|
1117
|
-
isPartial,
|
|
1118
|
-
result.isError === true,
|
|
1119
|
-
),
|
|
1120
|
-
...(details?.statusEvents ?? []).map(describeStatusEvent),
|
|
1121
|
-
...jsonNodes,
|
|
1122
|
-
];
|
|
1123
|
-
cells =
|
|
1124
|
-
argCells.length > 0
|
|
1125
|
-
? argCells.map((cell, i) =>
|
|
1126
|
-
evalCellSection(
|
|
1127
|
-
{
|
|
1128
|
-
...cell,
|
|
1129
|
-
status: isPartial ? "running" : result.isError ? "error" : "complete",
|
|
1130
|
-
output: i === argCells.length - 1 ? output : undefined,
|
|
1131
|
-
},
|
|
1132
|
-
i,
|
|
1133
|
-
argCells.length,
|
|
1134
|
-
),
|
|
1135
|
-
)
|
|
1136
|
-
: output;
|
|
1137
|
-
}
|
|
1138
|
-
return {
|
|
1139
|
-
tool: head,
|
|
1140
|
-
body: compact<NativeChild>([...cells, footer]),
|
|
1141
|
-
preview: { lines: previewLines },
|
|
1295
|
+
),
|
|
1296
|
+
body: runs.map((run, i) => evalCellBox(run, i, runs.length)),
|
|
1297
|
+
preview: "children",
|
|
1142
1298
|
};
|
|
1143
1299
|
},
|
|
1144
1300
|
|