@talk2view/sdk 0.13.0 → 0.15.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.
Files changed (123) hide show
  1. package/README.md +291 -69
  2. package/dist/assistant-ui/convert.d.ts +40 -0
  3. package/dist/assistant-ui/convert.d.ts.map +1 -0
  4. package/dist/assistant-ui/convert.js +113 -0
  5. package/dist/assistant-ui/convert.js.map +1 -0
  6. package/dist/assistant-ui/dictation.d.ts +39 -0
  7. package/dist/assistant-ui/dictation.d.ts.map +1 -0
  8. package/dist/assistant-ui/dictation.js +128 -0
  9. package/dist/assistant-ui/dictation.js.map +1 -0
  10. package/dist/assistant-ui/index.d.ts +37 -0
  11. package/dist/assistant-ui/index.d.ts.map +1 -0
  12. package/dist/assistant-ui/index.js +224 -0
  13. package/dist/assistant-ui/index.js.map +1 -0
  14. package/dist/auth.d.ts +26 -4
  15. package/dist/auth.d.ts.map +1 -1
  16. package/dist/auth.js +82 -17
  17. package/dist/auth.js.map +1 -1
  18. package/dist/client.d.ts +1 -1
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +4 -4
  21. package/dist/client.js.map +1 -1
  22. package/dist/errors.d.ts +5 -3
  23. package/dist/errors.d.ts.map +1 -1
  24. package/dist/errors.js +28 -6
  25. package/dist/errors.js.map +1 -1
  26. package/dist/index.d.ts +63 -15
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +231 -37
  29. package/dist/index.js.map +1 -1
  30. package/dist/react/T2VProvider.d.ts +2 -2
  31. package/dist/react/T2VProvider.d.ts.map +1 -1
  32. package/dist/react/T2VProvider.js +1 -1
  33. package/dist/react/T2VProvider.js.map +1 -1
  34. package/dist/react/index.d.ts +14 -14
  35. package/dist/react/index.d.ts.map +1 -1
  36. package/dist/react/index.js +7 -7
  37. package/dist/react/index.js.map +1 -1
  38. package/dist/react/usePartnerConfig.d.ts +1 -1
  39. package/dist/react/usePartnerConfig.d.ts.map +1 -1
  40. package/dist/react/usePartnerConfig.js +1 -1
  41. package/dist/react/usePartnerConfig.js.map +1 -1
  42. package/dist/react/useT2VAuth.d.ts +9 -2
  43. package/dist/react/useT2VAuth.d.ts.map +1 -1
  44. package/dist/react/useT2VAuth.js +26 -7
  45. package/dist/react/useT2VAuth.js.map +1 -1
  46. package/dist/react/useT2VChat.d.ts +3 -3
  47. package/dist/react/useT2VChat.d.ts.map +1 -1
  48. package/dist/react/useT2VChat.js +1 -1
  49. package/dist/react/useT2VChat.js.map +1 -1
  50. package/dist/react/useT2VTools.d.ts +1 -1
  51. package/dist/react/useT2VTools.d.ts.map +1 -1
  52. package/dist/react/useT2VTools.js +1 -1
  53. package/dist/react/useT2VTools.js.map +1 -1
  54. package/dist/react/useUserPreferences.d.ts +1 -1
  55. package/dist/react/useUserPreferences.d.ts.map +1 -1
  56. package/dist/react/useUserPreferences.js +1 -1
  57. package/dist/react/useUserPreferences.js.map +1 -1
  58. package/dist/sessions.d.ts +3 -3
  59. package/dist/sessions.d.ts.map +1 -1
  60. package/dist/skills.d.ts +2 -2
  61. package/dist/skills.d.ts.map +1 -1
  62. package/dist/streaming.d.ts +1 -1
  63. package/dist/streaming.d.ts.map +1 -1
  64. package/dist/tools.d.ts +2 -2
  65. package/dist/tools.d.ts.map +1 -1
  66. package/dist/types.d.ts +146 -2
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/ui/components/ApprovalCard.d.ts +1 -1
  69. package/dist/ui/components/ApprovalCard.d.ts.map +1 -1
  70. package/dist/ui/components/ChatHeader.js +1 -1
  71. package/dist/ui/components/ChatHeader.js.map +1 -1
  72. package/dist/ui/components/ChatPanel.d.ts +1 -1
  73. package/dist/ui/components/ChatPanel.d.ts.map +1 -1
  74. package/dist/ui/components/ChatPanel.js +14 -13
  75. package/dist/ui/components/ChatPanel.js.map +1 -1
  76. package/dist/ui/components/ChatWidget.d.ts +1 -1
  77. package/dist/ui/components/ChatWidget.d.ts.map +1 -1
  78. package/dist/ui/components/ChatWidget.js +2 -2
  79. package/dist/ui/components/ChatWidget.js.map +1 -1
  80. package/dist/ui/components/Composer.d.ts.map +1 -1
  81. package/dist/ui/components/Composer.js +13 -6
  82. package/dist/ui/components/Composer.js.map +1 -1
  83. package/dist/ui/components/LoginForm.d.ts.map +1 -1
  84. package/dist/ui/components/LoginForm.js +19 -5
  85. package/dist/ui/components/LoginForm.js.map +1 -1
  86. package/dist/ui/components/MarkdownRenderer.d.ts +4 -0
  87. package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -1
  88. package/dist/ui/components/MarkdownRenderer.js +7 -35
  89. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  90. package/dist/ui/components/MessageActions.js +1 -1
  91. package/dist/ui/components/MessageActions.js.map +1 -1
  92. package/dist/ui/components/MessageBubble.d.ts +1 -1
  93. package/dist/ui/components/MessageBubble.d.ts.map +1 -1
  94. package/dist/ui/components/MessageBubble.js +9 -9
  95. package/dist/ui/components/MessageBubble.js.map +1 -1
  96. package/dist/ui/components/MessageList.js +2 -2
  97. package/dist/ui/components/MessageList.js.map +1 -1
  98. package/dist/ui/components/SettingsPanel.js +6 -6
  99. package/dist/ui/components/SettingsPanel.js.map +1 -1
  100. package/dist/ui/components/Talk2View.d.ts +1 -1
  101. package/dist/ui/components/Talk2View.d.ts.map +1 -1
  102. package/dist/ui/components/Talk2View.js +16 -12
  103. package/dist/ui/components/Talk2View.js.map +1 -1
  104. package/dist/ui/components/ThinkingBlock.js +2 -2
  105. package/dist/ui/components/ThinkingBlock.js.map +1 -1
  106. package/dist/ui/components/WelcomeScreen.js +2 -2
  107. package/dist/ui/components/WelcomeScreen.js.map +1 -1
  108. package/dist/ui/context.d.ts +4 -2
  109. package/dist/ui/context.d.ts.map +1 -1
  110. package/dist/ui/context.js.map +1 -1
  111. package/dist/ui/index.d.ts +27 -26
  112. package/dist/ui/index.d.ts.map +1 -1
  113. package/dist/ui/index.js +21 -20
  114. package/dist/ui/index.js.map +1 -1
  115. package/dist/ui/safeMarkdown.d.ts +17 -0
  116. package/dist/ui/safeMarkdown.d.ts.map +1 -0
  117. package/dist/ui/safeMarkdown.js +196 -0
  118. package/dist/ui/safeMarkdown.js.map +1 -0
  119. package/dist/ui/theme.d.ts +1 -1
  120. package/dist/ui/theme.d.ts.map +1 -1
  121. package/dist/ui/utils.d.ts +1 -1
  122. package/dist/ui/utils.d.ts.map +1 -1
  123. package/package.json +26 -2
