@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.
@@ -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 ?? /* @__PURE__ */ jsx(AaiLogo, { size: 22 }), title && /* @__PURE__ */ jsx("span", {
327
- className: "font-aai-serif text-[22px] leading-[1.2] font-normal truncate",
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 cream page with a header
361
- * (logo + live-status eyebrow), the conversation on a raised white card,
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 cream page with a header
6
- * (logo + live-status eyebrow), the conversation on a raised white card,
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 in place of the logo in the header. */
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;
@@ -1,3 +1,3 @@
1
- import { t as ChatView } from "../chat-view-BCbI7gD4.js";
1
+ import { t as ChatView } from "../chat-view-DIwPoAEG.js";
2
2
  import "../context.js";
3
3
  export { ChatView };
@@ -6,7 +6,7 @@ import type { AgentState } from "../types.ts";
6
6
  * @public
7
7
  */
8
8
  export type ConsoleShellProps = {
9
- /** Element rendered in place of the logo in the header. */
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 white card on the cream page with the logo, an
4
- * eyebrow label, a serif title, subtitle, and the start CTA. Renders
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 in place of the logo on the card. */
27
+ /** Element rendered above the eyebrow on the card. None by default. */
28
28
  icon?: ReactNode | undefined;
29
- /** The card's serif title. Defaults to the agent's declared name. */
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 white card on the cream page with the logo, an
12
- * eyebrow label, a serif title, subtitle, and the start CTA. Renders
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 ?? /* @__PURE__ */ jsx(AaiLogo, { size: 24 }),
47
+ icon,
49
48
  /* @__PURE__ */ jsx(Eyebrow, { children: "Voice Agent" }),
50
49
  title && /* @__PURE__ */ jsx("h1", {
51
- className: "font-aai-serif font-normal text-[32px] leading-[1.15] tracking-[-0.2px] m-0 text-balance",
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: "#FBF8F2",
6
- primary: "#3F2BC1",
7
- text: "#1B1A18",
5
+ bg: "#FAFAFA",
6
+ primary: "#18181B",
7
+ text: "#18181B",
8
8
  surface: "#FFFFFF",
9
- border: "#DCD7CC"
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-Cc5bATbP.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};
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};
@@ -1,4 +1,4 @@
1
- import{n as e,t}from"./index-Cc5bATbP.js";import{t as n}from"./_module-url-BX0RuRU2.js";var r=`
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();