@alexkroman1/aai-ui 0.12.2 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_react-test-utils.d.ts +86 -0
- package/dist/audio.js +4 -5
- package/dist/build-default-client.d.ts +1 -0
- package/dist/{_components → components}/button.d.ts +4 -4
- package/dist/{_components → components}/button.js +28 -5
- package/dist/components/chat-view.d.ts +38 -0
- package/dist/components/chat-view.js +102 -0
- package/dist/{_components → components}/controls.d.ts +1 -1
- package/dist/{_components → components}/controls.js +8 -5
- package/dist/{_components → components}/message-list.d.ts +2 -2
- package/dist/components/message-list.js +149 -0
- package/dist/components/sidebar-layout.d.ts +21 -0
- package/dist/components/sidebar-layout.js +43 -0
- package/dist/{_components → components}/start-screen.d.ts +4 -4
- package/dist/{_components → components}/start-screen.js +17 -8
- package/dist/{_components → components}/tool-call-block.d.ts +5 -6
- package/dist/components/tool-call-block.js +3 -0
- package/dist/components/tool-config-context.d.ts +22 -0
- package/dist/context.d.ts +23 -0
- package/dist/context.js +39 -0
- package/dist/default-client/assets/audio-DH9LpexG.js +1 -0
- package/dist/default-client/assets/capture-processor-C26lSiVr.js +53 -0
- package/dist/default-client/assets/default-client-AeJhjHfj.js +49 -0
- package/dist/default-client/assets/default-client-BK1ItCvw.css +2 -0
- package/dist/default-client/assets/playback-processor-dSA8Im99.js +101 -0
- package/dist/default-client/default-client.html +15 -0
- package/dist/default-client.d.ts +2 -0
- package/dist/define-client.d.ts +72 -24
- package/dist/define-client.js +71 -45
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.js +55 -0
- package/dist/index.d.ts +15 -37
- package/dist/index.js +11 -18
- package/dist/session-core.d.ts +70 -0
- package/dist/session-core.js +437 -0
- package/dist/tool-call-block-CCuChsFm.js +131 -0
- package/dist/types.d.ts +19 -22
- package/package.json +24 -18
- package/styles.css +3 -33
- package/dist/_components/app.d.ts +0 -23
- package/dist/_components/app.js +0 -41
- package/dist/_components/chat-view.d.ts +0 -29
- package/dist/_components/chat-view.js +0 -61
- package/dist/_components/error-banner.d.ts +0 -21
- package/dist/_components/error-banner.js +0 -27
- package/dist/_components/message-bubble.d.ts +0 -23
- package/dist/_components/message-bubble.js +0 -35
- package/dist/_components/message-list.js +0 -76
- package/dist/_components/sidebar-layout.d.ts +0 -21
- package/dist/_components/sidebar-layout.js +0 -36
- package/dist/_components/state-indicator.d.ts +0 -29
- package/dist/_components/state-indicator.js +0 -37
- package/dist/_components/thinking-indicator.d.ts +0 -16
- package/dist/_components/thinking-indicator.js +0 -34
- package/dist/_components/tool-call-block.js +0 -118
- package/dist/_components/tool-icons.d.ts +0 -17
- package/dist/_components/tool-icons.js +0 -128
- package/dist/_components/transcript.d.ts +0 -25
- package/dist/_components/transcript.js +0 -35
- package/dist/client-context.d.ts +0 -33
- package/dist/client-context.js +0 -15
- package/dist/client-handler.d.ts +0 -43
- package/dist/session-CWB7vmqz.js +0 -429
- package/dist/session.d.ts +0 -69
- package/dist/session.js +0 -2
- package/dist/signals.d.ts +0 -120
- package/dist/signals.js +0 -161
- package/dist/types.test-d.d.ts +0 -7
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--container-sm:24rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}html,body{margin:0;padding:0}}@layer components;@layer utilities{.static{position:static}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.inline{display:inline}.inline-flex{display:inline-flex}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-screen{height:100vh}.max-h-64{max-height:calc(var(--spacing) * 64)}.min-h-5{min-height:calc(var(--spacing) * 5)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-4{width:calc(var(--spacing) * 4)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-130{max-width:calc(var(--spacing) * 130)}.max-w-\[min\(82\%\,64ch\)\]{max-width:min(82%,64ch)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.appearance-none{appearance:none}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-4\.5{gap:calc(var(--spacing) * 4.5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-12{padding-inline:calc(var(--spacing) * 12)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-10{padding-block:calc(var(--spacing) * 10)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-\[1\.1\]{--tw-leading:1.1;line-height:1.1}.leading-\[130\%\]{--tw-leading:130%;line-height:130%}.leading-\[150\%\]{--tw-leading:150%;line-height:150%}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.wrap-break-word{overflow-wrap:break-word}.whitespace-pre-wrap{white-space:pre-wrap}.capitalize{text-transform:capitalize}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.\[scrollbar-width\:none\]{scrollbar-width:none}}@keyframes aai-bounce{0%,80%,to{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}@keyframes aai-shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}.tool-shimmer{-webkit-text-fill-color:transparent;background:linear-gradient(90deg,currentColor 25%,#0000 50%,currentColor 75%) 0 0/200% 100%;-webkit-background-clip:text;background-clip:text;animation:2s infinite aai-shimmer}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
var e=new Blob([`
|
|
2
|
+
class PlaybackProcessor extends AudioWorkletProcessor {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
super();
|
|
5
|
+
this.interrupted = false;
|
|
6
|
+
this.isDone = false;
|
|
7
|
+
this.playing = false;
|
|
8
|
+
const rate = options.processorOptions?.sampleRate ?? 24000;
|
|
9
|
+
// Wait for ~400ms of audio before starting.
|
|
10
|
+
// If 'done' arrives first (short utterance), start immediately.
|
|
11
|
+
this.jitterSamples = Math.floor(rate * 0.4);
|
|
12
|
+
// Carry-over byte for split samples across chunks
|
|
13
|
+
this.carry = null;
|
|
14
|
+
// Float32 sample buffer — 60s at the context sample rate
|
|
15
|
+
this.samples = new Float32Array(rate * 60);
|
|
16
|
+
this.writePos = 0;
|
|
17
|
+
this.readPos = 0;
|
|
18
|
+
// Report playback position every ~50ms for word-level text sync
|
|
19
|
+
this.progressInterval = Math.floor(rate * 0.05);
|
|
20
|
+
this.samplesSinceProgress = 0;
|
|
21
|
+
|
|
22
|
+
this.port.onmessage = (e) => {
|
|
23
|
+
const d = e.data;
|
|
24
|
+
if (d.event === 'write') {
|
|
25
|
+
this.ingestBytes(d.buffer);
|
|
26
|
+
} else if (d.event === 'interrupt') {
|
|
27
|
+
this.interrupted = true;
|
|
28
|
+
} else if (d.event === 'done') {
|
|
29
|
+
this.isDone = true;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
ingestBytes(uint8) {
|
|
35
|
+
let bytes = uint8;
|
|
36
|
+
|
|
37
|
+
if (this.carry !== null) {
|
|
38
|
+
const merged = new Uint8Array(1 + bytes.length);
|
|
39
|
+
merged[0] = this.carry;
|
|
40
|
+
merged.set(bytes, 1);
|
|
41
|
+
bytes = merged;
|
|
42
|
+
this.carry = null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (bytes.length % 2 !== 0) {
|
|
46
|
+
this.carry = bytes[bytes.length - 1];
|
|
47
|
+
bytes = bytes.subarray(0, bytes.length - 1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (bytes.length === 0) return;
|
|
51
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
52
|
+
const numSamples = bytes.length / 2;
|
|
53
|
+
for (let i = 0; i < numSamples; i++) {
|
|
54
|
+
this.samples[this.writePos++] = view.getInt16(i * 2, true) / 0x8000;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
process(inputs, outputs) {
|
|
59
|
+
const out = outputs[0][0];
|
|
60
|
+
if (this.interrupted) {
|
|
61
|
+
this.port.postMessage({ event: 'stop' });
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const avail = this.writePos - this.readPos;
|
|
66
|
+
|
|
67
|
+
// Wait for jitter buffer to fill, unless done (short utterance)
|
|
68
|
+
if (!this.playing) {
|
|
69
|
+
if (avail >= this.jitterSamples || this.isDone) {
|
|
70
|
+
this.playing = true;
|
|
71
|
+
} else {
|
|
72
|
+
out.fill(0);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (avail > 0) {
|
|
78
|
+
const n = Math.min(avail, out.length);
|
|
79
|
+
out.set(this.samples.subarray(this.readPos, this.readPos + n));
|
|
80
|
+
this.readPos += n;
|
|
81
|
+
this.samplesSinceProgress += n;
|
|
82
|
+
if (this.samplesSinceProgress >= this.progressInterval) {
|
|
83
|
+
this.port.postMessage({ event: 'progress', readPos: this.readPos });
|
|
84
|
+
this.samplesSinceProgress = 0;
|
|
85
|
+
}
|
|
86
|
+
out.fill(0, n);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// No data: output silence, stop only when done
|
|
91
|
+
out.fill(0);
|
|
92
|
+
if (this.isDone) {
|
|
93
|
+
this.port.postMessage({ event: 'stop' });
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
registerProcessor('playback-processor', PlaybackProcessor);
|
|
101
|
+
`],{type:`application/javascript`}),t=URL.createObjectURL(e);export{t as default};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<title>aai</title>
|
|
7
|
+
<link rel="icon" href="data:," />
|
|
8
|
+
<style>html, body { background: #101010; margin: 0; }</style>
|
|
9
|
+
<script type="module" crossorigin src="./assets/default-client-AeJhjHfj.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/default-client-BK1ItCvw.css">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<main id="app"></main>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/dist/define-client.d.ts
CHANGED
|
@@ -1,41 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
import { type
|
|
3
|
-
import { type
|
|
4
|
-
import { type
|
|
1
|
+
/** @jsxImportSource react */
|
|
2
|
+
import { type ComponentType } from "react";
|
|
3
|
+
import { type ToolDisplayConfig } from "./components/tool-config-context.ts";
|
|
4
|
+
import { type SessionCore, type WebSocketConstructor } from "./session-core.ts";
|
|
5
|
+
import type { ClientTheme } from "./types.ts";
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Base options shared by both client tiers.
|
|
7
8
|
*
|
|
8
9
|
* @public
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
type BaseOptions = {
|
|
11
12
|
/** CSS selector or DOM element to render into. Defaults to `"#app"`. */
|
|
12
13
|
target?: string | HTMLElement;
|
|
13
14
|
/** Base URL of the AAI platform server. Derived from `location.href` by default. */
|
|
14
15
|
platformUrl?: string;
|
|
15
|
-
/** Agent title shown in the header and start screen. */
|
|
16
|
-
title?: string;
|
|
17
16
|
/** Theme color overrides. */
|
|
18
17
|
theme?: ClientTheme;
|
|
19
18
|
/** Called when the server sends a session ID. Store it for reconnection. */
|
|
20
|
-
onSessionId?: (
|
|
19
|
+
onSessionId?: (sessionId: string) => void;
|
|
21
20
|
/** Session ID from a previous connection for resuming persisted state. */
|
|
22
|
-
resumeSessionId?: string
|
|
23
|
-
/** WebSocket constructor override. Passed through to
|
|
24
|
-
WebSocket?: WebSocketConstructor
|
|
21
|
+
resumeSessionId?: string;
|
|
22
|
+
/** WebSocket constructor override. Passed through to session options. */
|
|
23
|
+
WebSocket?: WebSocketConstructor;
|
|
25
24
|
};
|
|
26
25
|
/**
|
|
27
|
-
*
|
|
26
|
+
* Tier 1: Config-only options. Renders the default shell (StartScreen + ChatView).
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
type ConfigTier = BaseOptions & {
|
|
31
|
+
component?: never;
|
|
32
|
+
/** Agent name shown in the header and start screen. */
|
|
33
|
+
name?: string;
|
|
34
|
+
/** Optional sidebar component rendered alongside the chat view. */
|
|
35
|
+
sidebar?: ComponentType;
|
|
36
|
+
/** CSS width of the sidebar. Defaults to `"18rem"`. */
|
|
37
|
+
sidebarWidth?: string;
|
|
38
|
+
/** Tool display config: icon and label overrides keyed by tool name. */
|
|
39
|
+
tools?: ToolDisplayConfig;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Tier 2: Custom component. Renders the provided component inside the providers.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
type ComponentTier = BaseOptions & {
|
|
47
|
+
/** Full custom component to render instead of the default shell. */
|
|
48
|
+
component: ComponentType;
|
|
49
|
+
name?: never;
|
|
50
|
+
sidebar?: never;
|
|
51
|
+
sidebarWidth?: never;
|
|
52
|
+
tools?: never;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Configuration passed to {@link client}.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export type ClientConfig = ConfigTier | ComponentTier;
|
|
60
|
+
/**
|
|
61
|
+
* Handle returned by {@link client} for cleanup.
|
|
28
62
|
*
|
|
29
63
|
* Implements `Disposable` so it can be used with `using`.
|
|
30
64
|
*
|
|
31
65
|
* @public
|
|
32
66
|
*/
|
|
33
67
|
export type ClientHandle = {
|
|
34
|
-
/** The underlying
|
|
35
|
-
session:
|
|
36
|
-
/**
|
|
37
|
-
signals: SessionSignals;
|
|
38
|
-
/** Unmount the UI, remove injected styles, and disconnect the session. */
|
|
68
|
+
/** The underlying session core. */
|
|
69
|
+
session: SessionCore;
|
|
70
|
+
/** Unmount the UI and disconnect the session. */
|
|
39
71
|
dispose(): void;
|
|
40
72
|
/** Alias for `dispose` for use with `using`. */
|
|
41
73
|
[Symbol.dispose](): void;
|
|
@@ -43,15 +75,31 @@ export type ClientHandle = {
|
|
|
43
75
|
/**
|
|
44
76
|
* Define and mount a client UI for a voice agent.
|
|
45
77
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
78
|
+
* **Tier 1 (config-only):** Pass options without `component` to get the
|
|
79
|
+
* default shell (StartScreen + ChatView, optional sidebar).
|
|
80
|
+
*
|
|
81
|
+
* **Tier 2 (custom component):** Pass `component` to render a fully custom
|
|
82
|
+
* root component inside the providers.
|
|
83
|
+
*
|
|
84
|
+
* @example Tier 1
|
|
85
|
+
* ```tsx
|
|
86
|
+
* client({
|
|
87
|
+
* name: "Pizza Ordering",
|
|
88
|
+
* theme: { bg: "#1a1a1a", primary: "#e55" },
|
|
89
|
+
* sidebar: OrderPanel,
|
|
90
|
+
* tools: { add_pizza: { icon: "🍕", label: "Adding pizza" } },
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example Tier 2
|
|
95
|
+
* ```tsx
|
|
96
|
+
* client({ component: MyCustomApp });
|
|
97
|
+
* ```
|
|
49
98
|
*
|
|
50
|
-
* @param Component - The Preact component to render.
|
|
51
|
-
* @param options - Client options (target element, platform URL, theme).
|
|
52
99
|
* @returns A {@link ClientHandle} for cleanup.
|
|
53
100
|
* @throws If the target element is not found in the DOM.
|
|
54
101
|
*
|
|
55
102
|
* @public
|
|
56
103
|
*/
|
|
57
|
-
export declare function
|
|
104
|
+
export declare function client(config: ClientConfig): ClientHandle;
|
|
105
|
+
export {};
|
package/dist/define-client.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
2
|
+
import { n as ToolConfigContext } from "./tool-call-block-CCuChsFm.js";
|
|
3
|
+
import { ChatView } from "./components/chat-view.js";
|
|
4
|
+
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
5
|
+
import { StartScreen } from "./components/start-screen.js";
|
|
6
|
+
import { createSessionCore } from "./session-core.js";
|
|
7
|
+
import { createElement } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
import { flushSync } from "react-dom";
|
|
10
|
+
import { createRoot } from "react-dom/client";
|
|
7
11
|
//#region define-client.tsx
|
|
12
|
+
/** @jsxImportSource react */
|
|
8
13
|
function resolveContainer(target = "#app") {
|
|
9
14
|
if (typeof target !== "string") return target;
|
|
10
15
|
const el = document.querySelector(target);
|
|
@@ -12,57 +17,78 @@ function resolveContainer(target = "#app") {
|
|
|
12
17
|
return el;
|
|
13
18
|
}
|
|
14
19
|
/**
|
|
20
|
+
* Default shell rendered in config tier.
|
|
21
|
+
* Wraps StartScreen → (SidebarLayout →) ChatView.
|
|
22
|
+
*/
|
|
23
|
+
function DefaultShell({ name, Sidebar, sidebarWidth }) {
|
|
24
|
+
const chat = /* @__PURE__ */ jsx(ChatView, { ...name !== void 0 ? { title: name } : {} });
|
|
25
|
+
const inner = Sidebar ? /* @__PURE__ */ jsx(SidebarLayout, {
|
|
26
|
+
sidebar: /* @__PURE__ */ jsx(Sidebar, {}),
|
|
27
|
+
...sidebarWidth !== void 0 ? { sidebarWidth } : {},
|
|
28
|
+
children: chat
|
|
29
|
+
}) : chat;
|
|
30
|
+
return /* @__PURE__ */ jsx(StartScreen, {
|
|
31
|
+
...name !== void 0 ? { title: name } : {},
|
|
32
|
+
children: inner
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
15
36
|
* Define and mount a client UI for a voice agent.
|
|
16
37
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
38
|
+
* **Tier 1 (config-only):** Pass options without `component` to get the
|
|
39
|
+
* default shell (StartScreen + ChatView, optional sidebar).
|
|
40
|
+
*
|
|
41
|
+
* **Tier 2 (custom component):** Pass `component` to render a fully custom
|
|
42
|
+
* root component inside the providers.
|
|
43
|
+
*
|
|
44
|
+
* @example Tier 1
|
|
45
|
+
* ```tsx
|
|
46
|
+
* client({
|
|
47
|
+
* name: "Pizza Ordering",
|
|
48
|
+
* theme: { bg: "#1a1a1a", primary: "#e55" },
|
|
49
|
+
* sidebar: OrderPanel,
|
|
50
|
+
* tools: { add_pizza: { icon: "🍕", label: "Adding pizza" } },
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example Tier 2
|
|
55
|
+
* ```tsx
|
|
56
|
+
* client({ component: MyCustomApp });
|
|
57
|
+
* ```
|
|
20
58
|
*
|
|
21
|
-
* @param Component - The Preact component to render.
|
|
22
|
-
* @param options - Client options (target element, platform URL, theme).
|
|
23
59
|
* @returns A {@link ClientHandle} for cleanup.
|
|
24
60
|
* @throws If the target element is not found in the DOM.
|
|
25
61
|
*
|
|
26
62
|
* @public
|
|
27
63
|
*/
|
|
28
|
-
function
|
|
29
|
-
const container = resolveContainer(
|
|
30
|
-
const session =
|
|
31
|
-
platformUrl:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
resumeSessionId: options?.resumeSessionId,
|
|
36
|
-
...options?.WebSocket ? { WebSocket: options.WebSocket } : {}
|
|
64
|
+
function client(config) {
|
|
65
|
+
const container = resolveContainer(config.target);
|
|
66
|
+
const session = createSessionCore({
|
|
67
|
+
platformUrl: config.platformUrl ?? globalThis.location.origin + globalThis.location.pathname,
|
|
68
|
+
onSessionId: config.onSessionId,
|
|
69
|
+
resumeSessionId: config.resumeSessionId,
|
|
70
|
+
...config.WebSocket ? { WebSocket: config.WebSocket } : {}
|
|
37
71
|
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (t.primary) el.style.setProperty("--color-aai-primary", t.primary);
|
|
48
|
-
if (t.text) el.style.setProperty("--color-aai-text", t.text);
|
|
49
|
-
if (t.surface) el.style.setProperty("--color-aai-surface", t.surface);
|
|
50
|
-
if (t.border) el.style.setProperty("--color-aai-border", t.border);
|
|
72
|
+
let RootComponent;
|
|
73
|
+
if ("component" in config && config.component) RootComponent = config.component;
|
|
74
|
+
else {
|
|
75
|
+
const { name, sidebar: Sidebar, sidebarWidth } = config;
|
|
76
|
+
RootComponent = () => createElement(DefaultShell, {
|
|
77
|
+
...name !== void 0 ? { name } : {},
|
|
78
|
+
...Sidebar !== void 0 ? { Sidebar } : {},
|
|
79
|
+
...sidebarWidth !== void 0 ? { sidebarWidth } : {}
|
|
80
|
+
});
|
|
51
81
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
})
|
|
58
|
-
}), container);
|
|
82
|
+
const toolConfig = "tools" in config && config.tools ? config.tools : {};
|
|
83
|
+
const root = createRoot(container);
|
|
84
|
+
flushSync(() => {
|
|
85
|
+
root.render(createElement(ToolConfigContext.Provider, { value: toolConfig }, createElement(ThemeProvider, config.theme !== void 0 ? { value: config.theme } : {}, createElement(SessionProvider, { value: session }, createElement(RootComponent)))));
|
|
86
|
+
});
|
|
59
87
|
const handle = {
|
|
60
88
|
session,
|
|
61
|
-
signals,
|
|
62
89
|
dispose() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
session.disconnect();
|
|
90
|
+
root.unmount();
|
|
91
|
+
session[Symbol.dispose]();
|
|
66
92
|
},
|
|
67
93
|
[Symbol.dispose]() {
|
|
68
94
|
handle.dispose();
|
|
@@ -71,4 +97,4 @@ function defineClient(Component, options) {
|
|
|
71
97
|
return handle;
|
|
72
98
|
}
|
|
73
99
|
//#endregion
|
|
74
|
-
export {
|
|
100
|
+
export { client };
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToolCallInfo } from "./types.ts";
|
|
2
|
+
export declare function useToolResult<R = unknown>(toolName: string, callback: (result: R, toolCall: ToolCallInfo) => void): void;
|
|
3
|
+
export declare function useToolResult(callback: (name: string, result: unknown, toolCall: ToolCallInfo) => void): void;
|
|
4
|
+
export declare function useToolCallStart(toolName: string, callback: (toolCall: ToolCallInfo) => void): void;
|
|
5
|
+
export declare function useToolCallStart(callback: (toolCall: ToolCallInfo) => void): void;
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useSession } from "./context.js";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
//#region hooks.ts
|
|
4
|
+
function tryParseJSON(str) {
|
|
5
|
+
if (!str) return str;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(str);
|
|
8
|
+
} catch {
|
|
9
|
+
return str;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Shared effect loop: fires `onNew` once per tool call that passes `shouldProcess`.
|
|
14
|
+
* Clears seen IDs when toolCalls is empty (session reset).
|
|
15
|
+
*/
|
|
16
|
+
function processToolCalls(toolCalls, seen, shouldProcess, onNew) {
|
|
17
|
+
if (toolCalls.length === 0) {
|
|
18
|
+
seen.clear();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
for (const tc of toolCalls) {
|
|
22
|
+
if (!shouldProcess(tc)) continue;
|
|
23
|
+
if (seen.has(tc.callId)) continue;
|
|
24
|
+
seen.add(tc.callId);
|
|
25
|
+
onNew(tc);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function useToolResult(...args) {
|
|
29
|
+
const filterName = typeof args[0] === "string" ? args[0] : null;
|
|
30
|
+
const callback = typeof args[0] === "string" ? args[1] : args[0];
|
|
31
|
+
const session = useSession();
|
|
32
|
+
const seenRef = useRef(/* @__PURE__ */ new Set());
|
|
33
|
+
const callbackRef = useRef(callback);
|
|
34
|
+
callbackRef.current = callback;
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
processToolCalls(session.toolCalls, seenRef.current, (tc) => tc.status === "done" && (!filterName || tc.name === filterName), (tc) => {
|
|
37
|
+
const parsed = tryParseJSON(tc.result);
|
|
38
|
+
if (filterName) callbackRef.current(parsed, tc);
|
|
39
|
+
else callbackRef.current(tc.name, parsed, tc);
|
|
40
|
+
});
|
|
41
|
+
}, [session.toolCalls, filterName]);
|
|
42
|
+
}
|
|
43
|
+
function useToolCallStart(...args) {
|
|
44
|
+
const filterName = typeof args[0] === "string" ? args[0] : null;
|
|
45
|
+
const callback = typeof args[0] === "string" ? args[1] : args[0];
|
|
46
|
+
const session = useSession();
|
|
47
|
+
const seenRef = useRef(/* @__PURE__ */ new Set());
|
|
48
|
+
const callbackRef = useRef(callback);
|
|
49
|
+
callbackRef.current = callback;
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
processToolCalls(session.toolCalls, seenRef.current, (tc) => tc.status === "pending" && (!filterName || tc.name === filterName), (tc) => callbackRef.current(tc));
|
|
52
|
+
}, [session.toolCalls, filterName]);
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { useToolCallStart, useToolResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,37 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export {
|
|
16
|
-
export type { ButtonSize, ButtonVariant } from "./_components/button.tsx";
|
|
17
|
-
export { Button } from "./_components/button.tsx";
|
|
18
|
-
export { ChatView } from "./_components/chat-view.tsx";
|
|
19
|
-
export { Controls } from "./_components/controls.tsx";
|
|
20
|
-
export { ErrorBanner } from "./_components/error-banner.tsx";
|
|
21
|
-
export { MessageBubble } from "./_components/message-bubble.tsx";
|
|
22
|
-
export { MessageList } from "./_components/message-list.tsx";
|
|
23
|
-
export { SidebarLayout } from "./_components/sidebar-layout.tsx";
|
|
24
|
-
export { StartScreen } from "./_components/start-screen.tsx";
|
|
25
|
-
export { StateIndicator } from "./_components/state-indicator.tsx";
|
|
26
|
-
export { ThinkingIndicator } from "./_components/thinking-indicator.tsx";
|
|
27
|
-
export { ToolCallBlock } from "./_components/tool-call-block.tsx";
|
|
28
|
-
export { Transcript } from "./_components/transcript.tsx";
|
|
29
|
-
export type { ClientConfig, ClientTheme } from "./client-context.ts";
|
|
30
|
-
export { useClientConfig } from "./client-context.ts";
|
|
31
|
-
export type { ClientHandle, ClientOptions } from "./define-client.tsx";
|
|
32
|
-
export { defineClient } from "./define-client.tsx";
|
|
33
|
-
export type { VoiceSession } from "./session.ts";
|
|
34
|
-
export { createVoiceSession } from "./session.ts";
|
|
35
|
-
export type { SessionSignals } from "./signals.ts";
|
|
36
|
-
export { createSessionControls, SessionProvider, useAutoScroll, useSession, useToolCallStart, useToolResult, } from "./signals.ts";
|
|
37
|
-
export type { AgentState, ChatMessage, Reactive, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, } from "./types.ts";
|
|
1
|
+
export { Button } from "./components/button.tsx";
|
|
2
|
+
export { ChatView } from "./components/chat-view.tsx";
|
|
3
|
+
export { MessageList } from "./components/message-list.tsx";
|
|
4
|
+
export { SidebarLayout } from "./components/sidebar-layout.tsx";
|
|
5
|
+
export { StartScreen } from "./components/start-screen.tsx";
|
|
6
|
+
export type { ToolDisplayConfig } from "./components/tool-config-context.ts";
|
|
7
|
+
export { ToolConfigContext } from "./components/tool-config-context.ts";
|
|
8
|
+
export type { Session } from "./context.ts";
|
|
9
|
+
export { SessionProvider, ThemeProvider, useSession, useTheme } from "./context.ts";
|
|
10
|
+
export type { ClientConfig, ClientHandle, } from "./define-client.tsx";
|
|
11
|
+
export { client } from "./define-client.tsx";
|
|
12
|
+
export { useToolCallStart, useToolResult } from "./hooks.ts";
|
|
13
|
+
export type { SessionCore, SessionCoreOptions, SessionSnapshot, } from "./session-core.ts";
|
|
14
|
+
export { createSessionCore } from "./session-core.ts";
|
|
15
|
+
export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import { ChatView } from "./_components/chat-view.js";
|
|
13
|
-
import { StartScreen } from "./_components/start-screen.js";
|
|
14
|
-
import { App } from "./_components/app.js";
|
|
15
|
-
import { SidebarLayout } from "./_components/sidebar-layout.js";
|
|
16
|
-
import { t as createVoiceSession } from "./session-CWB7vmqz.js";
|
|
17
|
-
import { defineClient } from "./define-client.js";
|
|
18
|
-
export { App, Button, ChatView, Controls, ErrorBanner, MessageBubble, MessageList, SessionProvider, SidebarLayout, StartScreen, StateIndicator, ThinkingIndicator, ToolCallBlock, Transcript, createSessionControls, createVoiceSession, defineClient, useAutoScroll, useClientConfig, useSession, useToolCallStart, useToolResult };
|
|
1
|
+
import { SessionProvider, ThemeProvider, useSession, useTheme } from "./context.js";
|
|
2
|
+
import { Button } from "./components/button.js";
|
|
3
|
+
import { n as ToolConfigContext } from "./tool-call-block-CCuChsFm.js";
|
|
4
|
+
import { MessageList } from "./components/message-list.js";
|
|
5
|
+
import { ChatView } from "./components/chat-view.js";
|
|
6
|
+
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
7
|
+
import { StartScreen } from "./components/start-screen.js";
|
|
8
|
+
import { createSessionCore } from "./session-core.js";
|
|
9
|
+
import { client } from "./define-client.js";
|
|
10
|
+
import { useToolCallStart, useToolResult } from "./hooks.js";
|
|
11
|
+
export { Button, ChatView, MessageList, SessionProvider, SidebarLayout, StartScreen, ThemeProvider, ToolConfigContext, client, createSessionCore, useSession, useTheme, useToolCallStart, useToolResult };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { AgentState, ChatMessage, SessionError, ToolCallInfo, VoiceSessionOptions } from "./types.ts";
|
|
2
|
+
export type { AgentState, ChatMessage, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Immutable snapshot of the session state.
|
|
5
|
+
*
|
|
6
|
+
* Consumers (e.g. React hooks via `useSyncExternalStore`) read this to render.
|
|
7
|
+
* A new object reference is created on every state change.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export type SessionSnapshot = {
|
|
12
|
+
readonly state: AgentState;
|
|
13
|
+
readonly messages: ChatMessage[];
|
|
14
|
+
readonly toolCalls: ToolCallInfo[];
|
|
15
|
+
readonly userTranscript: string | null;
|
|
16
|
+
readonly agentTranscript: string | null;
|
|
17
|
+
readonly error: SessionError | null;
|
|
18
|
+
readonly started: boolean;
|
|
19
|
+
readonly running: boolean;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A framework-agnostic voice session that manages WebSocket communication,
|
|
23
|
+
* audio capture/playback, and agent state transitions.
|
|
24
|
+
*
|
|
25
|
+
* Uses a subscribe/getSnapshot pattern (compatible with React's
|
|
26
|
+
* `useSyncExternalStore`). Implements `Disposable` for resource cleanup.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export type SessionCore = {
|
|
31
|
+
/** Return the current immutable state snapshot. */
|
|
32
|
+
getSnapshot(): SessionSnapshot;
|
|
33
|
+
/** Subscribe to state changes. Returns an unsubscribe function. */
|
|
34
|
+
subscribe(callback: () => void): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Open a WebSocket connection to the server and begin audio capture.
|
|
37
|
+
* @param options - Optional. `signal` is an AbortSignal that, when aborted, disconnects the session.
|
|
38
|
+
*/
|
|
39
|
+
connect(options?: {
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}): void;
|
|
42
|
+
/** Cancel the current agent turn and discard in-flight TTS audio. */
|
|
43
|
+
cancel(): void;
|
|
44
|
+
/** Clear messages, transcript, and error state without disconnecting. */
|
|
45
|
+
resetState(): void;
|
|
46
|
+
/** Reset the session: clear state and reconnect. */
|
|
47
|
+
reset(): void;
|
|
48
|
+
/** Close the WebSocket and release all audio resources. */
|
|
49
|
+
disconnect(): void;
|
|
50
|
+
/** Start the session for the first time (sets `started` and `running`). */
|
|
51
|
+
start(): void;
|
|
52
|
+
/** Toggle between connected and disconnected states. */
|
|
53
|
+
toggle(): void;
|
|
54
|
+
/** Alias for `disconnect` for use with `using`. */
|
|
55
|
+
[Symbol.dispose](): void;
|
|
56
|
+
};
|
|
57
|
+
export type SessionCoreOptions = VoiceSessionOptions;
|
|
58
|
+
/**
|
|
59
|
+
* Create a framework-agnostic voice session core that connects to an AAI
|
|
60
|
+
* server via WebSocket.
|
|
61
|
+
*
|
|
62
|
+
* Uses a subscribe/getSnapshot pattern for state management, compatible with
|
|
63
|
+
* React's `useSyncExternalStore` and other external store integrations.
|
|
64
|
+
*
|
|
65
|
+
* @param options - Session configuration including the platform server URL.
|
|
66
|
+
* @returns A {@link SessionCore} handle for controlling the session.
|
|
67
|
+
*
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
export declare function createSessionCore(options: SessionCoreOptions): SessionCore;
|