@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,144 @@
|
|
|
1
|
+
import { parseMessageText, type MessageBlock, type MessageInline } from './parse-message-text'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Citations that arrive as positions in the text, placed as markers.
|
|
5
|
+
*
|
|
6
|
+
* A producer that cites a passage says *where*: a half-open span of the exact
|
|
7
|
+
* text and the sources behind it. `MessageText` binds `[^n]` markers, so this
|
|
8
|
+
* turns the one into the other without ever changing what the text says:
|
|
9
|
+
*
|
|
10
|
+
* - A marker goes at the **end** of the span, nowhere else, and only for numbers
|
|
11
|
+
* within `count`. Several spans ending at one place share one marker.
|
|
12
|
+
* - **The parser is the judge of where a marker may go.** The text is parsed
|
|
13
|
+
* without the markers and again with them; a marker is kept only if everything
|
|
14
|
+
* that is not a marker reads exactly as before. A position inside a code
|
|
15
|
+
* block, an inline code span, a link target or anything else the parser reads
|
|
16
|
+
* as something other than prose changes that reading, so it is dropped (the
|
|
17
|
+
* source still belongs in `Sources`; it just has no badge there). No second
|
|
18
|
+
* copy of the Markdown rules exists to drift from the real one.
|
|
19
|
+
* - **Text that already has footnote marks gets none.** `[^1]` typed by a model
|
|
20
|
+
* would otherwise be indistinguishable from a marker placed here, and a
|
|
21
|
+
* citation must never come from the text alone.
|
|
22
|
+
*
|
|
23
|
+
* The result's `text` is for display only. Copy the original.
|
|
24
|
+
*/
|
|
25
|
+
export type CitationPlacement = Readonly<{
|
|
26
|
+
/** Offset into the text after which the marker goes (the span's end). */
|
|
27
|
+
end: number
|
|
28
|
+
/** 1-based positions in the host's source list. */
|
|
29
|
+
numbers: readonly number[]
|
|
30
|
+
}>
|
|
31
|
+
|
|
32
|
+
export type PlacedCitations = Readonly<{
|
|
33
|
+
/** The text with markers, for `MessageText` with `citations`. */
|
|
34
|
+
text: string
|
|
35
|
+
/** Distinct end positions that received a marker. */
|
|
36
|
+
placed: number
|
|
37
|
+
/** Those positions, ascending: a span is represented exactly when its end is among them. */
|
|
38
|
+
ends: readonly number[]
|
|
39
|
+
/** Distinct end positions left without one, for any reason. */
|
|
40
|
+
skipped: number
|
|
41
|
+
/** The text had footnote marks of its own, so nothing was placed. */
|
|
42
|
+
collision: boolean
|
|
43
|
+
}>
|
|
44
|
+
|
|
45
|
+
const FOOTNOTE = /\[\^\d/
|
|
46
|
+
const PER_MARKER = 6
|
|
47
|
+
|
|
48
|
+
function marker(numbers: readonly number[]): string {
|
|
49
|
+
const parts: string[] = []
|
|
50
|
+
for (let index = 0; index < numbers.length; index += PER_MARKER) {
|
|
51
|
+
parts.push(`[^${numbers.slice(index, index + PER_MARKER).join(',')}]`)
|
|
52
|
+
}
|
|
53
|
+
return parts.join('')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalise(nodes: readonly MessageInline[]): unknown[] {
|
|
57
|
+
const out: unknown[] = []
|
|
58
|
+
for (const node of nodes) {
|
|
59
|
+
if (node.kind === 'cite') continue
|
|
60
|
+
if (node.kind === 'strong' || node.kind === 'em' || node.kind === 'link') {
|
|
61
|
+
out.push({ ...node, children: normalise(node.children) })
|
|
62
|
+
continue
|
|
63
|
+
}
|
|
64
|
+
const last = out.at(-1) as { kind?: string; text?: string } | undefined
|
|
65
|
+
if (node.kind === 'text' && last?.kind === 'text') {
|
|
66
|
+
out[out.length - 1] = { kind: 'text', text: `${last.text}${node.text}` }
|
|
67
|
+
} else {
|
|
68
|
+
out.push(node)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** What the blocks say with the markers and every `raw` slice taken out. */
|
|
75
|
+
function reading(blocks: readonly MessageBlock[]): string {
|
|
76
|
+
return JSON.stringify(
|
|
77
|
+
blocks.map((block) => {
|
|
78
|
+
const { raw: _raw, ...rest } = block
|
|
79
|
+
if (block.kind === 'list') return { ...rest, items: block.items.map(normalise) }
|
|
80
|
+
if (block.kind === 'code') return rest
|
|
81
|
+
return { ...rest, inline: normalise(block.inline) }
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function placeCitationMarkers(
|
|
87
|
+
text: string,
|
|
88
|
+
citations: readonly CitationPlacement[],
|
|
89
|
+
count: number
|
|
90
|
+
): PlacedCitations {
|
|
91
|
+
const byEnd = new Map<number, Set<number>>()
|
|
92
|
+
for (const { end, numbers } of citations) {
|
|
93
|
+
if (!Number.isInteger(end) || end <= 0 || end > text.length) continue
|
|
94
|
+
for (const number of numbers) {
|
|
95
|
+
if (!Number.isInteger(number) || number < 1 || number > count) continue
|
|
96
|
+
const set = byEnd.get(end) ?? new Set<number>()
|
|
97
|
+
set.add(number)
|
|
98
|
+
byEnd.set(end, set)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const candidates = [...byEnd.entries()]
|
|
102
|
+
.toSorted(([left], [right]) => left - right)
|
|
103
|
+
.map(([end, numbers]) => ({ end, marker: marker([...numbers].toSorted((a, b) => a - b)) }))
|
|
104
|
+
if (candidates.length === 0) return { text, placed: 0, ends: [], skipped: 0, collision: false }
|
|
105
|
+
if (FOOTNOTE.test(text)) {
|
|
106
|
+
return { text, placed: 0, ends: [], skipped: candidates.length, collision: true }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const insert = (chosen: readonly { end: number; marker: string }[]): string => {
|
|
110
|
+
let out = ''
|
|
111
|
+
let cursor = 0
|
|
112
|
+
for (const item of chosen) {
|
|
113
|
+
out += text.slice(cursor, item.end) + item.marker
|
|
114
|
+
cursor = item.end
|
|
115
|
+
}
|
|
116
|
+
return out + text.slice(cursor)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const baseline = reading(parseMessageText(text))
|
|
120
|
+
const holds = (chosen: readonly { end: number; marker: string }[]) =>
|
|
121
|
+
reading(parseMessageText(insert(chosen), { citations: count })) === baseline
|
|
122
|
+
|
|
123
|
+
// Usual case: every position is prose, one check covers all of them.
|
|
124
|
+
if (holds(candidates)) {
|
|
125
|
+
return {
|
|
126
|
+
text: insert(candidates),
|
|
127
|
+
placed: candidates.length,
|
|
128
|
+
ends: candidates.map((candidate) => candidate.end),
|
|
129
|
+
skipped: 0,
|
|
130
|
+
collision: false,
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const accepted: { end: number; marker: string }[] = []
|
|
134
|
+
for (const candidate of candidates) {
|
|
135
|
+
if (holds([...accepted, candidate])) accepted.push(candidate)
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
text: insert(accepted),
|
|
139
|
+
placed: accepted.length,
|
|
140
|
+
ends: accepted.map((candidate) => candidate.end),
|
|
141
|
+
skipped: candidates.length - accepted.length,
|
|
142
|
+
collision: false,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export {
|
|
2
|
+
Message,
|
|
3
|
+
MessageActions,
|
|
4
|
+
MessageContent,
|
|
5
|
+
MessageFooter,
|
|
6
|
+
MessageHeader,
|
|
7
|
+
MessageText,
|
|
8
|
+
type MessageCitations,
|
|
9
|
+
type MessageCodeBlockInfo,
|
|
10
|
+
type MessageCodeBlockProps,
|
|
11
|
+
type MessageProps,
|
|
12
|
+
type MessageRole,
|
|
13
|
+
type MessageTextProps,
|
|
14
|
+
} from './message'
|
|
15
|
+
export { placeCitationMarkers, type CitationPlacement, type PlacedCitations } from './cite-ranges'
|
|
16
|
+
export {
|
|
17
|
+
parseInline,
|
|
18
|
+
parseMessageText,
|
|
19
|
+
safeHref,
|
|
20
|
+
type MessageBlock,
|
|
21
|
+
type MessageInline,
|
|
22
|
+
type ParseInlineOptions,
|
|
23
|
+
} from './parse-message-text'
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMemo,
|
|
3
|
+
For,
|
|
4
|
+
Index,
|
|
5
|
+
Match,
|
|
6
|
+
Show,
|
|
7
|
+
splitProps,
|
|
8
|
+
Switch,
|
|
9
|
+
type ComponentProps,
|
|
10
|
+
type JSX,
|
|
11
|
+
} from 'solid-js'
|
|
12
|
+
import { cn } from '#lib/utils'
|
|
13
|
+
import { CodeBlock, InlineCode, type CodeBlockProps } from '../code-block'
|
|
14
|
+
import { parseMessageText, type MessageBlock, type MessageInline } from './parse-message-text'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Message.
|
|
18
|
+
*
|
|
19
|
+
* One turn. The two speakers are laid out differently on purpose, and that is
|
|
20
|
+
* the whole design:
|
|
21
|
+
*
|
|
22
|
+
* - **The person's turn is a bubble on the trailing edge** — short, bounded, and
|
|
23
|
+
* easy to find when scrolling back through a long session.
|
|
24
|
+
* - **The assistant's turn is the page.** It has no surface, spans the reading
|
|
25
|
+
* column, and holds everything the agent did *for that request* — activity
|
|
26
|
+
* (a `Trace`), prose, code, a pending decision — in one place, so a turn
|
|
27
|
+
* reads as an answer with its working underneath it rather than as a chain of
|
|
28
|
+
* unrelated cards.
|
|
29
|
+
*
|
|
30
|
+
* `label` is the turn's accessible name ("You", "Assistant"): the avatar and
|
|
31
|
+
* name are not drawn for every turn, because a transcript that repeats a speaker
|
|
32
|
+
* on every line is one nobody reads, but the name must still be announced.
|
|
33
|
+
* `streaming` sets `aria-busy`, which tells assistive technology to wait for the
|
|
34
|
+
* turn to settle before reading it instead of announcing every token.
|
|
35
|
+
*
|
|
36
|
+
* `anchorId` is the stable identity `MessageScroller` uses to keep the reader's
|
|
37
|
+
* place when older turns are inserted above it.
|
|
38
|
+
*/
|
|
39
|
+
export type MessageRole = 'user' | 'assistant' | 'system'
|
|
40
|
+
|
|
41
|
+
export type MessageProps = Omit<ComponentProps<'article'>, 'role'> & {
|
|
42
|
+
role: MessageRole
|
|
43
|
+
/** The turn's accessible name. */
|
|
44
|
+
label: string
|
|
45
|
+
streaming?: boolean
|
|
46
|
+
anchorId?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function Message(props: MessageProps) {
|
|
50
|
+
const [local, rest] = splitProps(props, [
|
|
51
|
+
'class',
|
|
52
|
+
'role',
|
|
53
|
+
'label',
|
|
54
|
+
'streaming',
|
|
55
|
+
'anchorId',
|
|
56
|
+
'children',
|
|
57
|
+
])
|
|
58
|
+
return (
|
|
59
|
+
<article
|
|
60
|
+
data-slot="message"
|
|
61
|
+
data-role={local.role}
|
|
62
|
+
data-anchor-id={local.anchorId}
|
|
63
|
+
aria-label={local.label}
|
|
64
|
+
aria-busy={local.streaming || undefined}
|
|
65
|
+
class={cn(
|
|
66
|
+
'group/message mx-auto flex w-full max-w-3xl min-w-0 flex-col gap-2 py-2',
|
|
67
|
+
// The engine may skip layout for turns far off screen; the intrinsic size
|
|
68
|
+
// keeps the scrollbar honest while it does.
|
|
69
|
+
'[content-visibility:auto] [contain-intrinsic-size:auto_6rem]',
|
|
70
|
+
{
|
|
71
|
+
'items-end ps-[clamp(0rem,12%,4rem)]': local.role === 'user',
|
|
72
|
+
'items-stretch': local.role !== 'user',
|
|
73
|
+
},
|
|
74
|
+
local.class
|
|
75
|
+
)}
|
|
76
|
+
{...rest}
|
|
77
|
+
>
|
|
78
|
+
{local.children}
|
|
79
|
+
</article>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The speaker's mark and name, for the turns that draw one. */
|
|
84
|
+
export function MessageHeader(
|
|
85
|
+
props: ComponentProps<'header'> & { avatar?: JSX.Element; time?: JSX.Element }
|
|
86
|
+
) {
|
|
87
|
+
const [local, rest] = splitProps(props, ['class', 'avatar', 'time', 'children'])
|
|
88
|
+
return (
|
|
89
|
+
<header
|
|
90
|
+
data-slot="message-header"
|
|
91
|
+
class={cn('flex items-center gap-2 text-xs text-muted-foreground', local.class)}
|
|
92
|
+
{...rest}
|
|
93
|
+
>
|
|
94
|
+
<Show when={local.avatar}>{local.avatar}</Show>
|
|
95
|
+
<span class="font-medium text-foreground">{local.children}</span>
|
|
96
|
+
<Show when={local.time}>
|
|
97
|
+
<span class="tabular-nums">{local.time}</span>
|
|
98
|
+
</Show>
|
|
99
|
+
</header>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The turn's parts, stacked. Gap is the rhythm between prose, activity and code. */
|
|
104
|
+
export function MessageContent(props: ComponentProps<'div'>) {
|
|
105
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
106
|
+
return (
|
|
107
|
+
<div
|
|
108
|
+
data-slot="message-content"
|
|
109
|
+
class={cn(
|
|
110
|
+
'flex w-full max-w-3xl min-w-0 flex-col gap-3 font-content text-content',
|
|
111
|
+
local.class
|
|
112
|
+
)}
|
|
113
|
+
{...rest}
|
|
114
|
+
>
|
|
115
|
+
{local.children}
|
|
116
|
+
</div>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Actions that belong to the turn (copy, retry). Hidden until the turn is hovered
|
|
122
|
+
* or focused so the column is not a wall of buttons, but never `display: none`:
|
|
123
|
+
* a control that only exists under the pointer cannot be reached by keyboard,
|
|
124
|
+
* and on a touch screen there is no hover, so coarse pointers always see them.
|
|
125
|
+
*/
|
|
126
|
+
export function MessageActions(props: ComponentProps<'div'>) {
|
|
127
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
128
|
+
return (
|
|
129
|
+
<div
|
|
130
|
+
data-slot="message-actions"
|
|
131
|
+
class={cn(
|
|
132
|
+
'flex items-center gap-1 opacity-0 transition-opacity ease-out group-focus-within/message:opacity-100 group-hover/message:opacity-100 [@media(hover:none)]:opacity-100',
|
|
133
|
+
local.class
|
|
134
|
+
)}
|
|
135
|
+
{...rest}
|
|
136
|
+
>
|
|
137
|
+
{local.children}
|
|
138
|
+
</div>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function MessageFooter(props: ComponentProps<'footer'>) {
|
|
143
|
+
const [local, rest] = splitProps(props, ['class', 'children'])
|
|
144
|
+
return (
|
|
145
|
+
<footer
|
|
146
|
+
data-slot="message-footer"
|
|
147
|
+
class={cn('flex min-w-0 items-center gap-2 text-xs text-muted-foreground', local.class)}
|
|
148
|
+
{...rest}
|
|
149
|
+
>
|
|
150
|
+
{local.children}
|
|
151
|
+
</footer>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The props of a fenced block the host may set. */
|
|
156
|
+
export type MessageCodeBlockProps = Pick<
|
|
157
|
+
CodeBlockProps,
|
|
158
|
+
'loadHighlight' | 'maxHeight' | 'wrap' | 'showLineNumbers' | 'lineMarks' | 'lineLimit'
|
|
159
|
+
>
|
|
160
|
+
|
|
161
|
+
/** What the host is told about a fenced block when it chooses that block's props. */
|
|
162
|
+
export type MessageCodeBlockInfo = Readonly<{
|
|
163
|
+
/** Position among the text's fenced blocks, from 0. */
|
|
164
|
+
index: number
|
|
165
|
+
language: string | undefined
|
|
166
|
+
code: string
|
|
167
|
+
complete: boolean
|
|
168
|
+
}>
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* How `MessageText` draws citation markers. `count` is how many sources the host
|
|
172
|
+
* has; a `[^n]` marker is a citation only when every `n` is within it. `render`
|
|
173
|
+
* receives the 1-based source numbers and draws the marker, so the host decides
|
|
174
|
+
* what a number means (`messageCitations` in the inline-citation composite does
|
|
175
|
+
* this for a `Source` list).
|
|
176
|
+
*/
|
|
177
|
+
export type MessageCitations = Readonly<{
|
|
178
|
+
count: number
|
|
179
|
+
render: (numbers: readonly number[]) => JSX.Element
|
|
180
|
+
}>
|
|
181
|
+
|
|
182
|
+
export type MessageTextProps = Omit<ComponentProps<'div'>, 'children'> & {
|
|
183
|
+
text: string
|
|
184
|
+
/** True while text may still arrive: a trailing open fence renders as partial code. */
|
|
185
|
+
streaming?: boolean
|
|
186
|
+
/**
|
|
187
|
+
* Forwarded to each fenced block, e.g. to supply a lazy highlighter. A function
|
|
188
|
+
* chooses per block, which is how line marks reach a block: marks belong to the
|
|
189
|
+
* host's knowledge of the code (a diff, a failing line), never to the text.
|
|
190
|
+
*/
|
|
191
|
+
codeBlockProps?: MessageCodeBlockProps | ((block: MessageCodeBlockInfo) => MessageCodeBlockProps)
|
|
192
|
+
/** Without it, `[^1]` stays the literal text it was written as. */
|
|
193
|
+
citations?: MessageCitations
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function sameBlock(a: MessageBlock | undefined, b: MessageBlock): boolean {
|
|
197
|
+
return (
|
|
198
|
+
a !== undefined &&
|
|
199
|
+
a.kind === b.kind &&
|
|
200
|
+
a.raw === b.raw &&
|
|
201
|
+
(a.kind !== 'code' || (b.kind === 'code' && a.complete === b.complete))
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Text, read safely.
|
|
207
|
+
*
|
|
208
|
+
* Renders `parseMessageText`'s blocks as elements: nothing is interpreted as
|
|
209
|
+
* HTML and a link only becomes an anchor when its scheme is http, https or
|
|
210
|
+
* mailto. Blocks are kept by *position* and reuse their previous parsed object
|
|
211
|
+
* when unchanged, so a streaming turn updates the block that is growing and
|
|
212
|
+
* leaves every earlier paragraph and code block — and any selection or focus
|
|
213
|
+
* inside them — untouched.
|
|
214
|
+
*/
|
|
215
|
+
export function MessageText(props: MessageTextProps) {
|
|
216
|
+
const [local, rest] = splitProps(props, [
|
|
217
|
+
'class',
|
|
218
|
+
'text',
|
|
219
|
+
'streaming',
|
|
220
|
+
'codeBlockProps',
|
|
221
|
+
'citations',
|
|
222
|
+
])
|
|
223
|
+
let previous: readonly MessageBlock[] = []
|
|
224
|
+
let previousCount = 0
|
|
225
|
+
// Only the number of sources reaches the parser, so a new `render` function
|
|
226
|
+
// does not reparse the text, and a changed count does.
|
|
227
|
+
const citationCount = () => local.citations?.count ?? 0
|
|
228
|
+
const blocks = createMemo(() => {
|
|
229
|
+
const count = citationCount()
|
|
230
|
+
if (count !== previousCount) previous = []
|
|
231
|
+
previousCount = count
|
|
232
|
+
const next = parseMessageText(local.text, {
|
|
233
|
+
streaming: local.streaming,
|
|
234
|
+
citations: count || undefined,
|
|
235
|
+
})
|
|
236
|
+
const merged = next.map((block, index) =>
|
|
237
|
+
sameBlock(previous[index], block) ? previous[index]! : block
|
|
238
|
+
)
|
|
239
|
+
previous = merged
|
|
240
|
+
return merged
|
|
241
|
+
})
|
|
242
|
+
// The nth fenced block, so a host can address it. Blocks keep their positions
|
|
243
|
+
// while text streams in after them, so an index stays attached to its block.
|
|
244
|
+
const codeIndexes = createMemo(() => {
|
|
245
|
+
let next = 0
|
|
246
|
+
return blocks().map((block) => (block.kind === 'code' ? next++ : -1))
|
|
247
|
+
})
|
|
248
|
+
const lastIsProse = () => {
|
|
249
|
+
const last = blocks().at(-1)
|
|
250
|
+
return last !== undefined && last.kind !== 'code'
|
|
251
|
+
}
|
|
252
|
+
return (
|
|
253
|
+
<div data-slot="message-text" class={cn('flex min-w-0 flex-col gap-3', local.class)} {...rest}>
|
|
254
|
+
<Index each={blocks()}>
|
|
255
|
+
{(block, index) => (
|
|
256
|
+
<BlockView
|
|
257
|
+
block={block()}
|
|
258
|
+
codeProps={local.codeBlockProps}
|
|
259
|
+
codeIndex={() => codeIndexes()[index] ?? 0}
|
|
260
|
+
citations={local.citations}
|
|
261
|
+
/>
|
|
262
|
+
)}
|
|
263
|
+
</Index>
|
|
264
|
+
<Show when={local.streaming && lastIsProse()}>
|
|
265
|
+
<span class="streaming-caret" aria-hidden="true" />
|
|
266
|
+
</Show>
|
|
267
|
+
</div>
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function BlockView(props: {
|
|
272
|
+
block: MessageBlock
|
|
273
|
+
codeProps?: MessageTextProps['codeBlockProps']
|
|
274
|
+
codeIndex: () => number
|
|
275
|
+
citations?: MessageCitations
|
|
276
|
+
}) {
|
|
277
|
+
return (
|
|
278
|
+
<Switch>
|
|
279
|
+
<Match when={props.block.kind === 'code' && props.block}>
|
|
280
|
+
{(block) => {
|
|
281
|
+
const code = () => block() as Extract<MessageBlock, { kind: 'code' }>
|
|
282
|
+
const chosen = () => {
|
|
283
|
+
const choice = props.codeProps
|
|
284
|
+
return typeof choice === 'function'
|
|
285
|
+
? choice({
|
|
286
|
+
index: props.codeIndex(),
|
|
287
|
+
language: code().language,
|
|
288
|
+
code: code().code,
|
|
289
|
+
complete: code().complete,
|
|
290
|
+
})
|
|
291
|
+
: choice
|
|
292
|
+
}
|
|
293
|
+
return (
|
|
294
|
+
<CodeBlock
|
|
295
|
+
code={code().code}
|
|
296
|
+
language={code().language}
|
|
297
|
+
complete={code().complete}
|
|
298
|
+
{...chosen()}
|
|
299
|
+
/>
|
|
300
|
+
)
|
|
301
|
+
}}
|
|
302
|
+
</Match>
|
|
303
|
+
<Match when={props.block.kind === 'heading' && props.block}>
|
|
304
|
+
{(block) => {
|
|
305
|
+
const heading = () => block() as Extract<MessageBlock, { kind: 'heading' }>
|
|
306
|
+
return (
|
|
307
|
+
<p
|
|
308
|
+
role="heading"
|
|
309
|
+
aria-level={heading().level + 2}
|
|
310
|
+
class="font-semibold text-foreground [overflow-wrap:anywhere]"
|
|
311
|
+
>
|
|
312
|
+
<Inline nodes={heading().inline} citations={props.citations} />
|
|
313
|
+
</p>
|
|
314
|
+
)
|
|
315
|
+
}}
|
|
316
|
+
</Match>
|
|
317
|
+
<Match when={props.block.kind === 'list' && props.block}>
|
|
318
|
+
{(block) => {
|
|
319
|
+
const list = () => block() as Extract<MessageBlock, { kind: 'list' }>
|
|
320
|
+
return (
|
|
321
|
+
<Show
|
|
322
|
+
when={list().ordered}
|
|
323
|
+
fallback={
|
|
324
|
+
<ul class="m-0 ms-5 flex list-disc flex-col gap-1 p-0 marker:text-muted-foreground">
|
|
325
|
+
<For each={list().items}>
|
|
326
|
+
{(item) => (
|
|
327
|
+
<li class="[overflow-wrap:anywhere]">
|
|
328
|
+
<Inline nodes={item} citations={props.citations} />
|
|
329
|
+
</li>
|
|
330
|
+
)}
|
|
331
|
+
</For>
|
|
332
|
+
</ul>
|
|
333
|
+
}
|
|
334
|
+
>
|
|
335
|
+
<ol
|
|
336
|
+
start={list().start}
|
|
337
|
+
class="m-0 ms-5 flex list-decimal flex-col gap-1 p-0 marker:text-muted-foreground"
|
|
338
|
+
>
|
|
339
|
+
<For each={list().items}>
|
|
340
|
+
{(item) => (
|
|
341
|
+
<li class="[overflow-wrap:anywhere]">
|
|
342
|
+
<Inline nodes={item} citations={props.citations} />
|
|
343
|
+
</li>
|
|
344
|
+
)}
|
|
345
|
+
</For>
|
|
346
|
+
</ol>
|
|
347
|
+
</Show>
|
|
348
|
+
)
|
|
349
|
+
}}
|
|
350
|
+
</Match>
|
|
351
|
+
<Match when={props.block.kind === 'quote' && props.block}>
|
|
352
|
+
{(block) => {
|
|
353
|
+
const quote = () => block() as Extract<MessageBlock, { kind: 'quote' }>
|
|
354
|
+
return (
|
|
355
|
+
<blockquote class="m-0 border-s-2 border-border ps-3 whitespace-pre-wrap text-muted-foreground [overflow-wrap:anywhere]">
|
|
356
|
+
<Inline nodes={quote().inline} citations={props.citations} />
|
|
357
|
+
</blockquote>
|
|
358
|
+
)
|
|
359
|
+
}}
|
|
360
|
+
</Match>
|
|
361
|
+
<Match when={props.block.kind === 'paragraph' && props.block}>
|
|
362
|
+
{(block) => {
|
|
363
|
+
const paragraph = () => block() as Extract<MessageBlock, { kind: 'paragraph' }>
|
|
364
|
+
return (
|
|
365
|
+
<p class="m-0 whitespace-pre-wrap [overflow-wrap:anywhere]">
|
|
366
|
+
<Inline nodes={paragraph().inline} citations={props.citations} />
|
|
367
|
+
</p>
|
|
368
|
+
)
|
|
369
|
+
}}
|
|
370
|
+
</Match>
|
|
371
|
+
</Switch>
|
|
372
|
+
)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function Inline(props: { nodes: readonly MessageInline[]; citations?: MessageCitations }) {
|
|
376
|
+
return (
|
|
377
|
+
<For each={props.nodes}>
|
|
378
|
+
{(node) => (
|
|
379
|
+
<Switch>
|
|
380
|
+
<Match when={node.kind === 'text' && node}>
|
|
381
|
+
{(text) => (text() as { text: string }).text}
|
|
382
|
+
</Match>
|
|
383
|
+
<Match when={node.kind === 'code' && node}>
|
|
384
|
+
{(code) => <InlineCode>{(code() as { text: string }).text}</InlineCode>}
|
|
385
|
+
</Match>
|
|
386
|
+
<Match when={node.kind === 'strong' && node}>
|
|
387
|
+
{(strong) => (
|
|
388
|
+
<strong class="font-semibold">
|
|
389
|
+
<Inline
|
|
390
|
+
nodes={(strong() as { children: readonly MessageInline[] }).children}
|
|
391
|
+
citations={props.citations}
|
|
392
|
+
/>
|
|
393
|
+
</strong>
|
|
394
|
+
)}
|
|
395
|
+
</Match>
|
|
396
|
+
<Match when={node.kind === 'em' && node}>
|
|
397
|
+
{(em) => (
|
|
398
|
+
<em>
|
|
399
|
+
<Inline
|
|
400
|
+
nodes={(em() as { children: readonly MessageInline[] }).children}
|
|
401
|
+
citations={props.citations}
|
|
402
|
+
/>
|
|
403
|
+
</em>
|
|
404
|
+
)}
|
|
405
|
+
</Match>
|
|
406
|
+
<Match when={node.kind === 'link' && node}>
|
|
407
|
+
{(link) => (
|
|
408
|
+
<a
|
|
409
|
+
href={(link() as { href: string }).href}
|
|
410
|
+
target="_blank"
|
|
411
|
+
rel="noreferrer noopener"
|
|
412
|
+
class="text-primary underline underline-offset-2 hover:no-underline"
|
|
413
|
+
>
|
|
414
|
+
<Inline nodes={(link() as { children: readonly MessageInline[] }).children} />
|
|
415
|
+
</a>
|
|
416
|
+
)}
|
|
417
|
+
</Match>
|
|
418
|
+
<Match when={node.kind === 'cite' && node}>
|
|
419
|
+
{(cite) => {
|
|
420
|
+
const marker = () => cite() as { numbers: readonly number[]; raw: string }
|
|
421
|
+
// The parser read this as a citation only while the host had sources;
|
|
422
|
+
// if they have gone since, the marker is the text it was written as.
|
|
423
|
+
// Match invokes this callback untracked; JSX keeps renderer and
|
|
424
|
+
// same-count source replacements reactive without replacing the block.
|
|
425
|
+
return (
|
|
426
|
+
<>{props.citations ? props.citations.render(marker().numbers) : marker().raw}</>
|
|
427
|
+
)
|
|
428
|
+
}}
|
|
429
|
+
</Match>
|
|
430
|
+
</Switch>
|
|
431
|
+
)}
|
|
432
|
+
</For>
|
|
433
|
+
)
|
|
434
|
+
}
|