@alexkroman1/aai-ui 1.8.2 → 1.8.3

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.
@@ -6,8 +6,8 @@
6
6
  <title>aai</title>
7
7
  <link rel="icon" href="data:," />
8
8
  <style>html, body { background: #101010; margin: 0; }</style>
9
- <script type="module" crossorigin src="./assets/index-YW9WUhbL.js"></script>
10
- <link rel="stylesheet" crossorigin href="./assets/index-BZqVGR2o.css">
9
+ <script type="module" crossorigin src="./assets/index-D1MWTIM_.js"></script>
10
+ <link rel="stylesheet" crossorigin href="./assets/index-CSyVJsy5.css">
11
11
  </head>
12
12
  <body>
13
13
  <main id="app"></main>
@@ -14,6 +14,10 @@ import { ServerMessageSchema, lenientParse } from "@alexkroman1/aai/protocol";
14
14
  const MAX_CUSTOM_EVENTS = 200;
15
15
  /** Cap on `messages` retained in the session snapshot; mirrors host-side DEFAULT_MAX_HISTORY. */
16
16
  const MAX_MESSAGES = 200;
17
+ /** Cap on pre-init audio chunks buffered while `voiceIO` is initializing. ~100 chunks at
18
+ * typical S2S chunk sizes is well over a second of audio — far longer than init takes
19
+ * in practice, but bounded against pathological cases (mic-permission stalls). */
20
+ const MAX_PREINIT_AUDIO_CHUNKS = 100;
17
21
  function appendCapped(list, item, cap) {
18
22
  const next = [...list, item];
19
23
  return next.length > cap ? next.slice(-cap) : next;
@@ -60,6 +64,10 @@ async function initAudioCapture(conn, msg, deps) {
60
64
  return;
61
65
  }
62
66
  conn.voiceIO = io;
67
+ if (conn.preInitAudio.length > 0) {
68
+ for (const chunk of conn.preInitAudio) io.enqueue(chunk.buffer);
69
+ conn.preInitAudio = [];
70
+ }
63
71
  deps.sendJson({ type: "audio_ready" });
64
72
  deps.updateState({ state: "listening" });
65
73
  } catch (err) {
@@ -132,7 +140,8 @@ function createSessionCore(options) {
132
140
  ws: null,
133
141
  voiceIO: null,
134
142
  audioSetupInFlight: false,
135
- generation: 0
143
+ generation: 0,
144
+ preInitAudio: []
136
145
  };
137
146
  let connectionController = null;
138
147
  let hasConnected = false;
@@ -140,6 +149,7 @@ function createSessionCore(options) {
140
149
  conn.audioSetupInFlight = false;
141
150
  conn.voiceIO?.close();
142
151
  conn.voiceIO = null;
152
+ conn.preInitAudio = [];
143
153
  }
144
154
  function resetState() {
145
155
  updateState({
@@ -281,7 +291,8 @@ function createSessionCore(options) {
281
291
  function playAudioChunk(chunk) {
282
292
  if (currentSnapshot.state === "disconnected" && currentSnapshot.error !== null) return;
283
293
  if (currentSnapshot.state !== "speaking") updateState({ state: "speaking" });
284
- conn.voiceIO?.enqueue(chunk.buffer);
294
+ if (conn.voiceIO) conn.voiceIO.enqueue(chunk.buffer);
295
+ else if (conn.preInitAudio.length < MAX_PREINIT_AUDIO_CHUNKS) conn.preInitAudio.push(chunk);
285
296
  }
286
297
  /**
287
298
  * Signal that the server has finished sending audio for this turn.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-ui",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -18,11 +18,11 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "clsx": "^2.1.1",
21
- "@alexkroman1/aai": "1.8.2"
21
+ "@alexkroman1/aai": "1.8.3"
22
22
  },
23
23
  "peerDependencies": {
24
- "react": "^19.0.0",
25
- "react-dom": "^19.0.0",
24
+ "react": "^19.2.6",
25
+ "react-dom": "^19.2.6",
26
26
  "tailwindcss": "^4.2.1"
27
27
  },
28
28
  "peerDependenciesMeta": {
@@ -31,19 +31,19 @@
31
31
  }
32
32
  },
33
33
  "devDependencies": {
34
- "@tailwindcss/vite": "^4.2.1",
35
- "@testing-library/dom": "^10.0.0",
36
- "@testing-library/react": "^16.3.0",
37
- "@types/react": "^19.0.0",
38
- "@types/react-dom": "^19.0.0",
34
+ "@tailwindcss/vite": "^4.3.0",
35
+ "@testing-library/dom": "^10.4.1",
36
+ "@testing-library/react": "^16.3.2",
37
+ "@types/react": "^19.2.14",
38
+ "@types/react-dom": "^19.2.3",
39
39
  "@vitejs/plugin-react": "^6.0.1",
40
- "jsdom": "^29.0.2",
41
- "react": "^19.0.0",
42
- "react-dom": "^19.0.0",
43
- "tsdown": "^0.21.7",
40
+ "jsdom": "^29.1.1",
41
+ "react": "^19.2.6",
42
+ "react-dom": "^19.2.6",
43
+ "tsdown": "^0.21.10",
44
44
  "tsx": "^4.21.0",
45
- "vite": "^8.0.8",
46
- "vitest": "^4.1.3"
45
+ "vite": "^8.0.12",
46
+ "vitest": "^4.1.6"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=24"
@@ -1,2 +0,0 @@
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-\[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}