@@ -0,0 +1,113 @@
1
+ /** Option ids the stock assistant-ui approval card sends back; we map them onto `HumanDecision`. */
2
+ export const APPROVAL_OPTION_IDS = {
3
+ once: 'allow-once',
4
+ always: 'allow-always',
5
+ deny: 'reject-once',
6
+ };
7
+ const APPROVAL_OPTIONS = [
8
+ { id: APPROVAL_OPTION_IDS.once, kind: 'allow-once', label: 'Allow once' },
9
+ { id: APPROVAL_OPTION_IDS.always, kind: 'allow-always', label: 'Always allow' },
10
+ { id: APPROVAL_OPTION_IDS.deny, kind: 'reject-once', label: 'Deny' },
11
+ ];
12
+ /** Stable id for a completed step: steps carry no id of their own. */
13
+ export function stepToolCallId(messageId, index) {
14
+ return `${messageId}:step:${index}`;
15
+ }
16
+ function stepPart(messageId, step, index) {
17
+ const denied = step.status === 'denied';
18
+ return {
19
+ type: 'tool-call',
20
+ toolCallId: stepToolCallId(messageId, index),
21
+ toolName: step.name,
22
+ args: (step.args ?? {}),
23
+ // A running step has no result yet, which is how assistant-ui shows a spinner.
24
+ ...(step.status === 'running'
25
+ ? {}
26
+ : { result: step.result ?? (denied ? 'Denied by the user' : ''), isError: denied }),
27
+ };
28
+ }
29
+ /** The approval gate assistant-ui draws for a tool call that needs a decision. */
30
+ export function approvalPart(approval) {
31
+ return {
32
+ type: 'tool-call',
33
+ toolCallId: approval.toolCallId,
34
+ toolName: approval.toolName,
35
+ args: approval.arguments,
36
+ approval: {
37
+ id: approval.toolCallId,
38
+ prompt: approval.description,
39
+ display: 'decision',
40
+ // A reason may accompany the decision; the SDK forwards it as feedback.
41
+ allowFreeform: true,
42
+ options: APPROVAL_OPTIONS,
43
+ },
44
+ };
45
+ }
46
+ /**
47
+ * The SDK records a `running` step for the tool awaiting approval, so the
48
+ * gate replaces that step rather than sitting beside it; the part keeps the
49
+ * engine's tool-call id so the decision can be matched back.
50
+ */
51
+ function withApprovalGate(parts, approval) {
52
+ const gate = approvalPart(approval);
53
+ for (let i = parts.length - 1; i >= 0; i--) {
54
+ const p = parts[i];
55
+ if (p.type === 'tool-call' && p.toolName === approval.toolName && p.result === undefined) {
56
+ return [...parts.slice(0, i), gate, ...parts.slice(i + 1)];
57
+ }
58
+ }
59
+ return [...parts, gate];
60
+ }
61
+ function attachmentType(mime) {
62
+ return mime.startsWith('image/') ? 'image' : 'document';
63
+ }
64
+ function toThreadAttachment(a) {
65
+ return {
66
+ id: a.id,
67
+ type: attachmentType(a.mime_type),
68
+ name: a.filename,
69
+ contentType: a.mime_type,
70
+ status: { type: 'complete' },
71
+ // The engine resolves the bytes by id; nothing is inlined into the message.
72
+ content: [],
73
+ };
74
+ }
75
+ /** Convert one SDK message for assistant-ui. */
76
+ export function toThreadMessage(msg, ctx) {
77
+ if (msg.role === 'user') {
78
+ return {
79
+ id: msg.id,
80
+ role: 'user',
81
+ createdAt: msg.timestamp,
82
+ content: [{ type: 'text', text: msg.content }],
83
+ ...(msg.attachments?.length ? { attachments: msg.attachments.map(toThreadAttachment) } : {}),
84
+ };
85
+ }
86
+ let parts = (msg.steps ?? []).map((step, i) => stepPart(msg.id, step, i));
87
+ const waiting = ctx.isLast && ctx.pendingApproval ? ctx.pendingApproval : null;
88
+ if (waiting)
89
+ parts = withApprovalGate(parts, waiting);
90
+ if (msg.plan)
91
+ parts.push({ type: 'data-plan', data: { markdown: msg.plan } });
92
+ if (msg.content || parts.length === 0)
93
+ parts.push({ type: 'text', text: msg.content });
94
+ const status = waiting
95
+ ? { type: 'requires-action', reason: 'tool-calls' }
96
+ : msg.isStreaming
97
+ ? { type: 'running' }
98
+ : ctx.isLast && ctx.error
99
+ ? { type: 'incomplete', reason: 'error', error: ctx.error }
100
+ : { type: 'complete', reason: 'stop' };
101
+ return { id: msg.id, role: 'assistant', createdAt: msg.timestamp, content: parts, status };
102
+ }
103
+ /** Turn the stock approval card's answer into the SDK's `HumanDecision`. */
104
+ export function toHumanDecision(response) {
105
+ const feedback = response.text ?? response.reason;
106
+ const action = response.optionId === APPROVAL_OPTION_IDS.always
107
+ ? 'always'
108
+ : response.optionId === APPROVAL_OPTION_IDS.once || (response.optionId === undefined && response.approved)
109
+ ? 'once'
110
+ : 'deny';
111
+ return feedback ? { action, feedback } : { action };
112
+ }
113
+ //# sourceMappingURL=convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/assistant-ui/convert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Dictation for assistant-ui's composer, transcribed by Talk2View.
3
+ *
4
+ * assistant-ui shows its mic button whenever the runtime has a dictation
5
+ * adapter. This one records with MediaRecorder and sends the clip to the
6
+ * engine's speech-to-text endpoint (`t2v.transcribe`) when the end-user stops
7
+ * — the same flow as the first-party composer in `/ui`, so the partner's
8
+ * speech-to-text models, language setting and billing all apply.
9
+ */
10
+ import type { DictationAdapter } from '@assistant-ui/react';
11
+ import type { Talk2View } from '../index.js';
12
+ export interface Talk2ViewDictationOptions {
13
+ /** Speech-to-text model id (one of `t2v.listAudioModels()`). */
14
+ model?: string;
15
+ /** Spoken language hint, e.g. `'en'`. Omit to let the model detect it. */
16
+ language?: string;
17
+ /**
18
+ * Called when the microphone is refused or transcription fails. assistant-ui
19
+ * has no surface for a dictation error, so without this the mic just stops.
20
+ */
21
+ onError?: (error: unknown) => void;
22
+ /**
23
+ * Where a dictation is up to. assistant-ui reports "listening" for the whole
24
+ * time, including the wait for the transcript after the end-user stops —
25
+ * use this to show that wait as its own state (`'transcribing'`).
26
+ */
27
+ onPhaseChange?: (phase: Talk2ViewDictationPhase) => void;
28
+ }
29
+ export type Talk2ViewDictationPhase = 'listening' | 'transcribing' | 'idle';
30
+ /** The client, as far as dictation needs it. Only `transcribe` is required. */
31
+ export type Talk2ViewDictationClient = Pick<Talk2View, 'transcribe'> & Partial<Pick<Talk2View, 'ensureSession' | 'getConfig' | 'warmUp'>>;
32
+ /** Used when neither the caller nor the partner configuration names a model. */
33
+ export declare const DEFAULT_DICTATION_MODEL = "faster-whisper-base";
34
+ /**
35
+ * @param getOptions read when a recording is sent, so a settings change
36
+ * applies to the next dictation without rebuilding the runtime.
37
+ */
38
+ export declare function createTalk2ViewDictationAdapter(t2v: Talk2ViewDictationClient, getOptions?: () => Talk2ViewDictationOptions): DictationAdapter;
39
+ //# sourceMappingURL=dictation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictation.d.ts","sourceRoot":"","sources":["../../src/assistant-ui/dictation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,yBAAyB;IACxC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,cAAc,GAAG,MAAM,CAAC;AAE5E,+EAA+E;AAC/E,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,GAClE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,GAAG,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC;AAErE,gFAAgF;AAChF,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAW7D;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,wBAAwB,EAC7B,UAAU,GAAE,MAAM,yBAAsC,GACvD,gBAAgB,CAgHlB"}
@@ -0,0 +1,128 @@
1
+ /** Used when neither the caller nor the partner configuration names a model. */
2
+ export const DEFAULT_DICTATION_MODEL = 'faster-whisper-base';
3
+ function subscribe(set, cb) {
4
+ set.add(cb);
5
+ return () => {
6
+ set.delete(cb);
7
+ };
8
+ }
9
+ /**
10
+ * @param getOptions read when a recording is sent, so a settings change
11
+ * applies to the next dictation without rebuilding the runtime.
12
+ */
13
+ export function createTalk2ViewDictationAdapter(t2v, getOptions = () => ({})) {
14
+ return {
15
+ listen() {
16
+ const onStart = new Set();
17
+ const onEnd = new Set();
18
+ const onSpeech = new Set();
19
+ const chunks = [];
20
+ let stream = null;
21
+ let recorder = null;
22
+ let cancelled = false;
23
+ let settle;
24
+ const settled = new Promise((resolve) => {
25
+ settle = resolve;
26
+ });
27
+ const releaseMic = () => stream?.getTracks().forEach((track) => track.stop());
28
+ const phase = (next) => getOptions().onPhaseChange?.(next);
29
+ const finish = (reason) => {
30
+ releaseMic();
31
+ session.status = { type: 'ended', reason };
32
+ phase('idle');
33
+ settle();
34
+ };
35
+ // A logged-out visitor's first action can be the mic. Start the session
36
+ // and mint their key now, while they talk. The two are kept apart: the
37
+ // model lookup below needs only the session, and the mint is seconds long
38
+ // — a short clip must not wait for it. `async` wrappers so a client whose
39
+ // method throws synchronously cannot take the mic down with it.
40
+ const startSession = async () => void (await t2v.ensureSession?.());
41
+ const warm = async () => void (await t2v.warmUp?.());
42
+ const warming = warm().catch(() => undefined);
43
+ // Without ensureSession() the warm-up is the only thing that starts one.
44
+ const ready = t2v.ensureSession ? startSession().catch(() => undefined) : warming;
45
+ const partnerModel = ready
46
+ .then(() => t2v.getConfig?.())
47
+ .then((config) => config?.default_stt_model || undefined)
48
+ .catch(() => undefined);
49
+ const session = {
50
+ status: { type: 'starting' },
51
+ // Resolves only once the transcript has been delivered: the composer
52
+ // unsubscribes as soon as stop() settles, and the clip is transcribed
53
+ // after the recording ends, not during it.
54
+ stop: async () => {
55
+ if (recorder?.state === 'recording')
56
+ recorder.stop();
57
+ else if (session.status.type !== 'ended' && !recorder)
58
+ cancelled = true;
59
+ await settled;
60
+ },
61
+ cancel: () => {
62
+ cancelled = true;
63
+ if (recorder?.state === 'recording')
64
+ recorder.stop();
65
+ else if (session.status.type !== 'ended')
66
+ finish('cancelled');
67
+ },
68
+ onSpeechStart: (cb) => subscribe(onStart, cb),
69
+ onSpeechEnd: (cb) => subscribe(onEnd, cb),
70
+ onSpeech: (cb) => subscribe(onSpeech, cb),
71
+ };
72
+ void (async () => {
73
+ try {
74
+ stream = await navigator.mediaDevices.getUserMedia({ audio: true });
75
+ if (cancelled)
76
+ return finish('cancelled');
77
+ const mimeType = MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
78
+ ? 'audio/webm;codecs=opus'
79
+ : 'audio/webm';
80
+ recorder = new MediaRecorder(stream, { mimeType });
81
+ recorder.ondataavailable = (e) => {
82
+ if (e.data.size > 0)
83
+ chunks.push(e.data);
84
+ };
85
+ recorder.onstop = async () => {
86
+ // The clip is complete: the browser's recording indicator goes off
87
+ // now, not after the engine answers.
88
+ releaseMic();
89
+ if (cancelled || chunks.length === 0)
90
+ return finish(cancelled ? 'cancelled' : 'stopped');
91
+ phase('transcribing');
92
+ try {
93
+ const { model: chosen, language } = getOptions();
94
+ const model = chosen || (await partnerModel);
95
+ const form = new FormData();
96
+ form.append('file', new Blob(chunks, { type: mimeType }), 'recording.webm');
97
+ form.append('model', model || DEFAULT_DICTATION_MODEL);
98
+ if (language)
99
+ form.append('language', language);
100
+ const transcript = (await t2v.transcribe(form)).text.trim();
101
+ if (transcript && !cancelled) {
102
+ // The composer appends on a final `onSpeech`; `onSpeechEnd` only closes the session.
103
+ onSpeech.forEach((cb) => cb({ transcript, isFinal: true }));
104
+ onEnd.forEach((cb) => cb({ transcript }));
105
+ }
106
+ finish(cancelled ? 'cancelled' : 'stopped');
107
+ }
108
+ catch (error) {
109
+ getOptions().onError?.(error);
110
+ finish('error');
111
+ }
112
+ };
113
+ recorder.start();
114
+ session.status = { type: 'running' };
115
+ phase('listening');
116
+ onStart.forEach((cb) => cb());
117
+ }
118
+ catch (error) {
119
+ // Microphone refused, or no MediaRecorder in this browser.
120
+ getOptions().onError?.(error);
121
+ finish('error');
122
+ }
123
+ })();
124
+ return session;
125
+ },
126
+ };
127
+ }
128
+ //# sourceMappingURL=dictation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dictation.js","sourceRoot":"","sources":["../../src/assistant-ui/dictation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { AssistantRuntime } from '@assistant-ui/react';
2
+ import { Talk2View } from '../index.js';
3
+ import type { ClientTool, ClientToolSchema, T2VConfig } from '../types.js';
4
+ import { type Talk2ViewDictationOptions } from './dictation.js';
5
+ export type { Talk2ViewDictationClient, Talk2ViewDictationPhase } from './dictation.js';
6
+ export { toThreadMessage, toHumanDecision, APPROVAL_OPTION_IDS } from './convert.js';
7
+ export type { ConvertContext } from './convert.js';
8
+ export { createTalk2ViewDictationAdapter, DEFAULT_DICTATION_MODEL } from './dictation.js';
9
+ export type { Talk2ViewDictationOptions } from './dictation.js';
10
+ /** Options shared by both forms of the hook. */
11
+ export interface Talk2ViewRuntimeOptions {
12
+ /** Sent with every message. */
13
+ systemPrompt?: string;
14
+ /**
15
+ * Client tools the agent may call; handlers run in your app. Registered
16
+ * with the engine whenever the set of schemas changes (compared by value,
17
+ * so an inline array is fine).
18
+ */
19
+ tools?: (ClientToolSchema | ClientTool)[];
20
+ /**
21
+ * Model for the next message — for example the end-user's choice from a
22
+ * settings screen. Unlike the client's `model`, changing it keeps the chat.
23
+ */
24
+ model?: string;
25
+ /**
26
+ * Turn on assistant-ui's mic button, transcribed by Talk2View. `true` uses
27
+ * the default speech-to-text model; pass `{ model, language }` to choose.
28
+ */
29
+ dictation?: boolean | Talk2ViewDictationOptions;
30
+ }
31
+ export interface UseTalk2ViewRuntimeOptions extends T2VConfig, Talk2ViewRuntimeOptions {
32
+ }
33
+ /** Create a Talk2View client and expose it as an assistant-ui runtime. */
34
+ export declare function useTalk2ViewRuntime(options: UseTalk2ViewRuntimeOptions): AssistantRuntime;
35
+ /** Expose an existing client (for example the one from `useT2V()`) as an assistant-ui runtime. */
36
+ export declare function useTalk2ViewRuntimeForClient(t2v: Talk2View, { systemPrompt, tools, model, dictation }?: Talk2ViewRuntimeOptions): AssistantRuntime;
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/assistant-ui/index.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAEV,gBAAgB,EAKjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EAEV,UAAU,EACV,gBAAgB,EAGhB,SAAS,EACV,MAAM,aAAa,CAAC;AAErB,OAAO,EAAmC,KAAK,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AACjG,YAAY,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAExF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACrF,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,+BAA+B,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC1F,YAAY,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAEhE,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,gBAAgB,GAAG,UAAU,CAAC,EAAE,CAAC;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC;CACjD;AAED,MAAM,WAAW,0BAA2B,SAAQ,SAAS,EAAE,uBAAuB;CAAG;AAKzF,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,gBAAgB,CAezF;AAED,kGAAkG;AAClG,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,SAAS,EACd,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAE,uBAA4B,GACtE,gBAAgB,CAiMlB"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * assistant-ui runtime for Talk2View.
3
+ *
4
+ * Talk2View plugs into assistant-ui the way its other backends do — at the
5
+ * runtime seam, not by shipping a fork of its components. Hand the runtime to
6
+ * `<AssistantRuntimeProvider>` and render the stock `<Thread />` (or the
7
+ * primitives): messages stream, client tools run in your app, and tool
8
+ * approvals appear as assistant-ui's own approval card.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * import { AssistantRuntimeProvider } from '@assistant-ui/react';
13
+ * import { useTalk2ViewRuntime } from '@talk2view/sdk/assistant-ui';
14
+ *
15
+ * function Chat() {
16
+ * const runtime = useTalk2ViewRuntime({ partnerKey: 'pk_live_...', tools });
17
+ * return (
18
+ * <AssistantRuntimeProvider runtime={runtime}>
19
+ * <Thread />
20
+ * </AssistantRuntimeProvider>
21
+ * );
22
+ * }
23
+ * ```
24
+ *
25
+ * `@assistant-ui/react` is an optional peer dependency: it is only loaded by
26
+ * this entry point, never by `@talk2view/sdk`, `/react` or `/ui`.
27
+ *
28
+ * @packageDocumentation
29
+ */
30
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
31
+ import { useExternalStoreRuntime } from '@assistant-ui/react';
32
+ import { Talk2View } from '../index.js';
33
+ import { ATTACHMENT_ACCEPT } from '../constants.js';
34
+ import { toHumanDecision, toThreadMessage } from './convert.js';
35
+ import { createTalk2ViewDictationAdapter } from './dictation.js';
36
+ export { toThreadMessage, toHumanDecision, APPROVAL_OPTION_IDS } from './convert.js';
37
+ export { createTalk2ViewDictationAdapter, DEFAULT_DICTATION_MODEL } from './dictation.js';
38
+ /** What Stop means while a tool call is waiting on the end-user. */
39
+ const CANCELLED_APPROVAL_FEEDBACK = 'Cancelled by the user';
40
+ /** Create a Talk2View client and expose it as an assistant-ui runtime. */
41
+ export function useTalk2ViewRuntime(options) {
42
+ const { systemPrompt, tools, model: messageModel, dictation, ...config } = options;
43
+ // A new client only when the connection details change. `model` is not one
44
+ // of them here: it travels with each message, so an end-user can switch
45
+ // models from a settings screen without losing the chat.
46
+ const t2v = useMemo(() => new Talk2View(config),
47
+ // eslint-disable-next-line react-hooks/exhaustive-deps
48
+ [config.partnerKey, config.baseUrl, config.debug, config.anonymousAutoStart]);
49
+ const runtime = useTalk2ViewRuntimeForClient(t2v, { systemPrompt, tools, model: messageModel, dictation });
50
+ // Declared after the subscriptions above so, on a client swap or unmount,
51
+ // React runs their cleanup first and destroys the client last.
52
+ useEffect(() => () => t2v.destroy(), [t2v]);
53
+ return runtime;
54
+ }
55
+ /** Expose an existing client (for example the one from `useT2V()`) as an assistant-ui runtime. */
56
+ export function useTalk2ViewRuntimeForClient(t2v, { systemPrompt, tools, model, dictation } = {}) {
57
+ const [messages, setMessages] = useState(t2v.messages);
58
+ const [isLoading, setIsLoading] = useState(t2v.isLoading);
59
+ const [error, setError] = useState(t2v.error);
60
+ const [pendingApproval, setPendingApproval] = useState(t2v.pendingApproval);
61
+ useEffect(() => {
62
+ setMessages(t2v.messages);
63
+ setIsLoading(t2v.isLoading);
64
+ setError(t2v.error);
65
+ setPendingApproval(t2v.pendingApproval);
66
+ const unsubs = [
67
+ t2v.on('messagesChange', setMessages),
68
+ t2v.on('loadingChange', setIsLoading),
69
+ t2v.on('errorChange', setError),
70
+ t2v.on('approvalChange', setPendingApproval),
71
+ ];
72
+ return () => unsubs.forEach((u) => u());
73
+ }, [t2v]);
74
+ // Register tools the way <Talk2View> does: schemas to the engine, handlers
75
+ // locally. Keyed by value so a partner's inline `tools` array does not
76
+ // re-register on every render (this hook re-renders on every stream chunk).
77
+ const schemas = useMemo(() => (tools ?? []).map((tool) => {
78
+ const { execute: _execute, ...schema } = tool;
79
+ return schema;
80
+ }), [tools]);
81
+ const schemaKey = useMemo(() => JSON.stringify(schemas), [schemas]);
82
+ const registered = useRef(null);
83
+ useEffect(() => {
84
+ if (schemas.length === 0)
85
+ return;
86
+ for (const tool of tools ?? []) {
87
+ if ('execute' in tool && tool.execute)
88
+ t2v.tools.handle(tool.name, tool.execute);
89
+ }
90
+ if (registered.current?.t2v === t2v && registered.current.key === schemaKey)
91
+ return;
92
+ registered.current = { t2v, key: schemaKey };
93
+ t2v.tools.register(schemas).catch(() => { });
94
+ }, [t2v, tools, schemas, schemaKey]);
95
+ // Uploaded files, by the id assistant-ui hands back in the composed message.
96
+ const uploaded = useRef(new Map());
97
+ const attachments = useMemo(() => ({
98
+ accept: ATTACHMENT_ACCEPT,
99
+ async add({ file }) {
100
+ return {
101
+ id: pendingId(),
102
+ type: file.type.startsWith('image/') ? 'image' : 'document',
103
+ name: file.name,
104
+ contentType: file.type,
105
+ file,
106
+ status: { type: 'requires-action', reason: 'composer-send' },
107
+ };
108
+ },
109
+ async send(pending) {
110
+ const stored = await t2v.uploadAttachment(pending.file, pending.file.name);
111
+ uploaded.current.set(stored.id, stored);
112
+ return {
113
+ id: stored.id,
114
+ type: pending.type,
115
+ name: stored.filename,
116
+ contentType: stored.mime_type,
117
+ status: { type: 'complete' },
118
+ // The engine resolves the bytes by id; nothing is inlined.
119
+ content: [],
120
+ };
121
+ },
122
+ async remove() {
123
+ // Uploads are cheap and expire server-side; nothing to undo client-side.
124
+ },
125
+ }), [t2v]);
126
+ // One adapter per client; the options are read when a clip is sent, so a
127
+ // settings change applies to the next dictation without a new runtime.
128
+ const dictationOptions = useRef({});
129
+ dictationOptions.current = typeof dictation === 'object' ? dictation : {};
130
+ const dictationEnabled = Boolean(dictation);
131
+ const dictationAdapter = useMemo(() => (dictationEnabled ? createTalk2ViewDictationAdapter(t2v, () => dictationOptions.current) : null), [t2v, dictationEnabled]);
132
+ // A turn that fails before its first text chunk leaves no assistant message
133
+ // behind (the SDK drops the empty one), and assistant-ui can only show an
134
+ // error on an assistant message — so give it one to show it on.
135
+ const threadMessages = useMemo(() => {
136
+ const last = messages[messages.length - 1];
137
+ if (error && last && last.role !== 'assistant') {
138
+ return [...messages, { id: `${last.id}:error`, role: 'assistant', content: '', timestamp: new Date() }];
139
+ }
140
+ return messages;
141
+ }, [messages, error]);
142
+ const convertMessage = useCallback((msg, idx) => toThreadMessage(msg, { isLast: idx === threadMessages.length - 1, pendingApproval, error }), [threadMessages.length, pendingApproval, error]);
143
+ const onNew = useCallback(async (message) => {
144
+ const text = message.content
145
+ .filter((p) => p.type === 'text')
146
+ .map((p) => p.text)
147
+ .join('\n');
148
+ const files = (message.attachments ?? []).map((a) => {
149
+ const stored = uploaded.current.get(a.id);
150
+ uploaded.current.delete(a.id);
151
+ // The id is the engine's whichever way we got here; rebuild the rest
152
+ // if the upload happened before this hook instance existed.
153
+ return stored ?? { id: a.id, filename: a.name, mime_type: a.contentType ?? '', size_bytes: a.file?.size ?? 0 };
154
+ });
155
+ await t2v.sendMessage(text, {
156
+ ...(systemPrompt ? { systemPrompt } : {}),
157
+ ...(model ? { model } : {}),
158
+ ...(files.length ? { attachments: files } : {}),
159
+ });
160
+ }, [t2v, systemPrompt, model]);
161
+ // assistant-ui puts a reload action on every assistant message; the SDK
162
+ // can only regenerate the latest turn — the one started by the last user
163
+ // message. That includes the error card and every segment of that turn;
164
+ // reload of an older reply is a no-op rather than a silent rewrite of the
165
+ // newest one.
166
+ const onReload = useCallback(async (parentId) => {
167
+ const lastUser = [...messages].reverse().find((m) => m.role === 'user');
168
+ if (!lastUser || parentId !== lastUser.id)
169
+ return;
170
+ await t2v.retryLastMessage();
171
+ }, [t2v, messages]);
172
+ // Stop while a tool call waits on the end-user: the SDK is not streaming,
173
+ // so stop() would do nothing — deny the call instead, which is what a
174
+ // partner expects Stop to mean there.
175
+ const onCancel = useCallback(async () => {
176
+ if (t2v.pendingApproval) {
177
+ await t2v.approveToolCall({ action: 'deny', feedback: CANCELLED_APPROVAL_FEEDBACK });
178
+ return;
179
+ }
180
+ t2v.stop();
181
+ }, [t2v]);
182
+ const adapter = useMemo(() => ({
183
+ messages: threadMessages,
184
+ // A turn waiting on an approval is still in progress: the engine holds
185
+ // the interrupt, and a second message would land on top of it.
186
+ isRunning: isLoading || pendingApproval !== null,
187
+ convertMessage,
188
+ onNew,
189
+ onCancel,
190
+ onReload,
191
+ onRespondToToolApproval: async (response) => {
192
+ // Only the current gate can be answered; a stale card is ignored.
193
+ if (response.approvalId !== t2v.pendingApproval?.toolCallId)
194
+ return;
195
+ await t2v.approveToolCall(toHumanDecision(response));
196
+ },
197
+ adapters: { attachments, ...(dictationAdapter ? { dictation: dictationAdapter } : {}) },
198
+ }), [threadMessages, isLoading, pendingApproval, convertMessage, onNew, onCancel, onReload, t2v, attachments, dictationAdapter]);
199
+ const runtime = useExternalStoreRuntime(adapter);
200
+ // First character typed = intent. Mint the end-user's key while they finish
201
+ // the sentence. Not on mount and not on focus: the composer autofocuses when a
202
+ // chat opens, and a visitor who opens it and leaves should cost nothing.
203
+ // A ref, not a local: the effect re-runs under StrictMode and must not
204
+ // re-arm. It remembers which client it warmed, so a new client gets its own.
205
+ const warmedFor = useRef(null);
206
+ useEffect(() => {
207
+ const composer = runtime.thread.composer;
208
+ const check = () => {
209
+ if (warmedFor.current === t2v || !composer.getState().text)
210
+ return;
211
+ warmedFor.current = t2v;
212
+ void t2v.warmUp();
213
+ };
214
+ check();
215
+ return composer.subscribe(check);
216
+ }, [runtime, t2v]);
217
+ return runtime;
218
+ }
219
+ let pendingCounter = 0;
220
+ function pendingId() {
221
+ pendingCounter += 1;
222
+ return `pending-${Date.now()}-${pendingCounter}`;
223
+ }
224
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/assistant-ui/index.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Auth module — login, signup, refresh, logout, auth state management.
3
3
  */
4
- import type { T2VClient } from './client';
5
- import type { User } from './types';
4
+ import type { T2VClient } from './client.js';
5
+ import type { SignupOutcome, User } from './types.js';
6
6
  type AuthStateCallback = (user: User | null) => void;
7
+ export type PopupProvider = 'google' | 'apple';
7
8
  export declare class T2VAuth {
8
9
  private readonly client;
9
10
  private listeners;
@@ -28,16 +29,37 @@ export declare class T2VAuth {
28
29
  /** True if the current session is an anonymous demo session. */
29
30
  isAnonymous(): boolean;
30
31
  /**
31
- * Create a new Talk2View account.
32
+ * Create a permanent account.
33
+ *
34
+ * From an anonymous session this CONVERTS in place (same user id — history
35
+ * and purchases stay). The server emails a confirmation link; until it is
36
+ * clicked the session remains anonymous and `confirmationRequired` is true.
37
+ * A 409 means the email already has an account → we sign into it instead.
32
38
  */
33
- signup(email: string, password: string): Promise<User>;
39
+ signup(email: string, password: string): Promise<SignupOutcome>;
34
40
  /**
35
41
  * Authenticate with email and password.
36
42
  */
37
43
  login(email: string, password: string): Promise<User>;
38
44
  private oauthAbort?;
45
+ private popupProviders;
46
+ /**
47
+ * Which popup sign-ins work from this page. They work on any https:// website;
48
+ * on one the partner has not registered, the end-user first sees a Talk2View
49
+ * screen naming the site (the partner's key is public — this is what stops
50
+ * another site quietly using it). Partners who only allow their registered
51
+ * websites get an empty list elsewhere. Never rejects.
52
+ */
53
+ getPopupProviders(): Promise<PopupProvider[]>;
39
54
  /** Sign in with Google via a popup (engine-mediated OAuth). */
40
55
  signInWithGoogle(): Promise<User>;
56
+ /**
57
+ * Sign in with Apple via a popup (engine-mediated OAuth). An account made
58
+ * with Apple in a native app has no password, so on the web this is its only
59
+ * way in. Needs an engine that offers Apple in the popup flow; an older one
60
+ * answers the popup with 404 and this rejects when the attempt expires.
61
+ */
62
+ signInWithApple(): Promise<User>;
41
63
  signInWithOAuth(provider: string): Promise<User>;
42
64
  private pollOAuthExchange;
43
65
  /** Abortable delay used by the OAuth poll loop. */