@alexkroman1/aai-ui 1.16.0 → 3.0.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/dist/_module-url-C_4gRVL0.js +15 -0
- package/dist/audio.d.ts +85 -11
- package/dist/audio.js +112 -83
- package/dist/chat-view-C1oJxsWz.js +129 -0
- package/dist/client-config.d.ts +6 -6
- package/dist/components/chat-view.d.ts +1 -8
- package/dist/components/chat-view.js +2 -2
- package/dist/components/console-shell.d.ts +37 -0
- package/dist/components/controls.js +1 -1
- package/dist/components/url-chips.d.ts +1 -4
- package/dist/context.d.ts +1 -1
- package/dist/context.js +1 -4
- package/dist/{controls-BbZcmnJf.js → controls-DV368uhb.js} +2 -5
- package/dist/default-client/assets/_module-url-BX0RuRU2.js +1 -0
- package/dist/default-client/assets/audio-BGHiiDY_.js +1 -0
- package/dist/default-client/assets/capture-processor-BLPsqnGl.js +90 -0
- package/dist/default-client/assets/{index-BunwIXSP.js → index-DXf7-M0Q.js} +156 -36
- package/dist/default-client/assets/index-Dv-Q5VRL.css +2 -0
- package/dist/default-client/assets/playback-processor-B_T_1KQP.js +278 -0
- package/dist/default-client/index.html +2 -2
- package/dist/define-client-Cyf1jqAl.js +150 -0
- package/dist/define-client.d.ts +0 -9
- package/dist/define-client.js +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.js +7 -5
- package/dist/{session-core-B64kau_v.js → session-core-BM3WHeoY.js} +36 -128
- package/dist/session-core-messages.d.ts +0 -4
- package/dist/session-core-types.d.ts +1 -27
- package/dist/session-core.js +1 -1
- package/dist/types.d.ts +24 -1
- package/dist/types.js +32 -2
- package/dist/worklets/_module-url.d.ts +10 -0
- package/dist/worklets/capture-processor.d.ts +3 -3
- package/dist/worklets/capture-processor.js +35 -52
- package/dist/worklets/playback-processor.d.ts +3 -3
- package/dist/worklets/playback-processor.js +149 -26
- package/package.json +2 -2
- package/dist/chat-view-gi6FccZq.js +0 -193
- package/dist/components/sync-chat-view.d.ts +0 -18
- package/dist/components/text-controls.d.ts +0 -14
- package/dist/default-client/assets/audio-DNDZgEZp.js +0 -1
- package/dist/default-client/assets/capture-processor-UlKEKyIW.js +0 -108
- package/dist/default-client/assets/index-BogmeUln.css +0 -2
- package/dist/default-client/assets/playback-processor-C5HVRVbu.js +0 -156
- package/dist/define-client-DdpijqAu.js +0 -906
- package/dist/session-core-upload.d.ts +0 -16
- package/dist/sync-mic.d.ts +0 -93
- package/dist/sync-session.d.ts +0 -49
- package/dist/sync-vad.d.ts +0 -54
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.3.3 | 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-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--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-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, 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;--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;--tracking-wide:.025em;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--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);--font-aai:"Monument Grotesk", "ABC Monument Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-aai-serif:"Source Serif 4", "Source Serif Pro", Charter, "Iowan Old Style", Georgia, serif;--font-aai-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;--radius-aai:4px}}@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,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, 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:where(:not(iframe)){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{.collapse{visibility:collapse}.invisible{visibility:hidden}.absolute{position:absolute}.relative{position:relative}.static{position:static}.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:0}.mx-auto{margin-inline:auto}.mt-2{margin-top:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.box-border{box-sizing:border-box}.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-4{height:calc(var(--spacing) * 4)}.h-9{height:calc(var(--spacing) * 9)}.h-11{height:calc(var(--spacing) * 11)}.h-\[7px\]{height:7px}.h-screen{height:100vh}.max-h-64{max-height:calc(var(--spacing) * 64)}.min-h-0{min-height:0}.min-h-5{min-height:calc(var(--spacing) * 5)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-4{width:calc(var(--spacing) * 4)}.w-\[7px\]{width:7px}.w-fit{width:fit-content}.w-full{width:100%}.max-w-75{max-width:calc(var(--spacing) * 75)}.max-w-105{max-width:calc(var(--spacing) * 105)}.max-w-190{max-width:calc(var(--spacing) * 190)}.max-w-\[60\%\]{max-width:60%}.max-w-\[82\%\]{max-width:82%}.max-w-\[min\(78\%\,64ch\)\]{max-width:min(78%,64ch)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.rotate-90{rotate:90deg}.cursor-pointer{cursor:pointer}.\[scrollbar-width\:none\]{scrollbar-width:none}.appearance-none{appearance:none}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-aai{border-radius:var(--radius-aai)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-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-none{--tw-border-style:none;border-style:none}.bg-transparent{background-color:#0000}.p-7{padding:calc(var(--spacing) * 7)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-10{padding-inline:calc(var(--spacing) * 10)}.py-1{padding-block:var(--spacing)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.text-center{text-align:center}.text-left{text-align:left}.font-aai{font-family:var(--font-aai)}.font-aai-mono{font-family:var(--font-aai-mono)}.font-aai-serif{font-family:var(--font-aai-serif)}.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-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[22px\]{font-size:22px}.text-\[32px\]{font-size:32px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-\[1\.15\]{--tw-leading:1.15;line-height:1.15}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[23px\]{--tw-leading:23px;line-height:23px}.leading-\[130\%\]{--tw-leading:130%;line-height:130%}.leading-none{--tw-leading:1;line-height:1}.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)}.tracking-\[-0\.2px\]{--tw-tracking:-.2px;letter-spacing:-.2px}.tracking-\[1\.2px\]{--tw-tracking:1.2px;letter-spacing:1.2px}.tracking-\[1\.4px\]{--tw-tracking:1.4px;letter-spacing:1.4px}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-balance{text-wrap:balance}.wrap-break-word{overflow-wrap:break-word}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.uppercase{text-transform:uppercase}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.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))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.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}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (width>=40rem){.sm\:px-16{padding-inline:calc(var(--spacing) * 16)}.sm\:py-14{padding-block:calc(var(--spacing) * 14)}}}@keyframes aai-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.82)}}@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-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import{i as e}from"./index-DXf7-M0Q.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
|
|
2
|
+
class PlaybackProcessor extends AudioWorkletProcessor {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
super();
|
|
5
|
+
const opts = options.processorOptions || {};
|
|
6
|
+
// The node's context IS the playback context (audio.ts asserts its rate),
|
|
7
|
+
// so the worklet-global sampleRate is authoritative; the option exists
|
|
8
|
+
// for the node-less test harness.
|
|
9
|
+
const rate = opts.sampleRate ?? sampleRate;
|
|
10
|
+
// Fill target for the start of a turn. If 'done' arrives first (short
|
|
11
|
+
// utterance), start immediately instead of waiting for audio that is
|
|
12
|
+
// never coming.
|
|
13
|
+
this.jitterSamples = Math.floor((rate * (opts.jitterMs ?? 400)) / 1000);
|
|
14
|
+
// Fill target after an underrun — see PLAYBACK_REFILL_MS.
|
|
15
|
+
this.refillSamples = Math.floor((rate * (opts.refillMs ?? 200)) / 1000);
|
|
16
|
+
// Concealment source: a ring of the most recently played samples, looped
|
|
17
|
+
// under a decaying gain to cover a gap. Sized to the fade window, with a
|
|
18
|
+
// per-sample decay that reaches the floor exactly at its end.
|
|
19
|
+
this.concealCapacity = Math.max(1, Math.floor((rate * 40) / 1000));
|
|
20
|
+
this.concealBuf = new Float32Array(this.concealCapacity);
|
|
21
|
+
this.concealDecay = Math.exp(Math.log(${e}) / this.concealCapacity);
|
|
22
|
+
// Float32 ring buffer — PLAYBACK_BUFFER_SECONDS at the context sample
|
|
23
|
+
// rate. Allocated once for the node's lifetime; per-turn state resets via
|
|
24
|
+
// resetTurn(). writePos and readPos are absolute (monotonic) sample
|
|
25
|
+
// counts; the buffer is indexed modulo capacity so a longer reply keeps
|
|
26
|
+
// playing instead of writing past the end and going silent.
|
|
27
|
+
this.capacity = rate * 60;
|
|
28
|
+
this.samples = new Float32Array(this.capacity);
|
|
29
|
+
// Platform endianness probe: the wire format is PCM16 little-endian, so
|
|
30
|
+
// the Int16Array fast path in ingestBytes is only valid on LE hosts
|
|
31
|
+
// (every shipping browser target; the DataView path is the fallback).
|
|
32
|
+
this.littleEndian = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
|
|
33
|
+
this.resetTurn();
|
|
34
|
+
|
|
35
|
+
this.port.onmessage = (e) => {
|
|
36
|
+
const d = e.data;
|
|
37
|
+
if (d.event === 'write') {
|
|
38
|
+
this.ingestBytes(d.buffer);
|
|
39
|
+
} else if (d.event === 'interrupt') {
|
|
40
|
+
// Applied eagerly, not deferred to the next process(): onmessage and
|
|
41
|
+
// process() never interleave (one audio thread), and a deferred
|
|
42
|
+
// interrupt would let 'write'/'done' frames for the NEXT turn
|
|
43
|
+
// coalesce in ahead of it and be wiped by the reset along with the
|
|
44
|
+
// cancelled turn's audio.
|
|
45
|
+
this.stopTurn('interrupt');
|
|
46
|
+
} else if (d.event === 'done') {
|
|
47
|
+
this.isDone = true;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Reset per-turn state so the node is reusable across replies without
|
|
53
|
+
// reallocating the sample buffer or re-instantiating the worklet.
|
|
54
|
+
resetTurn() {
|
|
55
|
+
this.isDone = false;
|
|
56
|
+
this.playing = false;
|
|
57
|
+
// Whether any real audio has been rendered this turn. Separates a turn's
|
|
58
|
+
// pre-roll (nothing to extrapolate from, and not a defect) from a
|
|
59
|
+
// mid-turn underrun.
|
|
60
|
+
this.hasPlayed = false;
|
|
61
|
+
this.fillTarget = this.jitterSamples;
|
|
62
|
+
// Carry-over byte for split samples across chunks
|
|
63
|
+
this.carry = null;
|
|
64
|
+
this.writePos = 0;
|
|
65
|
+
this.readPos = 0;
|
|
66
|
+
// Concealment ring state and the current fade position.
|
|
67
|
+
this.concealLen = 0;
|
|
68
|
+
this.concealWrite = 0;
|
|
69
|
+
this.concealPos = 0;
|
|
70
|
+
this.concealGain = 1;
|
|
71
|
+
// Episode flags, so a multi-quantum gap counts as one event.
|
|
72
|
+
this.concealing = false;
|
|
73
|
+
this.concealedSilence = false;
|
|
74
|
+
// Reported to the host on 'stop'. A fresh object per turn: the one just
|
|
75
|
+
// posted must not be mutated by the next turn.
|
|
76
|
+
this.stats = {
|
|
77
|
+
concealedSamples: 0,
|
|
78
|
+
silentConcealedSamples: 0,
|
|
79
|
+
concealmentEvents: 0,
|
|
80
|
+
silentConcealmentEvents: 0,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// End the current turn: notify the host and rearm for the next reply.
|
|
85
|
+
// Must NOT return false from process() — a processor that stops is dead
|
|
86
|
+
// for good, forcing a new node (and buffer) per reply.
|
|
87
|
+
// \`reason\` ('interrupt' | 'done') tells the host which turn boundary this
|
|
88
|
+
// stop belongs to: interrupt-stops are dropped host-side (flush() already
|
|
89
|
+
// settled that turn), so they can never resolve a later turn's done() early.
|
|
90
|
+
stopTurn(reason) {
|
|
91
|
+
this.port.postMessage({ event: 'stop', reason, stats: this.stats });
|
|
92
|
+
this.resetTurn();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Cover a quantum (from \`start\`) where real audio should have been.
|
|
96
|
+
//
|
|
97
|
+
// Before the turn's first samples there is nothing to extrapolate from, so
|
|
98
|
+
// the gap is plain silence and counted as nothing — WebRTC likewise only
|
|
99
|
+
// counts concealment once playout has begun. After that, loop the retained
|
|
100
|
+
// tail under a decaying gain: a hard zero-fill is a discontinuity mid-word,
|
|
101
|
+
// which is the click that makes a brief stall sound like breakage.
|
|
102
|
+
coverGap(out, start) {
|
|
103
|
+
if (!this.hasPlayed) {
|
|
104
|
+
out.fill(0, start);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!this.concealing) {
|
|
108
|
+
this.concealing = true;
|
|
109
|
+
this.concealedSilence = false;
|
|
110
|
+
this.stats.concealmentEvents++;
|
|
111
|
+
}
|
|
112
|
+
const total = out.length - start;
|
|
113
|
+
const len = this.concealLen;
|
|
114
|
+
let silent = 0;
|
|
115
|
+
// Second condition: once the fade has decayed to the floor, every sample
|
|
116
|
+
// the loop would emit is 0 anyway — bulk-fill instead of running 128
|
|
117
|
+
// branchy iterations per quantum for the whole tail of a long stall.
|
|
118
|
+
if (len === 0 || this.concealGain < ${e}) {
|
|
119
|
+
out.fill(0, start);
|
|
120
|
+
silent = total;
|
|
121
|
+
} else {
|
|
122
|
+
let g = this.concealGain;
|
|
123
|
+
for (let i = start; i < out.length; i++) {
|
|
124
|
+
if (g < ${e}) {
|
|
125
|
+
// The fade has run out: keep counting the gap, but stop looping a
|
|
126
|
+
// fragment that is now inaudible anyway.
|
|
127
|
+
out[i] = 0;
|
|
128
|
+
silent++;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
out[i] = this.concealBuf[this.concealPos] * g;
|
|
132
|
+
this.concealPos = this.concealPos + 1 === len ? 0 : this.concealPos + 1;
|
|
133
|
+
g *= this.concealDecay;
|
|
134
|
+
}
|
|
135
|
+
this.concealGain = g;
|
|
136
|
+
}
|
|
137
|
+
this.stats.concealedSamples += total;
|
|
138
|
+
if (silent > 0) {
|
|
139
|
+
this.stats.silentConcealedSamples += silent;
|
|
140
|
+
if (!this.concealedSilence) {
|
|
141
|
+
this.concealedSilence = true;
|
|
142
|
+
this.stats.silentConcealmentEvents++;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Retain the tail of a rendered quantum as the next gap's concealment
|
|
148
|
+
// source, and close any episode the real audio just ended.
|
|
149
|
+
rememberTail(out, n) {
|
|
150
|
+
const cap = this.concealCapacity;
|
|
151
|
+
const take = Math.min(n, cap);
|
|
152
|
+
// Bulk copies (this runs on every cleanly rendered quantum): the tail is
|
|
153
|
+
// one contiguous source run, landing in at most two ring runs.
|
|
154
|
+
const tail = out.subarray(n - take, n);
|
|
155
|
+
const first = Math.min(take, cap - this.concealWrite);
|
|
156
|
+
this.concealBuf.set(tail.subarray(0, first), this.concealWrite);
|
|
157
|
+
if (take > first) this.concealBuf.set(tail.subarray(first), 0);
|
|
158
|
+
this.concealWrite = (this.concealWrite + take) % cap;
|
|
159
|
+
this.concealLen = Math.min(cap, this.concealLen + take);
|
|
160
|
+
// Read the loop oldest-first; once the ring is full the write cursor is
|
|
161
|
+
// the oldest retained sample.
|
|
162
|
+
this.concealPos = this.concealLen === cap ? this.concealWrite : 0;
|
|
163
|
+
this.concealing = false;
|
|
164
|
+
this.concealGain = 1;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
ingestBytes(uint8) {
|
|
168
|
+
let bytes = uint8;
|
|
169
|
+
|
|
170
|
+
if (this.carry !== null) {
|
|
171
|
+
const merged = new Uint8Array(1 + bytes.length);
|
|
172
|
+
merged[0] = this.carry;
|
|
173
|
+
merged.set(bytes, 1);
|
|
174
|
+
bytes = merged;
|
|
175
|
+
this.carry = null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (bytes.length % 2 !== 0) {
|
|
179
|
+
this.carry = bytes[bytes.length - 1];
|
|
180
|
+
bytes = bytes.subarray(0, bytes.length - 1);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (bytes.length === 0) return;
|
|
184
|
+
const numSamples = bytes.length / 2;
|
|
185
|
+
const cap = this.capacity;
|
|
186
|
+
const samples = this.samples;
|
|
187
|
+
if (this.littleEndian && (bytes.byteOffset & 1) === 0) {
|
|
188
|
+
// Fast path: 2-byte-aligned LE bytes wrap directly as an Int16Array;
|
|
189
|
+
// copy wrap-aware in at most two runs with no per-sample DataView call
|
|
190
|
+
// or modulo. This runs on the realtime audio thread.
|
|
191
|
+
const int16 = new Int16Array(bytes.buffer, bytes.byteOffset, numSamples);
|
|
192
|
+
let src = 0;
|
|
193
|
+
let dst = this.writePos % cap;
|
|
194
|
+
while (src < numSamples) {
|
|
195
|
+
const run = Math.min(numSamples - src, cap - dst);
|
|
196
|
+
for (let j = 0; j < run; j++) {
|
|
197
|
+
samples[dst + j] = int16[src + j] / 0x8000;
|
|
198
|
+
}
|
|
199
|
+
src += run;
|
|
200
|
+
dst = 0;
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
// Odd byte offset (or big-endian host): fall back to per-sample reads.
|
|
204
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
205
|
+
let dst = this.writePos % cap;
|
|
206
|
+
for (let i = 0; i < numSamples; i++) {
|
|
207
|
+
samples[dst] = view.getInt16(i * 2, true) / 0x8000;
|
|
208
|
+
dst++;
|
|
209
|
+
if (dst === cap) dst = 0;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
this.writePos += numSamples;
|
|
213
|
+
// If the producer outran the consumer by more than the buffer holds, drop
|
|
214
|
+
// the oldest unplayed audio rather than reading samples we've overwritten.
|
|
215
|
+
if (this.writePos - this.readPos > this.capacity) {
|
|
216
|
+
this.readPos = this.writePos - this.capacity;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
process(inputs, outputs) {
|
|
221
|
+
// No output wired up yet — nothing to render this quantum. Throwing here
|
|
222
|
+
// would permanently kill the processor (the node is persistent per
|
|
223
|
+
// session), so guard like the capture processor does.
|
|
224
|
+
if (!outputs[0] || !outputs[0][0]) return true;
|
|
225
|
+
const out = outputs[0][0];
|
|
226
|
+
const avail = this.writePos - this.readPos;
|
|
227
|
+
|
|
228
|
+
// Filling: wait for the target. 'done' short-circuits it — what is
|
|
229
|
+
// buffered is all there will be, so there is nothing left to wait for.
|
|
230
|
+
if (!this.playing) {
|
|
231
|
+
if (avail >= this.fillTarget || this.isDone) {
|
|
232
|
+
this.playing = true;
|
|
233
|
+
} else {
|
|
234
|
+
this.coverGap(out, 0);
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Underrun: this quantum cannot be filled and more audio is still coming.
|
|
240
|
+
// Go back to filling (at the refill target) and cover the gap, leaving
|
|
241
|
+
// readPos untouched — the fragment stays buffered and plays intact once
|
|
242
|
+
// the buffer recovers, instead of being dribbled out a few samples at a
|
|
243
|
+
// time for the rest of the turn.
|
|
244
|
+
if (avail < out.length && !this.isDone) {
|
|
245
|
+
this.playing = false;
|
|
246
|
+
this.fillTarget = this.refillSamples;
|
|
247
|
+
this.coverGap(out, 0);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (avail > 0) {
|
|
252
|
+
const n = Math.min(avail, out.length);
|
|
253
|
+
// Copy from the ring buffer, splitting across the wrap boundary.
|
|
254
|
+
const start = this.readPos % this.capacity;
|
|
255
|
+
const first = Math.min(n, this.capacity - start);
|
|
256
|
+
out.set(this.samples.subarray(start, start + first), 0);
|
|
257
|
+
if (n > first) out.set(this.samples.subarray(0, n - first), first);
|
|
258
|
+
this.readPos += n;
|
|
259
|
+
// Only reachable with n < out.length on the turn's final partial
|
|
260
|
+
// quantum (the underrun branch above catches every other case).
|
|
261
|
+
out.fill(0, n);
|
|
262
|
+
this.hasPlayed = true;
|
|
263
|
+
this.rememberTail(out, n);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Drained and done: end the turn. Not reachable mid-turn — an empty
|
|
268
|
+
// buffer with audio still coming is the underrun branch above.
|
|
269
|
+
out.fill(0);
|
|
270
|
+
if (this.isDone) {
|
|
271
|
+
this.stopTurn('done');
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
registerProcessor('playback-processor', PlaybackProcessor);
|
|
278
|
+
`);export{n as default};
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<title>aai</title>
|
|
7
7
|
<link rel="icon" href="data:," />
|
|
8
8
|
<style>html, body { background: #FBF8F2; margin: 0; }</style>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-DXf7-M0Q.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/index-Dv-Q5VRL.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<main id="app"></main>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
2
|
+
import { t as ChatView } from "./chat-view-C1oJxsWz.js";
|
|
3
|
+
import { n as ToolConfigContext } from "./tool-call-block-DIxpG8GM.js";
|
|
4
|
+
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
5
|
+
import { StartScreen } from "./components/start-screen.js";
|
|
6
|
+
import { t as createSessionCore } from "./session-core-BM3WHeoY.js";
|
|
7
|
+
import { CLIENT_CONFIG_PATH, ClientConfigResponseSchema } from "@alexkroman1/aai/protocol";
|
|
8
|
+
import { createElement, useEffect, useState } from "react";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
import { flushSync } from "react-dom";
|
|
11
|
+
import { createRoot } from "react-dom/client";
|
|
12
|
+
//#region client-config.ts
|
|
13
|
+
/**
|
|
14
|
+
* Pre-connection client-config lookup.
|
|
15
|
+
*
|
|
16
|
+
* `GET client-config` (relative to the agent's base URL — see
|
|
17
|
+
* `sdk/client-config.ts` in `@alexkroman1/aai`) gives the default client the
|
|
18
|
+
* agent's display name and greeting before any connection exists. Every
|
|
19
|
+
* failure path — network error, 404 from an older server, malformed body —
|
|
20
|
+
* degrades to the empty default, so this lookup can never break an existing
|
|
21
|
+
* agent.
|
|
22
|
+
*/
|
|
23
|
+
/** Resolve a relative endpoint path against the agent's base URL. */
|
|
24
|
+
function buildAgentUrl(platformUrl, endpointPath) {
|
|
25
|
+
return new URL(endpointPath, platformUrl.endsWith("/") ? platformUrl : `${platformUrl}/`);
|
|
26
|
+
}
|
|
27
|
+
const AGENT_DEFAULT = {};
|
|
28
|
+
/** Fetch the agent's client config; any failure yields the agent default. */
|
|
29
|
+
async function fetchClientConfig(platformUrl, fetchFn) {
|
|
30
|
+
const doFetch = fetchFn ?? ((input, init) => globalThis.fetch(input, init));
|
|
31
|
+
try {
|
|
32
|
+
const resp = await doFetch(buildAgentUrl(platformUrl, CLIENT_CONFIG_PATH).href);
|
|
33
|
+
if (!resp.ok) return AGENT_DEFAULT;
|
|
34
|
+
const parsed = ClientConfigResponseSchema.safeParse(await resp.json());
|
|
35
|
+
return parsed.success ? parsed.data : AGENT_DEFAULT;
|
|
36
|
+
} catch {
|
|
37
|
+
return AGENT_DEFAULT;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region define-client.tsx
|
|
42
|
+
/** @jsxImportSource react */
|
|
43
|
+
function resolveContainer(target = "#app") {
|
|
44
|
+
if (typeof target !== "string") return target;
|
|
45
|
+
const el = document.querySelector(target);
|
|
46
|
+
if (!el) throw new Error(`Element not found: ${target}`);
|
|
47
|
+
return el;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Default shell rendered in config tier.
|
|
51
|
+
* Wraps StartScreen → (SidebarLayout →) ChatView.
|
|
52
|
+
*/
|
|
53
|
+
function DefaultShell({ name, Sidebar, sidebarWidth }) {
|
|
54
|
+
const chat = /* @__PURE__ */ jsx(ChatView, { title: name });
|
|
55
|
+
return /* @__PURE__ */ jsx(StartScreen, {
|
|
56
|
+
title: name,
|
|
57
|
+
children: Sidebar ? /* @__PURE__ */ jsx(SidebarLayout, {
|
|
58
|
+
sidebar: /* @__PURE__ */ jsx(Sidebar, {}),
|
|
59
|
+
sidebarWidth,
|
|
60
|
+
children: chat
|
|
61
|
+
}) : chat
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Config-tier root: fetches the server-declared display name via
|
|
66
|
+
* `GET client-config` and renders the chat shell. The shell renders
|
|
67
|
+
* immediately — optimistically — while the lookup is in flight; servers
|
|
68
|
+
* without the endpoint (every lookup failure resolves to the empty default)
|
|
69
|
+
* work exactly as before.
|
|
70
|
+
*/
|
|
71
|
+
function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
|
|
72
|
+
const [resolved, setResolved] = useState(null);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
let cancelled = false;
|
|
75
|
+
fetchClientConfig(platformUrl).then((cfg) => {
|
|
76
|
+
if (!cancelled) setResolved(cfg);
|
|
77
|
+
});
|
|
78
|
+
return () => {
|
|
79
|
+
cancelled = true;
|
|
80
|
+
};
|
|
81
|
+
}, [platformUrl]);
|
|
82
|
+
return /* @__PURE__ */ jsx(DefaultShell, {
|
|
83
|
+
name: name ?? resolved?.name,
|
|
84
|
+
Sidebar,
|
|
85
|
+
sidebarWidth
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Define and mount a client UI for a voice agent.
|
|
90
|
+
*
|
|
91
|
+
* **Tier 1 (config-only):** Pass options without `component` to get the
|
|
92
|
+
* default shell (StartScreen + ChatView, optional sidebar).
|
|
93
|
+
*
|
|
94
|
+
* **Tier 2 (custom component):** Pass `component` to render a fully custom
|
|
95
|
+
* root component inside the providers.
|
|
96
|
+
*
|
|
97
|
+
* @example Tier 1
|
|
98
|
+
* ```tsx
|
|
99
|
+
* client({
|
|
100
|
+
* name: "Pizza Ordering",
|
|
101
|
+
* theme: { bg: "#1a1a1a", primary: "#e55" },
|
|
102
|
+
* sidebar: OrderPanel,
|
|
103
|
+
* tools: { add_pizza: { icon: "🍕", label: "Adding pizza" } },
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* @example Tier 2
|
|
108
|
+
* ```tsx
|
|
109
|
+
* client({ component: MyCustomApp });
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @returns A {@link ClientHandle} for cleanup.
|
|
113
|
+
* @throws If the target element is not found in the DOM.
|
|
114
|
+
*
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
function client(config) {
|
|
118
|
+
const container = resolveContainer(config.target);
|
|
119
|
+
const platformUrl = config.platformUrl ?? globalThis.location.origin + globalThis.location.pathname;
|
|
120
|
+
const session = createSessionCore({
|
|
121
|
+
platformUrl,
|
|
122
|
+
onSessionId: config.onSessionId,
|
|
123
|
+
resumeSessionId: config.resumeSessionId,
|
|
124
|
+
WebSocket: config.WebSocket
|
|
125
|
+
});
|
|
126
|
+
const rootNode = config.component ? createElement(config.component) : createElement(DefaultRoot, {
|
|
127
|
+
platformUrl,
|
|
128
|
+
name: config.name,
|
|
129
|
+
Sidebar: config.sidebar,
|
|
130
|
+
sidebarWidth: config.sidebarWidth
|
|
131
|
+
});
|
|
132
|
+
const toolConfig = config.tools ?? {};
|
|
133
|
+
const root = createRoot(container);
|
|
134
|
+
flushSync(() => {
|
|
135
|
+
root.render(createElement(ToolConfigContext.Provider, { value: toolConfig }, createElement(ThemeProvider, { value: config.theme }, createElement(SessionProvider, { value: session }, rootNode))));
|
|
136
|
+
});
|
|
137
|
+
const handle = {
|
|
138
|
+
session,
|
|
139
|
+
dispose() {
|
|
140
|
+
root.unmount();
|
|
141
|
+
session[Symbol.dispose]();
|
|
142
|
+
},
|
|
143
|
+
[Symbol.dispose]() {
|
|
144
|
+
handle.dispose();
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
return handle;
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
export { buildAgentUrl as n, fetchClientConfig as r, client as t };
|
package/dist/define-client.d.ts
CHANGED
|
@@ -21,15 +21,6 @@ type BaseOptions = {
|
|
|
21
21
|
resumeSessionId?: string;
|
|
22
22
|
/** WebSocket constructor override. Passed through to session options. */
|
|
23
23
|
WebSocket?: WebSocketConstructor;
|
|
24
|
-
/**
|
|
25
|
-
* Transport the UI talks over. Unset (the default) asks the server via
|
|
26
|
-
* `GET client-config`, so `agent({ transport })` decides — an agent that
|
|
27
|
-
* declared `transport: "sync"` gets the sync shell (HTTP turns, no
|
|
28
|
-
* WebSocket) with no custom client needed. An explicit value here skips
|
|
29
|
-
* the lookup. Only the config tier branches on it; a custom `component`
|
|
30
|
-
* owns its own transport.
|
|
31
|
-
*/
|
|
32
|
-
transport?: "websocket" | "sync";
|
|
33
24
|
};
|
|
34
25
|
/**
|
|
35
26
|
* Tier 1: Config-only options. Renders the default shell (StartScreen + ChatView).
|
package/dist/define-client.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { floatToPcm16 } from "./audio.ts";
|
|
1
2
|
export { buildAgentUrl, type ClientConfigResponse, fetchClientConfig, } from "./client-config.ts";
|
|
2
3
|
export { Button } from "./components/button.tsx";
|
|
3
4
|
export { ChatView } from "./components/chat-view.tsx";
|
|
@@ -5,8 +6,6 @@ export { Controls } from "./components/controls.tsx";
|
|
|
5
6
|
export { MessageList } from "./components/message-list.tsx";
|
|
6
7
|
export { SidebarLayout } from "./components/sidebar-layout.tsx";
|
|
7
8
|
export { StartScreen } from "./components/start-screen.tsx";
|
|
8
|
-
export { SyncChatView } from "./components/sync-chat-view.tsx";
|
|
9
|
-
export { TextControls } from "./components/text-controls.tsx";
|
|
10
9
|
export type { ToolDisplayConfig } from "./components/tool-config-context.ts";
|
|
11
10
|
export { ToolConfigContext } from "./components/tool-config-context.ts";
|
|
12
11
|
export { ApiUrlChip, SessionUrlChips, UiUrlChip } from "./components/url-chips.tsx";
|
|
@@ -17,7 +16,5 @@ export { client } from "./define-client.tsx";
|
|
|
17
16
|
export { useEvent, useToolCallStart, useToolResult } from "./hooks.ts";
|
|
18
17
|
export type { CustomEvent, SessionCore, SessionCoreOptions, SessionSnapshot, } from "./session-core.ts";
|
|
19
18
|
export { createSessionCore } from "./session-core.ts";
|
|
20
|
-
export { CAPTURE_WORKLET_MODULE_URL, createPttRecorder, DEFAULT_SYNC_MIC_SAMPLE_RATE, floatToPcm16, type PttRecorder, type SyncMicrophone, type SyncMicrophoneOptions, startSyncMicrophone, } from "./sync-mic.ts";
|
|
21
|
-
export { base64ToPcm16, createSyncSession, pcm16ToBase64, type SyncSession, type SyncSessionOptions, type SyncTurnResult, } from "./sync-session.ts";
|
|
22
|
-
export { createUtteranceDetector, type UtteranceDetector, type UtteranceDetectorOptions, } from "./sync-vad.ts";
|
|
23
19
|
export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
|
|
20
|
+
export { VOICE_CAPTURE_CONSTRAINTS } from "./types.ts";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
|
|
2
|
+
import { floatToPcm16 } from "./audio.js";
|
|
3
|
+
import { n as buildAgentUrl, r as fetchClientConfig, t as client } from "./define-client-Cyf1jqAl.js";
|
|
2
4
|
import { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme } from "./context.js";
|
|
3
5
|
import { Button } from "./components/button.js";
|
|
4
|
-
import {
|
|
6
|
+
import { t as ChatView } from "./chat-view-C1oJxsWz.js";
|
|
7
|
+
import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-DV368uhb.js";
|
|
5
8
|
import { n as ToolConfigContext } from "./tool-call-block-DIxpG8GM.js";
|
|
6
9
|
import { MessageList } from "./components/message-list.js";
|
|
7
|
-
import { r as TextControls, t as ChatView } from "./chat-view-gi6FccZq.js";
|
|
8
10
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
9
11
|
import { StartScreen } from "./components/start-screen.js";
|
|
10
|
-
import { t as createSessionCore } from "./session-core-
|
|
12
|
+
import { t as createSessionCore } from "./session-core-BM3WHeoY.js";
|
|
11
13
|
import { useEvent, useToolCallStart, useToolResult } from "./hooks.js";
|
|
12
|
-
export { ApiUrlChip, Button,
|
|
14
|
+
export { ApiUrlChip, Button, ChatView, Controls, MessageList, SessionProvider, SessionUrlChips, SidebarLayout, StartScreen, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, client, createSessionCore, fetchClientConfig, floatToPcm16, useEvent, useSession, useSessionSelector, useTheme, useToolCallStart, useToolResult };
|