@adea-ai/ui 0.140.0 → 0.142.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/dist/components/composites/appearance-editor/appearance-editor.js +2 -2
- package/dist/components/composites/appearance-editor/appearance-editor.js.map +1 -1
- package/dist/components/composites/catalog-browser/catalog-browser-group.js +1 -1
- package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts +56 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.d.ts.map +1 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.js +117 -0
- package/dist/components/composites/chain-of-thought/chain-of-thought.js.map +1 -0
- package/dist/components/composites/chain-of-thought/index.d.ts +2 -0
- package/dist/components/composites/chain-of-thought/index.d.ts.map +1 -0
- package/dist/components/composites/chain-of-thought/index.js +2 -0
- package/dist/components/composites/chat/chat.d.ts +67 -0
- package/dist/components/composites/chat/chat.d.ts.map +1 -0
- package/dist/components/composites/chat/chat.js +179 -0
- package/dist/components/composites/chat/chat.js.map +1 -0
- package/dist/components/composites/chat/index.d.ts +2 -0
- package/dist/components/composites/chat/index.d.ts.map +1 -0
- package/dist/components/composites/chat/index.js +2 -0
- package/dist/components/composites/checkpoint/checkpoint-model.d.ts +34 -0
- package/dist/components/composites/checkpoint/checkpoint-model.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint-model.js +48 -0
- package/dist/components/composites/checkpoint/checkpoint-model.js.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint.d.ts +48 -0
- package/dist/components/composites/checkpoint/checkpoint.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/checkpoint.js +160 -0
- package/dist/components/composites/checkpoint/checkpoint.js.map +1 -0
- package/dist/components/composites/checkpoint/index.d.ts +3 -0
- package/dist/components/composites/checkpoint/index.d.ts.map +1 -0
- package/dist/components/composites/checkpoint/index.js +3 -0
- package/dist/components/composites/confirmation/confirmation-model.d.ts +45 -0
- package/dist/components/composites/confirmation/confirmation-model.d.ts.map +1 -0
- package/dist/components/composites/confirmation/confirmation-model.js +51 -0
- package/dist/components/composites/confirmation/confirmation-model.js.map +1 -0
- package/dist/components/composites/confirmation/confirmation.d.ts +72 -0
- package/dist/components/composites/confirmation/confirmation.d.ts.map +1 -0
- package/dist/components/composites/confirmation/confirmation.js +300 -0
- package/dist/components/composites/confirmation/confirmation.js.map +1 -0
- package/dist/components/composites/confirmation/index.d.ts +3 -0
- package/dist/components/composites/confirmation/index.d.ts.map +1 -0
- package/dist/components/composites/confirmation/index.js +3 -0
- package/dist/components/composites/context/context-model.d.ts +69 -0
- package/dist/components/composites/context/context-model.d.ts.map +1 -0
- package/dist/components/composites/context/context-model.js +122 -0
- package/dist/components/composites/context/context-model.js.map +1 -0
- package/dist/components/composites/context/context.d.ts +38 -0
- package/dist/components/composites/context/context.d.ts.map +1 -0
- package/dist/components/composites/context/context.js +234 -0
- package/dist/components/composites/context/context.js.map +1 -0
- package/dist/components/composites/context/index.d.ts +3 -0
- package/dist/components/composites/context/index.d.ts.map +1 -0
- package/dist/components/composites/context/index.js +3 -0
- package/dist/components/composites/file-tree/build-file-tree.d.ts +138 -0
- package/dist/components/composites/file-tree/build-file-tree.d.ts.map +1 -0
- package/dist/components/composites/file-tree/build-file-tree.js +325 -0
- package/dist/components/composites/file-tree/build-file-tree.js.map +1 -0
- package/dist/components/composites/file-tree/file-tree.d.ts +74 -0
- package/dist/components/composites/file-tree/file-tree.d.ts.map +1 -0
- package/dist/components/composites/file-tree/file-tree.js +389 -0
- package/dist/components/composites/file-tree/file-tree.js.map +1 -0
- package/dist/components/composites/file-tree/index.d.ts +3 -0
- package/dist/components/composites/file-tree/index.d.ts.map +1 -0
- package/dist/components/composites/file-tree/index.js +3 -0
- package/dist/components/composites/inline-citation/citation.d.ts +37 -0
- package/dist/components/composites/inline-citation/citation.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/citation.js +52 -0
- package/dist/components/composites/inline-citation/citation.js.map +1 -0
- package/dist/components/composites/inline-citation/index.d.ts +3 -0
- package/dist/components/composites/inline-citation/index.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/index.js +3 -0
- package/dist/components/composites/inline-citation/inline-citation.d.ts +64 -0
- package/dist/components/composites/inline-citation/inline-citation.d.ts.map +1 -0
- package/dist/components/composites/inline-citation/inline-citation.js +272 -0
- package/dist/components/composites/inline-citation/inline-citation.js.map +1 -0
- package/dist/components/composites/message-scroller/index.d.ts +3 -0
- package/dist/components/composites/message-scroller/index.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/index.js +3 -0
- package/dist/components/composites/message-scroller/message-scroller.d.ts +55 -0
- package/dist/components/composites/message-scroller/message-scroller.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/message-scroller.js +201 -0
- package/dist/components/composites/message-scroller/message-scroller.js.map +1 -0
- package/dist/components/composites/message-scroller/scroll-anchor.d.ts +66 -0
- package/dist/components/composites/message-scroller/scroll-anchor.d.ts.map +1 -0
- package/dist/components/composites/message-scroller/scroll-anchor.js +122 -0
- package/dist/components/composites/message-scroller/scroll-anchor.js.map +1 -0
- package/dist/components/composites/model-selector/index.d.ts +3 -0
- package/dist/components/composites/model-selector/index.d.ts.map +1 -0
- package/dist/components/composites/model-selector/index.js +3 -0
- package/dist/components/composites/model-selector/model-selector.d.ts +55 -0
- package/dist/components/composites/model-selector/model-selector.d.ts.map +1 -0
- package/dist/components/composites/model-selector/model-selector.js +490 -0
- package/dist/components/composites/model-selector/model-selector.js.map +1 -0
- package/dist/components/composites/model-selector/models.d.ts +51 -0
- package/dist/components/composites/model-selector/models.d.ts.map +1 -0
- package/dist/components/composites/model-selector/models.js +71 -0
- package/dist/components/composites/model-selector/models.js.map +1 -0
- package/dist/components/composites/plan/index.d.ts +2 -0
- package/dist/components/composites/plan/index.d.ts.map +1 -0
- package/dist/components/composites/plan/index.js +2 -0
- package/dist/components/composites/plan/plan.d.ts +61 -0
- package/dist/components/composites/plan/plan.d.ts.map +1 -0
- package/dist/components/composites/plan/plan.js +130 -0
- package/dist/components/composites/plan/plan.js.map +1 -0
- package/dist/components/composites/queue/index.d.ts +2 -0
- package/dist/components/composites/queue/index.d.ts.map +1 -0
- package/dist/components/composites/queue/index.js +2 -0
- package/dist/components/composites/queue/queue.d.ts +77 -0
- package/dist/components/composites/queue/queue.d.ts.map +1 -0
- package/dist/components/composites/queue/queue.js +271 -0
- package/dist/components/composites/queue/queue.js.map +1 -0
- package/dist/components/composites/reasoning/index.d.ts +2 -0
- package/dist/components/composites/reasoning/index.d.ts.map +1 -0
- package/dist/components/composites/reasoning/index.js +2 -0
- package/dist/components/composites/reasoning/reasoning.d.ts +62 -0
- package/dist/components/composites/reasoning/reasoning.d.ts.map +1 -0
- package/dist/components/composites/reasoning/reasoning.js +156 -0
- package/dist/components/composites/reasoning/reasoning.js.map +1 -0
- package/dist/components/composites/sources/index.d.ts +3 -0
- package/dist/components/composites/sources/index.d.ts.map +1 -0
- package/dist/components/composites/sources/index.js +3 -0
- package/dist/components/composites/sources/source.d.ts +46 -0
- package/dist/components/composites/sources/source.d.ts.map +1 -0
- package/dist/components/composites/sources/source.js +74 -0
- package/dist/components/composites/sources/source.js.map +1 -0
- package/dist/components/composites/sources/sources.d.ts +45 -0
- package/dist/components/composites/sources/sources.d.ts.map +1 -0
- package/dist/components/composites/sources/sources.js +175 -0
- package/dist/components/composites/sources/sources.js.map +1 -0
- package/dist/components/composites/stack-trace/index.d.ts +3 -0
- package/dist/components/composites/stack-trace/index.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/index.js +3 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.d.ts +118 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.js +376 -0
- package/dist/components/composites/stack-trace/parse-stack-trace.js.map +1 -0
- package/dist/components/composites/stack-trace/stack-trace.d.ts +63 -0
- package/dist/components/composites/stack-trace/stack-trace.d.ts.map +1 -0
- package/dist/components/composites/stack-trace/stack-trace.js +491 -0
- package/dist/components/composites/stack-trace/stack-trace.js.map +1 -0
- package/dist/components/composites/subagent/index.d.ts +2 -0
- package/dist/components/composites/subagent/index.d.ts.map +1 -0
- package/dist/components/composites/subagent/index.js +2 -0
- package/dist/components/composites/subagent/subagent.d.ts +55 -0
- package/dist/components/composites/subagent/subagent.d.ts.map +1 -0
- package/dist/components/composites/subagent/subagent.js +138 -0
- package/dist/components/composites/subagent/subagent.js.map +1 -0
- package/dist/components/composites/suggestion/index.d.ts +2 -0
- package/dist/components/composites/suggestion/index.d.ts.map +1 -0
- package/dist/components/composites/suggestion/index.js +2 -0
- package/dist/components/composites/suggestion/suggestion.d.ts +37 -0
- package/dist/components/composites/suggestion/suggestion.d.ts.map +1 -0
- package/dist/components/composites/suggestion/suggestion.js +100 -0
- package/dist/components/composites/suggestion/suggestion.js.map +1 -0
- package/dist/components/composites/task/index.d.ts +2 -0
- package/dist/components/composites/task/index.d.ts.map +1 -0
- package/dist/components/composites/task/index.js +2 -0
- package/dist/components/composites/task/task.d.ts +96 -0
- package/dist/components/composites/task/task.d.ts.map +1 -0
- package/dist/components/composites/task/task.js +311 -0
- package/dist/components/composites/task/task.js.map +1 -0
- package/dist/components/composites/terminal/ansi.d.ts +101 -0
- package/dist/components/composites/terminal/ansi.d.ts.map +1 -0
- package/dist/components/composites/terminal/ansi.js +544 -0
- package/dist/components/composites/terminal/ansi.js.map +1 -0
- package/dist/components/composites/terminal/index.d.ts +4 -0
- package/dist/components/composites/terminal/index.d.ts.map +1 -0
- package/dist/components/composites/terminal/index.js +4 -0
- package/dist/components/composites/terminal/terminal-model.d.ts +63 -0
- package/dist/components/composites/terminal/terminal-model.d.ts.map +1 -0
- package/dist/components/composites/terminal/terminal-model.js +69 -0
- package/dist/components/composites/terminal/terminal-model.js.map +1 -0
- package/dist/components/composites/terminal/terminal.d.ts +88 -0
- package/dist/components/composites/terminal/terminal.d.ts.map +1 -0
- package/dist/components/composites/terminal/terminal.js +500 -0
- package/dist/components/composites/terminal/terminal.js.map +1 -0
- package/dist/components/composites/test-results/index.d.ts +3 -0
- package/dist/components/composites/test-results/index.d.ts.map +1 -0
- package/dist/components/composites/test-results/index.js +3 -0
- package/dist/components/composites/test-results/test-results-model.d.ts +154 -0
- package/dist/components/composites/test-results/test-results-model.d.ts.map +1 -0
- package/dist/components/composites/test-results/test-results-model.js +252 -0
- package/dist/components/composites/test-results/test-results-model.js.map +1 -0
- package/dist/components/composites/test-results/test-results.d.ts +60 -0
- package/dist/components/composites/test-results/test-results.d.ts.map +1 -0
- package/dist/components/composites/test-results/test-results.js +631 -0
- package/dist/components/composites/test-results/test-results.js.map +1 -0
- package/dist/components/composites/tool/format-tool-value.d.ts +37 -0
- package/dist/components/composites/tool/format-tool-value.d.ts.map +1 -0
- package/dist/components/composites/tool/format-tool-value.js +135 -0
- package/dist/components/composites/tool/format-tool-value.js.map +1 -0
- package/dist/components/composites/tool/index.d.ts +3 -0
- package/dist/components/composites/tool/index.d.ts.map +1 -0
- package/dist/components/composites/tool/index.js +3 -0
- package/dist/components/composites/tool/tool.d.ts +69 -0
- package/dist/components/composites/tool/tool.d.ts.map +1 -0
- package/dist/components/composites/tool/tool.js +214 -0
- package/dist/components/composites/tool/tool.js.map +1 -0
- package/dist/components/composites/update-dialog/update-dialog.js +1 -1
- package/dist/components/conversation/conversation-surface.d.ts +7 -0
- package/dist/components/conversation/conversation-surface.d.ts.map +1 -1
- package/dist/components/conversation/conversation-surface.js +2 -0
- package/dist/components/conversation/conversation-surface.js.map +1 -1
- package/dist/components/conversation/scroll-follow-core.d.ts +24 -0
- package/dist/components/conversation/scroll-follow-core.d.ts.map +1 -1
- package/dist/components/conversation/scroll-follow-core.js +23 -1
- package/dist/components/conversation/scroll-follow-core.js.map +1 -1
- package/dist/components/conversation/scroll-follow.d.ts +3 -0
- package/dist/components/conversation/scroll-follow.d.ts.map +1 -1
- package/dist/components/conversation/scroll-follow.js +80 -1
- package/dist/components/conversation/scroll-follow.js.map +1 -1
- package/dist/components/ui/attachment/attachment.d.ts +58 -0
- package/dist/components/ui/attachment/attachment.d.ts.map +1 -0
- package/dist/components/ui/attachment/attachment.js +279 -0
- package/dist/components/ui/attachment/attachment.js.map +1 -0
- package/dist/components/ui/attachment/index.d.ts +2 -0
- package/dist/components/ui/attachment/index.d.ts.map +1 -0
- package/dist/components/ui/attachment/index.js +2 -0
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/bubble/bubble.d.ts +33 -0
- package/dist/components/ui/bubble/bubble.d.ts.map +1 -0
- package/dist/components/ui/bubble/bubble.js +95 -0
- package/dist/components/ui/bubble/bubble.js.map +1 -0
- package/dist/components/ui/bubble/index.d.ts +2 -0
- package/dist/components/ui/bubble/index.d.ts.map +1 -0
- package/dist/components/ui/bubble/index.js +2 -0
- package/dist/components/ui/button/button.d.ts +1 -1
- package/dist/components/ui/code-block/code-block.d.ts +56 -3
- package/dist/components/ui/code-block/code-block.d.ts.map +1 -1
- package/dist/components/ui/code-block/code-block.js +231 -50
- package/dist/components/ui/code-block/code-block.js.map +1 -1
- package/dist/components/ui/code-block/index.d.ts +1 -1
- package/dist/components/ui/code-block/index.d.ts.map +1 -1
- package/dist/components/ui/code-block/index.js +2 -2
- package/dist/components/ui/field/number-field.d.ts +21 -4
- package/dist/components/ui/field/number-field.d.ts.map +1 -1
- package/dist/components/ui/field/number-field.js +22 -11
- package/dist/components/ui/field/number-field.js.map +1 -1
- package/dist/components/ui/marker/index.d.ts +2 -0
- package/dist/components/ui/marker/index.d.ts.map +1 -0
- package/dist/components/ui/marker/index.js +2 -0
- package/dist/components/ui/marker/marker.d.ts +35 -0
- package/dist/components/ui/marker/marker.d.ts.map +1 -0
- package/dist/components/ui/marker/marker.js +123 -0
- package/dist/components/ui/marker/marker.js.map +1 -0
- package/dist/components/ui/message/cite-ranges.d.ts +42 -0
- package/dist/components/ui/message/cite-ranges.d.ts.map +1 -0
- package/dist/components/ui/message/cite-ranges.js +105 -0
- package/dist/components/ui/message/cite-ranges.js.map +1 -0
- package/dist/components/ui/message/index.d.ts +4 -0
- package/dist/components/ui/message/index.d.ts.map +1 -0
- package/dist/components/ui/message/index.js +4 -0
- package/dist/components/ui/message/message.d.ts +95 -0
- package/dist/components/ui/message/message.d.ts.map +1 -0
- package/dist/components/ui/message/message.js +443 -0
- package/dist/components/ui/message/message.js.map +1 -0
- package/dist/components/ui/message/parse-message-text.d.ts +93 -0
- package/dist/components/ui/message/parse-message-text.d.ts.map +1 -0
- package/dist/components/ui/message/parse-message-text.js +365 -0
- package/dist/components/ui/message/parse-message-text.js.map +1 -0
- package/dist/components/ui/questionnaire/index.d.ts +2 -0
- package/dist/components/ui/questionnaire/index.d.ts.map +1 -0
- package/dist/components/ui/questionnaire/index.js +2 -0
- package/dist/components/ui/questionnaire/questionnaire.d.ts +83 -0
- package/dist/components/ui/questionnaire/questionnaire.d.ts.map +1 -0
- package/dist/components/ui/questionnaire/questionnaire.js +470 -0
- package/dist/components/ui/questionnaire/questionnaire.js.map +1 -0
- package/dist/components/ui/status-chip/status-chip.d.ts +1 -1
- package/dist/components/ui/switch/switch.js +11 -11
- package/dist/components/ui/switch/switch.js.map +1 -1
- package/dist/components/ui/trace/index.d.ts +2 -0
- package/dist/components/ui/trace/index.d.ts.map +1 -0
- package/dist/components/ui/trace/index.js +2 -0
- package/dist/components/ui/trace/trace.d.ts +72 -0
- package/dist/components/ui/trace/trace.d.ts.map +1 -0
- package/dist/components/ui/trace/trace.js +340 -0
- package/dist/components/ui/trace/trace.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -5
- package/dist/r/attachment.json +25 -0
- package/dist/r/bubble.json +22 -0
- package/dist/r/chain-of-thought.json +26 -0
- package/dist/r/chat.json +24 -0
- package/dist/r/checkpoint.json +35 -0
- package/dist/r/confirmation.json +34 -0
- package/dist/r/context.json +33 -0
- package/dist/r/file-tree.json +32 -0
- package/dist/r/inline-citation.json +35 -0
- package/dist/r/marker.json +22 -0
- package/dist/r/message-scroller.json +31 -0
- package/dist/r/message.json +33 -0
- package/dist/r/model-selector.json +34 -0
- package/dist/r/plan.json +26 -0
- package/dist/r/questionnaire.json +28 -0
- package/dist/r/queue.json +26 -0
- package/dist/r/reasoning.json +26 -0
- package/dist/r/registry.json +811 -52
- package/dist/r/sources.json +32 -0
- package/dist/r/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
- package/dist/r/src/components/composites/chain-of-thought/index.ts +11 -0
- package/dist/r/src/components/composites/chat/chat.tsx +190 -0
- package/dist/r/src/components/composites/chat/index.ts +11 -0
- package/dist/r/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
- package/dist/r/src/components/composites/checkpoint/checkpoint.tsx +214 -0
- package/dist/r/src/components/composites/checkpoint/index.ts +8 -0
- package/dist/r/src/components/composites/confirmation/confirmation-model.ts +83 -0
- package/dist/r/src/components/composites/confirmation/confirmation.tsx +311 -0
- package/dist/r/src/components/composites/confirmation/index.ts +9 -0
- package/dist/r/src/components/composites/context/context-model.ts +168 -0
- package/dist/r/src/components/composites/context/context.tsx +187 -0
- package/dist/r/src/components/composites/context/index.ts +18 -0
- package/dist/r/src/components/composites/file-tree/build-file-tree.ts +456 -0
- package/dist/r/src/components/composites/file-tree/file-tree.tsx +405 -0
- package/dist/r/src/components/composites/file-tree/index.ts +25 -0
- package/dist/r/src/components/composites/inline-citation/citation.ts +78 -0
- package/dist/r/src/components/composites/inline-citation/index.ts +9 -0
- package/dist/r/src/components/composites/inline-citation/inline-citation.tsx +285 -0
- package/dist/r/src/components/composites/message-scroller/index.ts +2 -0
- package/dist/r/src/components/composites/message-scroller/message-scroller.tsx +301 -0
- package/dist/r/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
- package/dist/r/src/components/composites/model-selector/index.ts +14 -0
- package/dist/r/src/components/composites/model-selector/model-selector.tsx +420 -0
- package/dist/r/src/components/composites/model-selector/models.ts +103 -0
- package/dist/r/src/components/composites/plan/index.ts +1 -0
- package/dist/r/src/components/composites/plan/plan.tsx +155 -0
- package/dist/r/src/components/composites/queue/index.ts +10 -0
- package/dist/r/src/components/composites/queue/queue.tsx +264 -0
- package/dist/r/src/components/composites/reasoning/index.ts +1 -0
- package/dist/r/src/components/composites/reasoning/reasoning.tsx +176 -0
- package/dist/r/src/components/composites/sources/index.ts +11 -0
- package/dist/r/src/components/composites/sources/source.ts +116 -0
- package/dist/r/src/components/composites/sources/sources.tsx +163 -0
- package/dist/r/src/components/composites/stack-trace/index.ts +19 -0
- package/dist/r/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
- package/dist/r/src/components/composites/stack-trace/stack-trace.tsx +395 -0
- package/dist/r/src/components/composites/subagent/index.ts +1 -0
- package/dist/r/src/components/composites/subagent/subagent.tsx +159 -0
- package/dist/r/src/components/composites/suggestion/index.ts +1 -0
- package/dist/r/src/components/composites/suggestion/suggestion.tsx +140 -0
- package/dist/r/src/components/composites/task/index.ts +14 -0
- package/dist/r/src/components/composites/task/task.tsx +317 -0
- package/dist/r/src/components/composites/terminal/ansi.ts +674 -0
- package/dist/r/src/components/composites/terminal/index.ts +20 -0
- package/dist/r/src/components/composites/terminal/terminal-model.ts +111 -0
- package/dist/r/src/components/composites/terminal/terminal.tsx +574 -0
- package/dist/r/src/components/composites/test-results/index.ts +20 -0
- package/dist/r/src/components/composites/test-results/test-results-model.ts +368 -0
- package/dist/r/src/components/composites/test-results/test-results.tsx +586 -0
- package/dist/r/src/components/composites/tool/format-tool-value.ts +221 -0
- package/dist/r/src/components/composites/tool/index.ts +2 -0
- package/dist/r/src/components/composites/tool/tool.tsx +228 -0
- package/dist/r/src/components/conversation/conversation-surface.tsx +9 -0
- package/dist/r/src/components/conversation/scroll-follow-core.ts +31 -0
- package/dist/r/src/components/conversation/scroll-follow.ts +92 -0
- package/dist/r/src/components/ui/attachment/attachment.tsx +282 -0
- package/dist/r/src/components/ui/attachment/index.ts +10 -0
- package/dist/r/src/components/ui/bubble/bubble.tsx +86 -0
- package/dist/r/src/components/ui/bubble/index.ts +1 -0
- package/dist/r/src/components/ui/code-block/code-block.tsx +256 -26
- package/dist/r/src/components/ui/code-block/index.ts +9 -1
- package/dist/r/src/components/ui/field/number-field.tsx +51 -14
- package/dist/r/src/components/ui/marker/index.ts +1 -0
- package/dist/r/src/components/ui/marker/marker.tsx +90 -0
- package/dist/r/src/components/ui/message/cite-ranges.ts +144 -0
- package/dist/r/src/components/ui/message/index.ts +23 -0
- package/dist/r/src/components/ui/message/message.tsx +434 -0
- package/dist/r/src/components/ui/message/parse-message-text.ts +450 -0
- package/dist/r/src/components/ui/questionnaire/index.ts +10 -0
- package/dist/r/src/components/ui/questionnaire/questionnaire.tsx +446 -0
- package/dist/r/src/components/ui/trace/index.ts +9 -0
- package/dist/r/src/components/ui/trace/trace.tsx +334 -0
- package/dist/r/src/styles/base.css +34 -0
- package/dist/r/stack-trace.json +32 -0
- package/dist/r/subagent.json +27 -0
- package/dist/r/suggestion.json +24 -0
- package/dist/r/task.json +28 -0
- package/dist/r/terminal.json +35 -0
- package/dist/r/test-results.json +33 -0
- package/dist/r/tool.json +31 -0
- package/dist/r/trace.json +25 -0
- package/package.json +6 -3
- package/registry.json +811 -52
- package/src/components/composites/chain-of-thought/chain-of-thought.tsx +141 -0
- package/src/components/composites/chain-of-thought/index.ts +11 -0
- package/src/components/composites/chat/chat.tsx +190 -0
- package/src/components/composites/chat/index.ts +11 -0
- package/src/components/composites/checkpoint/checkpoint-model.ts +71 -0
- package/src/components/composites/checkpoint/checkpoint.tsx +214 -0
- package/src/components/composites/checkpoint/index.ts +8 -0
- package/src/components/composites/confirmation/confirmation-model.ts +83 -0
- package/src/components/composites/confirmation/confirmation.tsx +311 -0
- package/src/components/composites/confirmation/index.ts +9 -0
- package/src/components/composites/context/context-model.ts +168 -0
- package/src/components/composites/context/context.tsx +187 -0
- package/src/components/composites/context/index.ts +18 -0
- package/src/components/composites/file-tree/build-file-tree.ts +456 -0
- package/src/components/composites/file-tree/file-tree.tsx +405 -0
- package/src/components/composites/file-tree/index.ts +25 -0
- package/src/components/composites/inline-citation/citation.ts +78 -0
- package/src/components/composites/inline-citation/index.ts +9 -0
- package/src/components/composites/inline-citation/inline-citation.tsx +285 -0
- package/src/components/composites/message-scroller/index.ts +2 -0
- package/src/components/composites/message-scroller/message-scroller.tsx +301 -0
- package/src/components/composites/message-scroller/scroll-anchor.ts +170 -0
- package/src/components/composites/model-selector/index.ts +14 -0
- package/src/components/composites/model-selector/model-selector.tsx +420 -0
- package/src/components/composites/model-selector/models.ts +103 -0
- package/src/components/composites/plan/index.ts +1 -0
- package/src/components/composites/plan/plan.tsx +155 -0
- package/src/components/composites/queue/index.ts +10 -0
- package/src/components/composites/queue/queue.tsx +264 -0
- package/src/components/composites/reasoning/index.ts +1 -0
- package/src/components/composites/reasoning/reasoning.tsx +176 -0
- package/src/components/composites/sources/index.ts +11 -0
- package/src/components/composites/sources/source.ts +116 -0
- package/src/components/composites/sources/sources.tsx +163 -0
- package/src/components/composites/stack-trace/index.ts +19 -0
- package/src/components/composites/stack-trace/parse-stack-trace.ts +507 -0
- package/src/components/composites/stack-trace/stack-trace.tsx +395 -0
- package/src/components/composites/subagent/index.ts +1 -0
- package/src/components/composites/subagent/subagent.tsx +159 -0
- package/src/components/composites/suggestion/index.ts +1 -0
- package/src/components/composites/suggestion/suggestion.tsx +140 -0
- package/src/components/composites/task/index.ts +14 -0
- package/src/components/composites/task/task.tsx +317 -0
- package/src/components/composites/terminal/ansi.ts +674 -0
- package/src/components/composites/terminal/index.ts +20 -0
- package/src/components/composites/terminal/terminal-model.ts +111 -0
- package/src/components/composites/terminal/terminal.tsx +574 -0
- package/src/components/composites/test-results/index.ts +20 -0
- package/src/components/composites/test-results/test-results-model.ts +368 -0
- package/src/components/composites/test-results/test-results.tsx +586 -0
- package/src/components/composites/tool/format-tool-value.ts +221 -0
- package/src/components/composites/tool/index.ts +2 -0
- package/src/components/composites/tool/tool.tsx +228 -0
- package/src/components/conversation/conversation-surface.tsx +9 -0
- package/src/components/conversation/scroll-follow-core.ts +31 -0
- package/src/components/conversation/scroll-follow.ts +92 -0
- package/src/components/ui/attachment/attachment.tsx +282 -0
- package/src/components/ui/attachment/index.ts +10 -0
- package/src/components/ui/bubble/bubble.tsx +86 -0
- package/src/components/ui/bubble/index.ts +1 -0
- package/src/components/ui/code-block/code-block.tsx +256 -26
- package/src/components/ui/code-block/index.ts +9 -1
- package/src/components/ui/field/number-field.tsx +51 -14
- package/src/components/ui/marker/index.ts +1 -0
- package/src/components/ui/marker/marker.tsx +90 -0
- package/src/components/ui/message/cite-ranges.ts +144 -0
- package/src/components/ui/message/index.ts +23 -0
- package/src/components/ui/message/message.tsx +434 -0
- package/src/components/ui/message/parse-message-text.ts +450 -0
- package/src/components/ui/questionnaire/index.ts +10 -0
- package/src/components/ui/questionnaire/questionnaire.tsx +446 -0
- package/src/components/ui/trace/index.ts +9 -0
- package/src/components/ui/trace/trace.tsx +334 -0
- package/src/index.ts +26 -0
- package/src/styles/base.css +34 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a tool's input or output into text, safely.
|
|
3
|
+
*
|
|
4
|
+
* A tool call's payload is whatever the model sent and whatever the tool
|
|
5
|
+
* returned: it can be a megabyte of log, an object that refers to itself, a
|
|
6
|
+
* `BigInt` (which `JSON.stringify` throws on), or a getter that throws. A
|
|
7
|
+
* transcript component that calls `JSON.stringify` on that and renders the result
|
|
8
|
+
* is one hostile payload away from a frozen tab or a blank page, so this is a
|
|
9
|
+
* small serializer of our own rather than a call to the built-in one:
|
|
10
|
+
*
|
|
11
|
+
* - **It never throws.** Anything it cannot read becomes a marker string.
|
|
12
|
+
* - **It stops early.** Output is written into a budget of `maxChars`; the moment
|
|
13
|
+
* the budget is spent it stops walking, so the cost is bounded by the budget and
|
|
14
|
+
* not by the size of the value.
|
|
15
|
+
* - **It says when it stopped.** `truncated` is true whenever text was cut, so the
|
|
16
|
+
* caller can tell the reader the view is partial instead of passing off a cut
|
|
17
|
+
* JSON document as the whole thing.
|
|
18
|
+
* - **It does not lie about types.** Values JSON cannot carry are written as what
|
|
19
|
+
* they are (`12n`, `undefined`, `NaN`) rather than coerced to `null`, which
|
|
20
|
+
* would read as the tool having returned null.
|
|
21
|
+
*
|
|
22
|
+
* Strings are returned as given, not quoted and not re-parsed: re-serializing a
|
|
23
|
+
* JSON string would silently round numbers beyond double precision.
|
|
24
|
+
*/
|
|
25
|
+
export type ToolValueText = Readonly<{
|
|
26
|
+
text: string
|
|
27
|
+
/** `json` for structured values, `text` for strings and anything that is not JSON. */
|
|
28
|
+
language: 'json' | 'text'
|
|
29
|
+
/** True when `text` is only the start of the value. */
|
|
30
|
+
truncated: boolean
|
|
31
|
+
}>
|
|
32
|
+
|
|
33
|
+
/** Characters shown per section unless the caller says otherwise. */
|
|
34
|
+
export const TOOL_VALUE_MAX_CHARS = 20_000
|
|
35
|
+
|
|
36
|
+
/** Nesting deeper than this is written as a marker. */
|
|
37
|
+
const MAX_DEPTH = 12
|
|
38
|
+
|
|
39
|
+
class BudgetSpent extends Error {}
|
|
40
|
+
|
|
41
|
+
type Writer = {
|
|
42
|
+
out: string[]
|
|
43
|
+
length: number
|
|
44
|
+
max: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function write(writer: Writer, chunk: string) {
|
|
48
|
+
writer.out.push(chunk)
|
|
49
|
+
writer.length += chunk.length
|
|
50
|
+
if (writer.length > writer.max) throw new BudgetSpent()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A JSON string literal, without stringifying more than the budget could hold. */
|
|
54
|
+
function quote(writer: Writer, value: string): string {
|
|
55
|
+
const room = Math.max(0, writer.max - writer.length)
|
|
56
|
+
// Past the budget the result is thrown away, so the tail need not be well formed.
|
|
57
|
+
return value.length > room + 1
|
|
58
|
+
? JSON.stringify(value.slice(0, room + 1)).slice(0, -1)
|
|
59
|
+
: JSON.stringify(value)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function describeNonJson(value: unknown): string {
|
|
63
|
+
switch (typeof value) {
|
|
64
|
+
case 'undefined':
|
|
65
|
+
return 'undefined'
|
|
66
|
+
case 'bigint':
|
|
67
|
+
return `${value}n`
|
|
68
|
+
case 'symbol':
|
|
69
|
+
return value.toString()
|
|
70
|
+
case 'function':
|
|
71
|
+
return `[Function${value.name ? ` ${value.name}` : ''}]`
|
|
72
|
+
default:
|
|
73
|
+
return String(value)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** At most `limit` items: each costs at least a character, so more could never be shown. */
|
|
78
|
+
function take<T>(source: Iterable<T>, limit: number): T[] {
|
|
79
|
+
const taken: T[] = []
|
|
80
|
+
for (const item of source) {
|
|
81
|
+
if (taken.length > limit) break
|
|
82
|
+
taken.push(item)
|
|
83
|
+
}
|
|
84
|
+
return taken
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readEntries(value: object, limit: number): [string, unknown][] {
|
|
88
|
+
const entries: [string, unknown][] = []
|
|
89
|
+
for (const key of Object.keys(value).slice(0, limit + 1)) {
|
|
90
|
+
try {
|
|
91
|
+
entries.push([key, (value as Record<string, unknown>)[key]])
|
|
92
|
+
} catch {
|
|
93
|
+
entries.push([key, '[Unreadable]'])
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return entries
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function writeValue(writer: Writer, value: unknown, depth: number, ancestors: object[]) {
|
|
100
|
+
if (value === null) return write(writer, 'null')
|
|
101
|
+
if (typeof value === 'string') return write(writer, quote(writer, value))
|
|
102
|
+
if (typeof value === 'number') {
|
|
103
|
+
return write(writer, Number.isFinite(value) ? JSON.stringify(value) : String(value))
|
|
104
|
+
}
|
|
105
|
+
if (typeof value === 'boolean') return write(writer, String(value))
|
|
106
|
+
if (typeof value !== 'object') {
|
|
107
|
+
// bigint, undefined, symbol, function: written as what they are, in quotes
|
|
108
|
+
// only where a bare token would be mistaken for the surrounding structure.
|
|
109
|
+
const text = describeNonJson(value)
|
|
110
|
+
return write(
|
|
111
|
+
writer,
|
|
112
|
+
typeof value === 'bigint' || typeof value === 'undefined' ? text : quote(writer, text)
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (ancestors.includes(value)) return write(writer, '"[Circular]"')
|
|
117
|
+
|
|
118
|
+
let subject: unknown = value
|
|
119
|
+
if (!Array.isArray(value) && typeof (value as { toJSON?: unknown }).toJSON === 'function') {
|
|
120
|
+
try {
|
|
121
|
+
subject = (value as { toJSON: () => unknown }).toJSON()
|
|
122
|
+
} catch {
|
|
123
|
+
return write(writer, '"[Unreadable]"')
|
|
124
|
+
}
|
|
125
|
+
if (typeof subject !== 'object' || subject === null) {
|
|
126
|
+
return writeValue(writer, subject, depth, ancestors)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const node = subject as object
|
|
130
|
+
|
|
131
|
+
if (ArrayBuffer.isView(node) || node instanceof ArrayBuffer) {
|
|
132
|
+
return write(
|
|
133
|
+
writer,
|
|
134
|
+
quote(writer, `[${node.constructor.name}: ${node.byteLength.toLocaleString('en')} bytes]`)
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let items: unknown[] | undefined
|
|
139
|
+
let fields: [string, unknown][] | undefined
|
|
140
|
+
if (Array.isArray(node)) items = node
|
|
141
|
+
else if (node instanceof Set) items = take(node, writer.max)
|
|
142
|
+
else if (node instanceof Map) items = take(node, writer.max).map(([key, entry]) => [key, entry])
|
|
143
|
+
else if (node instanceof Error) {
|
|
144
|
+
fields = [
|
|
145
|
+
['name', node.name],
|
|
146
|
+
['message', node.message],
|
|
147
|
+
]
|
|
148
|
+
} else fields = readEntries(node, writer.max)
|
|
149
|
+
|
|
150
|
+
if (depth >= MAX_DEPTH) {
|
|
151
|
+
return write(writer, quote(writer, items ? `[Array(${items.length})]` : '[Object]'))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const nested = [...ancestors, value]
|
|
155
|
+
const indent = ' '.repeat(depth + 1)
|
|
156
|
+
const closing = ' '.repeat(depth)
|
|
157
|
+
|
|
158
|
+
if (items) {
|
|
159
|
+
if (items.length === 0) return write(writer, '[]')
|
|
160
|
+
write(writer, '[\n')
|
|
161
|
+
// Indexed rather than `forEach`, which skips the holes of a sparse array: a
|
|
162
|
+
// million-slot hole would loop a million times without ever spending the budget.
|
|
163
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
164
|
+
write(writer, indent)
|
|
165
|
+
writeValue(writer, items[index], depth + 1, nested)
|
|
166
|
+
write(writer, index < items.length - 1 ? ',\n' : '\n')
|
|
167
|
+
}
|
|
168
|
+
return write(writer, `${closing}]`)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const present = fields ?? []
|
|
172
|
+
if (present.length === 0) return write(writer, '{}')
|
|
173
|
+
write(writer, '{\n')
|
|
174
|
+
present.forEach(([key, entry], index) => {
|
|
175
|
+
write(writer, `${indent}${quote(writer, key)}: `)
|
|
176
|
+
writeValue(writer, entry, depth + 1, nested)
|
|
177
|
+
write(writer, index < present.length - 1 ? ',\n' : '\n')
|
|
178
|
+
})
|
|
179
|
+
write(writer, `${closing}}`)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function formatToolValue(
|
|
183
|
+
value: unknown,
|
|
184
|
+
options: { maxChars?: number } = {}
|
|
185
|
+
): ToolValueText {
|
|
186
|
+
const requested = options.maxChars
|
|
187
|
+
const max =
|
|
188
|
+
requested === undefined || Number.isNaN(requested)
|
|
189
|
+
? TOOL_VALUE_MAX_CHARS
|
|
190
|
+
: Math.max(0, Math.floor(requested))
|
|
191
|
+
|
|
192
|
+
if (typeof value === 'string') {
|
|
193
|
+
return {
|
|
194
|
+
text: value.slice(0, max),
|
|
195
|
+
language: 'text',
|
|
196
|
+
truncated: value.length > max,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (value === undefined || typeof value === 'symbol' || typeof value === 'function') {
|
|
200
|
+
return { text: describeNonJson(value).slice(0, max), language: 'text', truncated: false }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const writer: Writer = { out: [], length: 0, max }
|
|
204
|
+
let truncated = false
|
|
205
|
+
try {
|
|
206
|
+
writeValue(writer, value, 0, [])
|
|
207
|
+
} catch (error) {
|
|
208
|
+
// Anything other than the budget running out is a bug in a getter or a proxy
|
|
209
|
+
// we could not foresee; the reader still gets what was written so far.
|
|
210
|
+
truncated = true
|
|
211
|
+
if (!(error instanceof BudgetSpent) && writer.out.length === 0) {
|
|
212
|
+
return { text: '[Unreadable]', language: 'text', truncated: false }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const joined = writer.out.join('')
|
|
216
|
+
return {
|
|
217
|
+
text: joined.length > max ? joined.slice(0, max) : joined,
|
|
218
|
+
language: 'json',
|
|
219
|
+
truncated: truncated || joined.length > max,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Wrench } from 'lucide-solid'
|
|
2
|
+
import { children as resolveChildren, createMemo, Show, splitProps, type JSX } from 'solid-js'
|
|
3
|
+
import { Badge } from '../../ui/badge'
|
|
4
|
+
import { CodeBlock, type CodeLineMark } from '../../ui/code-block'
|
|
5
|
+
import { TraceDetail, TraceLine, type TraceLineProps, type TraceStatus } from '../../ui/trace'
|
|
6
|
+
import { formatToolValue, TOOL_VALUE_MAX_CHARS } from './format-tool-value'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* `TraceLine` reads its children twice: once to decide whether the line can
|
|
10
|
+
* expand, and once to draw them when it is open. A function child is returned
|
|
11
|
+
* unevaluated by the first read and run once, when the content mounts, by the
|
|
12
|
+
* second — so a folded line builds none of its body. Solid's `insert` unwraps
|
|
13
|
+
* functions; the JSX types simply do not admit them.
|
|
14
|
+
*/
|
|
15
|
+
const deferred = (render: () => JSX.Element) => render as unknown as JSX.Element
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tool.
|
|
19
|
+
*
|
|
20
|
+
* One tool call, from what was asked to what came back, as a `TraceLine`: the
|
|
21
|
+
* tool's name and a short description on the line, and — when there is anything
|
|
22
|
+
* to show — an input section, an output section and an error underneath. Reach
|
|
23
|
+
* for `Subagent` when the "tool" is another agent with steps of its own, for a
|
|
24
|
+
* bare `CodeBlock` when the point is the output itself and not the call that made
|
|
25
|
+
* it, and for a confirmation (passed as `children`) when the reader has to decide
|
|
26
|
+
* something about the call.
|
|
27
|
+
*
|
|
28
|
+
* ## Everything is optional, and absence is not a claim
|
|
29
|
+
*
|
|
30
|
+
* A call with no `status` shows no mark at all — an event that merely arrived is
|
|
31
|
+
* not "done". `input`, `output` and `errorText` each render a section only when
|
|
32
|
+
* the host passed them: no empty "Output" box under a call that is still running,
|
|
33
|
+
* and no invented "No output" under one that failed. An error with no output is
|
|
34
|
+
* just the error. A call with nothing to expand is a plain line, not a
|
|
35
|
+
* disclosure that opens onto nothing.
|
|
36
|
+
*
|
|
37
|
+
* Two statuses are words, not only marks, because the glyphs for them are easy to
|
|
38
|
+
* misread: `awaiting-approval` and `denied` also show a badge. Both are spoken
|
|
39
|
+
* once (the badge is hidden from assistive technology and the status word is
|
|
40
|
+
* read in its place). A call awaiting approval opens by default, since it is the
|
|
41
|
+
* one state in which the reader has something to do. The component never decides
|
|
42
|
+
* whether an approval is allowed: the controls live in `children`, supplied by
|
|
43
|
+
* the host, or are absent.
|
|
44
|
+
*
|
|
45
|
+
* ## Payloads are untrusted and unbounded
|
|
46
|
+
*
|
|
47
|
+
* `input` and `output` are `unknown` — whatever the model sent and the tool
|
|
48
|
+
* returned. They go through `formatToolValue`, which cannot throw (circular
|
|
49
|
+
* references, `BigInt`, throwing getters) and stops after `maxChars`; a cut view
|
|
50
|
+
* says so rather than presenting half a document as the whole. Sections render in
|
|
51
|
+
* a small `CodeBlock` with a capped height. A string is shown as given; anything
|
|
52
|
+
* structured is pretty-printed JSON. The sections mount only when the line is
|
|
53
|
+
* opened, so a transcript of hundreds of calls formats none of them until asked.
|
|
54
|
+
*
|
|
55
|
+
* A `Tool` is a line: place it inside a `Trace`.
|
|
56
|
+
*/
|
|
57
|
+
export type ToolStatus =
|
|
58
|
+
| 'pending'
|
|
59
|
+
| 'running'
|
|
60
|
+
| 'success'
|
|
61
|
+
| 'error'
|
|
62
|
+
| 'awaiting-approval'
|
|
63
|
+
| 'denied'
|
|
64
|
+
| 'cancelled'
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The words spoken (and, for the last three, shown) for each status. `denied` is
|
|
68
|
+
* a decision about the call; `cancelled` is the run being stopped while the call
|
|
69
|
+
* was in flight. Give a call `cancelled` only when the host knows that call was
|
|
70
|
+
* stopped: a run ending does not by itself say what became of each call.
|
|
71
|
+
*/
|
|
72
|
+
export const TOOL_STATUS_LABELS: Readonly<Record<ToolStatus, string>> = {
|
|
73
|
+
pending: 'Pending',
|
|
74
|
+
running: 'Running',
|
|
75
|
+
success: 'Completed',
|
|
76
|
+
error: 'Failed',
|
|
77
|
+
'awaiting-approval': 'Awaiting approval',
|
|
78
|
+
denied: 'Denied',
|
|
79
|
+
cancelled: 'Cancelled',
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const TRACE_STATUS: Readonly<Record<ToolStatus, TraceStatus>> = {
|
|
83
|
+
pending: 'pending',
|
|
84
|
+
running: 'running',
|
|
85
|
+
success: 'success',
|
|
86
|
+
error: 'error',
|
|
87
|
+
'awaiting-approval': 'pending',
|
|
88
|
+
denied: 'cancelled',
|
|
89
|
+
cancelled: 'cancelled',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type ToolProps = Omit<
|
|
93
|
+
TraceLineProps,
|
|
94
|
+
'title' | 'status' | 'statusLabel' | 'href' | 'onSelect' | 'selectHaspopup'
|
|
95
|
+
> & {
|
|
96
|
+
/** The tool's name, as the host knows it. Rendered as text. */
|
|
97
|
+
name: string
|
|
98
|
+
/** What this call is for: a path, a query, a command. */
|
|
99
|
+
description?: JSX.Element
|
|
100
|
+
status?: ToolStatus
|
|
101
|
+
/** What the model asked the tool to do. Any value; omit it to show no section. */
|
|
102
|
+
input?: unknown
|
|
103
|
+
/** What the tool returned. Any value; omit it to show no section. */
|
|
104
|
+
output?: unknown
|
|
105
|
+
/** The failure, as text. */
|
|
106
|
+
errorText?: string
|
|
107
|
+
/** Characters of each section shown before it is cut. Defaults to 20,000. */
|
|
108
|
+
maxChars?: number
|
|
109
|
+
/** Extra detail below the sections: an approval, a link to the full output. */
|
|
110
|
+
children?: JSX.Element
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const SECTION_MAX_HEIGHT = '16rem'
|
|
114
|
+
|
|
115
|
+
function Section(props: {
|
|
116
|
+
title: string
|
|
117
|
+
value: unknown
|
|
118
|
+
maxChars: number
|
|
119
|
+
complete?: boolean
|
|
120
|
+
failure?: boolean
|
|
121
|
+
}) {
|
|
122
|
+
const formatted = createMemo(() => formatToolValue(props.value, { maxChars: props.maxChars }))
|
|
123
|
+
// Every line is marked as an error rather than recolouring the block, which
|
|
124
|
+
// keeps the mark in the gutter (a glyph, not colour alone) and the copy exact.
|
|
125
|
+
const marks = createMemo((): Readonly<Record<number, CodeLineMark>> | undefined => {
|
|
126
|
+
if (!props.failure) return undefined
|
|
127
|
+
const lines = formatted().text.split('\n').length
|
|
128
|
+
return Object.fromEntries(Array.from({ length: lines }, (_, index) => [index + 1, 'error']))
|
|
129
|
+
})
|
|
130
|
+
return (
|
|
131
|
+
<div class="flex min-w-0 flex-col gap-1">
|
|
132
|
+
<CodeBlock
|
|
133
|
+
size="sm"
|
|
134
|
+
title={props.title}
|
|
135
|
+
language={props.failure ? 'error' : formatted().language}
|
|
136
|
+
code={formatted().text}
|
|
137
|
+
lineMarks={marks()}
|
|
138
|
+
complete={props.complete ?? true}
|
|
139
|
+
maxHeight={SECTION_MAX_HEIGHT}
|
|
140
|
+
wrap={formatted().language === 'text'}
|
|
141
|
+
/>
|
|
142
|
+
<Show when={formatted().truncated}>
|
|
143
|
+
<p class="m-0 px-1 text-xs text-muted-foreground">
|
|
144
|
+
Showing the first {props.maxChars.toLocaleString('en')} characters.
|
|
145
|
+
</p>
|
|
146
|
+
</Show>
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function Tool(props: ToolProps) {
|
|
152
|
+
const [local, rest] = splitProps(props, [
|
|
153
|
+
'name',
|
|
154
|
+
'description',
|
|
155
|
+
'status',
|
|
156
|
+
'input',
|
|
157
|
+
'output',
|
|
158
|
+
'errorText',
|
|
159
|
+
'maxChars',
|
|
160
|
+
'icon',
|
|
161
|
+
'meta',
|
|
162
|
+
'defaultOpen',
|
|
163
|
+
'children',
|
|
164
|
+
])
|
|
165
|
+
const maxChars = () => local.maxChars ?? TOOL_VALUE_MAX_CHARS
|
|
166
|
+
const hasInput = () => local.input !== undefined
|
|
167
|
+
const hasOutput = () => local.output !== undefined
|
|
168
|
+
const hasError = () => local.errorText !== undefined && local.errorText !== ''
|
|
169
|
+
// Resolved once: a host's approval controls are created once and keep their
|
|
170
|
+
// state and focus however often the line is folded.
|
|
171
|
+
const extra = resolveChildren(() => local.children)
|
|
172
|
+
const hasDetail = () => hasInput() || hasOutput() || hasError() || extra.toArray().length > 0
|
|
173
|
+
|
|
174
|
+
const detail = () => (
|
|
175
|
+
<TraceDetail class="flex flex-col gap-2">
|
|
176
|
+
<Show when={hasInput()}>
|
|
177
|
+
<Section title="Input" value={local.input} maxChars={maxChars()} />
|
|
178
|
+
</Show>
|
|
179
|
+
<Show when={hasOutput()}>
|
|
180
|
+
<Section
|
|
181
|
+
title="Output"
|
|
182
|
+
value={local.output}
|
|
183
|
+
maxChars={maxChars()}
|
|
184
|
+
complete={local.status !== 'running'}
|
|
185
|
+
/>
|
|
186
|
+
</Show>
|
|
187
|
+
<Show when={hasError()}>
|
|
188
|
+
<Section title="Error" value={local.errorText} maxChars={maxChars()} failure />
|
|
189
|
+
</Show>
|
|
190
|
+
{extra()}
|
|
191
|
+
</TraceDetail>
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
// Words as well as marks for the states whose glyph is easy to misread. The
|
|
195
|
+
// badge is hidden from assistive technology: the status word is already spoken.
|
|
196
|
+
const wordBadge = () =>
|
|
197
|
+
local.status === 'awaiting-approval' ||
|
|
198
|
+
local.status === 'denied' ||
|
|
199
|
+
local.status === 'cancelled' ? (
|
|
200
|
+
<span class="flex items-center gap-2">
|
|
201
|
+
<Badge
|
|
202
|
+
aria-hidden="true"
|
|
203
|
+
size="sm"
|
|
204
|
+
variant={local.status === 'awaiting-approval' ? 'warning' : 'outline'}
|
|
205
|
+
>
|
|
206
|
+
{TOOL_STATUS_LABELS[local.status]}
|
|
207
|
+
</Badge>
|
|
208
|
+
{local.meta}
|
|
209
|
+
</span>
|
|
210
|
+
) : (
|
|
211
|
+
local.meta
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<TraceLine
|
|
216
|
+
icon={local.icon ?? <Wrench />}
|
|
217
|
+
title={local.name}
|
|
218
|
+
description={local.description}
|
|
219
|
+
status={local.status ? TRACE_STATUS[local.status] : undefined}
|
|
220
|
+
statusLabel={local.status ? TOOL_STATUS_LABELS[local.status] : undefined}
|
|
221
|
+
meta={wordBadge()}
|
|
222
|
+
defaultOpen={local.defaultOpen ?? local.status === 'awaiting-approval'}
|
|
223
|
+
{...rest}
|
|
224
|
+
>
|
|
225
|
+
{hasDetail() ? deferred(detail) : undefined}
|
|
226
|
+
</TraceLine>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
@@ -4,6 +4,7 @@ import { Show, splitProps } from 'solid-js'
|
|
|
4
4
|
import { cn } from '#lib/utils'
|
|
5
5
|
import { Button } from '../ui/button/button'
|
|
6
6
|
import { createScrollFollow } from './scroll-follow'
|
|
7
|
+
import type { ScrollFollowHold } from './scroll-follow'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* ConversationSurface.
|
|
@@ -44,6 +45,12 @@ export type ConversationSurfaceProps = ComponentProps<'div'> & {
|
|
|
44
45
|
* frame around the surface is `ConversationPane`'s job.
|
|
45
46
|
*/
|
|
46
47
|
gutter?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* Receives the surface's `hold`, once, when it is created. A host that moves content
|
|
50
|
+
* under a reader who is following (a history load that lands after the conversation
|
|
51
|
+
* changed) opens a hold around it, so the move is not read as the reader scrolling away.
|
|
52
|
+
*/
|
|
53
|
+
onFollowHold?: (hold: ScrollFollowHold) => void
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
export function ConversationSurface(props: ConversationSurfaceProps) {
|
|
@@ -57,6 +64,7 @@ export function ConversationSurface(props: ConversationSurfaceProps) {
|
|
|
57
64
|
'empty',
|
|
58
65
|
'header',
|
|
59
66
|
'gutter',
|
|
67
|
+
'onFollowHold',
|
|
60
68
|
'children',
|
|
61
69
|
'onScroll',
|
|
62
70
|
'ref',
|
|
@@ -72,6 +80,7 @@ export function ConversationSurface(props: ConversationSurfaceProps) {
|
|
|
72
80
|
initialPosition: () => local.initialReadingPosition,
|
|
73
81
|
onPositionChange: (position) => local.onReadingPositionChange?.(position),
|
|
74
82
|
})
|
|
83
|
+
local.onFollowHold?.(follow.hold)
|
|
75
84
|
const onScroll: JSX.EventHandlerUnion<HTMLDivElement, Event> = (event) => {
|
|
76
85
|
follow.onScroll()
|
|
77
86
|
const handler = local.onScroll
|
|
@@ -169,6 +169,37 @@ export function resolveUserScrollStick(args: {
|
|
|
169
169
|
return stick
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/** What the reader did to the scroller, as far as telling a scroll-up from anything else. */
|
|
173
|
+
export type ReaderInput =
|
|
174
|
+
| { kind: 'wheel'; deltaY: number }
|
|
175
|
+
| { kind: 'key'; key: string; shiftKey: boolean }
|
|
176
|
+
| { kind: 'touchmove' }
|
|
177
|
+
| { kind: 'pointerdown'; onScroller: boolean }
|
|
178
|
+
|
|
179
|
+
const SCROLL_UP_KEYS = new Set(['ArrowUp', 'PageUp', 'Home'])
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Is this the reader moving the view up, right now?
|
|
183
|
+
*
|
|
184
|
+
* A held position (see `createScrollFollow().hold`) is the caller's until the reader takes it,
|
|
185
|
+
* and only an input that can scroll the view up takes it: a wheel notch up, an up key, a
|
|
186
|
+
* touch drag, or a press on the scroller itself (its scrollbar or gutter). A click or a
|
|
187
|
+
* selection inside the content, a letter, a wheel notch down or a down key do not move the
|
|
188
|
+
* view away from the end, so they leave it where it is.
|
|
189
|
+
*/
|
|
190
|
+
export function isScrollUpIntent(input: ReaderInput): boolean {
|
|
191
|
+
switch (input.kind) {
|
|
192
|
+
case 'wheel':
|
|
193
|
+
return input.deltaY < 0
|
|
194
|
+
case 'key':
|
|
195
|
+
return SCROLL_UP_KEYS.has(input.key) || (input.key === ' ' && input.shiftKey)
|
|
196
|
+
case 'touchmove':
|
|
197
|
+
return true
|
|
198
|
+
case 'pointerdown':
|
|
199
|
+
return input.onScroller
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
172
203
|
/** Result of an automatic (RO / append) pin evaluation. */
|
|
173
204
|
export interface AutoPinResult {
|
|
174
205
|
/** Whether to write `el.scrollTop = target` now. */
|
|
@@ -16,11 +16,16 @@
|
|
|
16
16
|
import { createEffect, createSignal, onCleanup, untrack } from 'solid-js'
|
|
17
17
|
import type { ConversationReadingPosition } from './conversation-surface'
|
|
18
18
|
import {
|
|
19
|
+
atBottomEpsilon,
|
|
19
20
|
bottomTarget,
|
|
20
21
|
computeAtBottom,
|
|
22
|
+
distanceFromBottom,
|
|
21
23
|
evaluateAutoPin,
|
|
24
|
+
isScrollUpIntent,
|
|
22
25
|
isSelfScroll,
|
|
23
26
|
resolveUserScrollStick,
|
|
27
|
+
SELF_SCROLL_EPSILON,
|
|
28
|
+
type ReaderInput,
|
|
24
29
|
} from './scroll-follow-core'
|
|
25
30
|
|
|
26
31
|
const geometry = (element: HTMLDivElement) => ({
|
|
@@ -30,6 +35,9 @@ const geometry = (element: HTMLDivElement) => ({
|
|
|
30
35
|
})
|
|
31
36
|
const noop = () => {}
|
|
32
37
|
|
|
38
|
+
/** Opens a hold on the follow position (see `createScrollFollow`); the function it returns closes it. */
|
|
39
|
+
export type ScrollFollowHold = () => () => void
|
|
40
|
+
|
|
33
41
|
/** Internal plain-scroller binding; host-owned restoration can disable follow. */
|
|
34
42
|
export function createScrollFollow(options: {
|
|
35
43
|
enabled: () => boolean
|
|
@@ -49,6 +57,26 @@ export function createScrollFollow(options: {
|
|
|
49
57
|
let pendingRestore: { frame: number; fromTop: number; target: number } | undefined
|
|
50
58
|
let pendingRestoreUserIntent = false
|
|
51
59
|
let removeRestoreIntentListeners = noop
|
|
60
|
+
// A hold is the caller saying it is positioning the view (see `hold`): while one is
|
|
61
|
+
// open and the reader was following, the content's moves are not read as the reader's.
|
|
62
|
+
let holds = 0
|
|
63
|
+
let holdFollowing = false
|
|
64
|
+
let holdIntent = false
|
|
65
|
+
let holdTop = -1
|
|
66
|
+
// Bumped on every identity change, so a hold opened for the previous conversation can
|
|
67
|
+
// neither pin the next one nor close over its state.
|
|
68
|
+
let holdGeneration = 0
|
|
69
|
+
const holding = () => holds > 0 && holdFollowing && !holdIntent
|
|
70
|
+
// Is the view still where the hold left it? The content can move the offset only by
|
|
71
|
+
// clamping it to the end it has now; anything else moved it from outside (a reveal, a
|
|
72
|
+
// search jump), and that is the caller's to keep, so the hold gives way.
|
|
73
|
+
const holdsPosition = (element: HTMLDivElement) => {
|
|
74
|
+
if (!holding()) return false
|
|
75
|
+
const maxTop = Math.max(0, element.scrollHeight - element.clientHeight)
|
|
76
|
+
if (Math.abs(element.scrollTop - Math.min(holdTop, maxTop)) <= SELF_SCROLL_EPSILON) return true
|
|
77
|
+
holdIntent = true
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
52
80
|
const reportPosition = () => {
|
|
53
81
|
if (scroller)
|
|
54
82
|
untrack(() =>
|
|
@@ -68,8 +96,24 @@ export function createScrollFollow(options: {
|
|
|
68
96
|
lastWriteClientHeight = element.clientHeight
|
|
69
97
|
previousTop = element.scrollTop
|
|
70
98
|
}
|
|
99
|
+
const pinHeld = (element: HTMLDivElement) => {
|
|
100
|
+
const geom = geometry(element)
|
|
101
|
+
stick = true
|
|
102
|
+
if (distanceFromBottom(geom) > atBottomEpsilon()) writePin(element, bottomTarget(geom))
|
|
103
|
+
// An end the engine already clamped to is accepted as it stands, and is the reference
|
|
104
|
+
// from here on: the write before it is further down than the content now reaches.
|
|
105
|
+
else {
|
|
106
|
+
lastWriteTop = element.scrollTop
|
|
107
|
+
lastWriteClientHeight = element.clientHeight
|
|
108
|
+
previousTop = element.scrollTop
|
|
109
|
+
}
|
|
110
|
+
holdTop = element.scrollTop
|
|
111
|
+
setAtBottom(computeAtBottom(geometry(element), options.threshold()))
|
|
112
|
+
reportPosition()
|
|
113
|
+
}
|
|
71
114
|
const pinAuto = () => {
|
|
72
115
|
if (!scroller || !options.enabled() || pendingRestore) return
|
|
116
|
+
if (holdsPosition(scroller)) return pinHeld(scroller)
|
|
73
117
|
const geom = geometry(scroller)
|
|
74
118
|
const result = evaluateAutoPin({
|
|
75
119
|
stick,
|
|
@@ -112,6 +156,7 @@ export function createScrollFollow(options: {
|
|
|
112
156
|
reportPosition()
|
|
113
157
|
return
|
|
114
158
|
}
|
|
159
|
+
if (holdsPosition(scroller)) return pinHeld(scroller)
|
|
115
160
|
const geom = geometry(scroller)
|
|
116
161
|
setAtBottom(computeAtBottom(geom, options.threshold()))
|
|
117
162
|
if (!isSelfScroll(geom.scrollTop, lastWriteTop)) {
|
|
@@ -145,6 +190,46 @@ export function createScrollFollow(options: {
|
|
|
145
190
|
scroller.focus({ preventScroll: true })
|
|
146
191
|
}
|
|
147
192
|
|
|
193
|
+
// Open while the caller moves content under a reader who is following, so a clamp or an
|
|
194
|
+
// insert it causes is not mistaken for the reader leaving the end. It gives way to the
|
|
195
|
+
// reader's own scroll-up (`isScrollUpIntent`) and to anything else that moves the view
|
|
196
|
+
// from outside (a reveal, a search jump); closing it puts a reader who is still following
|
|
197
|
+
// back at the end. A change of conversation invalidates it, so the next conversation's
|
|
198
|
+
// saved position is its own. A reveal or search jump outside a hold is never affected.
|
|
199
|
+
const hold = () => {
|
|
200
|
+
if (holds === 0) {
|
|
201
|
+
holdFollowing = options.enabled() && stick && scroller !== undefined
|
|
202
|
+
holdIntent = false
|
|
203
|
+
holdTop = scroller ? scroller.scrollTop : -1
|
|
204
|
+
}
|
|
205
|
+
holds += 1
|
|
206
|
+
const generation = holdGeneration
|
|
207
|
+
let open = true
|
|
208
|
+
return () => {
|
|
209
|
+
if (!open || generation !== holdGeneration) return
|
|
210
|
+
open = false
|
|
211
|
+
// Asked while this hold still counts: `holdsPosition` is false once none is open.
|
|
212
|
+
const last = holds === 1
|
|
213
|
+
const resume = last && scroller !== undefined && holdsPosition(scroller)
|
|
214
|
+
holds -= 1
|
|
215
|
+
if (!last) return
|
|
216
|
+
holdFollowing = false
|
|
217
|
+
holdIntent = false
|
|
218
|
+
if (resume && scroller && options.enabled() && !pendingRestore) pinHeld(scroller)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const noteHoldInput = (event: Event) => {
|
|
222
|
+
if (holds === 0 || holdIntent) return
|
|
223
|
+
let input: ReaderInput | undefined
|
|
224
|
+
if (event instanceof WheelEvent) input = { kind: 'wheel', deltaY: event.deltaY }
|
|
225
|
+
else if (event instanceof KeyboardEvent)
|
|
226
|
+
input = { kind: 'key', key: event.key, shiftKey: event.shiftKey }
|
|
227
|
+
else if (event.type === 'touchmove') input = { kind: 'touchmove' }
|
|
228
|
+
else if (event.type === 'pointerdown')
|
|
229
|
+
input = { kind: 'pointerdown', onScroller: event.target === scroller }
|
|
230
|
+
if (input && isScrollUpIntent(input)) holdIntent = true
|
|
231
|
+
}
|
|
232
|
+
|
|
148
233
|
createEffect(() => {
|
|
149
234
|
options.resetKey()
|
|
150
235
|
const enabled = options.enabled()
|
|
@@ -165,6 +250,10 @@ export function createScrollFollow(options: {
|
|
|
165
250
|
observer?.disconnect()
|
|
166
251
|
})
|
|
167
252
|
stick = true
|
|
253
|
+
holdGeneration += 1
|
|
254
|
+
holds = 0
|
|
255
|
+
holdFollowing = false
|
|
256
|
+
holdIntent = false
|
|
168
257
|
lastWriteTop = -1
|
|
169
258
|
lastWriteClientHeight = -1
|
|
170
259
|
previousTop = -1
|
|
@@ -248,8 +337,11 @@ export function createScrollFollow(options: {
|
|
|
248
337
|
atBottom,
|
|
249
338
|
onScroll,
|
|
250
339
|
jump,
|
|
340
|
+
hold,
|
|
251
341
|
bindScroller: (element: HTMLDivElement) => {
|
|
252
342
|
scroller = element
|
|
343
|
+
for (const type of ['wheel', 'touchmove', 'pointerdown', 'keydown'])
|
|
344
|
+
element.addEventListener(type, noteHoldInput, { passive: true })
|
|
253
345
|
},
|
|
254
346
|
bindContent: (element: HTMLDivElement) => {
|
|
255
347
|
content = element
|