@signalcore/ui 0.1.0 → 1.0.0-beta.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/README.md +896 -513
- package/dist/AgentAbout.d.ts +186 -0
- package/dist/AgentAbout.js +1020 -0
- package/dist/AgentAbout.js.map +1 -0
- package/dist/AgentCard.d.ts +49 -0
- package/dist/AgentCard.js +77 -0
- package/dist/AgentCard.js.map +1 -0
- package/dist/AgentChat.d.ts +233 -0
- package/dist/AgentChat.js +1119 -0
- package/dist/AgentChat.js.map +1 -0
- package/dist/AgentSpace.d.ts +112 -0
- package/dist/AgentSpace.js +339 -0
- package/dist/AgentSpace.js.map +1 -0
- package/dist/AgentTasks.d.ts +48 -0
- package/dist/AgentTasks.js +120 -0
- package/dist/AgentTasks.js.map +1 -0
- package/dist/BrowserView.d.ts +52 -0
- package/dist/BrowserView.js +328 -0
- package/dist/BrowserView.js.map +1 -0
- package/dist/FileView.d.ts +63 -0
- package/dist/FileView.js +449 -0
- package/dist/FileView.js.map +1 -0
- package/dist/Modes.d.ts +13 -0
- package/dist/Modes.js +75 -0
- package/dist/Modes.js.map +1 -0
- package/dist/VoiceCall.d.ts +91 -0
- package/dist/VoiceCall.js +302 -0
- package/dist/VoiceCall.js.map +1 -0
- package/dist/about.d.ts +212 -0
- package/dist/about.js +136 -0
- package/dist/about.js.map +1 -0
- package/dist/agentIcons.d.ts +33 -0
- package/dist/agentIcons.js +36 -0
- package/dist/agentIcons.js.map +1 -0
- package/dist/automation/Automation.d.ts +35 -0
- package/dist/automation/Automation.js +268 -0
- package/dist/automation/Automation.js.map +1 -0
- package/dist/automation/RunView.d.ts +25 -0
- package/dist/automation/RunView.js +187 -0
- package/dist/automation/RunView.js.map +1 -0
- package/dist/automation/cron.d.ts +41 -0
- package/dist/automation/cron.js +169 -0
- package/dist/automation/cron.js.map +1 -0
- package/dist/automation/marks.js +121 -0
- package/dist/automation/marks.js.map +1 -0
- package/dist/automation/messages.d.ts +113 -0
- package/dist/automation/messages.js +113 -0
- package/dist/automation/messages.js.map +1 -0
- package/dist/automation/record.d.ts +47 -0
- package/dist/automation/record.js +177 -0
- package/dist/automation/record.js.map +1 -0
- package/dist/automation/types.d.ts +143 -0
- package/dist/automation/when.d.ts +36 -0
- package/dist/automation/when.js +168 -0
- package/dist/automation/when.js.map +1 -0
- package/dist/blocks.d.ts +185 -0
- package/dist/browser.js +292 -0
- package/dist/browser.js.map +1 -0
- package/dist/call.d.ts +89 -0
- package/dist/call.js +218 -0
- package/dist/call.js.map +1 -0
- package/dist/channelParts.js +26 -0
- package/dist/channelParts.js.map +1 -0
- package/dist/classes.js +8 -3
- package/dist/classes.js.map +1 -0
- package/dist/client.d.ts +146 -54
- package/dist/client.js +204 -1
- package/dist/client.js.map +1 -0
- package/dist/conversationFiles.js +46 -0
- package/dist/conversationFiles.js.map +1 -0
- package/dist/credentials.d.ts +45 -0
- package/dist/credentials.js +98 -0
- package/dist/credentials.js.map +1 -0
- package/dist/dev.js +17 -0
- package/dist/dev.js.map +1 -0
- package/dist/es.d.ts +17 -0
- package/dist/es.js +382 -0
- package/dist/es.js.map +1 -0
- package/dist/files.d.ts +21 -0
- package/dist/files.js +214 -0
- package/dist/files.js.map +1 -0
- package/dist/frames.d.ts +115 -0
- package/dist/frames.js +219 -0
- package/dist/frames.js.map +1 -0
- package/dist/icons.js +29 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +63 -60
- package/dist/index.js +59 -45
- package/dist/kit/AudioPlayer.d.ts +20 -0
- package/dist/kit/AudioPlayer.js +116 -0
- package/dist/kit/AudioPlayer.js.map +1 -0
- package/dist/kit/Button.d.ts +29 -0
- package/dist/kit/Button.js +59 -0
- package/dist/kit/Button.js.map +1 -0
- package/dist/kit/Card.d.ts +16 -0
- package/dist/kit/Card.js +36 -0
- package/dist/kit/Card.js.map +1 -0
- package/dist/kit/Chart.js +152 -0
- package/dist/kit/Chart.js.map +1 -0
- package/dist/kit/Choices.d.ts +21 -0
- package/dist/kit/Choices.js +99 -0
- package/dist/kit/Choices.js.map +1 -0
- package/dist/kit/Combobox.d.ts +26 -0
- package/dist/kit/Combobox.js +190 -0
- package/dist/kit/Combobox.js.map +1 -0
- package/dist/kit/DateField.d.ts +17 -0
- package/dist/kit/DateField.js +133 -0
- package/dist/kit/DateField.js.map +1 -0
- package/dist/kit/Field.d.ts +40 -0
- package/dist/kit/Field.js +98 -0
- package/dist/kit/Field.js.map +1 -0
- package/dist/kit/FileField.d.ts +113 -0
- package/dist/kit/FileField.js +341 -0
- package/dist/kit/FileField.js.map +1 -0
- package/dist/kit/FileMark.d.ts +15 -0
- package/dist/kit/FileMark.js +39 -0
- package/dist/kit/FileMark.js.map +1 -0
- package/dist/kit/Inputs.d.ts +59 -0
- package/dist/kit/Inputs.js +205 -0
- package/dist/kit/Inputs.js.map +1 -0
- package/dist/kit/List.d.ts +47 -0
- package/dist/kit/List.js +85 -0
- package/dist/kit/List.js.map +1 -0
- package/dist/kit/Mark.d.ts +30 -0
- package/dist/kit/Mark.js +27 -0
- package/dist/kit/Mark.js.map +1 -0
- package/dist/kit/MarkStack.d.ts +15 -0
- package/dist/kit/MarkStack.js +26 -0
- package/dist/kit/MarkStack.js.map +1 -0
- package/dist/kit/Note.d.ts +11 -0
- package/dist/kit/Note.js +31 -0
- package/dist/kit/Note.js.map +1 -0
- package/dist/kit/Popover.js +90 -0
- package/dist/kit/Popover.js.map +1 -0
- package/dist/kit/RangeField.d.ts +14 -0
- package/dist/kit/RangeField.js +47 -0
- package/dist/kit/RangeField.js.map +1 -0
- package/dist/kit/RatingField.d.ts +14 -0
- package/dist/kit/RatingField.js +50 -0
- package/dist/kit/RatingField.js.map +1 -0
- package/dist/kit/Stat.d.ts +26 -0
- package/dist/kit/Stat.js +46 -0
- package/dist/kit/Stat.js.map +1 -0
- package/dist/kit/Switch.d.ts +14 -0
- package/dist/kit/Switch.js +21 -0
- package/dist/kit/Switch.js.map +1 -0
- package/dist/kit/Tag.d.ts +16 -0
- package/dist/kit/Tag.js +20 -0
- package/dist/kit/Tag.js.map +1 -0
- package/dist/kit/Tile.d.ts +34 -0
- package/dist/kit/Tile.js +52 -0
- package/dist/kit/Tile.js.map +1 -0
- package/dist/kit/TimeField.d.ts +31 -0
- package/dist/kit/TimeField.js +109 -0
- package/dist/kit/TimeField.js.map +1 -0
- package/dist/kit/context.d.ts +22 -0
- package/dist/kit/context.js +46 -0
- package/dist/kit/context.js.map +1 -0
- package/dist/kit/dates.d.ts +14 -0
- package/dist/kit/dates.js +129 -0
- package/dist/kit/dates.js.map +1 -0
- package/dist/kit/messages.d.ts +99 -0
- package/dist/kit/messages.js +66 -0
- package/dist/kit/messages.js.map +1 -0
- package/dist/kit/numbers.d.ts +12 -0
- package/dist/kit/numbers.js +40 -0
- package/dist/kit/numbers.js.map +1 -0
- package/dist/kit/options.d.ts +10 -0
- package/dist/kit/options.js +23 -0
- package/dist/kit/options.js.map +1 -0
- package/dist/kit/uploads.d.ts +42 -0
- package/dist/kit/uploads.js +165 -0
- package/dist/kit/uploads.js.map +1 -0
- package/dist/kit/waveform.js +76 -0
- package/dist/kit/waveform.js.map +1 -0
- package/dist/locale.d.ts +1 -0
- package/dist/locale.js +1 -0
- package/dist/markdown.js +84 -0
- package/dist/markdown.js.map +1 -0
- package/dist/marks.js +217 -0
- package/dist/marks.js.map +1 -0
- package/dist/reveal.js +48 -0
- package/dist/reveal.js.map +1 -0
- package/dist/stepGlyphs.js +62 -0
- package/dist/stepGlyphs.js.map +1 -0
- package/dist/surface/Form.js +264 -0
- package/dist/surface/Form.js.map +1 -0
- package/dist/surface/Markdown.js +42 -0
- package/dist/surface/Markdown.js.map +1 -0
- package/dist/surface/Surface.d.ts +31 -17
- package/dist/surface/Surface.js +480 -57
- package/dist/surface/Surface.js.map +1 -0
- package/dist/surface/scope.d.ts +32 -0
- package/dist/surface/scope.js +23 -0
- package/dist/surface/scope.js.map +1 -0
- package/dist/surface/values.d.ts +44 -0
- package/dist/surface/values.js +237 -0
- package/dist/surface/values.js.map +1 -0
- package/dist/tint.d.ts +10 -0
- package/dist/tint.js +19 -0
- package/dist/tint.js.map +1 -0
- package/dist/types.d.ts +534 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/useAgentFace.d.ts +18 -0
- package/dist/useAgentFace.js +45 -0
- package/dist/useAgentFace.js.map +1 -0
- package/dist/useCall.d.ts +39 -0
- package/dist/useCall.js +273 -0
- package/dist/useCall.js.map +1 -0
- package/dist/useConversation.d.ts +77 -0
- package/dist/useConversation.js +523 -0
- package/dist/useConversation.js.map +1 -0
- package/dist/useDictation.d.ts +17 -0
- package/dist/useDictation.js +68 -0
- package/dist/useDictation.js.map +1 -0
- package/dist/useLive.d.ts +26 -0
- package/dist/useLive.js +88 -0
- package/dist/useLive.js.map +1 -0
- package/dist/usePolled.js +68 -0
- package/dist/usePolled.js.map +1 -0
- package/dist/voice/Orb.d.ts +10 -9
- package/dist/voice/Orb.js +43 -39
- package/dist/voice/Orb.js.map +1 -0
- package/dist/voice/StillOrb.js +33 -0
- package/dist/voice/StillOrb.js.map +1 -0
- package/dist/voice/WebGLOrb.js +98 -0
- package/dist/voice/WebGLOrb.js.map +1 -0
- package/dist/voice/fluidDots.js +161 -0
- package/dist/voice/fluidDots.js.map +1 -0
- package/dist/voice/motion.js +84 -0
- package/dist/voice/motion.js.map +1 -0
- package/dist/voice/orbs.d.ts +32 -0
- package/dist/voice/orbs.js +16 -0
- package/dist/voice/orbs.js.map +1 -0
- package/dist/voice/useReducedMotion.js +16 -16
- package/dist/voice/useReducedMotion.js.map +1 -0
- package/dist/voice/wave.js +116 -0
- package/dist/voice/wave.js.map +1 -0
- package/dist/voice/webgl.js +177 -0
- package/dist/voice/webgl.js.map +1 -0
- package/dist/widget.js +284 -8
- package/package.json +49 -39
- package/src/AgentAbout.tsx +1621 -0
- package/src/AgentCard.tsx +123 -0
- package/src/AgentChat.tsx +1795 -0
- package/src/AgentSpace.tsx +540 -0
- package/src/AgentTasks.tsx +163 -0
- package/src/BrowserView.tsx +442 -0
- package/src/FileView.tsx +620 -0
- package/src/Modes.tsx +112 -0
- package/src/VoiceCall.tsx +411 -0
- package/src/about.ts +355 -0
- package/src/agentIcons.ts +56 -0
- package/src/automation/Automation.tsx +308 -0
- package/src/automation/RunView.tsx +213 -0
- package/src/automation/cron.ts +196 -0
- package/src/automation/marks.tsx +144 -0
- package/src/automation/messages.ts +231 -0
- package/src/automation/record.ts +206 -0
- package/src/automation/types.ts +146 -0
- package/src/automation/when.ts +195 -0
- package/src/blocks.ts +249 -0
- package/src/browser.ts +334 -0
- package/src/call.ts +300 -0
- package/src/channelParts.ts +17 -0
- package/src/classes.ts +10 -0
- package/src/client.ts +397 -0
- package/src/conversationFiles.ts +54 -0
- package/src/credentials.ts +158 -0
- package/src/dev.ts +20 -0
- package/src/es.ts +423 -0
- package/src/files.ts +238 -0
- package/src/frames.ts +291 -0
- package/src/icons.tsx +49 -0
- package/src/index.ts +270 -0
- package/src/kit/AudioPlayer.tsx +129 -0
- package/src/kit/Button.tsx +97 -0
- package/src/kit/Card.tsx +47 -0
- package/src/kit/Chart.tsx +129 -0
- package/src/kit/Choices.tsx +131 -0
- package/src/kit/Combobox.tsx +247 -0
- package/src/kit/DateField.tsx +156 -0
- package/src/kit/Field.tsx +137 -0
- package/src/kit/FileField.tsx +492 -0
- package/src/kit/FileMark.tsx +56 -0
- package/src/kit/Inputs.tsx +250 -0
- package/src/kit/List.tsx +135 -0
- package/src/kit/Mark.tsx +64 -0
- package/src/kit/MarkStack.tsx +29 -0
- package/src/kit/Note.tsx +42 -0
- package/src/kit/Popover.tsx +121 -0
- package/src/kit/RangeField.tsx +53 -0
- package/src/kit/RatingField.tsx +62 -0
- package/src/kit/Stat.tsx +60 -0
- package/src/kit/Switch.tsx +28 -0
- package/src/kit/Tag.tsx +32 -0
- package/src/kit/Tile.tsx +74 -0
- package/src/kit/TimeField.tsx +157 -0
- package/src/kit/context.tsx +246 -0
- package/src/kit/dates.ts +150 -0
- package/src/kit/messages.ts +160 -0
- package/src/kit/numbers.ts +44 -0
- package/src/kit/options.ts +30 -0
- package/src/kit/uploads.ts +244 -0
- package/src/kit/waveform.ts +84 -0
- package/src/locale.ts +6 -0
- package/src/markdown.ts +69 -0
- package/src/marks.tsx +328 -0
- package/src/reveal.ts +52 -0
- package/src/stepGlyphs.ts +83 -0
- package/src/styles.css +6961 -0
- package/src/surface/Form.tsx +299 -0
- package/src/surface/Markdown.tsx +55 -0
- package/src/surface/Surface.tsx +605 -0
- package/src/surface/scope.ts +82 -0
- package/src/surface/values.ts +361 -0
- package/src/tint.ts +14 -0
- package/src/types.ts +596 -0
- package/src/useAgentFace.ts +47 -0
- package/src/useCall.ts +292 -0
- package/src/useConversation.ts +627 -0
- package/src/useDictation.ts +83 -0
- package/src/useLive.ts +115 -0
- package/src/usePolled.ts +60 -0
- package/src/voice/Orb.tsx +45 -0
- package/src/voice/StillOrb.tsx +29 -0
- package/src/voice/WebGLOrb.tsx +98 -0
- package/src/voice/fluidDots.tsx +171 -0
- package/src/voice/motion.ts +112 -0
- package/src/voice/orbs.ts +39 -0
- package/src/voice/useReducedMotion.ts +24 -0
- package/src/voice/wave.tsx +129 -0
- package/src/voice/webgl.ts +209 -0
- package/src/widget/css.d.ts +5 -0
- package/src/widget/element.tsx +535 -0
- package/src/widget/index.ts +10 -0
- package/src/widget/mount.ts +27 -0
- package/src/widget/widget.css +253 -0
- package/dist/SignalcoreProvider.d.ts +0 -113
- package/dist/SignalcoreProvider.js +0 -84
- package/dist/automations/AppMarks.d.ts +0 -11
- package/dist/automations/AppMarks.js +0 -18
- package/dist/automations/AutomationCard.d.ts +0 -27
- package/dist/automations/AutomationCard.js +0 -53
- package/dist/automations/AutomationsWindow.d.ts +0 -38
- package/dist/automations/AutomationsWindow.js +0 -57
- package/dist/automations/Card.d.ts +0 -46
- package/dist/automations/Card.js +0 -45
- package/dist/automations/ScheduleMarks.d.ts +0 -13
- package/dist/automations/ScheduleMarks.js +0 -24
- package/dist/automations/presentationIcons.d.ts +0 -7
- package/dist/automations/presentationIcons.js +0 -67
- package/dist/automations/schedule.d.ts +0 -25
- package/dist/automations/schedule.js +0 -59
- package/dist/automations/time.d.ts +0 -3
- package/dist/automations/time.js +0 -25
- package/dist/browser/BrowserView.d.ts +0 -43
- package/dist/browser/BrowserView.js +0 -94
- package/dist/browser/room.d.ts +0 -21
- package/dist/browser/room.js +0 -33
- package/dist/browser/useBrowserSession.d.ts +0 -17
- package/dist/browser/useBrowserSession.js +0 -67
- package/dist/builder/BuilderChat.d.ts +0 -32
- package/dist/builder/BuilderChat.js +0 -41
- package/dist/builder/BuilderTranscript.d.ts +0 -49
- package/dist/builder/BuilderTranscript.js +0 -62
- package/dist/builder/StatusLine.d.ts +0 -8
- package/dist/builder/StatusLine.js +0 -17
- package/dist/builder/answer.d.ts +0 -7
- package/dist/builder/answer.js +0 -8
- package/dist/builder/blocks.d.ts +0 -31
- package/dist/builder/blocks.js +0 -74
- package/dist/builder/items.d.ts +0 -15
- package/dist/builder/items.js +0 -21
- package/dist/builder/steps.d.ts +0 -20
- package/dist/builder/steps.js +0 -120
- package/dist/builder/time.d.ts +0 -4
- package/dist/builder/time.js +0 -24
- package/dist/builder/useBuildSession.d.ts +0 -36
- package/dist/builder/useBuildSession.js +0 -130
- package/dist/builder/workingOn.d.ts +0 -7
- package/dist/builder/workingOn.js +0 -15
- package/dist/chat/AgentChat.d.ts +0 -37
- package/dist/chat/AgentChat.js +0 -21
- package/dist/chat/ChatView.d.ts +0 -25
- package/dist/chat/ChatView.js +0 -34
- package/dist/chat/Composer.d.ts +0 -20
- package/dist/chat/Composer.js +0 -22
- package/dist/chat/MessageRow.d.ts +0 -22
- package/dist/chat/MessageRow.js +0 -32
- package/dist/chat/arrival.d.ts +0 -15
- package/dist/chat/arrival.js +0 -25
- package/dist/chat/history.d.ts +0 -24
- package/dist/chat/history.js +0 -45
- package/dist/chat/moments.d.ts +0 -25
- package/dist/chat/moments.js +0 -72
- package/dist/chat/types.d.ts +0 -12
- package/dist/chat/types.js +0 -1
- package/dist/chat/useComposer.d.ts +0 -46
- package/dist/chat/useComposer.js +0 -62
- package/dist/chat/useConversation.d.ts +0 -35
- package/dist/chat/useConversation.js +0 -71
- package/dist/chat/useStickToBottom.d.ts +0 -9
- package/dist/chat/useStickToBottom.js +0 -33
- package/dist/chat/useTurns.d.ts +0 -49
- package/dist/chat/useTurns.js +0 -111
- package/dist/classes.d.ts +0 -2
- package/dist/development.d.ts +0 -5
- package/dist/development.js +0 -8
- package/dist/flow/FlowWindow.d.ts +0 -42
- package/dist/flow/FlowWindow.js +0 -126
- package/dist/flow/index.d.ts +0 -16
- package/dist/flow/index.js +0 -16
- package/dist/flow/kinds.d.ts +0 -23
- package/dist/flow/kinds.js +0 -48
- package/dist/flow/map.d.ts +0 -44
- package/dist/flow/map.js +0 -225
- package/dist/flow/nodePaths.d.ts +0 -7
- package/dist/flow/nodePaths.js +0 -17
- package/dist/flow/relations.d.ts +0 -42
- package/dist/flow/relations.js +0 -174
- package/dist/host.d.ts +0 -124
- package/dist/host.js +0 -1
- package/dist/live/LiveView.d.ts +0 -28
- package/dist/live/LiveView.js +0 -55
- package/dist/live/capture.d.ts +0 -20
- package/dist/live/capture.js +0 -100
- package/dist/live/follow.d.ts +0 -26
- package/dist/live/follow.js +0 -72
- package/dist/live/paint.d.ts +0 -13
- package/dist/live/paint.js +0 -77
- package/dist/live/useLiveStream.d.ts +0 -16
- package/dist/live/useLiveStream.js +0 -57
- package/dist/look.d.ts +0 -33
- package/dist/look.js +0 -241
- package/dist/messages/en.d.ts +0 -3
- package/dist/messages/en.js +0 -251
- package/dist/messages/es.d.ts +0 -3
- package/dist/messages/es.js +0 -251
- package/dist/messages/index.d.ts +0 -16
- package/dist/messages/index.js +0 -33
- package/dist/messages/types.d.ts +0 -246
- package/dist/messages/types.js +0 -1
- package/dist/parts/Button.d.ts +0 -18
- package/dist/parts/Button.js +0 -17
- package/dist/parts/Icon.d.ts +0 -39
- package/dist/parts/Icon.js +0 -37
- package/dist/parts/Input.d.ts +0 -6
- package/dist/parts/Input.js +0 -11
- package/dist/parts/Spinner.d.ts +0 -2
- package/dist/parts/Spinner.js +0 -7
- package/dist/patterns.d.ts +0 -15
- package/dist/patterns.js +0 -5
- package/dist/presets.d.ts +0 -82
- package/dist/presets.js +0 -81
- package/dist/primitives.d.ts +0 -22
- package/dist/primitives.js +0 -58
- package/dist/request/RequestCard.d.ts +0 -34
- package/dist/request/RequestCard.js +0 -101
- package/dist/request/approval/ApprovalPreview.d.ts +0 -5
- package/dist/request/approval/ApprovalPreview.js +0 -27
- package/dist/request/approval/shapes.d.ts +0 -32
- package/dist/request/approval/shapes.js +0 -68
- package/dist/request/apps.d.ts +0 -11
- package/dist/request/apps.js +0 -27
- package/dist/request/cards.d.ts +0 -12
- package/dist/request/cards.js +0 -24
- package/dist/request/deliver.d.ts +0 -12
- package/dist/request/deliver.js +0 -21
- package/dist/request/handOver.d.ts +0 -18
- package/dist/request/handOver.js +0 -33
- package/dist/request/kinds/Approval.d.ts +0 -3
- package/dist/request/kinds/Approval.js +0 -9
- package/dist/request/kinds/Choice.d.ts +0 -3
- package/dist/request/kinds/Choice.js +0 -8
- package/dist/request/kinds/Connect.d.ts +0 -9
- package/dist/request/kinds/Connect.js +0 -119
- package/dist/request/kinds/FreeText.d.ts +0 -3
- package/dist/request/kinds/FreeText.js +0 -20
- package/dist/request/kinds/HandOver.d.ts +0 -13
- package/dist/request/kinds/HandOver.js +0 -20
- package/dist/request/kinds/Secret.d.ts +0 -7
- package/dist/request/kinds/Secret.js +0 -49
- package/dist/request/kinds/Upload.d.ts +0 -6
- package/dist/request/kinds/Upload.js +0 -47
- package/dist/request/types.d.ts +0 -83
- package/dist/request/types.js +0 -1
- package/dist/safeUrl.d.ts +0 -6
- package/dist/safeUrl.js +0 -8
- package/dist/stream/builder.d.ts +0 -176
- package/dist/stream/builder.js +0 -202
- package/dist/stream/reduce.d.ts +0 -51
- package/dist/stream/reduce.js +0 -58
- package/dist/stream/untilAborted.d.ts +0 -7
- package/dist/stream/untilAborted.js +0 -32
- package/dist/stream/useRunStream.d.ts +0 -26
- package/dist/stream/useRunStream.js +0 -137
- package/dist/styles.css +0 -2318
- package/dist/surface/HostNode.d.ts +0 -14
- package/dist/surface/HostNode.js +0 -30
- package/dist/surface/Node.d.ts +0 -7
- package/dist/surface/Node.js +0 -49
- package/dist/surface/SurfaceBoundary.d.ts +0 -26
- package/dist/surface/SurfaceBoundary.js +0 -20
- package/dist/surface/bindings.d.ts +0 -14
- package/dist/surface/bindings.js +0 -37
- package/dist/surface/check.d.ts +0 -27
- package/dist/surface/check.js +0 -102
- package/dist/surface/format.d.ts +0 -10
- package/dist/surface/format.js +0 -32
- package/dist/surface/hosts.d.ts +0 -6
- package/dist/surface/hosts.js +0 -11
- package/dist/surface/scene.d.ts +0 -21
- package/dist/surface/scene.js +0 -8
- package/dist/surface/templates/Browser.d.ts +0 -6
- package/dist/surface/templates/Browser.js +0 -11
- package/dist/surface/templates/Chart.d.ts +0 -6
- package/dist/surface/templates/Chart.js +0 -13
- package/dist/surface/templates/Choices.d.ts +0 -3
- package/dist/surface/templates/Choices.js +0 -12
- package/dist/surface/templates/Form.d.ts +0 -3
- package/dist/surface/templates/Form.js +0 -44
- package/dist/surface/templates/KeyValue.d.ts +0 -3
- package/dist/surface/templates/KeyValue.js +0 -7
- package/dist/surface/templates/Layout.d.ts +0 -5
- package/dist/surface/templates/Layout.js +0 -16
- package/dist/surface/templates/Live.d.ts +0 -6
- package/dist/surface/templates/Live.js +0 -9
- package/dist/surface/templates/Media.d.ts +0 -5
- package/dist/surface/templates/Media.js +0 -13
- package/dist/surface/templates/Slots.d.ts +0 -3
- package/dist/surface/templates/Slots.js +0 -19
- package/dist/surface/templates/Table.d.ts +0 -3
- package/dist/surface/templates/Table.js +0 -12
- package/dist/surface/templates/Text.d.ts +0 -4
- package/dist/surface/templates/Text.js +0 -15
- package/dist/surface/templates/index.d.ts +0 -7
- package/dist/surface/templates/index.js +0 -32
- package/dist/surface/types.d.ts +0 -68
- package/dist/surface/types.js +0 -6
- package/dist/theme.d.ts +0 -62
- package/dist/theme.js +0 -9
- package/dist/useTokens.d.ts +0 -7
- package/dist/useTokens.js +0 -41
- package/dist/voice/VoiceWindow.d.ts +0 -18
- package/dist/voice/VoiceWindow.js +0 -35
- package/dist/voice/index.d.ts +0 -13
- package/dist/voice/index.js +0 -12
- package/dist/voice/meter.d.ts +0 -16
- package/dist/voice/meter.js +0 -52
- package/dist/voice/orbColors.d.ts +0 -16
- package/dist/voice/orbColors.js +0 -75
- package/dist/voice/pushable.d.ts +0 -16
- package/dist/voice/pushable.js +0 -56
- package/dist/voice/useDictation.d.ts +0 -24
- package/dist/voice/useDictation.js +0 -60
- package/dist/voice/useReducedMotion.d.ts +0 -5
- package/dist/voice/useVoice.d.ts +0 -70
- package/dist/voice/useVoice.js +0 -197
- package/dist/voice/useVoicePrimitives.d.ts +0 -7
- package/dist/voice/useVoicePrimitives.js +0 -11
- package/dist/voice/voice.d.ts +0 -55
- package/dist/voice/voice.js +0 -9
- package/dist/voice/webSpeech.d.ts +0 -33
- package/dist/voice/webSpeech.js +0 -258
- package/dist/widget.js.map +0 -1
- package/dist/windows/AgentSpace.d.ts +0 -78
- package/dist/windows/AgentSpace.js +0 -135
- package/dist/windows/Captions.d.ts +0 -13
- package/dist/windows/Captions.js +0 -22
- package/dist/windows/Dock.d.ts +0 -37
- package/dist/windows/Dock.js +0 -22
- package/dist/windows/Journal.d.ts +0 -15
- package/dist/windows/Journal.js +0 -19
- package/dist/windows/KindMark.d.ts +0 -7
- package/dist/windows/KindMark.js +0 -31
- package/dist/windows/Pending.d.ts +0 -8
- package/dist/windows/Pending.js +0 -17
- package/dist/windows/Stage.d.ts +0 -18
- package/dist/windows/Stage.js +0 -21
- package/dist/windows/StatusLabel.d.ts +0 -9
- package/dist/windows/StatusLabel.js +0 -7
- package/dist/windows/Strip.d.ts +0 -17
- package/dist/windows/Strip.js +0 -42
- package/dist/windows/SurfaceWindow.d.ts +0 -20
- package/dist/windows/SurfaceWindow.js +0 -12
- package/dist/windows/WindowFrame.d.ts +0 -23
- package/dist/windows/WindowFrame.js +0 -22
- package/dist/windows/hearing.d.ts +0 -11
- package/dist/windows/hearing.js +0 -26
- package/dist/windows/kinds.d.ts +0 -47
- package/dist/windows/kinds.js +0 -28
- package/dist/windows/reduce.d.ts +0 -98
- package/dist/windows/reduce.js +0 -151
- package/dist/windows/registry.d.ts +0 -18
- package/dist/windows/registry.js +0 -61
- package/dist/windows/reveal.d.ts +0 -9
- package/dist/windows/reveal.js +0 -6
- package/dist/windows/space.d.ts +0 -21
- package/dist/windows/space.js +0 -6
- package/dist/windows/status.d.ts +0 -11
- package/dist/windows/status.js +0 -30
- package/dist/windows/types.d.ts +0 -15
- package/dist/windows/types.js +0 -1
- package/dist/windows/useLoaded.d.ts +0 -44
- package/dist/windows/useLoaded.js +0 -58
- package/dist/windows/useUnread.d.ts +0 -7
- package/dist/windows/useUnread.js +0 -21
- package/dist/windows/useWindows.d.ts +0 -70
- package/dist/windows/useWindows.js +0 -60
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
import { useEffect, useReducer, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { createScreen, type Screen } from "./browser";
|
|
4
|
+
import type { Client } from "./client";
|
|
5
|
+
import { note } from "./dev";
|
|
6
|
+
import { sayOf, toolResultOf, type Frame, type ToolResult } from "./frames";
|
|
7
|
+
import type {
|
|
8
|
+
Action,
|
|
9
|
+
BrowserControl,
|
|
10
|
+
BrowserFrame,
|
|
11
|
+
BrowserInput,
|
|
12
|
+
BrowserState,
|
|
13
|
+
Handover,
|
|
14
|
+
Holder,
|
|
15
|
+
Message,
|
|
16
|
+
Request,
|
|
17
|
+
Step,
|
|
18
|
+
ToolCall,
|
|
19
|
+
} from "./types";
|
|
20
|
+
import { useLive } from "./useLive";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Where a conversation stands: its stored messages, the turn (whether a reply is on its way, what
|
|
24
|
+
* of it has come so far, and what it waits on), and what its history read has said.
|
|
25
|
+
*/
|
|
26
|
+
export interface ConversationState {
|
|
27
|
+
messages: Message[];
|
|
28
|
+
pending: boolean;
|
|
29
|
+
draft: string;
|
|
30
|
+
/** The step the turn stopped on (a surface to answer, or an action to allow), until the person acts. */
|
|
31
|
+
awaiting: string | null;
|
|
32
|
+
/** Whether the history has landed once; until then an empty list means nothing. */
|
|
33
|
+
loaded: boolean;
|
|
34
|
+
/** What the last read threw; null once one lands. */
|
|
35
|
+
error: unknown;
|
|
36
|
+
/** The conversation's browser while it is open. */
|
|
37
|
+
browser: BrowserState | null;
|
|
38
|
+
/** Who answers it now; null until the history lands. */
|
|
39
|
+
holder: Holder | null;
|
|
40
|
+
/** Every change of who answers it, in order: read with the history, then heard live. */
|
|
41
|
+
handovers: Handover[];
|
|
42
|
+
/**
|
|
43
|
+
* The host's tools the page runs now, by the call's id: the turn is under way while one runs
|
|
44
|
+
* (its `done` said only that it stopped to wait for them), until its step is done or failed.
|
|
45
|
+
*/
|
|
46
|
+
tools: string[];
|
|
47
|
+
/**
|
|
48
|
+
* The yes or no the person just gave, until the step's own frames say what came of it: what
|
|
49
|
+
* the API refuses as the business's (`business`) is drawn as waiting for the business again.
|
|
50
|
+
*/
|
|
51
|
+
answered: { id: string; request: Request } | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const EMPTY: ConversationState = {
|
|
55
|
+
messages: [],
|
|
56
|
+
pending: false,
|
|
57
|
+
draft: "",
|
|
58
|
+
awaiting: null,
|
|
59
|
+
loaded: false,
|
|
60
|
+
error: null,
|
|
61
|
+
browser: null,
|
|
62
|
+
holder: null,
|
|
63
|
+
handovers: [],
|
|
64
|
+
tools: [],
|
|
65
|
+
answered: null,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* What moves the state: the socket opening afresh, a read landing (with who answers it, and its
|
|
70
|
+
* changes, when the API tells them) or failing, the person acting on a surface, or a frame.
|
|
71
|
+
*/
|
|
72
|
+
export type ConversationAction =
|
|
73
|
+
| { type: "reset" }
|
|
74
|
+
| {
|
|
75
|
+
type: "history";
|
|
76
|
+
messages: Message[];
|
|
77
|
+
pending: boolean;
|
|
78
|
+
holder?: Holder;
|
|
79
|
+
handovers?: Handover[];
|
|
80
|
+
}
|
|
81
|
+
| { type: "failed"; error: unknown }
|
|
82
|
+
| { type: "acted"; action: Action }
|
|
83
|
+
| Frame;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Errors told only to the socket that sent something (the agent still replying, a frame it did
|
|
87
|
+
* not understand, a turn waiting on a surface, files it can't carry, what only the channel or the
|
|
88
|
+
* business answers, a tool's answer no call waits on: nothing was stored): the turn, if there is
|
|
89
|
+
* one, goes on. Any other error ends it.
|
|
90
|
+
*/
|
|
91
|
+
const ASIDE: ReadonlySet<string> = new Set([
|
|
92
|
+
"busy",
|
|
93
|
+
"unknown",
|
|
94
|
+
"pending",
|
|
95
|
+
"files",
|
|
96
|
+
"channel",
|
|
97
|
+
"business",
|
|
98
|
+
"tool",
|
|
99
|
+
]);
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Told when the page answered a host's tool no call waits on any more (answered already, from
|
|
103
|
+
* another tab or before a reload; or late): nothing for the person to hear.
|
|
104
|
+
*/
|
|
105
|
+
const STALE = "tool";
|
|
106
|
+
|
|
107
|
+
/** Whether a step's state is its last: done, or failed. */
|
|
108
|
+
const settled = (step: Step | undefined): boolean =>
|
|
109
|
+
step?.state === "done" || step?.state === "failed";
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The turn, one step at a time, from what the socket says alone, so a page opened mid-turn (a
|
|
113
|
+
* reload, another tab) reads it as the one that sent. The person's message opens it (their words,
|
|
114
|
+
* or their answer on a surface); on a channel, where the reply comes on its own time, its first
|
|
115
|
+
* words or step do. `done`, `stopped` or an error closes it, and either way the
|
|
116
|
+
* draft goes: the reply now lives in the messages, and after an error there is none (on a
|
|
117
|
+
* refusal the partial text was never one). A reply that calls actions is stored before they run,
|
|
118
|
+
* so what `step`, `ui` and `request` frames say lands on its steps: the message is the one place
|
|
119
|
+
* a step is drawn from, live or read back. The socket opening afresh empties the draft too, since
|
|
120
|
+
* the turn so far is then told again. Who answers the conversation is the read's, then each
|
|
121
|
+
* `holder` frame's: its change kept once beside those read, in order, and who answers taken from
|
|
122
|
+
* it only when it is the newest; a `decision` lands on its message (null clears it). A host's
|
|
123
|
+
* tool the page runs (`tool`) is its step working, and a turn under way until its step is done
|
|
124
|
+
* or failed, whatever `done` said meanwhile. A yes the business gives (`decides: "business"`)
|
|
125
|
+
* waits on its step without stopping the turn or holding the person; one the person gave and the
|
|
126
|
+
* API refused as the business's (`business`) waits for the business again.
|
|
127
|
+
*/
|
|
128
|
+
export function reduce(state: ConversationState, action: ConversationAction): ConversationState {
|
|
129
|
+
switch (action.type) {
|
|
130
|
+
case "reset":
|
|
131
|
+
// The socket that opens is told the browser again, if there is one, and the tools awaited.
|
|
132
|
+
return {
|
|
133
|
+
...state,
|
|
134
|
+
pending: false,
|
|
135
|
+
draft: "",
|
|
136
|
+
awaiting: null,
|
|
137
|
+
browser: null,
|
|
138
|
+
tools: [],
|
|
139
|
+
answered: null,
|
|
140
|
+
};
|
|
141
|
+
case "history": {
|
|
142
|
+
// A change heard while the read was on its way is newer than what it says.
|
|
143
|
+
const read = action.handovers ?? [];
|
|
144
|
+
const handovers = withHandovers(read, state.handovers);
|
|
145
|
+
const heard = handovers.length > read.length ? handovers.at(-1)?.holder : undefined;
|
|
146
|
+
return {
|
|
147
|
+
...state,
|
|
148
|
+
messages: withMessages(action.messages, state.messages),
|
|
149
|
+
awaiting: action.pending ? awaited(action.messages) : null,
|
|
150
|
+
loaded: true,
|
|
151
|
+
error: null,
|
|
152
|
+
holder: heard ?? action.holder ?? state.holder,
|
|
153
|
+
handovers,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
case "failed":
|
|
157
|
+
return { ...state, error: action.error };
|
|
158
|
+
case "working":
|
|
159
|
+
// The agent began its reply: told first to a socket that opens while it thinks.
|
|
160
|
+
return { ...state, pending: true };
|
|
161
|
+
case "text":
|
|
162
|
+
return { ...state, pending: true, draft: state.draft + action.delta };
|
|
163
|
+
case "message": {
|
|
164
|
+
const { message } = action;
|
|
165
|
+
const messages = withStored(state.messages, message);
|
|
166
|
+
// On a channel the turn is no one's message's: the person's words wait for the agent's
|
|
167
|
+
// reply on its own time, and the business's own go out beside the turn, never in it.
|
|
168
|
+
if (message.author === "contact" || message.author === "operator") {
|
|
169
|
+
return { ...state, messages };
|
|
170
|
+
}
|
|
171
|
+
if (message.role === "assistant") return { ...state, messages, draft: "" };
|
|
172
|
+
return {
|
|
173
|
+
...state,
|
|
174
|
+
messages: message.action ? answered(messages, message.action) : messages,
|
|
175
|
+
pending: true,
|
|
176
|
+
draft: "",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
case "ui":
|
|
180
|
+
return {
|
|
181
|
+
...state,
|
|
182
|
+
messages: withStep(state.messages, action.id, (step) => ({
|
|
183
|
+
...step,
|
|
184
|
+
surface: action.surface,
|
|
185
|
+
awaits: action.awaits,
|
|
186
|
+
})),
|
|
187
|
+
awaiting: action.awaits ? action.id : state.awaiting,
|
|
188
|
+
};
|
|
189
|
+
case "step": {
|
|
190
|
+
// A step that waits holds the turn until the person answers, as the history reads it; one
|
|
191
|
+
// that runs says a turn is under way (on a channel, nobody's message told so before).
|
|
192
|
+
const waits = action.state === "waiting";
|
|
193
|
+
const ended = action.state === "done" || action.state === "failed";
|
|
194
|
+
return {
|
|
195
|
+
...state,
|
|
196
|
+
pending: state.pending || action.state === "running",
|
|
197
|
+
messages: withStep(state.messages, action.id, (step) => ({
|
|
198
|
+
...step,
|
|
199
|
+
state: action.state,
|
|
200
|
+
output: action.output ?? step.output,
|
|
201
|
+
awaits: waits || step.awaits,
|
|
202
|
+
})),
|
|
203
|
+
// One answered elsewhere (another screen, the owner's own Chrome) ends here too.
|
|
204
|
+
awaiting: waits ? action.id : ended && state.awaiting === action.id ? null : state.awaiting,
|
|
205
|
+
tools: ended ? state.tools.filter((id) => id !== action.id) : state.tools,
|
|
206
|
+
answered: state.answered?.id === action.id ? null : state.answered,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
case "tool":
|
|
210
|
+
// Told again once its answer is in (a socket opening as it went): nothing runs anew.
|
|
211
|
+
if (settled(stepOf(state.messages, action.id))) return state;
|
|
212
|
+
// The page runs it now: its step works like any step, until the step's own frames move it,
|
|
213
|
+
// and it is never the person's to answer.
|
|
214
|
+
return {
|
|
215
|
+
...state,
|
|
216
|
+
pending: true,
|
|
217
|
+
awaiting: state.awaiting === action.id ? null : state.awaiting,
|
|
218
|
+
messages: withStep(state.messages, action.id, (step) => ({
|
|
219
|
+
...step,
|
|
220
|
+
state: "running",
|
|
221
|
+
awaits: false,
|
|
222
|
+
})),
|
|
223
|
+
tools: state.tools.includes(action.id) ? state.tools : [...state.tools, action.id],
|
|
224
|
+
};
|
|
225
|
+
case "request": {
|
|
226
|
+
const { id, action: name, input, decides = "person" } = action;
|
|
227
|
+
// The business's yes: the turn went on, and nothing waits on the person.
|
|
228
|
+
const theirs = decides === "person";
|
|
229
|
+
return {
|
|
230
|
+
...state,
|
|
231
|
+
awaiting: theirs ? id : state.awaiting,
|
|
232
|
+
messages: withStep(state.messages, id, (step) => ({
|
|
233
|
+
...step,
|
|
234
|
+
state: "waiting",
|
|
235
|
+
awaits: theirs,
|
|
236
|
+
request: { action: name, input, decides },
|
|
237
|
+
})),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
case "acted": {
|
|
241
|
+
const { surface } = action.action;
|
|
242
|
+
const request = stepOf(state.messages, surface)?.request ?? null;
|
|
243
|
+
return {
|
|
244
|
+
...state,
|
|
245
|
+
awaiting: surface === state.awaiting ? null : state.awaiting,
|
|
246
|
+
// Leave given or refused: the card goes at once; the step's own frames say what came of it.
|
|
247
|
+
messages: withStep(state.messages, surface, (step) => ({ ...step, request: null })),
|
|
248
|
+
answered: request === null ? state.answered : { id: surface, request },
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
case "handoff":
|
|
252
|
+
// Nothing to keep: the reply's `escalate` step says it, live (its `done` follows this
|
|
253
|
+
// frame) and read back alike; who answers now comes in its `holder` frame.
|
|
254
|
+
return state;
|
|
255
|
+
case "holder": {
|
|
256
|
+
const handovers = withHandovers(state.handovers, [action.handover]);
|
|
257
|
+
// One older than a change known says nothing of who answers now.
|
|
258
|
+
const newest = handovers.at(-1) === action.handover;
|
|
259
|
+
return { ...state, holder: newest ? action.handled_by : state.holder, handovers };
|
|
260
|
+
}
|
|
261
|
+
case "decision":
|
|
262
|
+
return {
|
|
263
|
+
...state,
|
|
264
|
+
messages: withMessage(state.messages, action.message_id, (message) => ({
|
|
265
|
+
...message,
|
|
266
|
+
decision: action.decision,
|
|
267
|
+
})),
|
|
268
|
+
};
|
|
269
|
+
case "done":
|
|
270
|
+
// The turn ended, or stopped to wait: on the host's tools the page still runs, it goes on.
|
|
271
|
+
return { ...state, pending: state.tools.length > 0, draft: "" };
|
|
272
|
+
case "stopped":
|
|
273
|
+
return { ...state, pending: false, draft: "", tools: [] };
|
|
274
|
+
case "error":
|
|
275
|
+
if (action.code === "business" && state.answered !== null) {
|
|
276
|
+
// The person's yes or no on what the business decides: it waits for the business again.
|
|
277
|
+
const { id, request } = state.answered;
|
|
278
|
+
return {
|
|
279
|
+
...state,
|
|
280
|
+
answered: null,
|
|
281
|
+
messages: withStep(state.messages, id, (step) => ({
|
|
282
|
+
...step,
|
|
283
|
+
awaits: false,
|
|
284
|
+
request: { ...request, decides: "business" },
|
|
285
|
+
})),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return ASIDE.has(action.code)
|
|
289
|
+
? state
|
|
290
|
+
: { ...state, pending: false, draft: "", awaiting: null, tools: [], answered: null };
|
|
291
|
+
case "browser":
|
|
292
|
+
if (!action.open) return { ...state, browser: null };
|
|
293
|
+
return {
|
|
294
|
+
...state,
|
|
295
|
+
browser: {
|
|
296
|
+
url: action.url,
|
|
297
|
+
title: action.title,
|
|
298
|
+
where: action.where,
|
|
299
|
+
control: action.control,
|
|
300
|
+
reason: action.reason,
|
|
301
|
+
wait: action.wait,
|
|
302
|
+
width: action.width,
|
|
303
|
+
height: action.height,
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
case "browser.frame":
|
|
307
|
+
// Pictures repaint the screen, never the conversation (`Screen`).
|
|
308
|
+
return state;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* `known` with whatever of `more` it lacks, at the end, by id: a message is kept once however
|
|
314
|
+
* many times it is heard (stored live, then read in the history, or told again on a reconnect).
|
|
315
|
+
*/
|
|
316
|
+
function withMessages(known: Message[], more: Message[]): Message[] {
|
|
317
|
+
const ids = new Set(known.map((message) => message.id));
|
|
318
|
+
const missing = more.filter((message) => !ids.has(message.id));
|
|
319
|
+
return missing.length === 0 ? known : [...known, ...missing];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** What going out on a channel changes of a message once it is stored, as it goes. */
|
|
323
|
+
const OUTGOING = ["delivery", "delivery_error", "pieces", "sent_parts", "voice"] as const;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* `known` with a message stored: one it lacks joins at the end; one it holds takes what going out
|
|
327
|
+
* on its channel changed since (where it got to, its parts, its voice note) and keeps the rest as
|
|
328
|
+
* this page has it (its steps, moved by their own frames); untouched when nothing changed.
|
|
329
|
+
*/
|
|
330
|
+
function withStored(known: Message[], stored: Message): Message[] {
|
|
331
|
+
const held = known.find((message) => message.id === stored.id);
|
|
332
|
+
if (held === undefined) return [...known, stored];
|
|
333
|
+
if (OUTGOING.every((field) => isEqual(held[field], stored[field]))) return known;
|
|
334
|
+
const outgoing = Object.fromEntries(OUTGOING.map((field) => [field, stored[field]]));
|
|
335
|
+
return known.map((message) => (message === held ? { ...held, ...outgoing } : message));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** The same value, told again: equal by what it holds. */
|
|
339
|
+
const isEqual = (one: unknown, other: unknown): boolean =>
|
|
340
|
+
JSON.stringify(one ?? null) === JSON.stringify(other ?? null);
|
|
341
|
+
|
|
342
|
+
/** A change of who answers, as one however it was told: its moment, and to whom. */
|
|
343
|
+
const handoverKey = ({ at, holder }: Handover): string => `${Date.parse(at)} ${holder}`;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* `known` with whatever of `more` it lacks, in the order they were made: a change is kept once
|
|
347
|
+
* however often, and by whatever, it is told (the read, a frame, the host's own request).
|
|
348
|
+
*/
|
|
349
|
+
function withHandovers(known: Handover[], more: Handover[]): Handover[] {
|
|
350
|
+
const keys = new Set(known.map(handoverKey));
|
|
351
|
+
const missing = more.filter((handover) => !keys.has(handoverKey(handover)));
|
|
352
|
+
if (missing.length === 0) return known;
|
|
353
|
+
return [...known, ...missing].sort((one, other) => Date.parse(one.at) - Date.parse(other.at));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** The messages with message `id` changed; untouched when none is it. */
|
|
357
|
+
function withMessage(
|
|
358
|
+
messages: Message[],
|
|
359
|
+
id: string,
|
|
360
|
+
change: (message: Message) => Message,
|
|
361
|
+
): Message[] {
|
|
362
|
+
const at = messages.findIndex((message) => message.id === id);
|
|
363
|
+
const message = messages[at];
|
|
364
|
+
return message ? messages.with(at, change(message)) : messages;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Step `id`, wherever it is; none when no message holds it. */
|
|
368
|
+
function stepOf(messages: Message[], id: string): Step | undefined {
|
|
369
|
+
return messages.flatMap((message) => message.steps).findLast((step) => step.id === id);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** The messages with step `id` changed, wherever it is; untouched when no message holds it. */
|
|
373
|
+
function withStep(messages: Message[], id: string, change: (step: Step) => Step): Message[] {
|
|
374
|
+
const at = messages.findLastIndex((message) => message.steps.some((step) => step.id === id));
|
|
375
|
+
const message = messages[at];
|
|
376
|
+
if (!message) return messages;
|
|
377
|
+
const steps = message.steps.map((step) => (step.id === id ? change(step) : step));
|
|
378
|
+
return messages.with(at, { ...message, steps });
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** The surface a stopped turn waits on, as the history tells it. */
|
|
382
|
+
function awaited(messages: Message[]): string | null {
|
|
383
|
+
return messages.flatMap((message) => message.steps).find((step) => step.awaits)?.id ?? null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The person's answer, landed on the step that waited for it: a question is done with their
|
|
388
|
+
* words as its output (what the history reads back); an action they allowed or declined was
|
|
389
|
+
* already told its own state.
|
|
390
|
+
*/
|
|
391
|
+
function answered(messages: Message[], action: Action): Message[] {
|
|
392
|
+
return withStep(messages, action.surface, (step) =>
|
|
393
|
+
step.state === "waiting"
|
|
394
|
+
? { ...step, state: "done", output: action.label, awaits: false, request: null }
|
|
395
|
+
: { ...step, awaits: false, request: null },
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** How often the history is read again while something goes out on a channel. */
|
|
400
|
+
const DELIVERY_EVERY = 3_000;
|
|
401
|
+
/** How long a message sent is watched for its receipt before the next read brings it. */
|
|
402
|
+
const RECEIPT_WITHIN = 60_000;
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Whether a message is still on its way to the person on a channel: waiting to go, or gone a
|
|
406
|
+
* moment ago and not yet received. What it gets to moves without a frame, so it is read again.
|
|
407
|
+
*/
|
|
408
|
+
export function onItsWay(message: Message, now: number): boolean {
|
|
409
|
+
if (message.delivery === "queued") return true;
|
|
410
|
+
return message.delivery === "sent" && now - Date.parse(message.created_at) < RECEIPT_WITHIN;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Runs one of the host's own tools in the page, for the agent: what it resolves to goes back as
|
|
415
|
+
* the tool's output, what it rejects with as why it failed (an error's message).
|
|
416
|
+
*/
|
|
417
|
+
export type ToolHandler = (call: ToolCall) => Promise<unknown>;
|
|
418
|
+
|
|
419
|
+
/** What the page answers a tool of the host's when it runs none (no `onTool`), for the agent. */
|
|
420
|
+
export const NO_TOOL = "This page can't do that";
|
|
421
|
+
|
|
422
|
+
const refuse = (): Promise<never> => Promise.reject(new Error(NO_TOOL));
|
|
423
|
+
|
|
424
|
+
/** A conversation, live: its messages, where its turn stands, and the ways to speak. */
|
|
425
|
+
export interface LiveConversation {
|
|
426
|
+
messages: Message[];
|
|
427
|
+
draft: string;
|
|
428
|
+
pending: boolean;
|
|
429
|
+
/**
|
|
430
|
+
* The step the turn waits on: a surface to answer, or an action the person allows (its
|
|
431
|
+
* `request`, `decides: "person"`; `act` on its id with `approve` or `decline`). Nothing else
|
|
432
|
+
* goes until the person acts. A yes the business gives holds nothing.
|
|
433
|
+
*/
|
|
434
|
+
awaiting: string | null;
|
|
435
|
+
open: boolean;
|
|
436
|
+
/** Until the history has landed once. */
|
|
437
|
+
loading: boolean;
|
|
438
|
+
/** What the last history read threw, if it failed. */
|
|
439
|
+
error: unknown;
|
|
440
|
+
/**
|
|
441
|
+
* Says something: words, the ids of files uploaded to the conversation for it, or both; false
|
|
442
|
+
* when it cannot go now: nothing to say, a turn running or waiting, the socket closed.
|
|
443
|
+
*/
|
|
444
|
+
say: (text: string, files?: readonly string[]) => boolean;
|
|
445
|
+
/** What the person did on a surface; false when the socket is closed. */
|
|
446
|
+
act: (action: Action) => boolean;
|
|
447
|
+
/** Stops the reply on its way; false when the socket is closed. */
|
|
448
|
+
stop: () => boolean;
|
|
449
|
+
/** The conversation's browser while it is open: where it is, who holds it. */
|
|
450
|
+
browser: BrowserState | null;
|
|
451
|
+
/** Hears each picture of the browser's screen, the latest at once; returns how to stop. */
|
|
452
|
+
watchScreen: (listener: (frame: BrowserFrame) => void) => () => void;
|
|
453
|
+
/** Takes the browser from the agent, or gives it back; false when the socket is closed. */
|
|
454
|
+
control: (to: BrowserControl) => boolean;
|
|
455
|
+
/** Closes the browser now (it stops being billed); false when the socket is closed. */
|
|
456
|
+
closeBrowser: () => boolean;
|
|
457
|
+
/** What the person does on the browser's screen while they hold it. */
|
|
458
|
+
input: (event: BrowserInput) => boolean;
|
|
459
|
+
/** Who answers it now: its agent, a person of the business, or nobody; null until the history lands. */
|
|
460
|
+
holder: Holder | null;
|
|
461
|
+
/** Every change of who answers it, in order, kept live. */
|
|
462
|
+
handovers: Handover[];
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Conversation `conversationId` as the person sees it: the history, kept live by the socket.
|
|
467
|
+
* Each time the socket opens the history is read, with the socket already listening, so nothing
|
|
468
|
+
* stored can fall between the two; what came live meanwhile is kept. `onError` hears each
|
|
469
|
+
* error's code (the socket's, or `load` for a history that could not be read): the host words
|
|
470
|
+
* it, this hook shows no text; but `tool`, the page's answer to a call no longer waiting (one it
|
|
471
|
+
* answered already, told again), which is let pass (noted in development). `onHolder` hears each
|
|
472
|
+
* change of who answers it, live, for the host's own views of it; `handover` is the last change
|
|
473
|
+
* the host knows of (one it made itself, as its request answered), taken at once, so it shows
|
|
474
|
+
* whether or not the socket tells it.
|
|
475
|
+
* `onStep` hears each step the agent starts, live, by its action's name, for the host's own
|
|
476
|
+
* views of it (the builder's column, opened as the agent asks it).
|
|
477
|
+
* `onTool` runs the host's own tools the agent calls in the page (a `tool` frame), and its answer
|
|
478
|
+
* goes up (`tool_result`); each call runs once, and one told again while it waits (the socket
|
|
479
|
+
* opened anew) is answered again with what it gave. Without `onTool`, each is refused with
|
|
480
|
+
* `NO_TOOL`, so the turn never waits on a page that can't run it. One conversation per mount: key
|
|
481
|
+
* the component on the id.
|
|
482
|
+
*/
|
|
483
|
+
export function useConversation(
|
|
484
|
+
client: Client,
|
|
485
|
+
conversationId: string,
|
|
486
|
+
{
|
|
487
|
+
onError,
|
|
488
|
+
onHolder,
|
|
489
|
+
onStep,
|
|
490
|
+
handover,
|
|
491
|
+
onTool,
|
|
492
|
+
}: {
|
|
493
|
+
onError?: ((code: string) => void) | undefined;
|
|
494
|
+
onHolder?: ((holder: Holder, handover: Handover) => void) | undefined;
|
|
495
|
+
onStep?: ((action: string) => void) | undefined;
|
|
496
|
+
handover?: Handover | null | undefined;
|
|
497
|
+
onTool?: ToolHandler | undefined;
|
|
498
|
+
} = {},
|
|
499
|
+
): LiveConversation {
|
|
500
|
+
const [state, dispatch] = useReducer(reduce, EMPTY);
|
|
501
|
+
// The host's change, taken once by what it is: the same one told again changes nothing.
|
|
502
|
+
const told = handover ?? null;
|
|
503
|
+
const toldKey = told === null ? null : handoverKey(told);
|
|
504
|
+
useEffect(() => {
|
|
505
|
+
if (told !== null) dispatch({ type: "holder", handled_by: told.holder, handover: told });
|
|
506
|
+
}, [toldKey]);
|
|
507
|
+
// The browser's pictures, out of the state: each repaints its screen alone.
|
|
508
|
+
const [screen] = useState<Screen>(createScreen);
|
|
509
|
+
// Reads are numbered: one that lands after a newer one began, or after the conversation went,
|
|
510
|
+
// is dropped on the floor.
|
|
511
|
+
const reads = useRef(0);
|
|
512
|
+
useEffect(
|
|
513
|
+
() => () => {
|
|
514
|
+
reads.current += 1;
|
|
515
|
+
},
|
|
516
|
+
[client, conversationId],
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const read = () => {
|
|
520
|
+
const run = ++reads.current;
|
|
521
|
+
client.conversations.get(conversationId).then(
|
|
522
|
+
({ messages, pending, handled_by, handovers = [] }) => {
|
|
523
|
+
if (run !== reads.current) return;
|
|
524
|
+
dispatch({ type: "history", messages, pending, holder: handled_by, handovers });
|
|
525
|
+
},
|
|
526
|
+
(error: unknown) => {
|
|
527
|
+
if (run !== reads.current) return;
|
|
528
|
+
dispatch({ type: "failed", error });
|
|
529
|
+
onError?.("load");
|
|
530
|
+
},
|
|
531
|
+
);
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
// The host's tools the agent called, by the call's id: running (null), or what each answered.
|
|
535
|
+
const tools = useRef(new Map<string, ToolResult | null>());
|
|
536
|
+
const runTool = ({ id, name, input }: ToolCall) => {
|
|
537
|
+
const known = tools.current.get(id);
|
|
538
|
+
if (known !== undefined) {
|
|
539
|
+
if (known !== null) live.send(known);
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
tools.current.set(id, null);
|
|
543
|
+
void Promise.resolve({ id, name, input })
|
|
544
|
+
.then(onTool ?? refuse)
|
|
545
|
+
.then(
|
|
546
|
+
(value): PromiseSettledResult<unknown> => ({ status: "fulfilled", value }),
|
|
547
|
+
(reason: unknown): PromiseSettledResult<unknown> => ({ status: "rejected", reason }),
|
|
548
|
+
)
|
|
549
|
+
.then((settled) => {
|
|
550
|
+
const answer = toolResultOf(id, settled);
|
|
551
|
+
tools.current.set(id, answer);
|
|
552
|
+
// A socket closed now hears it when it opens: the call is told again while it waits.
|
|
553
|
+
live.send(answer);
|
|
554
|
+
});
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
const live = useLive(client, conversationId, {
|
|
558
|
+
onFrame: (frame: Frame) => {
|
|
559
|
+
if (frame.type === "browser.frame") {
|
|
560
|
+
screen.show({ jpeg: frame.jpeg, width: frame.width, height: frame.height });
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (frame.type === "error" && frame.code === STALE) {
|
|
564
|
+
// An answer of the page's that no call waits on any more: nothing for the person.
|
|
565
|
+
note("A host's tool answer was let pass:", frame.detail);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (frame.type === "browser" && !frame.open) screen.clear();
|
|
569
|
+
dispatch(frame);
|
|
570
|
+
if (frame.type === "error") onError?.(frame.code);
|
|
571
|
+
if (frame.type === "holder") onHolder?.(frame.handled_by, frame.handover);
|
|
572
|
+
if (frame.type === "step" && frame.state === "running" && frame.action !== undefined) {
|
|
573
|
+
onStep?.(frame.action);
|
|
574
|
+
}
|
|
575
|
+
if (frame.type === "tool") runTool(frame);
|
|
576
|
+
},
|
|
577
|
+
onOpen: () => {
|
|
578
|
+
dispatch({ type: "reset" });
|
|
579
|
+
read();
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// On a channel, while something of the business's is on its way to the person, the history is
|
|
584
|
+
// read again every few seconds: where it got to (sent, delivered, read, failed) comes no other
|
|
585
|
+
// way. Each read is a new state, so the question is asked again after it.
|
|
586
|
+
const travelling = state.messages.some((message) => onItsWay(message, Date.now()));
|
|
587
|
+
useEffect(() => {
|
|
588
|
+
if (!travelling || !live.open) return undefined;
|
|
589
|
+
const again = setInterval(read, DELIVERY_EVERY);
|
|
590
|
+
return () => {
|
|
591
|
+
clearInterval(again);
|
|
592
|
+
};
|
|
593
|
+
// `read` does the same work from any render: what it reads is in refs and the dispatch.
|
|
594
|
+
}, [travelling, live.open]);
|
|
595
|
+
|
|
596
|
+
const say = (text: string, files: readonly string[] = []): boolean => {
|
|
597
|
+
const frame = sayOf(text, files);
|
|
598
|
+
if (frame === null || state.pending || state.awaiting !== null) return false;
|
|
599
|
+
return live.send(frame);
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
const act = (action: Action): boolean => {
|
|
603
|
+
if (!live.send({ type: "action", ...action })) return false;
|
|
604
|
+
dispatch({ type: "acted", action });
|
|
605
|
+
return true;
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
return {
|
|
609
|
+
messages: state.messages,
|
|
610
|
+
draft: state.draft,
|
|
611
|
+
pending: state.pending,
|
|
612
|
+
awaiting: state.awaiting,
|
|
613
|
+
open: live.open,
|
|
614
|
+
loading: !state.loaded,
|
|
615
|
+
error: state.error,
|
|
616
|
+
say,
|
|
617
|
+
act,
|
|
618
|
+
stop: () => live.send({ type: "stop" }),
|
|
619
|
+
browser: state.browser,
|
|
620
|
+
watchScreen: screen.watch,
|
|
621
|
+
control: (to) => live.send({ type: "browser.control", to }),
|
|
622
|
+
closeBrowser: () => live.send({ type: "browser.close" }),
|
|
623
|
+
input: (event) => live.send({ type: "browser.input", event }),
|
|
624
|
+
holder: state.holder,
|
|
625
|
+
handovers: state.handovers,
|
|
626
|
+
};
|
|
627
|
+
}
|