@signalcore/ui 0.1.0 → 1.0.0-beta.1
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 +1127 -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 +541 -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 +1812 -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 +271 -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 +6970 -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 +604 -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,1127 @@
|
|
|
1
|
+
import { actionWords } from "./about.js";
|
|
2
|
+
import { classes } from "./classes.js";
|
|
3
|
+
import { KIT_MESSAGES } from "./kit/messages.js";
|
|
4
|
+
import { KitProvider } from "./kit/context.js";
|
|
5
|
+
import { actionMark } from "./marks.js";
|
|
6
|
+
import { BROWSER_MESSAGES, BrowserView } from "./BrowserView.js";
|
|
7
|
+
import { channelParts } from "./channelParts.js";
|
|
8
|
+
import { useDictation } from "./useDictation.js";
|
|
9
|
+
import { useReveal } from "./reveal.js";
|
|
10
|
+
import { useConversationFiles } from "./conversationFiles.js";
|
|
11
|
+
import "./frames.js";
|
|
12
|
+
import { AudioPlayer } from "./kit/AudioPlayer.js";
|
|
13
|
+
import { FileChips, UploadChips, carriesFiles, useUploads } from "./kit/FileField.js";
|
|
14
|
+
import { stepGlyph } from "./stepGlyphs.js";
|
|
15
|
+
import { Markdown } from "./surface/Markdown.js";
|
|
16
|
+
import { Surface, framesItself, usePlayed } from "./surface/Surface.js";
|
|
17
|
+
import { NO_TOOL, useConversation } from "./useConversation.js";
|
|
18
|
+
import { Fragment, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
19
|
+
import { ArrowUpIcon, CaretRightIcon, CheckIcon, ChecksIcon, ClockIcon, MicrophoneIcon, PaperclipIcon, ShieldWarningIcon, StopIcon, UploadSimpleIcon, WarningCircleIcon } from "@phosphor-icons/react";
|
|
20
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
//#region src/AgentChat.tsx
|
|
22
|
+
const CHAT_MESSAGES = {
|
|
23
|
+
placeholder: (name) => `Write to ${name}…`,
|
|
24
|
+
connecting: "Connecting…",
|
|
25
|
+
awaiting: "Answer above to go on…",
|
|
26
|
+
thinking: (name) => `${name} is thinking`,
|
|
27
|
+
typing: "Typing",
|
|
28
|
+
working: "Working",
|
|
29
|
+
writing: "Writing",
|
|
30
|
+
elapsed: (seconds) => `${seconds} s`,
|
|
31
|
+
escape: "esc to stop",
|
|
32
|
+
done: (seconds) => `Done in ${seconds} s`,
|
|
33
|
+
empty: (name) => `Talk with ${name}`,
|
|
34
|
+
intro: () => "",
|
|
35
|
+
send: "Send",
|
|
36
|
+
attach: "Attach files",
|
|
37
|
+
drop: "Drop to attach",
|
|
38
|
+
dictate: "Dictate",
|
|
39
|
+
dictateStop: "Stop and write it",
|
|
40
|
+
dictation: {
|
|
41
|
+
listening: "Listening…",
|
|
42
|
+
writing: "Writing it down…",
|
|
43
|
+
failed: "Couldn't hear you: allow the microphone and try again"
|
|
44
|
+
},
|
|
45
|
+
stop: "Stop",
|
|
46
|
+
log: "Conversation",
|
|
47
|
+
steps: {
|
|
48
|
+
show: "Shows",
|
|
49
|
+
ask_person: "Asks"
|
|
50
|
+
},
|
|
51
|
+
failed: "failed",
|
|
52
|
+
approval: "Needs your approval",
|
|
53
|
+
request: (name, action) => `${name} wants to ${action}`,
|
|
54
|
+
inputs: {},
|
|
55
|
+
allow: "Allow",
|
|
56
|
+
decline: "Decline",
|
|
57
|
+
confirming: "Waiting for the business to confirm",
|
|
58
|
+
handedOff: "Handed to a person",
|
|
59
|
+
handover: (holder, by, name) => {
|
|
60
|
+
const automation = by.kind === "automation" ? ` by “${by.title}”` : "";
|
|
61
|
+
switch (holder) {
|
|
62
|
+
case "agent":
|
|
63
|
+
if (by.kind === "owner") return `You gave it back to ${name}`;
|
|
64
|
+
return `Given back to ${name}${automation}`;
|
|
65
|
+
case "person":
|
|
66
|
+
if (by.kind === "owner") return `You paused ${name}`;
|
|
67
|
+
if (by.kind === "agent") return `${name} handed it to a person`;
|
|
68
|
+
return `Handed to a person${automation}`;
|
|
69
|
+
case "nobody": return `Ignored${automation}`;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
skipped: "Not answered",
|
|
73
|
+
cut: (heard) => heard === "" ? "Cut off before a word of it was heard" : `Cut off after «${heard}»`,
|
|
74
|
+
write: "Reply as the business…",
|
|
75
|
+
business: "You",
|
|
76
|
+
voiceNote: "Voice note",
|
|
77
|
+
delivery: {
|
|
78
|
+
queued: "Waiting to go",
|
|
79
|
+
sent: "Sent",
|
|
80
|
+
delivered: "Delivered",
|
|
81
|
+
read: "Read",
|
|
82
|
+
failed: "Not delivered"
|
|
83
|
+
},
|
|
84
|
+
undelivered: (error) => error ? `Not delivered: ${error}` : "Not delivered",
|
|
85
|
+
noTool: NO_TOOL,
|
|
86
|
+
kit: KIT_MESSAGES,
|
|
87
|
+
browser: BROWSER_MESSAGES
|
|
88
|
+
};
|
|
89
|
+
/** How close to the foot, in pixels, still counts as being at it (v2's). */
|
|
90
|
+
const NEAR_FOOT = 80;
|
|
91
|
+
/**
|
|
92
|
+
* The conversation with an agent: the person's messages at the right in a bubble, the agent's at
|
|
93
|
+
* the left as text with the steps it took and what they drew, its reply growing as it streams;
|
|
94
|
+
* the composer at the foot. On a channel, the business's side stays at the left: the agent's
|
|
95
|
+
* words with where they got to (a quiet mark), and what a person of the business wrote set apart
|
|
96
|
+
* in a bubble of its own; the surfaces went to the person there, so they only read here, and the
|
|
97
|
+
* reply, which runs on its own time, can't be stopped from here. With `handovers`, each change of
|
|
98
|
+
* who answers it is a quiet line where it fell, the moment it is made, and a person's message the
|
|
99
|
+
* agent let pass says so under it. The host picks the conversation; another id starts the chat
|
|
100
|
+
* afresh.
|
|
101
|
+
*/
|
|
102
|
+
function AgentChat(props) {
|
|
103
|
+
const taken = useRef(props.compose?.key ?? null);
|
|
104
|
+
const kit = props.messages?.kit ?? CHAT_MESSAGES.kit;
|
|
105
|
+
return /* @__PURE__ */ jsx(KitProvider, {
|
|
106
|
+
classNames: props.classNames,
|
|
107
|
+
messages: kit,
|
|
108
|
+
locale: props.locale,
|
|
109
|
+
children: /* @__PURE__ */ jsx(Chat, {
|
|
110
|
+
...props,
|
|
111
|
+
taken
|
|
112
|
+
}, props.conversationId)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function Chat({ client, conversationId, name, messages, classNames, components, locale, onError, actions, suggestions, compose, look = "agent", steps = client.who === "person" ? "hidden" : "shown", attachments = true, onOpenFile, dictate, write, handovers = false, onHolder, onStep, handover, onTool, taken }) {
|
|
116
|
+
const words = {
|
|
117
|
+
...CHAT_MESSAGES,
|
|
118
|
+
...messages
|
|
119
|
+
};
|
|
120
|
+
const live = useConversation(client, conversationId, {
|
|
121
|
+
onError,
|
|
122
|
+
onHolder,
|
|
123
|
+
onStep,
|
|
124
|
+
handover,
|
|
125
|
+
onTool: onTool ?? (() => Promise.reject(new Error(words.noTool)))
|
|
126
|
+
});
|
|
127
|
+
const files = useConversationFiles(client, conversationId, live.messages, onOpenFile);
|
|
128
|
+
const uploads = useUploads(attachments ? files : void 0, { max: 10 });
|
|
129
|
+
const attaching = attachments && (write !== void 0 || live.awaiting === null);
|
|
130
|
+
const [over, setOver] = useState(false);
|
|
131
|
+
const following = useRef(true);
|
|
132
|
+
const fresh = !live.loading && live.messages.length === 0 && !live.pending;
|
|
133
|
+
const took = useTook(live.pending);
|
|
134
|
+
const builder = look !== "agent";
|
|
135
|
+
const { pending } = live;
|
|
136
|
+
const onChannel = live.messages.some((message) => message.author != null);
|
|
137
|
+
const stop = useRef(live.stop);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
stop.current = live.stop;
|
|
140
|
+
});
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (!builder || !pending) return void 0;
|
|
143
|
+
const onKey = (event) => {
|
|
144
|
+
if (event.key === "Escape" && !event.defaultPrevented) stop.current();
|
|
145
|
+
};
|
|
146
|
+
window.addEventListener("keydown", onKey);
|
|
147
|
+
return () => {
|
|
148
|
+
window.removeEventListener("keydown", onKey);
|
|
149
|
+
};
|
|
150
|
+
}, [builder, pending]);
|
|
151
|
+
const looks = builder ? ["sc-chat--builder"] : [];
|
|
152
|
+
if (look === "console") looks.push("sc-chat--console");
|
|
153
|
+
const stepsShown = steps === "shown";
|
|
154
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
155
|
+
part: "chat",
|
|
156
|
+
className: `sc ${classes(classNames, "sc-chat", ...looks)}`,
|
|
157
|
+
onKeyDown: (event) => {
|
|
158
|
+
if (!builder && !onChannel && event.key === "Escape" && live.pending) live.stop();
|
|
159
|
+
},
|
|
160
|
+
onDragOver: (event) => {
|
|
161
|
+
if (!attaching || !carriesFiles(event)) return;
|
|
162
|
+
const zone = event.target instanceof Element && event.target.closest("[data-drop]");
|
|
163
|
+
setOver(!zone);
|
|
164
|
+
if (zone) return;
|
|
165
|
+
event.preventDefault();
|
|
166
|
+
event.dataTransfer.dropEffect = "copy";
|
|
167
|
+
},
|
|
168
|
+
onDragLeave: (event) => {
|
|
169
|
+
const to = event.relatedTarget;
|
|
170
|
+
if (!(to instanceof Node && event.currentTarget.contains(to))) setOver(false);
|
|
171
|
+
},
|
|
172
|
+
onDrop: (event) => {
|
|
173
|
+
setOver(false);
|
|
174
|
+
if (event.defaultPrevented || !attaching || !carriesFiles(event)) return;
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
uploads.add([...event.dataTransfer.files]);
|
|
177
|
+
},
|
|
178
|
+
children: [
|
|
179
|
+
fresh ? /* @__PURE__ */ jsxs("div", {
|
|
180
|
+
part: "empty",
|
|
181
|
+
className: classes(classNames, "sc-chat__empty"),
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ jsx("h2", { children: words.empty(name) }),
|
|
184
|
+
words.intro(name) !== "" && /* @__PURE__ */ jsx("p", { children: words.intro(name) }),
|
|
185
|
+
suggestions !== void 0 && suggestions.length > 0 && /* @__PURE__ */ jsx("ul", { children: suggestions.map((text) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", {
|
|
186
|
+
type: "button",
|
|
187
|
+
disabled: !live.open,
|
|
188
|
+
onClick: () => {
|
|
189
|
+
if (live.say(text)) following.current = true;
|
|
190
|
+
},
|
|
191
|
+
part: "suggestion",
|
|
192
|
+
className: classes(classNames, "sc-chat__suggestion"),
|
|
193
|
+
children: [
|
|
194
|
+
"«",
|
|
195
|
+
text,
|
|
196
|
+
"»"
|
|
197
|
+
]
|
|
198
|
+
}) }, text)) })
|
|
199
|
+
]
|
|
200
|
+
}) : /* @__PURE__ */ jsx(Log, {
|
|
201
|
+
live,
|
|
202
|
+
name,
|
|
203
|
+
words,
|
|
204
|
+
classNames,
|
|
205
|
+
components,
|
|
206
|
+
locale,
|
|
207
|
+
following,
|
|
208
|
+
took,
|
|
209
|
+
builder,
|
|
210
|
+
onChannel,
|
|
211
|
+
files,
|
|
212
|
+
handovers: handovers ? live.handovers : void 0,
|
|
213
|
+
who: client.who,
|
|
214
|
+
steps: stepsShown
|
|
215
|
+
}),
|
|
216
|
+
/* @__PURE__ */ jsx(BrowserView, {
|
|
217
|
+
live,
|
|
218
|
+
name,
|
|
219
|
+
messages: words.browser,
|
|
220
|
+
classNames
|
|
221
|
+
}),
|
|
222
|
+
live.pending && /* @__PURE__ */ jsx(Status, {
|
|
223
|
+
label: builder ? workingOn(live, words) : stepsShown ? words.thinking(name) : words.typing,
|
|
224
|
+
stoppable: !onChannel,
|
|
225
|
+
timed: stepsShown,
|
|
226
|
+
words,
|
|
227
|
+
classNames
|
|
228
|
+
}),
|
|
229
|
+
/* @__PURE__ */ jsx(Composer, {
|
|
230
|
+
live,
|
|
231
|
+
name,
|
|
232
|
+
words,
|
|
233
|
+
classNames,
|
|
234
|
+
actions,
|
|
235
|
+
compose,
|
|
236
|
+
taken,
|
|
237
|
+
fresh,
|
|
238
|
+
builder,
|
|
239
|
+
uploads: attachments ? uploads : void 0,
|
|
240
|
+
files,
|
|
241
|
+
dictate,
|
|
242
|
+
write,
|
|
243
|
+
onSent: () => {
|
|
244
|
+
following.current = true;
|
|
245
|
+
}
|
|
246
|
+
}),
|
|
247
|
+
over && /* @__PURE__ */ jsxs("div", {
|
|
248
|
+
"aria-hidden": true,
|
|
249
|
+
className: classes(classNames, "sc-chat__drop"),
|
|
250
|
+
children: [/* @__PURE__ */ jsx(UploadSimpleIcon, { weight: "bold" }), words.drop]
|
|
251
|
+
})
|
|
252
|
+
]
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* What the builder is doing right now, v2's way: the step running in this turn, by its name (the
|
|
257
|
+
* first one not settled: the actions of a reply run in its order); its words, while they come; or
|
|
258
|
+
* that it is working.
|
|
259
|
+
*/
|
|
260
|
+
function workingOn(live, words) {
|
|
261
|
+
const lastSaid = live.messages.findLastIndex((message) => message.role === "user");
|
|
262
|
+
const running = live.messages.slice(lastSaid + 1).flatMap((message) => message.steps).find((step) => step.state === "running");
|
|
263
|
+
if (running) return words.steps[running.action] ?? running.action;
|
|
264
|
+
return live.draft === "" ? words.working : words.writing;
|
|
265
|
+
}
|
|
266
|
+
const NO_HANDOFFS = /* @__PURE__ */ new Set();
|
|
267
|
+
/** Whether a message is the agent's own words: a reply, not what a person of the business wrote. */
|
|
268
|
+
const agentSaid = (message) => message?.role === "assistant" && message.author !== "operator";
|
|
269
|
+
/**
|
|
270
|
+
* The replies a handoff line follows: in each turn where the agent handed the conversation to a
|
|
271
|
+
* person (an `escalate` step done), its last reply, so the line closes what the agent said.
|
|
272
|
+
*/
|
|
273
|
+
function handoffs(messages) {
|
|
274
|
+
const after = /* @__PURE__ */ new Set();
|
|
275
|
+
let handed = false;
|
|
276
|
+
for (const [index, message] of messages.entries()) {
|
|
277
|
+
handed ||= message.steps.some((step) => step.action === "escalate" && step.state === "done");
|
|
278
|
+
if (handed && !agentSaid(messages[index + 1])) {
|
|
279
|
+
after.add(message.id);
|
|
280
|
+
handed = false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return after;
|
|
284
|
+
}
|
|
285
|
+
/** Who changed who answers, from a handover's `by`: anything but these three is an automation's name. */
|
|
286
|
+
function handoverBy({ by, title }) {
|
|
287
|
+
if (by === "owner" || by === "agent" || by === "platform") return { kind: by };
|
|
288
|
+
return {
|
|
289
|
+
kind: "automation",
|
|
290
|
+
title: title ?? by
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** A change of who answers, as its line says it: what changed and who changed it, then why. */
|
|
294
|
+
function handoverLine(handover, name, words) {
|
|
295
|
+
const line = words.handover(handover.holder, handoverBy(handover), name);
|
|
296
|
+
const reason = handover.reason.trim();
|
|
297
|
+
return reason === "" ? line : `${line}: ${reason}`;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* The line under a person's message the agent let pass this time, with why (the owner's words,
|
|
301
|
+
* else the automation that decided); none for any other decision: an answer is the reply itself,
|
|
302
|
+
* and a conversation held or ignored has its line where who answers changed.
|
|
303
|
+
*/
|
|
304
|
+
function decisionLine(decision, words) {
|
|
305
|
+
if (decision?.kind !== "skip") return null;
|
|
306
|
+
const why = decision.reason?.trim() || decision.title;
|
|
307
|
+
return why ? `${words.skipped}: ${why}` : words.skipped;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Where each change of who answers falls among the messages, by the index of the message it goes
|
|
311
|
+
* before (`messages.length`: after them all): before the first message said after it, and the
|
|
312
|
+
* agent's own after the last reply of its turn, so its line closes what the agent said.
|
|
313
|
+
*/
|
|
314
|
+
function handoversAt(messages, handovers) {
|
|
315
|
+
const at = /* @__PURE__ */ new Map();
|
|
316
|
+
let next = 0;
|
|
317
|
+
for (const [index, message] of messages.entries()) {
|
|
318
|
+
const said = Date.parse(message.created_at);
|
|
319
|
+
const before = [];
|
|
320
|
+
let handover = handovers[next];
|
|
321
|
+
while (handover !== void 0 && Date.parse(handover.at) < said && !(handover.by === "agent" && agentSaid(message))) {
|
|
322
|
+
before.push(handover);
|
|
323
|
+
next += 1;
|
|
324
|
+
handover = handovers[next];
|
|
325
|
+
}
|
|
326
|
+
if (before.length > 0) at.set(index, before);
|
|
327
|
+
}
|
|
328
|
+
if (next < handovers.length) at.set(messages.length, handovers.slice(next));
|
|
329
|
+
return at;
|
|
330
|
+
}
|
|
331
|
+
/** When a line across the log happened, as the locale writes it: the time today, else the day too. */
|
|
332
|
+
function whenSaid(at, now, code) {
|
|
333
|
+
const moment = new Date(at);
|
|
334
|
+
const today = moment.toDateString() === now.toDateString();
|
|
335
|
+
return new Intl.DateTimeFormat(code, {
|
|
336
|
+
...today ? {} : {
|
|
337
|
+
day: "numeric",
|
|
338
|
+
month: "short"
|
|
339
|
+
},
|
|
340
|
+
hour: "numeric",
|
|
341
|
+
minute: "2-digit"
|
|
342
|
+
}).format(moment);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* The messages, read down, and the reply on its way: who is thinking until its first words, then
|
|
346
|
+
* the words as they come with the agent's mark at their end. Where who answers the conversation
|
|
347
|
+
* changed (`handovers`, when the host draws them; else where the agent handed it to a person),
|
|
348
|
+
* one quiet line across the log says so, and under a person's message the agent let pass, that
|
|
349
|
+
* it did. Screen readers hear a reply once, when it is stored.
|
|
350
|
+
*/
|
|
351
|
+
function Log({ live, name, words, classNames, components, locale, following, took, builder, onChannel, files, handovers, who, steps }) {
|
|
352
|
+
const scroller = useRef(null);
|
|
353
|
+
const said = useRef(null);
|
|
354
|
+
const { messages, pending, draft, awaiting } = live;
|
|
355
|
+
const shown = useRef(0);
|
|
356
|
+
const last = messages.at(-1);
|
|
357
|
+
const outgoing = last !== void 0 && last.role === "assistant" && last.delivery != null && last.delivery !== "failed";
|
|
358
|
+
const drafted = useReveal(draft, 0, (count) => {
|
|
359
|
+
shown.current = count;
|
|
360
|
+
});
|
|
361
|
+
const lastDraft = useRef("");
|
|
362
|
+
const carried = useRef(null);
|
|
363
|
+
const latest = messages.at(-1);
|
|
364
|
+
if (latest?.role === "assistant" && lastDraft.current !== "" && draft === "" && carried.current?.id !== latest.id) carried.current = {
|
|
365
|
+
id: latest.id,
|
|
366
|
+
from: shown.current
|
|
367
|
+
};
|
|
368
|
+
lastDraft.current = draft;
|
|
369
|
+
useLayoutEffect(() => {
|
|
370
|
+
const box = scroller.current;
|
|
371
|
+
if (box && following.current) box.scrollTop = box.scrollHeight;
|
|
372
|
+
}, [
|
|
373
|
+
messages,
|
|
374
|
+
pending,
|
|
375
|
+
drafted,
|
|
376
|
+
following
|
|
377
|
+
]);
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
const box = scroller.current;
|
|
380
|
+
const log = said.current;
|
|
381
|
+
if (!box || !log || typeof ResizeObserver === "undefined") return void 0;
|
|
382
|
+
const observer = new ResizeObserver(() => {
|
|
383
|
+
if (following.current) box.scrollTop = box.scrollHeight;
|
|
384
|
+
});
|
|
385
|
+
observer.observe(log);
|
|
386
|
+
observer.observe(box);
|
|
387
|
+
return () => {
|
|
388
|
+
observer.disconnect();
|
|
389
|
+
};
|
|
390
|
+
}, [following]);
|
|
391
|
+
const idle = !onChannel && !pending && awaiting === null;
|
|
392
|
+
const lastSaid = messages.findLastIndex((message) => message.role === "user");
|
|
393
|
+
const answers = /* @__PURE__ */ new Map();
|
|
394
|
+
for (const message of messages) if (message.action) answers.set(message.action.surface, message.action);
|
|
395
|
+
const handed = handovers === void 0 ? handoffs(messages) : NO_HANDOFFS;
|
|
396
|
+
const placed = handoversAt(messages, handovers ?? []);
|
|
397
|
+
const lines = (index) => placed.get(index)?.map((handover) => /* @__PURE__ */ jsx(HandoverLine, {
|
|
398
|
+
handover,
|
|
399
|
+
name,
|
|
400
|
+
words,
|
|
401
|
+
classNames,
|
|
402
|
+
code: locale?.code ?? "en-US"
|
|
403
|
+
}, `${handover.at} ${handover.holder}`));
|
|
404
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
405
|
+
ref: scroller,
|
|
406
|
+
onScroll: (event) => {
|
|
407
|
+
const box = event.currentTarget;
|
|
408
|
+
following.current = box.scrollHeight - box.scrollTop - box.clientHeight < NEAR_FOOT;
|
|
409
|
+
},
|
|
410
|
+
part: "transcript",
|
|
411
|
+
className: classes(classNames, "sc-chat__log", ...onChannel ? ["sc-chat__log--channel"] : []),
|
|
412
|
+
children: [
|
|
413
|
+
/* @__PURE__ */ jsxs("div", {
|
|
414
|
+
ref: said,
|
|
415
|
+
role: "log",
|
|
416
|
+
"aria-label": words.log,
|
|
417
|
+
children: [messages.map((message, index) => /* @__PURE__ */ jsxs(Fragment, { children: [lines(index), message.role === "user" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
418
|
+
/* @__PURE__ */ jsx(Heard, {
|
|
419
|
+
message,
|
|
420
|
+
after: messages[index - 1],
|
|
421
|
+
words,
|
|
422
|
+
classNames
|
|
423
|
+
}),
|
|
424
|
+
/* @__PURE__ */ jsx(Said, {
|
|
425
|
+
message,
|
|
426
|
+
words,
|
|
427
|
+
classNames,
|
|
428
|
+
files
|
|
429
|
+
}),
|
|
430
|
+
handovers !== void 0 && /* @__PURE__ */ jsx(Decided, {
|
|
431
|
+
decision: message.decision,
|
|
432
|
+
words,
|
|
433
|
+
classNames
|
|
434
|
+
})
|
|
435
|
+
] }) : message.author === "operator" ? /* @__PURE__ */ jsx(Business, {
|
|
436
|
+
message,
|
|
437
|
+
words,
|
|
438
|
+
classNames,
|
|
439
|
+
files
|
|
440
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Reply, {
|
|
441
|
+
message,
|
|
442
|
+
from: carried.current?.id === message.id ? carried.current.from : void 0,
|
|
443
|
+
awaiting: onChannel ? null : awaiting,
|
|
444
|
+
current: idle && index > lastSaid,
|
|
445
|
+
answers,
|
|
446
|
+
name,
|
|
447
|
+
words,
|
|
448
|
+
classNames,
|
|
449
|
+
components,
|
|
450
|
+
locale,
|
|
451
|
+
onAction: live.act,
|
|
452
|
+
builder,
|
|
453
|
+
files,
|
|
454
|
+
who,
|
|
455
|
+
steps,
|
|
456
|
+
onChannel
|
|
457
|
+
}), handed.has(message.id) && /* @__PURE__ */ jsxs("p", {
|
|
458
|
+
className: classes(classNames, "sc-chat__handoff"),
|
|
459
|
+
children: [actionMark("escalate", "library"), /* @__PURE__ */ jsx("span", { children: words.handedOff })]
|
|
460
|
+
})] })] }, message.id)), lines(messages.length)]
|
|
461
|
+
}),
|
|
462
|
+
steps && !pending && took !== null && /* @__PURE__ */ jsx("p", {
|
|
463
|
+
className: classes(classNames, "sc-chat__done"),
|
|
464
|
+
children: words.done(took)
|
|
465
|
+
}),
|
|
466
|
+
pending && onChannel && !outgoing && /* @__PURE__ */ jsx(Typing, {
|
|
467
|
+
label: words.typing,
|
|
468
|
+
classNames
|
|
469
|
+
}),
|
|
470
|
+
pending && !onChannel && drafted !== "" && /* @__PURE__ */ jsx("div", {
|
|
471
|
+
"aria-hidden": true,
|
|
472
|
+
part: "message message-agent",
|
|
473
|
+
className: classes(classNames, "sc-chat__text", "sc-chat__reply"),
|
|
474
|
+
children: /* @__PURE__ */ jsx(Markdown, { text: drafted })
|
|
475
|
+
})
|
|
476
|
+
]
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/** The channel's "typing": three dots in the business's bubble, while a reply or its parts come. */
|
|
480
|
+
function Typing({ label, classNames }) {
|
|
481
|
+
return /* @__PURE__ */ jsxs("p", {
|
|
482
|
+
role: "status",
|
|
483
|
+
"aria-label": label,
|
|
484
|
+
className: classes(classNames, "sc-chat__typing"),
|
|
485
|
+
children: [
|
|
486
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
487
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
488
|
+
/* @__PURE__ */ jsx("span", {})
|
|
489
|
+
]
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
/** How many of the last words heard a cut line quotes. */
|
|
493
|
+
const HEARD_WORDS = 8;
|
|
494
|
+
/** The last words of what was heard, with an ellipsis before them when there was more. */
|
|
495
|
+
function heardTail(heard, count = HEARD_WORDS) {
|
|
496
|
+
const words = heard.trim().split(/\s+/).filter(Boolean);
|
|
497
|
+
if (words.length <= count) return words.join(" ");
|
|
498
|
+
return `…${words.slice(-count).join(" ")}`;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* On a call, what the person heard of the agent's last words before this message, when it wasn't
|
|
502
|
+
* what was stored. After a reply (the greeting is the first), they cut it short: a quiet line
|
|
503
|
+
* under it quotes the last of what they heard. With no reply before, it was a greeting from before
|
|
504
|
+
* the API kept it: drawn here as the agent's words, where it was said.
|
|
505
|
+
*/
|
|
506
|
+
function Heard({ message, after, words, classNames }) {
|
|
507
|
+
const { heard } = message;
|
|
508
|
+
if (heard == null) return null;
|
|
509
|
+
if (after?.role === "assistant") return /* @__PURE__ */ jsx("p", {
|
|
510
|
+
className: classes(classNames, "sc-chat__cut"),
|
|
511
|
+
children: words.cut(heardTail(heard))
|
|
512
|
+
});
|
|
513
|
+
if (heard.trim() === "") return null;
|
|
514
|
+
return /* @__PURE__ */ jsx("div", {
|
|
515
|
+
part: "message message-agent",
|
|
516
|
+
className: classes(classNames, "sc-chat__message", "sc-chat__message--agent", "sc-chat__message--heard"),
|
|
517
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
518
|
+
className: classes(classNames, "sc-chat__text"),
|
|
519
|
+
children: /* @__PURE__ */ jsx("p", { children: heard })
|
|
520
|
+
})
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* The person's message: their words in a bubble (a voice note's player with its words under it);
|
|
525
|
+
* the files they sent with it as chips over it, each opening where the host shows files. An
|
|
526
|
+
* answer on a surface is its words alone: the surface shows its files.
|
|
527
|
+
*/
|
|
528
|
+
function Said({ message, words, classNames, files }) {
|
|
529
|
+
const sent = message.action ? [] : message.files ?? [];
|
|
530
|
+
const bubble = message.voice ? /* @__PURE__ */ jsx(VoiceNote, {
|
|
531
|
+
file: message.voice,
|
|
532
|
+
text: message.text,
|
|
533
|
+
parts: "message message-person",
|
|
534
|
+
kind: "sc-chat__message--person",
|
|
535
|
+
words,
|
|
536
|
+
classNames,
|
|
537
|
+
files
|
|
538
|
+
}) : message.text !== "" && /* @__PURE__ */ jsx("p", {
|
|
539
|
+
part: "message message-person",
|
|
540
|
+
className: classes(classNames, "sc-chat__message", "sc-chat__message--person", ...message.action ? ["sc-chat__message--action"] : []),
|
|
541
|
+
children: message.text
|
|
542
|
+
});
|
|
543
|
+
if (sent.length === 0) return bubble;
|
|
544
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
545
|
+
part: "files",
|
|
546
|
+
className: classes(classNames, "sc-chat__said"),
|
|
547
|
+
children: [/* @__PURE__ */ jsx(FileChips, {
|
|
548
|
+
files: sent,
|
|
549
|
+
onOpen: files.open
|
|
550
|
+
}), bubble]
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* A voice note on a channel, either way: a bubble with the page's own player, streaming from where
|
|
555
|
+
* the file plays (asked again, once, when that ran out), and what was said under it.
|
|
556
|
+
*/
|
|
557
|
+
function VoiceNote({ file, text, parts, kind, words, classNames, files }) {
|
|
558
|
+
const played = usePlayed(file, files.play);
|
|
559
|
+
const lost = useRef(false);
|
|
560
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
561
|
+
part: parts,
|
|
562
|
+
className: classes(classNames, ...kind === "sc-chat__text" ? [] : ["sc-chat__message"], kind, "sc-chat__message--voice"),
|
|
563
|
+
children: [/* @__PURE__ */ jsx(AudioPlayer, {
|
|
564
|
+
src: played?.url,
|
|
565
|
+
label: words.voiceNote,
|
|
566
|
+
onError: () => {
|
|
567
|
+
if (lost.current || played === null) return;
|
|
568
|
+
lost.current = true;
|
|
569
|
+
played.again();
|
|
570
|
+
}
|
|
571
|
+
}), text !== "" && /* @__PURE__ */ jsx("div", {
|
|
572
|
+
className: classes(classNames, "sc-chat__transcript"),
|
|
573
|
+
children: /* @__PURE__ */ jsx(Markdown, { text })
|
|
574
|
+
})]
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
/** Under a person's message the agent let pass this time: that it didn't answer it, and why. */
|
|
578
|
+
function Decided({ decision, words, classNames }) {
|
|
579
|
+
const line = decisionLine(decision, words);
|
|
580
|
+
if (line === null) return null;
|
|
581
|
+
return /* @__PURE__ */ jsx("p", {
|
|
582
|
+
className: classes(classNames, "sc-chat__decision"),
|
|
583
|
+
children: line
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Where who answers the conversation changed: a quiet line across the log, what changed and who
|
|
588
|
+
* changed it, why, and when.
|
|
589
|
+
*/
|
|
590
|
+
function HandoverLine({ handover, name, words, classNames, code }) {
|
|
591
|
+
return /* @__PURE__ */ jsx("p", {
|
|
592
|
+
className: classes(classNames, "sc-chat__handover"),
|
|
593
|
+
children: /* @__PURE__ */ jsxs("span", { children: [handoverLine(handover, name, words), /* @__PURE__ */ jsx("time", {
|
|
594
|
+
dateTime: handover.at,
|
|
595
|
+
children: whenSaid(handover.at, /* @__PURE__ */ new Date(), code)
|
|
596
|
+
})] })
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* What a person of the business wrote on the channel, on the business's side but set apart from
|
|
601
|
+
* the agent's words: a bubble of its own, the files it carried over it, and under it who wrote it
|
|
602
|
+
* and where it got to.
|
|
603
|
+
*/
|
|
604
|
+
function Business({ message, words, classNames, files }) {
|
|
605
|
+
const sent = message.files ?? [];
|
|
606
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
607
|
+
className: classes(classNames, "sc-chat__business"),
|
|
608
|
+
children: [
|
|
609
|
+
sent.length > 0 && /* @__PURE__ */ jsx(FileChips, {
|
|
610
|
+
files: sent,
|
|
611
|
+
onOpen: files.open
|
|
612
|
+
}),
|
|
613
|
+
message.text !== "" && /* @__PURE__ */ jsx("p", {
|
|
614
|
+
part: "message message-business",
|
|
615
|
+
className: classes(classNames, "sc-chat__message", "sc-chat__message--business"),
|
|
616
|
+
children: message.text
|
|
617
|
+
}),
|
|
618
|
+
/* @__PURE__ */ jsxs("p", {
|
|
619
|
+
className: classes(classNames, "sc-chat__meta"),
|
|
620
|
+
children: [/* @__PURE__ */ jsx("span", { children: words.business }), /* @__PURE__ */ jsx(DeliveryMark, {
|
|
621
|
+
message,
|
|
622
|
+
words,
|
|
623
|
+
classNames
|
|
624
|
+
})]
|
|
625
|
+
})
|
|
626
|
+
]
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
const DELIVERY_MARKS = {
|
|
630
|
+
queued: /* @__PURE__ */ jsx(ClockIcon, { "aria-hidden": true }),
|
|
631
|
+
sent: /* @__PURE__ */ jsx(CheckIcon, {
|
|
632
|
+
"aria-hidden": true,
|
|
633
|
+
weight: "bold"
|
|
634
|
+
}),
|
|
635
|
+
delivered: /* @__PURE__ */ jsx(ChecksIcon, {
|
|
636
|
+
"aria-hidden": true,
|
|
637
|
+
weight: "bold"
|
|
638
|
+
}),
|
|
639
|
+
read: /* @__PURE__ */ jsx(ChecksIcon, {
|
|
640
|
+
"aria-hidden": true,
|
|
641
|
+
weight: "bold"
|
|
642
|
+
}),
|
|
643
|
+
failed: /* @__PURE__ */ jsx(WarningCircleIcon, {
|
|
644
|
+
"aria-hidden": true,
|
|
645
|
+
weight: "fill"
|
|
646
|
+
})
|
|
647
|
+
};
|
|
648
|
+
/**
|
|
649
|
+
* Where a message that went out on a channel got to, quietly: a clock while it waits to go, a
|
|
650
|
+
* check once sent, two once delivered, two in the accent once read; one that never got there in
|
|
651
|
+
* the danger tone, with why. Nothing for a message that didn't go out.
|
|
652
|
+
*/
|
|
653
|
+
function DeliveryMark({ message, words, classNames }) {
|
|
654
|
+
const { delivery } = message;
|
|
655
|
+
if (delivery == null) return null;
|
|
656
|
+
const failed = delivery === "failed";
|
|
657
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
658
|
+
role: failed ? void 0 : "img",
|
|
659
|
+
"aria-label": failed ? void 0 : words.delivery[delivery],
|
|
660
|
+
title: failed ? void 0 : words.delivery[delivery],
|
|
661
|
+
"data-delivery": delivery,
|
|
662
|
+
className: classes(classNames, "sc-chat__delivery"),
|
|
663
|
+
children: [DELIVERY_MARKS[delivery], failed && /* @__PURE__ */ jsx("span", { children: words.undelivered(message.delivery_error ?? null) })]
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* The agent's message: its words, then the steps it took as a compact list (a mark for the
|
|
668
|
+
* state, the action's name, its output), then what each step drew (with what the person did on
|
|
669
|
+
* it, from `answers`), and the card for one that waits to be allowed by whoever this page speaks
|
|
670
|
+
* for (on a person's page, one the business allows is a quiet line instead); on a channel, where
|
|
671
|
+
* it got to.
|
|
672
|
+
*/
|
|
673
|
+
function Reply({ message, from, awaiting, current, answers, name, words, classNames, components, locale, onAction, builder, files, who, steps, onChannel }) {
|
|
674
|
+
const text = useReveal(message.text, from ?? message.text.length);
|
|
675
|
+
const { shown: said, typing } = onChannel ? channelParts(message, text) : {
|
|
676
|
+
shown: [text],
|
|
677
|
+
typing: false
|
|
678
|
+
};
|
|
679
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
680
|
+
part: "message message-agent",
|
|
681
|
+
className: classes(classNames, "sc-chat__message", "sc-chat__message--agent"),
|
|
682
|
+
children: [
|
|
683
|
+
message.voice && said.length > 0 ? /* @__PURE__ */ jsx(VoiceNote, {
|
|
684
|
+
file: message.voice,
|
|
685
|
+
text,
|
|
686
|
+
parts: "text",
|
|
687
|
+
kind: "sc-chat__text",
|
|
688
|
+
words,
|
|
689
|
+
classNames,
|
|
690
|
+
files
|
|
691
|
+
}) : text !== "" && said.map((words, index) => /* @__PURE__ */ jsx("div", {
|
|
692
|
+
part: "text",
|
|
693
|
+
className: classes(classNames, "sc-chat__text"),
|
|
694
|
+
children: /* @__PURE__ */ jsx(Markdown, { text: words })
|
|
695
|
+
}, index)),
|
|
696
|
+
typing && /* @__PURE__ */ jsx(Typing, {
|
|
697
|
+
label: words.typing,
|
|
698
|
+
classNames
|
|
699
|
+
}),
|
|
700
|
+
steps && message.steps.length > 0 && /* @__PURE__ */ jsx("ol", {
|
|
701
|
+
className: classes(classNames, "sc-chat__steps"),
|
|
702
|
+
children: message.steps.map((step, index) => /* @__PURE__ */ jsx("li", {
|
|
703
|
+
className: classes(classNames, "sc-chat__step", `sc-chat__step--${shownState(step, message.steps.slice(0, index))}`),
|
|
704
|
+
children: builder ? /* @__PURE__ */ jsx(BuilderStep, {
|
|
705
|
+
step,
|
|
706
|
+
words,
|
|
707
|
+
classNames
|
|
708
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
709
|
+
/* @__PURE__ */ jsx(Mark, {
|
|
710
|
+
state: step.state,
|
|
711
|
+
action: step.action,
|
|
712
|
+
app: step.app ?? null,
|
|
713
|
+
classNames
|
|
714
|
+
}),
|
|
715
|
+
/* @__PURE__ */ jsx("span", { children: words.steps[step.action] ?? actionWords(step.action) }),
|
|
716
|
+
step.state === "failed" && step.output !== null && /* @__PURE__ */ jsx("small", { children: step.output })
|
|
717
|
+
] })
|
|
718
|
+
}, step.id))
|
|
719
|
+
}),
|
|
720
|
+
message.steps.map((step) => step.surface && /* @__PURE__ */ jsx("div", {
|
|
721
|
+
part: "surface",
|
|
722
|
+
className: classes(classNames, "sc-chat__screen", ...framesItself(step.surface) ? ["sc-chat__screen--bare"] : []),
|
|
723
|
+
children: /* @__PURE__ */ jsx(Surface, {
|
|
724
|
+
surface: step.surface,
|
|
725
|
+
active: step.id === awaiting || current,
|
|
726
|
+
answered: answers.get(step.id),
|
|
727
|
+
components,
|
|
728
|
+
classNames,
|
|
729
|
+
messages: words.kit,
|
|
730
|
+
locale,
|
|
731
|
+
files,
|
|
732
|
+
onAction: (action) => onAction({
|
|
733
|
+
surface: step.id,
|
|
734
|
+
...action
|
|
735
|
+
})
|
|
736
|
+
})
|
|
737
|
+
}, step.id)),
|
|
738
|
+
message.steps.map((step) => {
|
|
739
|
+
const { request } = step;
|
|
740
|
+
if (request === null) return null;
|
|
741
|
+
if (request.decides === "business" && who === "person") return /* @__PURE__ */ jsxs("p", {
|
|
742
|
+
part: "confirming",
|
|
743
|
+
className: classes(classNames, "sc-chat__confirming"),
|
|
744
|
+
children: [/* @__PURE__ */ jsx(ClockIcon, { "aria-hidden": true }), /* @__PURE__ */ jsx("span", { children: words.confirming })]
|
|
745
|
+
}, step.id);
|
|
746
|
+
return /* @__PURE__ */ jsx(Approval, {
|
|
747
|
+
request,
|
|
748
|
+
name,
|
|
749
|
+
words,
|
|
750
|
+
classNames,
|
|
751
|
+
components,
|
|
752
|
+
locale,
|
|
753
|
+
onAction: (action) => onAction({
|
|
754
|
+
surface: step.id,
|
|
755
|
+
...action
|
|
756
|
+
})
|
|
757
|
+
}, step.id);
|
|
758
|
+
}),
|
|
759
|
+
message.delivery != null && /* @__PURE__ */ jsxs("p", {
|
|
760
|
+
className: classes(classNames, "sc-chat__meta"),
|
|
761
|
+
children: [onChannel && /* @__PURE__ */ jsx("span", { children: name }), /* @__PURE__ */ jsx(DeliveryMark, {
|
|
762
|
+
message,
|
|
763
|
+
words,
|
|
764
|
+
classNames
|
|
765
|
+
})]
|
|
766
|
+
})
|
|
767
|
+
]
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* A step's state as its list shows it, after the steps `before` it in its reply: the actions of
|
|
772
|
+
* one reply run one after another, in its order, so one still `running` after another that runs
|
|
773
|
+
* is only to come (`queued`).
|
|
774
|
+
*/
|
|
775
|
+
function shownState(step, before) {
|
|
776
|
+
const behind = before.some((earlier) => earlier.state === "running");
|
|
777
|
+
return step.state === "running" && behind ? "queued" : step.state;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* A step in the builder's look, v2's: its mark and its name, "failed" beside it when it did, and
|
|
781
|
+
* what it returned folded under a caret that shows on hover, opened on a click.
|
|
782
|
+
*/
|
|
783
|
+
function BuilderStep({ step, words, classNames }) {
|
|
784
|
+
const row = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
785
|
+
/* @__PURE__ */ jsx(Mark, {
|
|
786
|
+
state: step.state,
|
|
787
|
+
action: step.action,
|
|
788
|
+
app: step.app ?? null,
|
|
789
|
+
classNames
|
|
790
|
+
}),
|
|
791
|
+
/* @__PURE__ */ jsx("span", { children: words.steps[step.action] ?? actionWords(step.action) }),
|
|
792
|
+
step.state === "failed" && /* @__PURE__ */ jsx("em", { children: words.failed })
|
|
793
|
+
] });
|
|
794
|
+
if (!step.output) return row;
|
|
795
|
+
return /* @__PURE__ */ jsxs("details", { children: [/* @__PURE__ */ jsxs("summary", { children: [row, /* @__PURE__ */ jsx(CaretRightIcon, { "aria-hidden": true })] }), /* @__PURE__ */ jsx("pre", {
|
|
796
|
+
className: classes(classNames, "sc-chat__output"),
|
|
797
|
+
children: step.output
|
|
798
|
+
})] });
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* A step's mark on the list's line: the kind of work it is (its glyph) once it is done, a turning
|
|
802
|
+
* ring while it runs, a ring while it waits for the person, a warning when it failed.
|
|
803
|
+
*/
|
|
804
|
+
function Mark({ state, action, app, classNames }) {
|
|
805
|
+
const Glyph = stepGlyph(action);
|
|
806
|
+
const logo = app?.icon && /^https:\/\//i.test(app.icon) ? app.icon : null;
|
|
807
|
+
return /* @__PURE__ */ jsx("span", {
|
|
808
|
+
"aria-hidden": true,
|
|
809
|
+
className: classes(classNames, "sc-chat__mark"),
|
|
810
|
+
children: state === "done" && logo !== null ? /* @__PURE__ */ jsx("img", {
|
|
811
|
+
src: logo,
|
|
812
|
+
alt: "",
|
|
813
|
+
loading: "lazy",
|
|
814
|
+
draggable: false
|
|
815
|
+
}) : state === "done" ? /* @__PURE__ */ jsx(Glyph, {}) : state === "running" ? null : /* @__PURE__ */ jsx("svg", {
|
|
816
|
+
viewBox: "0 0 14 14",
|
|
817
|
+
fill: "none",
|
|
818
|
+
children: MARKS[state]
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
const STROKE = {
|
|
823
|
+
stroke: "currentColor",
|
|
824
|
+
strokeWidth: 1.5,
|
|
825
|
+
strokeLinecap: "round"
|
|
826
|
+
};
|
|
827
|
+
const MARKS = {
|
|
828
|
+
waiting: /* @__PURE__ */ jsx("circle", {
|
|
829
|
+
cx: "7",
|
|
830
|
+
cy: "7",
|
|
831
|
+
r: "4.75",
|
|
832
|
+
...STROKE
|
|
833
|
+
}),
|
|
834
|
+
failed: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
835
|
+
/* @__PURE__ */ jsx("path", {
|
|
836
|
+
d: "M7 1.9l5.6 9.7H1.4L7 1.9z",
|
|
837
|
+
...STROKE,
|
|
838
|
+
strokeLinejoin: "round"
|
|
839
|
+
}),
|
|
840
|
+
/* @__PURE__ */ jsx("path", {
|
|
841
|
+
d: "M7 5.6v2.6",
|
|
842
|
+
...STROKE
|
|
843
|
+
}),
|
|
844
|
+
/* @__PURE__ */ jsx("circle", {
|
|
845
|
+
cx: "7",
|
|
846
|
+
cy: "10",
|
|
847
|
+
r: "0.8",
|
|
848
|
+
fill: "currentColor"
|
|
849
|
+
})
|
|
850
|
+
] })
|
|
851
|
+
};
|
|
852
|
+
/** How long the last reply took, in whole seconds, once it is in; none before the first. */
|
|
853
|
+
function useTook(pending) {
|
|
854
|
+
const [took, setTook] = useState(null);
|
|
855
|
+
const started = useRef(null);
|
|
856
|
+
useEffect(() => {
|
|
857
|
+
if (pending) {
|
|
858
|
+
started.current = Date.now();
|
|
859
|
+
setTook(null);
|
|
860
|
+
} else if (started.current !== null) {
|
|
861
|
+
setTook(Math.max(1, Math.round((Date.now() - started.current) / 1e3)));
|
|
862
|
+
started.current = null;
|
|
863
|
+
}
|
|
864
|
+
}, [pending]);
|
|
865
|
+
return took;
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* What is happening while a reply is on its way, in one quiet line over the composer: a dot that
|
|
869
|
+
* breathes, what goes on (`label`) under a sweeping light, the seconds it has taken, and how to
|
|
870
|
+
* stop it. A new label rises in where the last was.
|
|
871
|
+
*/
|
|
872
|
+
function Status({ label, stoppable, timed, words, classNames }) {
|
|
873
|
+
const [seconds, setSeconds] = useState(0);
|
|
874
|
+
useEffect(() => {
|
|
875
|
+
const started = Date.now();
|
|
876
|
+
const tick = setInterval(() => {
|
|
877
|
+
setSeconds(Math.floor((Date.now() - started) / 1e3));
|
|
878
|
+
}, 1e3);
|
|
879
|
+
return () => {
|
|
880
|
+
clearInterval(tick);
|
|
881
|
+
};
|
|
882
|
+
}, []);
|
|
883
|
+
return /* @__PURE__ */ jsxs("p", {
|
|
884
|
+
role: "status",
|
|
885
|
+
part: "status",
|
|
886
|
+
className: classes(classNames, "sc-chat__status"),
|
|
887
|
+
children: [
|
|
888
|
+
/* @__PURE__ */ jsx("i", { "aria-hidden": true }),
|
|
889
|
+
/* @__PURE__ */ jsxs("span", { children: [label, "…"] }, label),
|
|
890
|
+
timed && /* @__PURE__ */ jsx("small", { children: words.elapsed(seconds) }),
|
|
891
|
+
timed && stoppable && /* @__PURE__ */ jsx("kbd", { children: words.escape })
|
|
892
|
+
]
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* An action the platform holds until the person allows it, as v2's card: a head that says it
|
|
897
|
+
* needs their approval, then the sentence, what the action would take, and the two answers,
|
|
898
|
+
* drawn as a surface so the host's blocks and words apply. Drawn from the step, so it is there
|
|
899
|
+
* live and read back alike.
|
|
900
|
+
*/
|
|
901
|
+
function Approval({ request, name, words, classNames, components, locale, onAction }) {
|
|
902
|
+
const sentence = words.request(name, request.action);
|
|
903
|
+
const surface = {
|
|
904
|
+
blocks: [{
|
|
905
|
+
type: "fields",
|
|
906
|
+
items: Object.entries(request.input).map(([field, value]) => ({
|
|
907
|
+
label: words.inputs[field] ?? field,
|
|
908
|
+
value: typeof value === "string" ? value : JSON.stringify(value)
|
|
909
|
+
}))
|
|
910
|
+
}, {
|
|
911
|
+
type: "stack",
|
|
912
|
+
direction: "row",
|
|
913
|
+
children: [{
|
|
914
|
+
type: "button",
|
|
915
|
+
label: words.allow,
|
|
916
|
+
action: "approve",
|
|
917
|
+
tone: "primary"
|
|
918
|
+
}, {
|
|
919
|
+
type: "button",
|
|
920
|
+
label: words.decline,
|
|
921
|
+
action: "decline",
|
|
922
|
+
tone: "neutral"
|
|
923
|
+
}]
|
|
924
|
+
}],
|
|
925
|
+
text: sentence
|
|
926
|
+
};
|
|
927
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
928
|
+
part: "approval",
|
|
929
|
+
className: classes(classNames, "sc-chat__request"),
|
|
930
|
+
children: [/* @__PURE__ */ jsxs("header", { children: [/* @__PURE__ */ jsx(ShieldWarningIcon, { "aria-hidden": true }), words.approval] }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", { children: sentence }), /* @__PURE__ */ jsx(Surface, {
|
|
931
|
+
surface,
|
|
932
|
+
components,
|
|
933
|
+
classNames,
|
|
934
|
+
messages: words.kit,
|
|
935
|
+
locale,
|
|
936
|
+
onAction
|
|
937
|
+
})] })]
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Where the person writes: a box that grows a few lines with the text. Enter sends, Shift+Enter
|
|
942
|
+
* breaks the line; nothing goes while a reply is on its way or the socket is closed, but the
|
|
943
|
+
* person can keep writing. While the turn waits for them to act above, the box is closed and
|
|
944
|
+
* says so; while a reply is on its way, the send button is a stop button (Esc stops too). The
|
|
945
|
+
* host's `compose` is said from here, or put in the box. With `uploads`, the paperclip attaches
|
|
946
|
+
* files (a picture pasted too): they upload at once, as chips over the words, and go with them
|
|
947
|
+
* (or alone) once every one is in. With `write`, what is written goes to the host instead (a
|
|
948
|
+
* person of the business, on a channel): whatever the turn is doing, emptied once it went.
|
|
949
|
+
*/
|
|
950
|
+
function Composer({ live, name, words, classNames, actions, compose, taken, fresh, builder, uploads, files, dictate, write, onSent }) {
|
|
951
|
+
const [text, setText] = useState("");
|
|
952
|
+
const [writing, setWriting] = useState(false);
|
|
953
|
+
const input = useRef(null);
|
|
954
|
+
const picker = useRef(null);
|
|
955
|
+
const [placed, setPlaced] = useState(0);
|
|
956
|
+
const held = write === void 0 && live.awaiting !== null;
|
|
957
|
+
const dictation = useDictation(dictate, (words) => {
|
|
958
|
+
setText((now) => now.trim() === "" ? words : `${now.trimEnd()} ${words}`);
|
|
959
|
+
setPlaced((count) => count + 1);
|
|
960
|
+
});
|
|
961
|
+
const listening = dictation.state === "listening";
|
|
962
|
+
useEffect(() => {
|
|
963
|
+
if (compose === void 0 || taken.current === compose.key) return;
|
|
964
|
+
if (compose.send && !live.open) return;
|
|
965
|
+
taken.current = compose.key;
|
|
966
|
+
if (compose.send && live.say(compose.text)) {
|
|
967
|
+
onSent();
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
setText(compose.text);
|
|
971
|
+
setPlaced((count) => count + 1);
|
|
972
|
+
}, [
|
|
973
|
+
compose,
|
|
974
|
+
taken,
|
|
975
|
+
live,
|
|
976
|
+
onSent
|
|
977
|
+
]);
|
|
978
|
+
useLayoutEffect(() => {
|
|
979
|
+
const box = input.current;
|
|
980
|
+
if (placed === 0 || box === null) return;
|
|
981
|
+
box.focus();
|
|
982
|
+
box.setSelectionRange(box.value.length, box.value.length);
|
|
983
|
+
}, [placed]);
|
|
984
|
+
const attached = uploads?.ids ?? [];
|
|
985
|
+
const settled = uploads === void 0 || uploads.waiting === null;
|
|
986
|
+
const said = text.trim() !== "" || attached.length > 0;
|
|
987
|
+
const sent = () => {
|
|
988
|
+
setText("");
|
|
989
|
+
uploads?.clear();
|
|
990
|
+
onSent();
|
|
991
|
+
};
|
|
992
|
+
const submit = () => {
|
|
993
|
+
if (!settled) return;
|
|
994
|
+
if (write === void 0) {
|
|
995
|
+
if (live.say(text, attached)) sent();
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
if (writing || !said) return;
|
|
999
|
+
setWriting(true);
|
|
1000
|
+
write(text.trim(), attached).then(sent, () => void 0).finally(() => {
|
|
1001
|
+
setWriting(false);
|
|
1002
|
+
});
|
|
1003
|
+
};
|
|
1004
|
+
const onKeyDown = (event) => {
|
|
1005
|
+
if (event.key !== "Enter" || event.shiftKey || event.nativeEvent.isComposing) return;
|
|
1006
|
+
event.preventDefault();
|
|
1007
|
+
submit();
|
|
1008
|
+
};
|
|
1009
|
+
const ready = write === void 0 ? live.open && !live.pending && !held && settled && said : !writing && settled && said;
|
|
1010
|
+
const invitation = write === void 0 ? words.placeholder(name, fresh) : words.write;
|
|
1011
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
1012
|
+
onSubmit: (event) => {
|
|
1013
|
+
event.preventDefault();
|
|
1014
|
+
submit();
|
|
1015
|
+
},
|
|
1016
|
+
part: "composer",
|
|
1017
|
+
className: classes(classNames, "sc-chat__composer"),
|
|
1018
|
+
children: [
|
|
1019
|
+
uploads && uploads.items.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
1020
|
+
part: "files",
|
|
1021
|
+
className: classes(classNames, "sc-chat__files"),
|
|
1022
|
+
children: /* @__PURE__ */ jsx(UploadChips, {
|
|
1023
|
+
uploads,
|
|
1024
|
+
host: files
|
|
1025
|
+
})
|
|
1026
|
+
}),
|
|
1027
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
1028
|
+
ref: input,
|
|
1029
|
+
rows: 1,
|
|
1030
|
+
value: text,
|
|
1031
|
+
maxLength: 2e4,
|
|
1032
|
+
disabled: held,
|
|
1033
|
+
autoFocus: builder,
|
|
1034
|
+
"aria-label": invitation,
|
|
1035
|
+
placeholder: held ? words.awaiting : live.open || write !== void 0 ? invitation : words.connecting,
|
|
1036
|
+
onChange: (event) => {
|
|
1037
|
+
setText(event.target.value);
|
|
1038
|
+
},
|
|
1039
|
+
onKeyDown,
|
|
1040
|
+
part: "input",
|
|
1041
|
+
onPaste: (event) => {
|
|
1042
|
+
const pasted = [...event.clipboardData.files];
|
|
1043
|
+
if (!uploads || pasted.length === 0) return;
|
|
1044
|
+
if (event.clipboardData.getData("text/plain") !== "") return;
|
|
1045
|
+
event.preventDefault();
|
|
1046
|
+
uploads.add(pasted);
|
|
1047
|
+
},
|
|
1048
|
+
className: classes(classNames, "sc-chat__input")
|
|
1049
|
+
}),
|
|
1050
|
+
uploads && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
1051
|
+
type: "button",
|
|
1052
|
+
"aria-label": words.attach,
|
|
1053
|
+
title: words.attach,
|
|
1054
|
+
disabled: held,
|
|
1055
|
+
onClick: () => picker.current?.click(),
|
|
1056
|
+
part: "attach",
|
|
1057
|
+
className: classes(classNames, "sc-chat__attach"),
|
|
1058
|
+
children: /* @__PURE__ */ jsx(PaperclipIcon, { "aria-hidden": true })
|
|
1059
|
+
}), /* @__PURE__ */ jsx("input", {
|
|
1060
|
+
ref: picker,
|
|
1061
|
+
type: "file",
|
|
1062
|
+
multiple: true,
|
|
1063
|
+
hidden: true,
|
|
1064
|
+
tabIndex: -1,
|
|
1065
|
+
onChange: (event) => {
|
|
1066
|
+
uploads.add([...event.target.files ?? []]);
|
|
1067
|
+
event.target.value = "";
|
|
1068
|
+
}
|
|
1069
|
+
})] }),
|
|
1070
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1071
|
+
part: "actions",
|
|
1072
|
+
className: classes(classNames, "sc-chat__actions"),
|
|
1073
|
+
children: [
|
|
1074
|
+
dictation.available && /* @__PURE__ */ jsx("button", {
|
|
1075
|
+
type: "button",
|
|
1076
|
+
"aria-label": listening ? words.dictateStop : words.dictate,
|
|
1077
|
+
title: listening ? words.dictateStop : words.dictate,
|
|
1078
|
+
"aria-pressed": listening,
|
|
1079
|
+
"data-state": dictation.state,
|
|
1080
|
+
disabled: held || dictation.state === "writing",
|
|
1081
|
+
onClick: dictation.toggle,
|
|
1082
|
+
part: "dictate",
|
|
1083
|
+
className: classes(classNames, "sc-chat__dictate"),
|
|
1084
|
+
children: /* @__PURE__ */ jsx(MicrophoneIcon, {
|
|
1085
|
+
"aria-hidden": true,
|
|
1086
|
+
weight: listening ? "fill" : "regular"
|
|
1087
|
+
})
|
|
1088
|
+
}),
|
|
1089
|
+
dictation.state !== "idle" && /* @__PURE__ */ jsx("span", {
|
|
1090
|
+
role: "status",
|
|
1091
|
+
"data-state": dictation.state,
|
|
1092
|
+
className: classes(classNames, "sc-chat__dictation"),
|
|
1093
|
+
children: words.dictation[dictation.state]
|
|
1094
|
+
}),
|
|
1095
|
+
actions
|
|
1096
|
+
]
|
|
1097
|
+
}),
|
|
1098
|
+
live.pending && write === void 0 ? /* @__PURE__ */ jsx("button", {
|
|
1099
|
+
type: "button",
|
|
1100
|
+
"aria-label": words.stop,
|
|
1101
|
+
title: `${words.stop} (Esc)`,
|
|
1102
|
+
onClick: () => live.stop(),
|
|
1103
|
+
part: "stop",
|
|
1104
|
+
className: classes(classNames, "sc-chat__stop"),
|
|
1105
|
+
children: /* @__PURE__ */ jsx(StopIcon, {
|
|
1106
|
+
weight: "fill",
|
|
1107
|
+
"aria-hidden": true
|
|
1108
|
+
})
|
|
1109
|
+
}) : /* @__PURE__ */ jsx("button", {
|
|
1110
|
+
type: "submit",
|
|
1111
|
+
"aria-label": words.send,
|
|
1112
|
+
title: words.send,
|
|
1113
|
+
disabled: !ready,
|
|
1114
|
+
part: "send",
|
|
1115
|
+
className: classes(classNames, "sc-chat__send"),
|
|
1116
|
+
children: /* @__PURE__ */ jsx(ArrowUpIcon, {
|
|
1117
|
+
weight: "bold",
|
|
1118
|
+
"aria-hidden": true
|
|
1119
|
+
})
|
|
1120
|
+
})
|
|
1121
|
+
]
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
//#endregion
|
|
1125
|
+
export { AgentChat, CHAT_MESSAGES, decisionLine, handoffs, handoverBy, handoverLine, handoversAt, heardTail, shownState, whenSaid, workingOn };
|
|
1126
|
+
|
|
1127
|
+
//# sourceMappingURL=AgentChat.js.map
|