@talk2view/sdk 0.14.0 → 0.16.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 +336 -69
- package/dist/assistant-ui/convert.d.ts +40 -0
- package/dist/assistant-ui/convert.d.ts.map +1 -0
- package/dist/assistant-ui/convert.js +113 -0
- package/dist/assistant-ui/convert.js.map +1 -0
- package/dist/assistant-ui/dictation.d.ts +39 -0
- package/dist/assistant-ui/dictation.d.ts.map +1 -0
- package/dist/assistant-ui/dictation.js +128 -0
- package/dist/assistant-ui/dictation.js.map +1 -0
- package/dist/assistant-ui/index.d.ts +43 -0
- package/dist/assistant-ui/index.d.ts.map +1 -0
- package/dist/assistant-ui/index.js +227 -0
- package/dist/assistant-ui/index.js.map +1 -0
- package/dist/auth.d.ts +38 -3
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +101 -16
- package/dist/auth.js.map +1 -1
- package/dist/chat/auth-gate.d.ts +42 -0
- package/dist/chat/auth-gate.d.ts.map +1 -0
- package/dist/chat/auth-gate.js +93 -0
- package/dist/chat/auth-gate.js.map +1 -0
- package/dist/chat/chat.d.ts +36 -0
- package/dist/chat/chat.d.ts.map +1 -0
- package/dist/chat/chat.js +124 -0
- package/dist/chat/chat.js.map +1 -0
- package/dist/chat/composer-extras.d.ts +23 -0
- package/dist/chat/composer-extras.d.ts.map +1 -0
- package/dist/chat/composer-extras.js +48 -0
- package/dist/chat/composer-extras.js.map +1 -0
- package/dist/chat/hooks/use-attachment-src.d.ts +2 -0
- package/dist/chat/hooks/use-attachment-src.d.ts.map +1 -0
- package/dist/chat/hooks/use-attachment-src.js +38 -0
- package/dist/chat/hooks/use-attachment-src.js.map +1 -0
- package/dist/chat/hooks/use-copy-to-clipboard.d.ts +8 -0
- package/dist/chat/hooks/use-copy-to-clipboard.d.ts.map +1 -0
- package/dist/chat/hooks/use-copy-to-clipboard.js +16 -0
- package/dist/chat/hooks/use-copy-to-clipboard.js.map +1 -0
- package/dist/chat/index.d.ts +32 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +35 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/inject-styles.d.ts +2 -0
- package/dist/chat/inject-styles.d.ts.map +1 -0
- package/dist/chat/inject-styles.js +23 -0
- package/dist/chat/inject-styles.js.map +1 -0
- package/dist/chat/launcher.d.ts +37 -0
- package/dist/chat/launcher.d.ts.map +1 -0
- package/dist/chat/launcher.js +343 -0
- package/dist/chat/launcher.js.map +1 -0
- package/dist/chat/lib/cn.d.ts +19 -0
- package/dist/chat/lib/cn.d.ts.map +1 -0
- package/dist/chat/lib/cn.js +20 -0
- package/dist/chat/lib/cn.js.map +1 -0
- package/dist/chat/lib/dictation-phase.d.ts +9 -0
- package/dist/chat/lib/dictation-phase.d.ts.map +1 -0
- package/dist/chat/lib/dictation-phase.js +33 -0
- package/dist/chat/lib/dictation-phase.js.map +1 -0
- package/dist/chat/lib/guard.d.ts +4 -0
- package/dist/chat/lib/guard.d.ts.map +1 -0
- package/dist/chat/lib/guard.js +41 -0
- package/dist/chat/lib/guard.js.map +1 -0
- package/dist/chat/lib/launcher-variant.d.ts +33 -0
- package/dist/chat/lib/launcher-variant.d.ts.map +1 -0
- package/dist/chat/lib/launcher-variant.js +109 -0
- package/dist/chat/lib/launcher-variant.js.map +1 -0
- package/dist/chat/lib/portal-host.d.ts +13 -0
- package/dist/chat/lib/portal-host.d.ts.map +1 -0
- package/dist/chat/lib/portal-host.js +58 -0
- package/dist/chat/lib/portal-host.js.map +1 -0
- package/dist/chat/markdown.d.ts +32 -0
- package/dist/chat/markdown.d.ts.map +1 -0
- package/dist/chat/markdown.js +18 -0
- package/dist/chat/markdown.js.map +1 -0
- package/dist/chat/provider.d.ts +113 -0
- package/dist/chat/provider.d.ts.map +1 -0
- package/dist/chat/provider.js +176 -0
- package/dist/chat/provider.js.map +1 -0
- package/dist/chat/tool-fallback.d.ts +39 -0
- package/dist/chat/tool-fallback.d.ts.map +1 -0
- package/dist/chat/tool-fallback.js +167 -0
- package/dist/chat/tool-fallback.js.map +1 -0
- package/dist/chat/ui/avatar.d.ts +12 -0
- package/dist/chat/ui/avatar.d.ts.map +1 -0
- package/dist/chat/ui/avatar.js +24 -0
- package/dist/chat/ui/avatar.js.map +1 -0
- package/dist/chat/ui/button.d.ts +9 -0
- package/dist/chat/ui/button.d.ts.map +1 -0
- package/dist/chat/ui/button.js +35 -0
- package/dist/chat/ui/button.js.map +1 -0
- package/dist/chat/ui/collapsible.d.ts +6 -0
- package/dist/chat/ui/collapsible.d.ts.map +1 -0
- package/dist/chat/ui/collapsible.js +13 -0
- package/dist/chat/ui/collapsible.js.map +1 -0
- package/dist/chat/ui/dialog.d.ts +18 -0
- package/dist/chat/ui/dialog.d.ts.map +1 -0
- package/dist/chat/ui/dialog.js +42 -0
- package/dist/chat/ui/dialog.js.map +1 -0
- package/dist/chat/ui/input.d.ts +4 -0
- package/dist/chat/ui/input.d.ts.map +1 -0
- package/dist/chat/ui/input.js +8 -0
- package/dist/chat/ui/input.js.map +1 -0
- package/dist/chat/ui/skeleton.d.ts +3 -0
- package/dist/chat/ui/skeleton.d.ts.map +1 -0
- package/dist/chat/ui/skeleton.js +7 -0
- package/dist/chat/ui/skeleton.js.map +1 -0
- package/dist/chat/ui/textarea.d.ts +4 -0
- package/dist/chat/ui/textarea.d.ts.map +1 -0
- package/dist/chat/ui/textarea.js +7 -0
- package/dist/chat/ui/textarea.js.map +1 -0
- package/dist/chat/ui/tooltip.d.ts +7 -0
- package/dist/chat/ui/tooltip.d.ts.map +1 -0
- package/dist/chat/ui/tooltip.js +22 -0
- package/dist/chat/ui/tooltip.js.map +1 -0
- package/dist/chat/vendor/attachment.aui.d.ts +5 -0
- package/dist/chat/vendor/attachment.aui.d.ts.map +1 -0
- package/dist/chat/vendor/attachment.aui.js +79 -0
- package/dist/chat/vendor/attachment.aui.js.map +1 -0
- package/dist/chat/vendor/file.d.ts +41 -0
- package/dist/chat/vendor/file.d.ts.map +1 -0
- package/dist/chat/vendor/file.js +137 -0
- package/dist/chat/vendor/file.js.map +1 -0
- package/dist/chat/vendor/follow-up-suggestions.aui.d.ts +3 -0
- package/dist/chat/vendor/follow-up-suggestions.aui.d.ts.map +1 -0
- package/dist/chat/vendor/follow-up-suggestions.aui.js +45 -0
- package/dist/chat/vendor/follow-up-suggestions.aui.js.map +1 -0
- package/dist/chat/vendor/image.d.ts +47 -0
- package/dist/chat/vendor/image.d.ts.map +1 -0
- package/dist/chat/vendor/image.js +258 -0
- package/dist/chat/vendor/image.js.map +1 -0
- package/dist/chat/vendor/markdown-text.d.ts +8 -0
- package/dist/chat/vendor/markdown-text.d.ts.map +1 -0
- package/dist/chat/vendor/markdown-text.js +73 -0
- package/dist/chat/vendor/markdown-text.js.map +1 -0
- package/dist/chat/vendor/reasoning.aui.d.ts +22 -0
- package/dist/chat/vendor/reasoning.aui.d.ts.map +1 -0
- package/dist/chat/vendor/reasoning.aui.js +56 -0
- package/dist/chat/vendor/reasoning.aui.js.map +1 -0
- package/dist/chat/vendor/reasoning.d.ts +35 -0
- package/dist/chat/vendor/reasoning.d.ts.map +1 -0
- package/dist/chat/vendor/reasoning.js +112 -0
- package/dist/chat/vendor/reasoning.js.map +1 -0
- package/dist/chat/vendor/thread-list.aui.d.ts +37 -0
- package/dist/chat/vendor/thread-list.aui.d.ts.map +1 -0
- package/dist/chat/vendor/thread-list.aui.js +154 -0
- package/dist/chat/vendor/thread-list.aui.js.map +1 -0
- package/dist/chat/vendor/thread.aui.d.ts +47 -0
- package/dist/chat/vendor/thread.aui.d.ts.map +1 -0
- package/dist/chat/vendor/thread.aui.js +176 -0
- package/dist/chat/vendor/thread.aui.js.map +1 -0
- package/dist/chat/vendor/tool-fallback.aui.d.ts +39 -0
- package/dist/chat/vendor/tool-fallback.aui.d.ts.map +1 -0
- package/dist/chat/vendor/tool-fallback.aui.js +251 -0
- package/dist/chat/vendor/tool-fallback.aui.js.map +1 -0
- package/dist/chat/vendor/tool-group.aui.d.ts +34 -0
- package/dist/chat/vendor/tool-group.aui.d.ts.map +1 -0
- package/dist/chat/vendor/tool-group.aui.js +60 -0
- package/dist/chat/vendor/tool-group.aui.js.map +1 -0
- package/dist/chat/vendor/tooltip-icon-button.d.ts +8 -0
- package/dist/chat/vendor/tooltip-icon-button.d.ts.map +1 -0
- package/dist/chat/vendor/tooltip-icon-button.js +11 -0
- package/dist/chat/vendor/tooltip-icon-button.js.map +1 -0
- package/dist/chat/views/account.d.ts +6 -0
- package/dist/chat/views/account.d.ts.map +1 -0
- package/dist/chat/views/account.js +128 -0
- package/dist/chat/views/account.js.map +1 -0
- package/dist/chat/views/settings.d.ts +2 -0
- package/dist/chat/views/settings.d.ts.map +1 -0
- package/dist/chat/views/settings.js +104 -0
- package/dist/chat/views/settings.js.map +1 -0
- package/dist/chat/views/thread-list.d.ts +10 -0
- package/dist/chat/views/thread-list.d.ts.map +1 -0
- package/dist/chat/views/thread-list.js +21 -0
- package/dist/chat/views/thread-list.js.map +1 -0
- package/dist/chat/welcome.d.ts +10 -0
- package/dist/chat/welcome.d.ts.map +1 -0
- package/dist/chat/welcome.js +9 -0
- package/dist/chat/welcome.js.map +1 -0
- package/dist/chat-css.d.ts +1 -0
- package/dist/chat-css.js +1 -0
- package/dist/chat.css +2 -0
- package/dist/chat.isolated.css +3819 -0
- package/dist/chat.raw.css +3829 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -4
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +5 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +28 -6
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +68 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +236 -35
- package/dist/index.js.map +1 -1
- package/dist/react/T2VProvider.d.ts +2 -2
- package/dist/react/T2VProvider.d.ts.map +1 -1
- package/dist/react/T2VProvider.js +1 -1
- package/dist/react/T2VProvider.js.map +1 -1
- package/dist/react/index.d.ts +14 -14
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +7 -7
- package/dist/react/index.js.map +1 -1
- package/dist/react/usePartnerConfig.d.ts +1 -1
- package/dist/react/usePartnerConfig.d.ts.map +1 -1
- package/dist/react/usePartnerConfig.js +1 -1
- package/dist/react/usePartnerConfig.js.map +1 -1
- package/dist/react/useT2VAuth.d.ts +8 -1
- package/dist/react/useT2VAuth.d.ts.map +1 -1
- package/dist/react/useT2VAuth.js +25 -6
- package/dist/react/useT2VAuth.js.map +1 -1
- package/dist/react/useT2VChat.d.ts +3 -3
- package/dist/react/useT2VChat.d.ts.map +1 -1
- package/dist/react/useT2VChat.js +1 -1
- package/dist/react/useT2VChat.js.map +1 -1
- package/dist/react/useT2VTools.d.ts +1 -1
- package/dist/react/useT2VTools.d.ts.map +1 -1
- package/dist/react/useT2VTools.js +1 -1
- package/dist/react/useT2VTools.js.map +1 -1
- package/dist/react/useUserPreferences.d.ts +1 -1
- package/dist/react/useUserPreferences.d.ts.map +1 -1
- package/dist/react/useUserPreferences.js +1 -1
- package/dist/react/useUserPreferences.js.map +1 -1
- package/dist/sessions.d.ts +3 -3
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +6 -2
- package/dist/sessions.js.map +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/skills.d.ts.map +1 -1
- package/dist/streaming.d.ts +1 -1
- package/dist/streaming.d.ts.map +1 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/types.d.ts +119 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/components/ApprovalCard.d.ts +1 -1
- package/dist/ui/components/ApprovalCard.d.ts.map +1 -1
- package/dist/ui/components/ChatHeader.js +1 -1
- package/dist/ui/components/ChatHeader.js.map +1 -1
- package/dist/ui/components/ChatPanel.d.ts +1 -1
- package/dist/ui/components/ChatPanel.d.ts.map +1 -1
- package/dist/ui/components/ChatPanel.js +14 -13
- package/dist/ui/components/ChatPanel.js.map +1 -1
- package/dist/ui/components/ChatWidget.d.ts +1 -1
- package/dist/ui/components/ChatWidget.d.ts.map +1 -1
- package/dist/ui/components/ChatWidget.js +2 -2
- package/dist/ui/components/ChatWidget.js.map +1 -1
- package/dist/ui/components/Composer.d.ts.map +1 -1
- package/dist/ui/components/Composer.js +13 -6
- package/dist/ui/components/Composer.js.map +1 -1
- package/dist/ui/components/LoginForm.d.ts.map +1 -1
- package/dist/ui/components/LoginForm.js +19 -5
- package/dist/ui/components/LoginForm.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.d.ts +4 -0
- package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +7 -35
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageActions.js +1 -1
- package/dist/ui/components/MessageActions.js.map +1 -1
- package/dist/ui/components/MessageBubble.d.ts +1 -1
- package/dist/ui/components/MessageBubble.d.ts.map +1 -1
- package/dist/ui/components/MessageBubble.js +9 -9
- package/dist/ui/components/MessageBubble.js.map +1 -1
- package/dist/ui/components/MessageList.js +2 -2
- package/dist/ui/components/MessageList.js.map +1 -1
- package/dist/ui/components/SettingsPanel.js +4 -4
- package/dist/ui/components/SettingsPanel.js.map +1 -1
- package/dist/ui/components/Talk2View.d.ts +1 -1
- package/dist/ui/components/Talk2View.d.ts.map +1 -1
- package/dist/ui/components/Talk2View.js +16 -12
- package/dist/ui/components/Talk2View.js.map +1 -1
- package/dist/ui/components/ThinkingBlock.js +2 -2
- package/dist/ui/components/ThinkingBlock.js.map +1 -1
- package/dist/ui/components/WelcomeScreen.js +2 -2
- package/dist/ui/components/WelcomeScreen.js.map +1 -1
- package/dist/ui/context.d.ts +4 -2
- package/dist/ui/context.d.ts.map +1 -1
- package/dist/ui/context.js.map +1 -1
- package/dist/ui/index.d.ts +27 -26
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +21 -20
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/safeMarkdown.d.ts +17 -0
- package/dist/ui/safeMarkdown.d.ts.map +1 -0
- package/dist/ui/safeMarkdown.js +196 -0
- package/dist/ui/safeMarkdown.js.map +1 -0
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/utils.d.ts +1 -1
- package/dist/ui/utils.d.ts.map +1 -1
- package/package.json +64 -5
package/README.md
CHANGED
|
@@ -8,12 +8,51 @@ Add AI-powered natural language control to any application. Talk2View's SDK hand
|
|
|
8
8
|
npm install @talk2view/sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Chat UI
|
|
12
|
+
|
|
13
|
+
Three lines to a working chat. `@talk2view/sdk/chat` is the branded Talk2View
|
|
14
|
+
chat, packaged: your app needs no Tailwind, no PostCSS, no shadcn and no copied
|
|
15
|
+
component files.
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Talk2ViewChat } from '@talk2view/sdk/chat';
|
|
19
|
+
import '@talk2view/sdk/chat.css';
|
|
20
|
+
|
|
21
|
+
<Talk2ViewChat partnerKey="pk_live_…" tools={tools} welcome={{ suggestions: ['What can you do?'] }} />
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That is the full pane: sign-in, streaming replies, attachments, dictation,
|
|
25
|
+
Settings, earlier conversations and tool approvals. Give it a parent with a
|
|
26
|
+
height — it fills its box.
|
|
27
|
+
|
|
28
|
+
For a floating chat instead — a mark in the corner of the page, a popover on a
|
|
29
|
+
desktop, a full-screen sheet on a phone:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Talk2ViewChatLauncher } from '@talk2view/sdk/chat';
|
|
33
|
+
import '@talk2view/sdk/chat.css';
|
|
34
|
+
|
|
35
|
+
<Talk2ViewChatLauncher partnerKey="pk_live_…" tools={tools} label="Ask Talk2View" />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Theming is the custom properties on `.t2v-chat` (`--radius`, `--primary`, the
|
|
39
|
+
rest); dark mode is `className="dark"`. The chat fetches nothing at runtime — no
|
|
40
|
+
fonts, no CDN — and uses your page's font unless you pass `fontFamily`.
|
|
41
|
+
|
|
42
|
+
**It is large: 361.8 KB gzip, excluding React.** A consumer who never imports
|
|
43
|
+
`/chat` pays none of it.
|
|
44
|
+
|
|
45
|
+
Everything else — the full prop table, theming tokens, the launcher in a hostile
|
|
46
|
+
page, CSP, Next.js — is in **[`docs/chat.md`](docs/chat.md)**. A runnable
|
|
47
|
+
example with no Tailwind in the host is in
|
|
48
|
+
[`examples/react-chat`](examples/react-chat).
|
|
49
|
+
|
|
11
50
|
## Quick Start
|
|
12
51
|
|
|
13
52
|
### React (recommended)
|
|
14
53
|
|
|
15
54
|
```tsx
|
|
16
|
-
import {
|
|
55
|
+
import { Talk2View, ChatPanel } from '@talk2view/sdk/ui';
|
|
17
56
|
import type { ClientTool } from '@talk2view/sdk';
|
|
18
57
|
|
|
19
58
|
const tools: ClientTool[] = [
|
|
@@ -36,17 +75,26 @@ const tools: ClientTool[] = [
|
|
|
36
75
|
|
|
37
76
|
function App() {
|
|
38
77
|
return (
|
|
39
|
-
<
|
|
40
|
-
<ChatPanel
|
|
41
|
-
</
|
|
78
|
+
<Talk2View partnerKey="pk_live_..." tools={tools} systemPrompt="You control a canvas.">
|
|
79
|
+
<ChatPanel />
|
|
80
|
+
</Talk2View>
|
|
42
81
|
);
|
|
43
82
|
}
|
|
44
83
|
```
|
|
45
84
|
|
|
46
|
-
That's it.
|
|
85
|
+
That's it. `<Talk2View>` registers your tools and holds the chat state; `<ChatPanel>` is the UI — sign-in, streaming replies, tool calls and approvals. Both come from `@talk2view/sdk/ui`, and `<ChatPanel>` must be inside `<Talk2View>`.
|
|
86
|
+
|
|
87
|
+
> `/ui` is the previous chat panel, and is still supported. It is far smaller
|
|
88
|
+
> than the packaged chat (39.9 KB gzip against 361.8) and has no assistant-ui in
|
|
89
|
+
> it. New integrations that want the current Talk2View chat should use
|
|
90
|
+
> [`@talk2view/sdk/chat`](#chat-ui) above.
|
|
91
|
+
|
|
92
|
+
A logged-out visitor gets an anonymous demo session automatically, so there is nothing to wire up before the first reply. Pass `allowAnonymous={false}` to `<ChatPanel>` to ask people to sign in first.
|
|
47
93
|
|
|
48
94
|
### Vanilla JavaScript
|
|
49
95
|
|
|
96
|
+
The package root exports a `Talk2View` **class** — the framework-agnostic client. It shares a name with the `<Talk2View>` provider component from `/ui` above; if you need both in one file, alias one of them.
|
|
97
|
+
|
|
50
98
|
```typescript
|
|
51
99
|
import { Talk2View } from '@talk2view/sdk';
|
|
52
100
|
|
|
@@ -69,9 +117,10 @@ await t2v.tools.register([
|
|
|
69
117
|
]);
|
|
70
118
|
|
|
71
119
|
// 3. Chat — tool calls are handled automatically
|
|
120
|
+
let reply = '';
|
|
72
121
|
for await (const event of t2v.chat('What time is it?')) {
|
|
73
|
-
if (event.type === 'text')
|
|
74
|
-
if (event.type === 'done') console.log(
|
|
122
|
+
if (event.type === 'text') reply += event.content;
|
|
123
|
+
if (event.type === 'done') console.log(reply);
|
|
75
124
|
}
|
|
76
125
|
```
|
|
77
126
|
|
|
@@ -124,49 +173,79 @@ Tools with `return_direct: true` skip the AI's post-processing step. The tool re
|
|
|
124
173
|
|
|
125
174
|
## React API
|
|
126
175
|
|
|
127
|
-
|
|
176
|
+
There are four React entry points, and they do different jobs:
|
|
128
177
|
|
|
129
|
-
|
|
178
|
+
- **`@talk2view/sdk/chat`** — the branded Talk2View chat, packaged: `<Talk2ViewChat>` and `<Talk2ViewChatLauncher>`, one stylesheet, nothing to configure. Start here. See [Chat UI](#chat-ui) above and [`docs/chat.md`](docs/chat.md).
|
|
179
|
+
- **`@talk2view/sdk/ui`** — the previous chat panel, still supported: `<Talk2View>`, `<ChatPanel>`, `<ChatWidget>` and the components they are built from. 39.9 KB gzip against the packaged chat's 361.8, and no assistant-ui.
|
|
180
|
+
- **`@talk2view/sdk/react`** — headless: `<T2VProvider>` and hooks, for building your own UI.
|
|
181
|
+
- **`@talk2view/sdk/assistant-ui`** — a runtime for [assistant-ui](https://www.assistant-ui.com): render the stock `<Thread />` on Talk2View. See [assistant-ui](#assistant-ui) below.
|
|
182
|
+
|
|
183
|
+
### `<Talk2View>` (from `/ui`)
|
|
184
|
+
|
|
185
|
+
The root provider for the UI components. It creates the client, registers your tools, injects the theme, and holds the chat state every `/ui` component reads.
|
|
130
186
|
|
|
131
187
|
```tsx
|
|
132
|
-
<
|
|
133
|
-
partnerKey="pk_live_..."
|
|
134
|
-
|
|
135
|
-
|
|
188
|
+
<Talk2View
|
|
189
|
+
partnerKey="pk_live_..." // Required
|
|
190
|
+
tools={myTools} // Optional — ClientTool[] (with execute) or schemas
|
|
191
|
+
systemPrompt="You are..." // Optional — sent with every message
|
|
192
|
+
baseUrl="https://engine.talk2view.com" // Optional, this is the default
|
|
193
|
+
model="gpt-4.1-mini" // Optional, falls back to your partner default
|
|
194
|
+
theme={{ accent: '#26C8B8' }} // Optional
|
|
195
|
+
debug={false} // Optional — log to the browser console
|
|
136
196
|
>
|
|
137
197
|
{children}
|
|
138
|
-
</
|
|
198
|
+
</Talk2View>
|
|
139
199
|
```
|
|
140
200
|
|
|
141
|
-
### `<ChatPanel>`
|
|
201
|
+
### `<ChatPanel>` (from `/ui`)
|
|
142
202
|
|
|
143
|
-
|
|
203
|
+
The full chat surface: header, message list, composer, sign-in, tool approvals. It takes its client and state from `<Talk2View>`, so it must be rendered inside one — on its own it throws `useTalk2View must be used within <Talk2View>`. Note that `tools` and `systemPrompt` belong on `<Talk2View>`, not here.
|
|
144
204
|
|
|
145
205
|
```tsx
|
|
146
206
|
<ChatPanel
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
signupUrl="https://..."
|
|
150
|
-
|
|
151
|
-
|
|
207
|
+
welcome={{ heading: 'Ask about this document', suggestions: ['Summarise it'] }}
|
|
208
|
+
allowAnonymous={true} // Default. false = require sign-in before chatting
|
|
209
|
+
signupUrl="https://..." // Link shown on the sign-in form
|
|
210
|
+
resetPasswordUrl="https://..." // Adds a "Forgot password?" link
|
|
211
|
+
resetPasswordTarget="_blank" // Default. '_self' opens in your own app
|
|
212
|
+
describeToolActivity={(name, args) => (name === 'set_color' ? 'Recolouring' : null)}
|
|
213
|
+
isToolDestructive={(name) => name.startsWith('delete_')}
|
|
214
|
+
groupAssistantMessages={false}
|
|
152
215
|
/>
|
|
153
216
|
```
|
|
154
217
|
|
|
155
|
-
|
|
218
|
+
By default a logged-out visitor is signed into an anonymous demo session rather than being shown a login form. The sign-in form appears when `allowAnonymous` is `false`, when your partner account has anonymous access switched off or its daily cap is spent, or when the demo budget for that visitor runs out.
|
|
156
219
|
|
|
157
|
-
### `<
|
|
220
|
+
### `<LoginForm>` (from `/ui`)
|
|
158
221
|
|
|
159
|
-
|
|
222
|
+
The sign-in form on its own, if you want to place it yourself. It renders unconditionally — you decide when to show it (check `isAuthenticated` from `useTalk2View()`, the `/ui` hook).
|
|
160
223
|
|
|
161
224
|
```tsx
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
225
|
+
<LoginForm
|
|
226
|
+
heading="Sign in"
|
|
227
|
+
subheading="to keep your chat history"
|
|
228
|
+
defaultMode="login" // or 'signup'
|
|
229
|
+
signupUrl="https://talk2view.com/auth?signup"
|
|
230
|
+
resetPasswordUrl="https://..."
|
|
231
|
+
termsUrl="https://..."
|
|
232
|
+
privacyUrl="https://..."
|
|
166
233
|
/>
|
|
167
234
|
```
|
|
168
235
|
|
|
169
|
-
|
|
236
|
+
### `<T2VProvider>` (from `/react`)
|
|
237
|
+
|
|
238
|
+
The headless provider. Use it when you are building your own UI on the hooks below; `<Talk2View>` already includes it, so you never need both.
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
<T2VProvider
|
|
242
|
+
partnerKey="pk_live_..." // Required
|
|
243
|
+
baseUrl="https://engine.talk2view.com" // Optional, this is the default
|
|
244
|
+
model="gpt-4.1-mini" // Optional, uses your partner default
|
|
245
|
+
>
|
|
246
|
+
{children}
|
|
247
|
+
</T2VProvider>
|
|
248
|
+
```
|
|
170
249
|
|
|
171
250
|
### `useT2V()`
|
|
172
251
|
|
|
@@ -187,30 +266,45 @@ const {
|
|
|
187
266
|
isLoading, // boolean
|
|
188
267
|
error, // string | null
|
|
189
268
|
login, // (email: string, password: string) => Promise<void>
|
|
190
|
-
signup, // (email
|
|
269
|
+
signup, // (email, password) => Promise<{ user, confirmationRequired }>
|
|
191
270
|
logout, // () => Promise<void>
|
|
192
271
|
clearError, // () => void
|
|
272
|
+
signInWithGoogle, // () => Promise<void> — opens the Google sign-in popup
|
|
273
|
+
signInWithApple, // () => Promise<void> — opens the Apple sign-in popup
|
|
274
|
+
oauthLoading, // boolean — true while either popup is open
|
|
275
|
+
oauthProvider, // 'google' | 'apple' | null — which one
|
|
276
|
+
oauthProviders, // ('google' | 'apple')[] | null — popup sign-ins available on this website; null while loading
|
|
193
277
|
} = useT2VAuth();
|
|
194
278
|
```
|
|
195
279
|
|
|
280
|
+
`signup()` resolves to a `SignupOutcome`: `{ user: User | null; confirmationRequired: boolean }`. When your project has email confirmation switched on, `confirmationRequired` is `true` and `user` is `null` until the person clicks the link in their inbox.
|
|
281
|
+
|
|
282
|
+
Google and Apple sign-in open a popup and work on any `https://` website, with nothing to configure — your users have Talk2View accounts, and the sign-in form is the same in every app. Your publishable key is public, though, so on a website you have **not** registered your users first see a Talk2View screen naming the site that is asking, and press Continue. Add your site under **Settings → Allowed websites** in the dashboard (the exact `https://` address, nothing after the domain) and that screen goes away; the SDK logs one line to the console when it applies. If your account is set to allow only registered websites, `<LoginForm>` hides the two buttons elsewhere. Popup sign-in never runs on `localhost`; use email and password while developing.
|
|
283
|
+
|
|
196
284
|
### `useT2VChat()`
|
|
197
285
|
|
|
198
286
|
Chat state and message sending.
|
|
199
287
|
|
|
200
288
|
```tsx
|
|
201
289
|
const {
|
|
202
|
-
messages,
|
|
203
|
-
isLoading,
|
|
204
|
-
error,
|
|
205
|
-
threadId,
|
|
206
|
-
agentStatus,
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
290
|
+
messages, // DisplayMessage[]
|
|
291
|
+
isLoading, // boolean — true while streaming
|
|
292
|
+
error, // string | null
|
|
293
|
+
threadId, // string | null
|
|
294
|
+
agentStatus, // { status: string; message: string } | null
|
|
295
|
+
pendingApproval, // PendingApproval | null — a tool call awaiting a decision
|
|
296
|
+
alwaysAllowedTools, // ReadonlySet<string> — approved for the rest of the session
|
|
297
|
+
sendMessage, // (content, { attachments? }) => Promise<void>
|
|
298
|
+
approveToolCall, // (decision: HumanDecision) => Promise<void>
|
|
299
|
+
retryLastMessage, // () => Promise<void> — only meaningful while error is set
|
|
300
|
+
stop, // () => void — ends the reply, keeps the text so far
|
|
301
|
+
clearMessages, // () => void
|
|
302
|
+
clearError, // () => void
|
|
211
303
|
} = useT2VChat({ systemPrompt: 'You are a helpful assistant.' });
|
|
212
304
|
```
|
|
213
305
|
|
|
306
|
+
When a tool is registered with `permission: true`, the agent pauses and `pendingApproval` fills in. Show it, then call `approveToolCall({ action: 'once' | 'always' | 'deny' })` — `'always'` adds the tool to `alwaysAllowedTools` for the rest of the session. `<ChatPanel>` already does all of this; you only need it when building your own UI.
|
|
307
|
+
|
|
214
308
|
`DisplayMessage` shape:
|
|
215
309
|
```typescript
|
|
216
310
|
{
|
|
@@ -218,7 +312,10 @@ const {
|
|
|
218
312
|
role: 'user' | 'assistant'
|
|
219
313
|
content: string
|
|
220
314
|
timestamp: Date
|
|
221
|
-
isStreaming?: boolean
|
|
315
|
+
isStreaming?: boolean // true while the assistant is still generating
|
|
316
|
+
attachments?: Attachment[] // files sent with a user message
|
|
317
|
+
plan?: string // markdown checklist from the agent's planning tool
|
|
318
|
+
steps?: ToolStep[] // completed tool calls, rendered as inline steps
|
|
222
319
|
}
|
|
223
320
|
```
|
|
224
321
|
|
|
@@ -236,6 +333,86 @@ const {
|
|
|
236
333
|
|
|
237
334
|
---
|
|
238
335
|
|
|
336
|
+
## assistant-ui
|
|
337
|
+
|
|
338
|
+
assistant-ui already has a seam other backends plug into at the runtime level — `@assistant-ui/react-ai-sdk` for the Vercel AI SDK is the well-known example. `useTalk2ViewRuntime` is Talk2View's equivalent: it hands assistant-ui an `AssistantRuntime`, built on `useExternalStoreRuntime`, so the stock `<Thread />` (or the primitives) render Talk2View's messages, client tools, approvals and streaming — with no Talk2View-specific component in the tree.
|
|
339
|
+
|
|
340
|
+
This is a separate entry point from `/ui` and `/react`: `@assistant-ui/react` is an optional peer dependency, loaded only when you import `@talk2view/sdk/assistant-ui`. It never affects the root, `/react` or `/ui` bundles.
|
|
341
|
+
|
|
342
|
+
### Install
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
npm install @assistant-ui/react
|
|
346
|
+
npx shadcn@latest init --yes --defaults
|
|
347
|
+
npx shadcn@latest add @assistant-ui/thread --yes
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The `shadcn` commands generate the Thread's source into your own `src/components/` — they're your files, not a Talk2View package, so you can restyle or extend them freely. See `examples/react-assistant-ui` for a full app built this way, including the exact generated output.
|
|
351
|
+
|
|
352
|
+
One known wrinkle in the registry output at the time of writing: `tooltip-icon-button.tsx` passes `delayDuration={0}` to a `TooltipProvider` whose prop is `delay`. It is inert at runtime, but it fails `tsc`, so if your build type-checks (most Vite templates run `tsc -b && vite build`) change it to `delay={0}` — the example does.
|
|
353
|
+
|
|
354
|
+
### `useTalk2ViewRuntime`
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
import { AssistantRuntimeProvider } from '@assistant-ui/react';
|
|
358
|
+
import { useTalk2ViewRuntime } from '@talk2view/sdk/assistant-ui';
|
|
359
|
+
|
|
360
|
+
function Chat() {
|
|
361
|
+
const runtime = useTalk2ViewRuntime({ partnerKey: 'pk_live_...', tools });
|
|
362
|
+
return (
|
|
363
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
364
|
+
<Thread />
|
|
365
|
+
</AssistantRuntimeProvider>
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`useTalk2ViewRuntime(options)` takes the same connection options as `<T2VProvider>` (`partnerKey`, `baseUrl`, `model`, `debug`, `anonymousAutoStart`) plus `tools` and `systemPrompt`, and creates its own `Talk2View` client — a new one only when `partnerKey`, `baseUrl`, `debug` or `anonymousAutoStart` changes (`requestTimeout` is read once, at creation). `model` is sent with each message rather than baked into the client, so an end-user can switch models from a settings screen without losing the chat. `tools` are registered with the engine when their schemas change, compared by value, so an inline array is fine.
|
|
371
|
+
|
|
372
|
+
### `useTalk2ViewRuntimeForClient`
|
|
373
|
+
|
|
374
|
+
For an app that already has a `Talk2View` client — for example from `<T2VProvider>`, so auth and chat state stay shared with the rest of the app — pass it in instead of creating a second one:
|
|
375
|
+
|
|
376
|
+
```tsx
|
|
377
|
+
import { AssistantRuntimeProvider } from '@assistant-ui/react';
|
|
378
|
+
import { useT2V } from '@talk2view/sdk/react';
|
|
379
|
+
import { useTalk2ViewRuntimeForClient } from '@talk2view/sdk/assistant-ui';
|
|
380
|
+
|
|
381
|
+
function Chat() {
|
|
382
|
+
const { t2v } = useT2V(); // from <T2VProvider>
|
|
383
|
+
const runtime = useTalk2ViewRuntimeForClient(t2v, { tools });
|
|
384
|
+
return (
|
|
385
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
386
|
+
<Thread />
|
|
387
|
+
</AssistantRuntimeProvider>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### What maps to what
|
|
393
|
+
|
|
394
|
+
| assistant-ui | Talk2View SDK |
|
|
395
|
+
| --- | --- |
|
|
396
|
+
| Streaming replies | `DisplayMessage`s from `t2v.messages`, converted per-message by `toThreadMessage()` |
|
|
397
|
+
| Client tools | `tools` registers schemas via `t2v.tools.register()` and handlers via `t2v.tools.handle()` — same as `<Talk2View tools>` |
|
|
398
|
+
| Tool approvals | A `PendingApproval` becomes assistant-ui's own approval card (`allow-once` / `allow-always` / `reject-once`, plus a free-form reason); the decision is sent through `t2v.approveToolCall()` |
|
|
399
|
+
| Attachments | assistant-ui's `AttachmentAdapter` uploads through `t2v.uploadAttachment()` |
|
|
400
|
+
| Stop | assistant-ui's cancel action calls `t2v.stop()` — or, while a tool call is waiting for a decision, denies it with the reason "Cancelled by the user" |
|
|
401
|
+
| Retry | assistant-ui's reload action on the **latest turn** — its reply, or the error card when it failed — calls `t2v.retryLastMessage()`; on an older reply it does nothing, because the SDK can only regenerate the last turn |
|
|
402
|
+
|
|
403
|
+
Four things do not map, on purpose:
|
|
404
|
+
|
|
405
|
+
- **Editing tool arguments before approval.** The SDK supports it (`HumanDecision.updatedInput`, used by `<ApprovalCard>` in `/ui`), but the stock assistant-ui approval card has no edit-and-resubmit affordance to drive it from — it can only approve, deny, or attach a free-form reason.
|
|
406
|
+
- **Sign-in UI.** `useTalk2ViewRuntime` only creates a client and a runtime; there is no `<LoginForm>` equivalent. A logged-out visitor gets an anonymous demo session automatically (same default as `<ChatPanel>`), and building your own sign-in UI, or gating the app before it mounts, is on the partner.
|
|
407
|
+
- **The agent's plan.** The planning checklist `<ChatPanel>` shows arrives as a `data` part named `plan` (`{ markdown }`). The stock Thread has no renderer for it, so it is silently not shown; register one to see it: `<MessagePrimitive.Parts components={{ data: { by_name: { plan: PlanView } } }} />`.
|
|
408
|
+
- **Editing and deleting sent messages.** The runtime supplies no `onEdit`/`onDelete`, so the stock Thread's pencil on user messages stays disabled. Remove it from your copy of the Thread if you'd rather not show it.
|
|
409
|
+
|
|
410
|
+
### Bundle size
|
|
411
|
+
|
|
412
|
+
`<Thread />` and its dependencies are the partner's own assistant-ui bundle, sized however assistant-ui and its registry components size it; `@talk2view/sdk/assistant-ui` itself adds about 1.9 KB gzipped on top (`dist/assistant-ui/{index,convert}.js`, bundled and minified with esbuild, `react`, `react-dom`, `@assistant-ui/react` and the SDK's own `Talk2View` client marked external since a partner already has them).
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
239
416
|
## Core API (framework-agnostic)
|
|
240
417
|
|
|
241
418
|
### `Talk2View`
|
|
@@ -245,7 +422,7 @@ Main entry point. Use this directly for vanilla JS or non-React frameworks.
|
|
|
245
422
|
```typescript
|
|
246
423
|
const t2v = new Talk2View({
|
|
247
424
|
partnerKey: 'pk_live_...', // Required
|
|
248
|
-
baseUrl: 'https://
|
|
425
|
+
baseUrl: 'https://engine.talk2view.com', // Optional, this is the default
|
|
249
426
|
model: 'gpt-4.1-mini', // Optional
|
|
250
427
|
});
|
|
251
428
|
```
|
|
@@ -254,7 +431,7 @@ const t2v = new Talk2View({
|
|
|
254
431
|
|
|
255
432
|
```typescript
|
|
256
433
|
await t2v.auth.login(email, password) // Returns User
|
|
257
|
-
await t2v.auth.signup(email, password) // Returns
|
|
434
|
+
await t2v.auth.signup(email, password) // Returns { user, confirmationRequired }
|
|
258
435
|
await t2v.auth.logout()
|
|
259
436
|
t2v.auth.getUser() // Returns User | null
|
|
260
437
|
t2v.auth.isAuthenticated() // Returns boolean
|
|
@@ -358,6 +535,24 @@ for await (const event of t2v.chat('Zoom in please')) {
|
|
|
358
535
|
}
|
|
359
536
|
```
|
|
360
537
|
|
|
538
|
+
#### `t2v.warmUp()`
|
|
539
|
+
|
|
540
|
+
A new end-user's first AI call is slower than the rest: the engine sets up their
|
|
541
|
+
account with the model proxy on first use, which takes a few seconds. Call
|
|
542
|
+
`warmUp()` at the first sign they are going to use the chat — their first
|
|
543
|
+
keystroke, a tap on the mic — and that setup happens while they are still typing.
|
|
544
|
+
|
|
545
|
+
```ts
|
|
546
|
+
input.addEventListener('input', () => t2v.warmUp(), { once: true });
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
It is safe to call repeatedly (one request per signed-in end-user), never
|
|
550
|
+
throws, and is a no-op against an engine that predates it. Don't call it when
|
|
551
|
+
the chat merely opens: for a logged-out visitor it starts an anonymous session,
|
|
552
|
+
which counts toward your daily anonymous cap.
|
|
553
|
+
|
|
554
|
+
`<ChatWidget>`, `<ChatPanel>` and the assistant-ui runtime already do this.
|
|
555
|
+
|
|
361
556
|
#### `t2v.clearSession()`
|
|
362
557
|
|
|
363
558
|
Reset the current session. Clears the thread ID so the next `chat()` call starts a fresh conversation.
|
|
@@ -379,8 +574,15 @@ const audioModels = await t2v.listAudioModels(); // Speech-to-text models
|
|
|
379
574
|
|
|
380
575
|
Transcribe an audio file using the server's speech-to-text service:
|
|
381
576
|
|
|
577
|
+
Takes a `FormData`, with the fields the engine's `/v1/audio/transcriptions` endpoint accepts (`file`, `model`, and optionally `language`, `translate_to`, `translation_guidance`):
|
|
578
|
+
|
|
382
579
|
```typescript
|
|
383
|
-
const
|
|
580
|
+
const form = new FormData();
|
|
581
|
+
form.append('file', audioBlob, 'recording.webm');
|
|
582
|
+
form.append('model', 'faster-whisper-large-turbo-gcp'); // one of listAudioModels()
|
|
583
|
+
form.append('language', 'en'); // optional
|
|
584
|
+
|
|
585
|
+
const result = await t2v.transcribe(form);
|
|
384
586
|
console.log(result.text);
|
|
385
587
|
```
|
|
386
588
|
|
|
@@ -492,7 +694,7 @@ Use `enum` to restrict string values:
|
|
|
492
694
|
The `execute` function receives the AI's arguments as a `Record<string, unknown>` and must return a `Promise<string>`. The returned string is sent back to the AI as the tool's result.
|
|
493
695
|
|
|
494
696
|
- Return `JSON.stringify(...)` for structured results
|
|
495
|
-
- Throw an error or return an error string if the tool fails — the SDK catches
|
|
697
|
+
- Throw an error or return an error string if the tool fails — the SDK catches it and sends the message back to the AI as `{ result: '{"error":"..."}', is_error: true }`, so the agent can explain or try something else
|
|
496
698
|
|
|
497
699
|
---
|
|
498
700
|
|
|
@@ -523,22 +725,62 @@ To mitigate this:
|
|
|
523
725
|
|
|
524
726
|
---
|
|
525
727
|
|
|
728
|
+
## Rendering model replies
|
|
729
|
+
|
|
730
|
+
Treat every model reply as untrusted. Prompt injection through web search, documents, email or tool results can make the model write anything. `<ChatPanel>` renders replies as markdown only, and never loads remote content on its own:
|
|
731
|
+
|
|
732
|
+
- **Raw HTML** in a reply is shown as text, apart from a bare `<br>`, which is kept so a GFM table cell can break a line (a cell can't hold a literal newline).
|
|
733
|
+
- **Images** become links (`Image: <alt> (<host>)`) that the end-user can choose to open.
|
|
734
|
+
- **Links** open in a new tab with `noopener noreferrer`, and only `http(s)` and `mailto` link destinations are kept.
|
|
735
|
+
|
|
736
|
+
If you build your own chat UI, render replies the same way:
|
|
737
|
+
|
|
738
|
+
```tsx
|
|
739
|
+
import { renderSafeMarkdown } from '@talk2view/sdk/ui';
|
|
740
|
+
|
|
741
|
+
<div dangerouslySetInnerHTML={{ __html: renderSafeMarkdown(reply) }} />
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
Never pass model output to `innerHTML` or a markdown library's raw HTML output without it.
|
|
745
|
+
|
|
746
|
+
Call it in the browser (client components): without a DOM it returns the reply as escaped plain text.
|
|
747
|
+
|
|
748
|
+
## Chat sessions and deploys
|
|
749
|
+
|
|
750
|
+
A chat session lives in the engine's memory, so a Talk2View deploy, a restart, or eviction under load can end it. The SDK handles most of that for you:
|
|
751
|
+
|
|
752
|
+
- **Sending a message:** if the session is gone before the reply has started, the SDK opens a new one, re-registers your tools and resends the turn with the conversation so far — nothing from that turn is lost. It emits `sessionRecovered` with the new session id, which you can log.
|
|
753
|
+
- **Answering an approval:** the SDK can't safely resend the tool result, because your handler has already run. It emits one `error` event with `errorType: 'session_lost'` and clears the pending approval, so the end-user can send their message again.
|
|
754
|
+
- **Mid-reply or mid-tool-resume:** if the chat session is lost after the reply has started, or while a tool result is being sent back, the SDK reports `session_lost` and doesn't resend, because the tool handler may already have run.
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
t2v.on('sessionRecovered', (sessionId) => console.info('reconnected', sessionId));
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
This is why `sendMessage()` and `chat()` take the conversation history: the engine works out which messages are new, so a fresh session continues where the old one stopped.
|
|
761
|
+
|
|
526
762
|
## Error Handling
|
|
527
763
|
|
|
528
764
|
The SDK throws typed errors:
|
|
529
765
|
|
|
530
|
-
| Error Class | When |
|
|
531
|
-
|
|
532
|
-
| `AuthenticationError` |
|
|
533
|
-
| `PartnerKeyError` |
|
|
534
|
-
| `
|
|
535
|
-
| `
|
|
536
|
-
| `
|
|
766
|
+
| Error Class | When | `err.type` |
|
|
767
|
+
|-------------|------|------------|
|
|
768
|
+
| `AuthenticationError` | Bad credentials, expired or rejected token | `authentication_error` |
|
|
769
|
+
| `PartnerKeyError` | Unknown or inactive partner key | `partner_key_error` |
|
|
770
|
+
| `NetworkError` | Network failure, server unreachable, request timed out | `network_error` |
|
|
771
|
+
| `T2VError` | Base class — and what everything else arrives as | the engine's own type |
|
|
772
|
+
| `SessionError` | Reserved — see below | `session_not_found` |
|
|
773
|
+
|
|
774
|
+
Every error carries the engine's machine-readable `type`, so `err.type` is the precise test; the classes above are a convenience for the common cases. Types worth knowing that arrive as a plain `T2VError`: `origin_not_allowed` (403 — the request's Origin isn't on your key's allow-list), `not_found` (404), and `rate_limit_exceeded` (429).
|
|
537
775
|
|
|
538
|
-
|
|
776
|
+
Some failures never reach a `catch` at all, because they arrive inside the chat stream rather than as a rejected request: a spent anonymous demo budget comes through as an `error` event with `errorType: 'budget_exceeded'`, which the SDK turns into a `demoLimitReached` event rather than an error state. Listen for that instead of trying to catch it.
|
|
777
|
+
|
|
778
|
+
**On lost chat sessions:** `SessionError` is reserved for a dedicated engine type that isn't in use yet — today a chat session that no longer exists comes back as a `T2VError` with `type: 'not_found'` and `statusCode: 404`. You shouldn't need to catch it: the SDK recovers the session itself where that is safe, and otherwise reports an `error` event with `errorType: 'session_lost'`. See [Chat sessions and deploys](#chat-sessions-and-deploys).
|
|
779
|
+
|
|
780
|
+
All errors extend `T2VError`, which exposes `message`, `type`, `statusCode`, `code`, and `detail` (the server's raw diagnostic text, kept out of `message` so it never reaches an end-user by accident):
|
|
539
781
|
|
|
540
782
|
```typescript
|
|
541
|
-
import { T2VError, AuthenticationError, NetworkError,
|
|
783
|
+
import { T2VError, AuthenticationError, NetworkError, PartnerKeyError } from '@talk2view/sdk';
|
|
542
784
|
|
|
543
785
|
try {
|
|
544
786
|
await t2v.auth.login(email, password);
|
|
@@ -547,8 +789,8 @@ try {
|
|
|
547
789
|
console.log('Bad credentials');
|
|
548
790
|
} else if (err instanceof NetworkError) {
|
|
549
791
|
console.log('Server unreachable');
|
|
550
|
-
} else if (err instanceof
|
|
551
|
-
console.log('
|
|
792
|
+
} else if (err instanceof PartnerKeyError) {
|
|
793
|
+
console.log('Check your partner key:', err.message);
|
|
552
794
|
} else if (err instanceof T2VError) {
|
|
553
795
|
// Access the error code for programmatic handling
|
|
554
796
|
console.log(`Error [${err.code}]: ${err.message} (HTTP ${err.statusCode})`);
|
|
@@ -575,18 +817,25 @@ const { error: chatError } = useT2VChat({ systemPrompt: '...' });
|
|
|
575
817
|
| Property | Type | Required | Default | Description |
|
|
576
818
|
|----------|------|----------|---------|-------------|
|
|
577
819
|
| `partnerKey` | `string` | Yes | — | Your partner API key |
|
|
578
|
-
| `baseUrl` | `string` | No | `'
|
|
820
|
+
| `baseUrl` | `string` | No | `'https://engine.talk2view.com'` | Talk2View engine URL |
|
|
579
821
|
| `model` | `string` | No | Server default | LLM model to use |
|
|
580
822
|
| `requestTimeout` | `number` | No | `30000` | HTTP request timeout in ms. Does not apply to SSE streams after connection. |
|
|
823
|
+
| `anonymousAutoStart` | `boolean` | No | `true` | Start an anonymous demo session on the first `chat()` when nobody is signed in. Set `false` to require sign-in. |
|
|
824
|
+
| `debug` | `boolean` | No | `false` | Log streaming events, tool calls, history and state changes to the console. |
|
|
581
825
|
|
|
582
826
|
---
|
|
583
827
|
|
|
584
828
|
## System Prompts
|
|
585
829
|
|
|
586
|
-
System prompts set the AI's behavior and context for your application. Pass
|
|
830
|
+
System prompts set the AI's behavior and context for your application. Pass one to `<Talk2View>` (the UI components) or to `useT2VChat` (the hooks):
|
|
587
831
|
|
|
588
832
|
```tsx
|
|
589
|
-
<
|
|
833
|
+
<Talk2View
|
|
834
|
+
partnerKey="pk_live_..."
|
|
835
|
+
systemPrompt="You are a medical imaging assistant. Use the provided tools to control the DICOM viewer."
|
|
836
|
+
>
|
|
837
|
+
<ChatPanel />
|
|
838
|
+
</Talk2View>
|
|
590
839
|
```
|
|
591
840
|
|
|
592
841
|
Best practices:
|
|
@@ -603,7 +852,7 @@ Here's a complete example integrating Talk2View into a hypothetical drawing app:
|
|
|
603
852
|
|
|
604
853
|
```tsx
|
|
605
854
|
import React, { useRef, useMemo } from 'react';
|
|
606
|
-
import {
|
|
855
|
+
import { Talk2View, ChatPanel } from '@talk2view/sdk/ui';
|
|
607
856
|
import type { ClientTool } from '@talk2view/sdk';
|
|
608
857
|
import { Canvas } from './Canvas';
|
|
609
858
|
|
|
@@ -656,16 +905,18 @@ function App() {
|
|
|
656
905
|
], []);
|
|
657
906
|
|
|
658
907
|
return (
|
|
659
|
-
<
|
|
908
|
+
<Talk2View
|
|
909
|
+
partnerKey="pk_live_..."
|
|
910
|
+
tools={tools}
|
|
911
|
+
systemPrompt="You control a drawing canvas. Use the tools to draw shapes and manage the canvas."
|
|
912
|
+
>
|
|
660
913
|
<div style={{ display: 'flex', height: '100vh' }}>
|
|
661
914
|
<Canvas ref={canvasRef} style={{ flex: 1 }} />
|
|
662
|
-
<
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
style={{ width: 360 }}
|
|
666
|
-
/>
|
|
915
|
+
<div style={{ width: 360 }}>
|
|
916
|
+
<ChatPanel welcome={{ heading: 'What should I draw?' }} />
|
|
917
|
+
</div>
|
|
667
918
|
</div>
|
|
668
|
-
</
|
|
919
|
+
</Talk2View>
|
|
669
920
|
);
|
|
670
921
|
}
|
|
671
922
|
```
|
|
@@ -694,16 +945,32 @@ import type {
|
|
|
694
945
|
RegisterSkillsResponse,
|
|
695
946
|
} from '@talk2view/sdk';
|
|
696
947
|
|
|
697
|
-
// React types
|
|
948
|
+
// Headless React types
|
|
698
949
|
import type {
|
|
699
950
|
T2VProviderProps,
|
|
700
951
|
UseT2VAuthResult,
|
|
701
952
|
UseT2VChatResult,
|
|
702
953
|
UseT2VToolsResult,
|
|
954
|
+
UsePartnerConfigResult,
|
|
955
|
+
UseUserPreferencesResult,
|
|
703
956
|
DisplayMessage,
|
|
704
|
-
|
|
705
|
-
|
|
957
|
+
ToolStep,
|
|
958
|
+
PendingApproval,
|
|
706
959
|
} from '@talk2view/sdk/react';
|
|
960
|
+
|
|
961
|
+
// UI component types
|
|
962
|
+
import type {
|
|
963
|
+
Talk2ViewProps,
|
|
964
|
+
ChatPanelProps,
|
|
965
|
+
ChatWidgetProps,
|
|
966
|
+
} from '@talk2view/sdk/ui';
|
|
967
|
+
|
|
968
|
+
// assistant-ui runtime
|
|
969
|
+
import { useTalk2ViewRuntime, useTalk2ViewRuntimeForClient } from '@talk2view/sdk/assistant-ui';
|
|
970
|
+
import type {
|
|
971
|
+
UseTalk2ViewRuntimeOptions, // useTalk2ViewRuntime(options)
|
|
972
|
+
Talk2ViewRuntimeOptions, // useTalk2ViewRuntimeForClient(t2v, options)
|
|
973
|
+
} from '@talk2view/sdk/assistant-ui';
|
|
707
974
|
```
|
|
708
975
|
|
|
709
976
|
## Publishing
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure mapping from the SDK's chat state onto assistant-ui's message shape.
|
|
3
|
+
*
|
|
4
|
+
* assistant-ui renders `ThreadMessageLike`; the SDK keeps `DisplayMessage`.
|
|
5
|
+
* Everything here is a function of (message, surrounding state) so it can be
|
|
6
|
+
* unit-tested without React or a runtime.
|
|
7
|
+
*/
|
|
8
|
+
import type { ThreadMessageLike } from '@assistant-ui/react';
|
|
9
|
+
import type { DisplayMessage, HumanDecision, PendingApproval } from '../types.js';
|
|
10
|
+
/** What a message needs to know about the thread around it. */
|
|
11
|
+
export interface ConvertContext {
|
|
12
|
+
/** True for the newest message — the only one that can be streaming or waiting on a decision. */
|
|
13
|
+
isLast: boolean;
|
|
14
|
+
/** A tool call waiting for the end-user; rendered as an approval gate on the last assistant message. */
|
|
15
|
+
pendingApproval: PendingApproval | null;
|
|
16
|
+
/** The SDK's error state; shown on the last assistant message. */
|
|
17
|
+
error: string | null;
|
|
18
|
+
}
|
|
19
|
+
type ThreadPart = Extract<ThreadMessageLike['content'], readonly unknown[]>[number];
|
|
20
|
+
/** Option ids the stock assistant-ui approval card sends back; we map them onto `HumanDecision`. */
|
|
21
|
+
export declare const APPROVAL_OPTION_IDS: {
|
|
22
|
+
readonly once: "allow-once";
|
|
23
|
+
readonly always: "allow-always";
|
|
24
|
+
readonly deny: "reject-once";
|
|
25
|
+
};
|
|
26
|
+
/** Stable id for a completed step: steps carry no id of their own. */
|
|
27
|
+
export declare function stepToolCallId(messageId: string, index: number): string;
|
|
28
|
+
/** The approval gate assistant-ui draws for a tool call that needs a decision. */
|
|
29
|
+
export declare function approvalPart(approval: PendingApproval): ThreadPart;
|
|
30
|
+
/** Convert one SDK message for assistant-ui. */
|
|
31
|
+
export declare function toThreadMessage(msg: DisplayMessage, ctx: ConvertContext): ThreadMessageLike;
|
|
32
|
+
/** Turn the stock approval card's answer into the SDK's `HumanDecision`. */
|
|
33
|
+
export declare function toHumanDecision(response: {
|
|
34
|
+
approved: boolean;
|
|
35
|
+
optionId?: string;
|
|
36
|
+
text?: string;
|
|
37
|
+
reason?: string;
|
|
38
|
+
}): HumanDecision;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/assistant-ui/convert.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AAClF,OAAO,KAAK,EAAc,cAAc,EAAE,aAAa,EAAE,eAAe,EAAY,MAAM,aAAa,CAAC;AAExG,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,iGAAiG;IACjG,MAAM,EAAE,OAAO,CAAC;IAChB,wGAAwG;IACxG,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAGD,KAAK,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpF,oGAAoG;AACpG,eAAO,MAAM,mBAAmB;;;;CAItB,CAAC;AAQX,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvE;AAgBD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,UAAU,CAelE;AAkCD,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,cAAc,GAAG,iBAAiB,CA0B3F;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IACxC,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,aAAa,CAShB"}
|