@alexkroman1/aai-ui 0.15.2 → 0.15.4
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/{chat-view-BCbI7gD4.js → chat-view-DIwPoAEG.js} +4 -5
- package/dist/components/button.js +1 -1
- package/dist/components/chat-view.d.ts +3 -3
- package/dist/components/chat-view.js +1 -1
- package/dist/components/console-shell.d.ts +1 -1
- package/dist/components/start-screen.d.ts +4 -4
- package/dist/components/start-screen.js +4 -5
- package/dist/context.js +4 -4
- package/dist/default-client/assets/{audio-W0yIAgHB.js → audio-DzwGxdv4.js} +1 -1
- package/dist/default-client/assets/{capture-processor-CY8uqYKS.js → capture-processor-CXCWxCO8.js} +1 -1
- package/dist/default-client/assets/{index-Cc5bATbP.js → index-BOTLwsNO.js} +31 -31
- package/dist/default-client/assets/index-_-x5JLLa.css +2 -0
- package/dist/default-client/assets/{playback-processor-Cg3OLY-i.js → playback-processor-DXHfyQD9.js} +1 -1
- package/dist/default-client/index.html +3 -3
- package/dist/define-client.js +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +4 -4
- package/package.json +2 -2
- package/styles.css +13 -14
- package/dist/aai-logo-D8pMVn9_.js +0 -85
- package/dist/components/aai-logo.d.ts +0 -12
- package/dist/default-client/assets/index-8ihb1Urm.css +0 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useSessionError, useSessionStatus, useTheme } from "./context.js";
|
|
2
2
|
import { t as MessageList } from "./message-list-DHZcLhRA.js";
|
|
3
3
|
import { a as inkTint, r as THINKING_COLOR, t as ERROR_COLOR } from "./_colors-CpZO-88A.js";
|
|
4
|
-
import { t as AaiLogo } from "./aai-logo-D8pMVn9_.js";
|
|
5
4
|
import { t as Eyebrow } from "./eyebrow-UfmSz9yy.js";
|
|
6
5
|
import { Controls } from "./components/controls.js";
|
|
7
6
|
import clsx from "clsx";
|
|
@@ -323,8 +322,8 @@ function ConsoleShell({ icon, title, state, pulsing, children, footer, className
|
|
|
323
322
|
className: "flex items-center justify-between shrink-0",
|
|
324
323
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
325
324
|
className: "flex items-center gap-3 min-w-0",
|
|
326
|
-
children: [icon
|
|
327
|
-
className: "
|
|
325
|
+
children: [icon, title && /* @__PURE__ */ jsx("span", {
|
|
326
|
+
className: "text-[22px] leading-[1.2] font-semibold tracking-[-0.2px] truncate",
|
|
328
327
|
style: { color: theme.text },
|
|
329
328
|
children: title
|
|
330
329
|
})]
|
|
@@ -357,8 +356,8 @@ function ConsoleShell({ icon, title, state, pulsing, children, footer, className
|
|
|
357
356
|
const PULSING_STATES = /* @__PURE__ */ new Set(["listening", "speaking"]);
|
|
358
357
|
/**
|
|
359
358
|
* The main chat interface for a voice agent session — the design-system
|
|
360
|
-
* "voice agent console": a 760px column on the
|
|
361
|
-
* (
|
|
359
|
+
* "voice agent console": a 760px column on the page with a header
|
|
360
|
+
* (optional icon + live-status eyebrow), the conversation on a raised card,
|
|
362
361
|
* and the session controls beneath it.
|
|
363
362
|
*
|
|
364
363
|
* Must be rendered inside a `SessionProvider`.
|
|
@@ -11,7 +11,7 @@ function variantColors(variant, theme) {
|
|
|
11
11
|
bg: theme.primary,
|
|
12
12
|
fg: theme.surface,
|
|
13
13
|
border: "transparent",
|
|
14
|
-
hoverBg: inkTint(theme.text, theme.primary, 14),
|
|
14
|
+
hoverBg: theme.primary.toLowerCase() === theme.text.toLowerCase() ? primaryTint(theme.primary, theme.surface, 82) : inkTint(theme.text, theme.primary, 14),
|
|
15
15
|
hoverFg: theme.surface,
|
|
16
16
|
hoverBorder: "transparent"
|
|
17
17
|
};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
/**
|
|
4
4
|
* The main chat interface for a voice agent session — the design-system
|
|
5
|
-
* "voice agent console": a 760px column on the
|
|
6
|
-
* (
|
|
5
|
+
* "voice agent console": a 760px column on the page with a header
|
|
6
|
+
* (optional icon + live-status eyebrow), the conversation on a raised card,
|
|
7
7
|
* and the session controls beneath it.
|
|
8
8
|
*
|
|
9
9
|
* Must be rendered inside a `SessionProvider`.
|
|
@@ -26,7 +26,7 @@ import type { ReactNode } from "react";
|
|
|
26
26
|
* @public
|
|
27
27
|
*/
|
|
28
28
|
export declare function ChatView({ icon, title, className, }: {
|
|
29
|
-
/** Element rendered
|
|
29
|
+
/** Element rendered before the title in the header. None by default. */
|
|
30
30
|
icon?: ReactNode | undefined;
|
|
31
31
|
/** Title string for the header. Defaults to the agent's declared name. */
|
|
32
32
|
title?: string | undefined;
|
|
@@ -6,7 +6,7 @@ import type { AgentState } from "../types.ts";
|
|
|
6
6
|
* @public
|
|
7
7
|
*/
|
|
8
8
|
export type ConsoleShellProps = {
|
|
9
|
-
/** Element rendered
|
|
9
|
+
/** Element rendered before the title in the header. None by default. */
|
|
10
10
|
icon?: ReactNode | undefined;
|
|
11
11
|
/** Title string for the header. */
|
|
12
12
|
title?: string | undefined;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
/**
|
|
3
|
-
* A centered start screen: a
|
|
4
|
-
*
|
|
3
|
+
* A centered start screen: a card with an optional icon, an eyebrow label, a
|
|
4
|
+
* title, subtitle, and the start CTA. Renders
|
|
5
5
|
* `children` (the main app) once the session has started.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
@@ -24,9 +24,9 @@ import type { ReactNode } from "react";
|
|
|
24
24
|
export declare function StartScreen({ children, icon, title, subtitle, buttonText, className, }: {
|
|
25
25
|
/** The app, rendered once the session has started. */
|
|
26
26
|
children: ReactNode;
|
|
27
|
-
/** Element rendered
|
|
27
|
+
/** Element rendered above the eyebrow on the card. None by default. */
|
|
28
28
|
icon?: ReactNode | undefined;
|
|
29
|
-
/** The card's
|
|
29
|
+
/** The card's title. Defaults to the agent's declared name. */
|
|
30
30
|
title?: string | undefined;
|
|
31
31
|
/** A line under the title. */
|
|
32
32
|
subtitle?: string | undefined;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { useSessionCore, useSessionSelector, useTheme } from "../context.js";
|
|
2
2
|
import { a as inkTint } from "../_colors-CpZO-88A.js";
|
|
3
3
|
import { Button } from "./button.js";
|
|
4
|
-
import { t as AaiLogo } from "../aai-logo-D8pMVn9_.js";
|
|
5
4
|
import { t as Eyebrow } from "../eyebrow-UfmSz9yy.js";
|
|
6
5
|
import clsx from "clsx";
|
|
7
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
//#region src/components/start-screen.tsx
|
|
9
8
|
/** @jsxImportSource react */
|
|
10
9
|
/**
|
|
11
|
-
* A centered start screen: a
|
|
12
|
-
*
|
|
10
|
+
* A centered start screen: a card with an optional icon, an eyebrow label, a
|
|
11
|
+
* title, subtitle, and the start CTA. Renders
|
|
13
12
|
* `children` (the main app) once the session has started.
|
|
14
13
|
*
|
|
15
14
|
* @example
|
|
@@ -45,10 +44,10 @@ function StartScreen({ children, icon, title, subtitle, buttonText = "Start Conv
|
|
|
45
44
|
boxShadow: "0 4px 12px -2px rgb(20 18 12 / 0.08)"
|
|
46
45
|
},
|
|
47
46
|
children: [
|
|
48
|
-
icon
|
|
47
|
+
icon,
|
|
49
48
|
/* @__PURE__ */ jsx(Eyebrow, { children: "Voice Agent" }),
|
|
50
49
|
title && /* @__PURE__ */ jsx("h1", {
|
|
51
|
-
className: "font-
|
|
50
|
+
className: "font-semibold text-[32px] leading-[1.15] tracking-[-0.5px] m-0 text-balance",
|
|
52
51
|
style: { color: theme.text },
|
|
53
52
|
children: title
|
|
54
53
|
}),
|
package/dist/context.js
CHANGED
|
@@ -2,11 +2,11 @@ import { createContext, createElement, useContext, useEffect, useMemo, useSyncEx
|
|
|
2
2
|
import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
|
|
3
3
|
//#region src/context.ts
|
|
4
4
|
const DEFAULT_THEME = {
|
|
5
|
-
bg: "#
|
|
6
|
-
primary: "#
|
|
7
|
-
text: "#
|
|
5
|
+
bg: "#FAFAFA",
|
|
6
|
+
primary: "#18181B",
|
|
7
|
+
text: "#18181B",
|
|
8
8
|
surface: "#FFFFFF",
|
|
9
|
-
border: "#
|
|
9
|
+
border: "#E4E4E7"
|
|
10
10
|
};
|
|
11
11
|
const SessionCtx = createContext(null);
|
|
12
12
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,t as n}from"./index-
|
|
1
|
+
import{a as e,i as t,t as n}from"./index-BOTLwsNO.js";var r={echoCancellation:!0,noiseSuppression:!1,autoGainControl:!1,voiceIsolation:!1};function i(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function a(e){let t=Error(`Audio ${e} worklet crashed`);return console.error(`[aai-ui]`,t.message),t}function o(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function s(e,t,n){let r=new AudioWorkletNode(e,`capture-processor`,{channelCount:1,channelCountMode:`explicit`}),i=null;return r.port.onmessage=e=>{let r=e.data;r.event===`chunk`&&r.buffer?t(r.buffer):r.event===`silent`?n?.():r.event===`stopped`&&(i?.(),i=null)},{node:r,start(){r.port.postMessage({event:`start`})},stop(){let{promise:e,resolve:t}=Promise.withResolvers(),n=setTimeout(t,250);return i=()=>{clearTimeout(n),t()},r.port.postMessage({event:`stop`}),e}}}async function c(e){let{sampleRate:t,captureWorkletSrc:n,maxSeconds:a}=e,c=new AudioContext({sampleRate:t,latencyHint:`interactive`}),l=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),u;try{[u]=await Promise.all([l,c.resume(),c.audioWorklet.addModule(n)]),i(c.sampleRate,t,`capture`)}catch(e){throw o(l),await c.close().catch(()=>{}),e}let d=Math.round(t*a)*2,f=[],p=0,m=!1,h=null,g=c.createMediaStreamSource(u),_=s(c,e=>{if(h){h.onChunk(e);return}for(f.push(e),p+=e.byteLength;p>d&&f.length>1;)p-=f.shift()?.byteLength??0},()=>{h?h.onSilent?.():m=!0});g.connect(_.node),_.start();let v=()=>{let e=f;return f=[],p=0,e},y=!1,b=async()=>{y||(y=!0,g.disconnect(),_.node.disconnect(),await c.close().catch(e=>{console.warn(`AudioContext close failed:`,e)}))};return{sampleRate:t,stream:u,ctx:c,handOff(e){h=e;let t=v();return t.length>0&&e.onBuffered(t),m&&e.onSilent?.(),{mic:g,capture:_}},async detach(){return await _.stop(),await b(),{chunks:v(),sampleRate:t}},async close(){y||await _.stop();for(let e of u.getTracks())e.stop();await b()}}}function l(e){let t=new Int16Array(e.length);for(let n=0;n<e.length;n++){let r=Math.max(-1,Math.min(1,e[n]??0));t[n]=r<0?r*32768:r*32767}return t.buffer}async function u(e,t,r){let i=e.reduce((e,t)=>e+t.byteLength/2,0);if(i===0)return[];if(t===r)return e;try{let a=Math.round(i*r/t),o=new OfflineAudioContext(1,a,r),s=o.createBuffer(1,i,t),c=s.getChannelData(0),u=0;for(let t of e)for(let e of new Int16Array(t))c[u++]=e/32768;let d=o.createBufferSource();d.buffer=s,d.connect(o.destination),d.start();let f=(await o.startRendering()).getChannelData(0),p=Math.max(1,Math.round(r*n)),m=[];for(let e=0;e<f.length;e+=p)m.push(l(f.subarray(e,e+p)));return m}catch(e){return console.warn(`[aai-ui] pre-connect audio dropped: resample failed`,e),[]}}async function d(e,t,n){let r=e.createMediaStreamSource(t),i=s(e,n.onMicData,n.onMicSilent);if(r.connect(i.node),n.buffered){let{chunks:t,sampleRate:r}=n.buffered,i=await u(t,r,e.sampleRate);i.length>0&&n.onBuffered(i)}return i.start(),{mic:r,capture:i}}async function f(n){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:f,onError:p,onPlaybackStats:m,onPlaybackProgress:h,onMicSilent:g,preConnect:_}=n,v=n.onPreConnectAudio??(e=>{for(let t of e)f(t)}),y=_?.sampleRate===s?_:null,b=_&&!y?await _.detach():null,x=new AudioContext({sampleRate:c,latencyHint:`playback`}),S=!y&&s===c,C=y?.ctx??(S?x:new AudioContext({sampleRate:s,latencyHint:`interactive`}));async function w(){let e=S?[x]:[x,C];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let T=_?Promise.resolve(_.stream):navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...r}}),E;try{[E]=await Promise.all([T,x.resume(),C.resume(),y?void 0:C.audioWorklet.addModule(l),x.audioWorklet.addModule(u)]),i(C.sampleRate,s,`capture`),i(x.sampleRate,c,`playback`)}catch(e){throw o(T),await w(),e}let{mic:D,capture:O}=y?y.handOff({onBuffered:v,onChunk:f,onSilent:g}):await d(C,E,{onMicData:f,onMicSilent:g,buffered:b,onBuffered:v});O.node.onprocessorerror=()=>p?.(a(`capture`));let k=null,A=0,j=null,M=new AbortController;function N(){let e=j;j=null,e?.settle()}function P(e){e.stats&&e.stats.concealedSamples>0&&m?.(e.stats),e.reason!==`interrupt`&&(j===null||e.turn===j.turn)&&N()}function F(){if(k)return k;let e=new AudioWorkletNode(x,`playback-processor`);return e.connect(x.destination),e.port.onmessage=e=>{e.data.event===`stop`?P(e.data):e.data.event===`progress`&&h?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=a(`playback`);N(),p?.(e)},k=e,e}let I={enqueue(e){M.signal.aborted||e.byteLength!==0&&F().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!k)return Promise.resolve();let n=++A;if(k.port.postMessage({event:`done`,turn:n}),x.state!==`running`)return N(),Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();N();let a=()=>{clearInterval(o),clearTimeout(s),j?.settle===a&&(j=null),i()},o=setInterval(()=>{x.state!==`running`&&a()},e),s=setTimeout(a,t);return j={turn:n,settle:a},r},flush(){k&&(N(),k.port.postMessage({event:`interrupt`}))},async close(){if(!M.signal.aborted){M.abort(),await O.stop(),D.disconnect(),O.node.disconnect(),k&&k.disconnect();for(let e of E.getTracks())e.stop();await w()}},async[Symbol.asyncDispose](){await I.close()}};return I}export{f as createVoiceIO,c as openPreConnectCapture};
|
package/dist/default-client/assets/{capture-processor-CY8uqYKS.js → capture-processor-CXCWxCO8.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{n as e,t}from"./index-
|
|
1
|
+
import{n as e,t}from"./index-BOTLwsNO.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=`
|
|
2
2
|
class CaptureProcessor extends AudioWorkletProcessor {
|
|
3
3
|
constructor(options) {
|
|
4
4
|
super();
|