@alexkroman1/aai-ui 5.1.0 → 5.2.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/{_colors-DYX7XRTr.js → _colors-Bfh3-BVE.js} +3 -1
- package/dist/{_utils-CN1yVgYS.js → _utils-CsqbIVGI.js} +10 -1
- package/dist/_utils.d.ts +6 -0
- package/dist/{chat-view-CW-tZCMm.js → chat-view-C6N2oXjo.js} +4 -4
- package/dist/components/_colors.d.ts +2 -0
- package/dist/components/chat-view.js +1 -1
- package/dist/components/controls.js +1 -1
- package/dist/components/message-list.js +1 -1
- package/dist/components/start-screen.js +1 -1
- package/dist/components/tool-call-block.js +1 -1
- package/dist/components/url-chips.d.ts +2 -1
- package/dist/{controls-DV368uhb.js → controls-Cqg7T4FN.js} +5 -8
- package/dist/default-client/assets/{audio-BnLV_QB3.js → audio-C1U_foBG.js} +1 -1
- package/dist/default-client/assets/{capture-processor-ChXugkMd.js → capture-processor-dyyJArQs.js} +1 -1
- package/dist/default-client/assets/index-CGZajs1V.js +192 -0
- package/dist/default-client/assets/{playback-processor-BfJzQKW5.js → playback-processor-BO2TdYrv.js} +1 -1
- package/dist/default-client/index.html +1 -1
- package/dist/define-client.d.ts +6 -8
- package/dist/define-client.js +5 -4
- package/dist/hooks.js +1 -1
- package/dist/index.js +5 -5
- package/dist/{message-list-q2lTiFhF.js → message-list-CD9GxrlH.js} +106 -104
- package/dist/{session-core-CwCaFzL8.js → session-core-Bvga6tUS.js} +27 -18
- package/dist/session-core-audio-setup.d.ts +10 -1
- package/dist/session-core-types.d.ts +1 -1
- package/dist/session-core.js +1 -1
- package/dist/{tool-call-block-DIxpG8GM.js → tool-call-block-O9vLqoyU.js} +2 -2
- package/package.json +2 -2
- package/dist/default-client/assets/index-22Wylv4z.js +0 -192
package/dist/default-client/assets/{playback-processor-BfJzQKW5.js → playback-processor-BO2TdYrv.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"./index-
|
|
1
|
+
import{i as e}from"./index-CGZajs1V.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
|
|
2
2
|
class PlaybackProcessor extends AudioWorkletProcessor {
|
|
3
3
|
constructor(options) {
|
|
4
4
|
super();
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>aai</title>
|
|
7
7
|
<link rel="icon" href="./favicon.ico" />
|
|
8
8
|
<style>html, body { background: #FBF8F2; margin: 0; }</style>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-CGZajs1V.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-CRfdZPH1.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
package/dist/define-client.d.ts
CHANGED
|
@@ -2,25 +2,23 @@
|
|
|
2
2
|
import { type ComponentType } from "react";
|
|
3
3
|
import { type ToolDisplayConfig } from "./components/tool-config-context.ts";
|
|
4
4
|
import type { SessionCore } from "./session-core-types.ts";
|
|
5
|
-
import type { ClientTheme,
|
|
5
|
+
import type { ClientTheme, VoiceSessionOptions } from "./types.ts";
|
|
6
6
|
/**
|
|
7
7
|
* Base options shared by both client tiers.
|
|
8
8
|
*
|
|
9
|
+
* The session-forwarded fields are picked from {@link VoiceSessionOptions}
|
|
10
|
+
* (one source of truth for types and docs) rather than re-declared — a
|
|
11
|
+
* re-declared copy is exactly how doc comments drift.
|
|
12
|
+
*
|
|
9
13
|
* @public
|
|
10
14
|
*/
|
|
11
|
-
type BaseOptions = {
|
|
15
|
+
type BaseOptions = Pick<VoiceSessionOptions, "onSessionId" | "resumeSessionId" | "WebSocket"> & {
|
|
12
16
|
/** CSS selector or DOM element to render into. Defaults to `"#app"`. */
|
|
13
17
|
target?: string | HTMLElement;
|
|
14
18
|
/** Base URL of the AAI platform server. Derived from `location.href` by default. */
|
|
15
19
|
platformUrl?: string;
|
|
16
20
|
/** Theme color overrides. */
|
|
17
21
|
theme?: ClientTheme;
|
|
18
|
-
/** Called when the server sends a session ID. Store it for reconnection. */
|
|
19
|
-
onSessionId?: (sessionId: string) => void;
|
|
20
|
-
/** Session ID from a previous connection for resuming persisted state. */
|
|
21
|
-
resumeSessionId?: string;
|
|
22
|
-
/** WebSocket constructor override. Passed through to session options. */
|
|
23
|
-
WebSocket?: WebSocketConstructor;
|
|
24
22
|
};
|
|
25
23
|
/**
|
|
26
24
|
* Tier 1: Config-only options. Renders the default shell (StartScreen + ChatView).
|
package/dist/define-client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { r as fetchClientConfig, t as createSessionCore } from "./session-core-
|
|
1
|
+
import { r as fetchClientConfig, t as createSessionCore } from "./session-core-Bvga6tUS.js";
|
|
2
2
|
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
3
|
-
import { t as ChatView } from "./chat-view-
|
|
4
|
-
import {
|
|
3
|
+
import { t as ChatView } from "./chat-view-C6N2oXjo.js";
|
|
4
|
+
import { t as pageBaseUrl } from "./_utils-CsqbIVGI.js";
|
|
5
|
+
import { n as ToolConfigContext } from "./tool-call-block-O9vLqoyU.js";
|
|
5
6
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
6
7
|
import { StartScreen } from "./components/start-screen.js";
|
|
7
8
|
import { createElement, useEffect, useState } from "react";
|
|
@@ -86,7 +87,7 @@ function DefaultRoot({ platformUrl, name, Sidebar, sidebarWidth }) {
|
|
|
86
87
|
*/
|
|
87
88
|
function client(config) {
|
|
88
89
|
const container = resolveContainer(config.target);
|
|
89
|
-
const platformUrl = config.platformUrl ??
|
|
90
|
+
const platformUrl = config.platformUrl ?? pageBaseUrl();
|
|
90
91
|
const session = createSessionCore({
|
|
91
92
|
platformUrl,
|
|
92
93
|
onSessionId: config.onSessionId,
|
package/dist/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSessionSelector } from "./context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { r as tryParseJSON } from "./_utils-CsqbIVGI.js";
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
4
|
//#region hooks.ts
|
|
5
5
|
/** Index of the first item whose sequence number is above the watermark (tail scan from the end). */
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-
|
|
1
|
+
import { n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-Bvga6tUS.js";
|
|
2
2
|
import { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme } from "./context.js";
|
|
3
3
|
import { Button } from "./components/button.js";
|
|
4
|
-
import { t as ChatView } from "./chat-view-
|
|
5
|
-
import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-
|
|
6
|
-
import { n as Markdown, t as MessageList } from "./message-list-
|
|
7
|
-
import { n as ToolConfigContext } from "./tool-call-block-
|
|
4
|
+
import { t as ChatView } from "./chat-view-C6N2oXjo.js";
|
|
5
|
+
import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-Cqg7T4FN.js";
|
|
6
|
+
import { n as Markdown, t as MessageList } from "./message-list-CD9GxrlH.js";
|
|
7
|
+
import { n as ToolConfigContext } from "./tool-call-block-O9vLqoyU.js";
|
|
8
8
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
9
9
|
import { StartScreen } from "./components/start-screen.js";
|
|
10
10
|
import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSessionSelector, useTheme } from "./context.js";
|
|
2
|
-
import {
|
|
3
|
-
import { t as ToolCallBlock } from "./tool-call-block-
|
|
2
|
+
import { i as TEXT_MUTED, n as SURFACE_TINT, o as primaryTint, r as TEXT_FAINT } from "./_colors-Bfh3-BVE.js";
|
|
3
|
+
import { t as ToolCallBlock } from "./tool-call-block-O9vLqoyU.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { memo, useCallback, useEffect, useMemo, useRef } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -52,110 +52,111 @@ function escapeBareListMarkers(text) {
|
|
|
52
52
|
*/
|
|
53
53
|
const Markdown = memo(function Markdown({ text }) {
|
|
54
54
|
const theme = useTheme();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
style
|
|
89
|
-
color: theme.primary,
|
|
90
|
-
...style
|
|
91
|
-
},
|
|
92
|
-
target: "_blank",
|
|
93
|
-
rel: "noreferrer noopener",
|
|
94
|
-
...props
|
|
95
|
-
}),
|
|
96
|
-
code: ({ className, style, children, ...rest }) => {
|
|
97
|
-
return /language-/.test(className ?? "") ? /* @__PURE__ */ jsx("code", {
|
|
98
|
-
className: "font-aai-mono text-[12.5px]",
|
|
99
|
-
...rest,
|
|
100
|
-
children
|
|
101
|
-
}) : /* @__PURE__ */ jsx("code", {
|
|
102
|
-
className: "rounded-sm border px-1 py-0.5 font-aai-mono text-[12.5px]",
|
|
103
|
-
style: {
|
|
104
|
-
borderColor: theme.border,
|
|
105
|
-
background: SURFACE_TINT,
|
|
106
|
-
...style
|
|
107
|
-
},
|
|
108
|
-
...rest,
|
|
109
|
-
children
|
|
110
|
-
});
|
|
55
|
+
const components = useMemo(() => ({
|
|
56
|
+
p: (props) => /* @__PURE__ */ jsx("p", {
|
|
57
|
+
className: "my-1.5 first:mt-0 last:mb-0",
|
|
58
|
+
...props
|
|
59
|
+
}),
|
|
60
|
+
ul: (props) => /* @__PURE__ */ jsx("ul", {
|
|
61
|
+
className: "my-1.5 list-disc pl-5",
|
|
62
|
+
...props
|
|
63
|
+
}),
|
|
64
|
+
ol: (props) => /* @__PURE__ */ jsx("ol", {
|
|
65
|
+
className: "my-1.5 list-decimal pl-5",
|
|
66
|
+
...props
|
|
67
|
+
}),
|
|
68
|
+
li: (props) => /* @__PURE__ */ jsx("li", {
|
|
69
|
+
className: "my-0.5",
|
|
70
|
+
...props
|
|
71
|
+
}),
|
|
72
|
+
h1: (props) => /* @__PURE__ */ jsx("h1", {
|
|
73
|
+
className: "mt-3 mb-1.5 text-[17px] font-semibold",
|
|
74
|
+
...props
|
|
75
|
+
}),
|
|
76
|
+
h2: (props) => /* @__PURE__ */ jsx("h2", {
|
|
77
|
+
className: "mt-3 mb-1.5 text-[16px] font-semibold",
|
|
78
|
+
...props
|
|
79
|
+
}),
|
|
80
|
+
h3: (props) => /* @__PURE__ */ jsx("h3", {
|
|
81
|
+
className: "mt-3 mb-1.5 text-[15px] font-semibold",
|
|
82
|
+
...props
|
|
83
|
+
}),
|
|
84
|
+
a: ({ style, ...props }) => /* @__PURE__ */ jsx("a", {
|
|
85
|
+
className: "underline underline-offset-2",
|
|
86
|
+
style: {
|
|
87
|
+
color: theme.primary,
|
|
88
|
+
...style
|
|
111
89
|
},
|
|
112
|
-
|
|
113
|
-
|
|
90
|
+
target: "_blank",
|
|
91
|
+
rel: "noreferrer noopener",
|
|
92
|
+
...props
|
|
93
|
+
}),
|
|
94
|
+
code: ({ className, style, children, ...rest }) => {
|
|
95
|
+
return /language-/.test(className ?? "") ? /* @__PURE__ */ jsx("code", {
|
|
96
|
+
className: "font-aai-mono text-[12.5px]",
|
|
97
|
+
...rest,
|
|
98
|
+
children
|
|
99
|
+
}) : /* @__PURE__ */ jsx("code", {
|
|
100
|
+
className: "rounded-sm border px-1 py-0.5 font-aai-mono text-[12.5px]",
|
|
114
101
|
style: {
|
|
115
102
|
borderColor: theme.border,
|
|
116
103
|
background: SURFACE_TINT,
|
|
117
104
|
...style
|
|
118
105
|
},
|
|
119
|
-
...
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
className: "my-1.5 border-l-2 pl-3",
|
|
123
|
-
style: {
|
|
124
|
-
borderColor: theme.border,
|
|
125
|
-
color: TEXT_MUTED,
|
|
126
|
-
...style
|
|
127
|
-
},
|
|
128
|
-
...props
|
|
129
|
-
}),
|
|
130
|
-
table: (props) => /* @__PURE__ */ jsx("table", {
|
|
131
|
-
className: "my-1.5 w-full border-collapse text-sm",
|
|
132
|
-
...props
|
|
133
|
-
}),
|
|
134
|
-
th: ({ style, ...props }) => /* @__PURE__ */ jsx("th", {
|
|
135
|
-
className: "border px-2 py-1 text-left font-medium",
|
|
136
|
-
style: {
|
|
137
|
-
borderColor: theme.border,
|
|
138
|
-
...style
|
|
139
|
-
},
|
|
140
|
-
...props
|
|
141
|
-
}),
|
|
142
|
-
td: ({ style, ...props }) => /* @__PURE__ */ jsx("td", {
|
|
143
|
-
className: "border px-2 py-1",
|
|
144
|
-
style: {
|
|
145
|
-
borderColor: theme.border,
|
|
146
|
-
...style
|
|
147
|
-
},
|
|
148
|
-
...props
|
|
149
|
-
}),
|
|
150
|
-
hr: ({ style, ...props }) => /* @__PURE__ */ jsx("hr", {
|
|
151
|
-
className: "my-2.5 border-t",
|
|
152
|
-
style: {
|
|
153
|
-
borderColor: theme.border,
|
|
154
|
-
...style
|
|
155
|
-
},
|
|
156
|
-
...props
|
|
157
|
-
})
|
|
106
|
+
...rest,
|
|
107
|
+
children
|
|
108
|
+
});
|
|
158
109
|
},
|
|
110
|
+
pre: ({ style, ...props }) => /* @__PURE__ */ jsx("pre", {
|
|
111
|
+
className: "my-1.5 overflow-x-auto rounded-md border p-2.5 whitespace-pre-wrap wrap-break-word",
|
|
112
|
+
style: {
|
|
113
|
+
borderColor: theme.border,
|
|
114
|
+
background: SURFACE_TINT,
|
|
115
|
+
...style
|
|
116
|
+
},
|
|
117
|
+
...props
|
|
118
|
+
}),
|
|
119
|
+
blockquote: ({ style, ...props }) => /* @__PURE__ */ jsx("blockquote", {
|
|
120
|
+
className: "my-1.5 border-l-2 pl-3",
|
|
121
|
+
style: {
|
|
122
|
+
borderColor: theme.border,
|
|
123
|
+
color: TEXT_MUTED,
|
|
124
|
+
...style
|
|
125
|
+
},
|
|
126
|
+
...props
|
|
127
|
+
}),
|
|
128
|
+
table: (props) => /* @__PURE__ */ jsx("table", {
|
|
129
|
+
className: "my-1.5 w-full border-collapse text-sm",
|
|
130
|
+
...props
|
|
131
|
+
}),
|
|
132
|
+
th: ({ style, ...props }) => /* @__PURE__ */ jsx("th", {
|
|
133
|
+
className: "border px-2 py-1 text-left font-medium",
|
|
134
|
+
style: {
|
|
135
|
+
borderColor: theme.border,
|
|
136
|
+
...style
|
|
137
|
+
},
|
|
138
|
+
...props
|
|
139
|
+
}),
|
|
140
|
+
td: ({ style, ...props }) => /* @__PURE__ */ jsx("td", {
|
|
141
|
+
className: "border px-2 py-1",
|
|
142
|
+
style: {
|
|
143
|
+
borderColor: theme.border,
|
|
144
|
+
...style
|
|
145
|
+
},
|
|
146
|
+
...props
|
|
147
|
+
}),
|
|
148
|
+
hr: ({ style, ...props }) => /* @__PURE__ */ jsx("hr", {
|
|
149
|
+
className: "my-2.5 border-t",
|
|
150
|
+
style: {
|
|
151
|
+
borderColor: theme.border,
|
|
152
|
+
...style
|
|
153
|
+
},
|
|
154
|
+
...props
|
|
155
|
+
})
|
|
156
|
+
}), [theme]);
|
|
157
|
+
return /* @__PURE__ */ jsx(ReactMarkdown, {
|
|
158
|
+
remarkPlugins: [remarkGfm],
|
|
159
|
+
components,
|
|
159
160
|
children: escapeBareListMarkers(text)
|
|
160
161
|
});
|
|
161
162
|
});
|
|
@@ -342,6 +343,10 @@ const MessageList = memo(function MessageList({ className }) {
|
|
|
342
343
|
messages
|
|
343
344
|
]);
|
|
344
345
|
const { anchorRef, onScroll } = useAutoScroll(contentVersion, userTranscript !== null);
|
|
346
|
+
const streamingMessage = useMemo(() => agentTranscript ? {
|
|
347
|
+
role: "assistant",
|
|
348
|
+
content: agentTranscript
|
|
349
|
+
} : null, [agentTranscript]);
|
|
345
350
|
const items = useMemo(() => interleave(messages, toolCalls, (msg) => /* @__PURE__ */ jsx(MessageBubble, {
|
|
346
351
|
message: msg,
|
|
347
352
|
theme
|
|
@@ -359,11 +364,8 @@ const MessageList = memo(function MessageList({ className }) {
|
|
|
359
364
|
className: "flex flex-col gap-4 p-7",
|
|
360
365
|
children: [
|
|
361
366
|
items,
|
|
362
|
-
|
|
363
|
-
message:
|
|
364
|
-
role: "assistant",
|
|
365
|
-
content: agentTranscript
|
|
366
|
-
},
|
|
367
|
+
streamingMessage && /* @__PURE__ */ jsx(MessageBubble, {
|
|
368
|
+
message: streamingMessage,
|
|
367
369
|
theme
|
|
368
370
|
}),
|
|
369
371
|
userTranscript !== null && /* @__PURE__ */ jsx(UserBubble, {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MIC_SEND_MAX_BUFFERED_BYTES } from "./types.js";
|
|
2
2
|
import { CLIENT_CONFIG_PATH, ClientConfigResponseSchema, ServerMessageSchema, lenientParse } from "@alexkroman1/aai/protocol";
|
|
3
|
-
import { DEFAULT_MAX_HISTORY, WS_OPEN, createEpoch, errorMessage, safeJsonParse } from "@alexkroman1/aai";
|
|
3
|
+
import { DEFAULT_MAX_HISTORY, WS_OPEN, createEpoch, errorMessage, safeJsonParse, toArgsRecord } from "@alexkroman1/aai";
|
|
4
4
|
import ReconnectingWebSocket from "partysocket/ws";
|
|
5
5
|
//#region client-config.ts
|
|
6
6
|
/**
|
|
@@ -61,6 +61,24 @@ async function fetchClientConfig(platformUrl, fetchFn) {
|
|
|
61
61
|
* staleness/failure handling), while `session-core.ts` owns the state store
|
|
62
62
|
* and connection lifecycle.
|
|
63
63
|
*/
|
|
64
|
+
let audioModulesPromise = null;
|
|
65
|
+
/**
|
|
66
|
+
* Load the audio module and worklet sources, memoized so a prefetch at
|
|
67
|
+
* `connect()` time overlaps the chunk fetch with the WebSocket handshake
|
|
68
|
+
* instead of serializing it behind the server's `config` frame. A failed
|
|
69
|
+
* load clears the memo so the next attempt retries the import.
|
|
70
|
+
*/
|
|
71
|
+
function loadAudioModules() {
|
|
72
|
+
audioModulesPromise ??= Promise.all([
|
|
73
|
+
import("./audio.js"),
|
|
74
|
+
import("./worklets/capture-processor.js").then((m) => m.default),
|
|
75
|
+
import("./worklets/playback-processor.js").then((m) => m.default)
|
|
76
|
+
]).catch((err) => {
|
|
77
|
+
audioModulesPromise = null;
|
|
78
|
+
throw err;
|
|
79
|
+
});
|
|
80
|
+
return audioModulesPromise;
|
|
81
|
+
}
|
|
64
82
|
/**
|
|
65
83
|
* Initialize audio capture and playback after the server sends a ready config.
|
|
66
84
|
*
|
|
@@ -94,11 +112,7 @@ async function initAudioCapture(conn, msg, deps) {
|
|
|
94
112
|
});
|
|
95
113
|
};
|
|
96
114
|
try {
|
|
97
|
-
const [{ createVoiceIO }, captureWorklet, playbackWorklet] = await
|
|
98
|
-
import("./audio.js"),
|
|
99
|
-
import("./worklets/capture-processor.js").then((m) => m.default),
|
|
100
|
-
import("./worklets/playback-processor.js").then((m) => m.default)
|
|
101
|
-
]);
|
|
115
|
+
const [{ createVoiceIO }, captureWorklet, playbackWorklet] = await loadAudioModules();
|
|
102
116
|
const io = await createVoiceIO({
|
|
103
117
|
sttSampleRate: msg.sampleRate,
|
|
104
118
|
ttsSampleRate: msg.ttsSampleRate,
|
|
@@ -106,17 +120,11 @@ async function initAudioCapture(conn, msg, deps) {
|
|
|
106
120
|
playbackWorkletSrc: playbackWorklet,
|
|
107
121
|
onMicData: (pcm16) => {
|
|
108
122
|
try {
|
|
109
|
-
deps.sendAudio(
|
|
123
|
+
deps.sendAudio(pcm16);
|
|
110
124
|
} catch {
|
|
111
125
|
console.debug("[aai-ui] sendAudio dropped: connection closed");
|
|
112
126
|
}
|
|
113
127
|
},
|
|
114
|
-
onPlaybackStats: (stats) => {
|
|
115
|
-
console.warn("[aai-ui] playback concealed a gap in this turn", stats);
|
|
116
|
-
},
|
|
117
|
-
onMicSilent: () => {
|
|
118
|
-
console.warn("[aai-ui] microphone is delivering only silence — check the selected input device");
|
|
119
|
-
},
|
|
120
128
|
onError: (err) => {
|
|
121
129
|
if (!conn.generation.isCurrent(gen)) return;
|
|
122
130
|
reportAudioFailure(err.message);
|
|
@@ -129,7 +137,7 @@ async function initAudioCapture(conn, msg, deps) {
|
|
|
129
137
|
conn.voiceIO?.close().catch(() => {});
|
|
130
138
|
conn.voiceIO = io;
|
|
131
139
|
if (conn.preInitAudio.length > 0) {
|
|
132
|
-
for (const chunk of conn.preInitAudio) io.enqueue(chunk
|
|
140
|
+
for (const chunk of conn.preInitAudio) io.enqueue(chunk);
|
|
133
141
|
conn.preInitAudio = [];
|
|
134
142
|
}
|
|
135
143
|
deps.sendJson({ type: "audio_ready" });
|
|
@@ -305,7 +313,7 @@ function createMessageHandlers(deps) {
|
|
|
305
313
|
updateState({ toolCalls: appendCapped(getSnapshot().toolCalls, {
|
|
306
314
|
callId: e.toolCallId,
|
|
307
315
|
name: e.toolName,
|
|
308
|
-
args: e.args
|
|
316
|
+
args: toArgsRecord(e.args),
|
|
309
317
|
status: "pending",
|
|
310
318
|
seq: ++toolCallSeq,
|
|
311
319
|
afterMessageId: getSnapshot().messages.at(-1)?.id ?? -1
|
|
@@ -364,7 +372,7 @@ function createMessageHandlers(deps) {
|
|
|
364
372
|
const snap = getSnapshot();
|
|
365
373
|
if (snap.state === "error" || snap.state === "disconnected" && snap.error !== null) return;
|
|
366
374
|
if (snap.state !== "speaking") updateState({ state: "speaking" });
|
|
367
|
-
if (conn.voiceIO) conn.voiceIO.enqueue(chunk
|
|
375
|
+
if (conn.voiceIO) conn.voiceIO.enqueue(chunk);
|
|
368
376
|
else if (conn.preInitAudio.length < MAX_PREINIT_AUDIO_CHUNKS) conn.preInitAudio.push(chunk);
|
|
369
377
|
}
|
|
370
378
|
/** See {@link MessageHandlers.settleWhenAudioDrained}. Captures
|
|
@@ -394,7 +402,7 @@ function createMessageHandlers(deps) {
|
|
|
394
402
|
}
|
|
395
403
|
function handleMessage(data) {
|
|
396
404
|
if (data instanceof ArrayBuffer) {
|
|
397
|
-
playAudioChunk(
|
|
405
|
+
playAudioChunk(data);
|
|
398
406
|
return;
|
|
399
407
|
}
|
|
400
408
|
if (typeof data !== "string") {
|
|
@@ -469,7 +477,7 @@ function reconnectPending(socket) {
|
|
|
469
477
|
//#region session-core-url.ts
|
|
470
478
|
/** Build the session WebSocket URL from the platform URL and resume state. */
|
|
471
479
|
function buildWsUrl(platformUrl, resume, sessionId) {
|
|
472
|
-
return applyResumeParams(
|
|
480
|
+
return applyResumeParams(buildAgentUrl(platformUrl, "websocket"), resume, sessionId);
|
|
473
481
|
}
|
|
474
482
|
/**
|
|
475
483
|
* Turn a broker-provided session URL (`sessionUrl` from `GET client-config`
|
|
@@ -677,6 +685,7 @@ function createSessionCore(options) {
|
|
|
677
685
|
state: "connecting",
|
|
678
686
|
error: null
|
|
679
687
|
});
|
|
688
|
+
loadAudioModules().catch(() => {});
|
|
680
689
|
teardownConnection();
|
|
681
690
|
conn.generation.bump();
|
|
682
691
|
const controller = new AbortController();
|
|
@@ -4,7 +4,7 @@ import type { ConnState, SessionSnapshot } from "./session-core-types.ts";
|
|
|
4
4
|
/** Dependencies `initAudioCapture` needs from the owning session core. */
|
|
5
5
|
export type AudioSetupDeps = {
|
|
6
6
|
sendJson: (msg: ClientMessage) => void;
|
|
7
|
-
sendAudio: (bytes:
|
|
7
|
+
sendAudio: (bytes: ArrayBuffer) => void;
|
|
8
8
|
updateState: (partial: Partial<SessionSnapshot>) => void;
|
|
9
9
|
/** Turn-boundary-guarded drain from the message handlers — replays a
|
|
10
10
|
* buffered `audio_done` without stomping a barge-in's state. */
|
|
@@ -12,6 +12,14 @@ export type AudioSetupDeps = {
|
|
|
12
12
|
/** Release the mic/VoiceIO (used when the audio path dies non-fatally). */
|
|
13
13
|
cleanupAudio: () => void;
|
|
14
14
|
};
|
|
15
|
+
type AudioModules = [typeof import("./audio.ts"), string, string];
|
|
16
|
+
/**
|
|
17
|
+
* Load the audio module and worklet sources, memoized so a prefetch at
|
|
18
|
+
* `connect()` time overlaps the chunk fetch with the WebSocket handshake
|
|
19
|
+
* instead of serializing it behind the server's `config` frame. A failed
|
|
20
|
+
* load clears the memo so the next attempt retries the import.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadAudioModules(): Promise<AudioModules>;
|
|
15
23
|
/**
|
|
16
24
|
* Initialize audio capture and playback after the server sends a ready config.
|
|
17
25
|
*
|
|
@@ -31,3 +39,4 @@ export declare function initAudioCapture(conn: ConnState, msg: {
|
|
|
31
39
|
sampleRate: number;
|
|
32
40
|
ttsSampleRate: number;
|
|
33
41
|
}, deps: AudioSetupDeps): Promise<void>;
|
|
42
|
+
export {};
|
|
@@ -116,7 +116,7 @@ export type ConnState = {
|
|
|
116
116
|
* the playback worklet once init completes. Closes the race between the
|
|
117
117
|
* server starting greeting audio (immediately on S2S connect) and the
|
|
118
118
|
* client awaiting mic permission + worklet registration. */
|
|
119
|
-
preInitAudio:
|
|
119
|
+
preInitAudio: ArrayBuffer[];
|
|
120
120
|
/** True if `audio_done` arrived before `voiceIO` was initialized. The done
|
|
121
121
|
* signal must be replayed after draining preInitAudio, or a short greeting
|
|
122
122
|
* buffered during mic-permission never finishes playing. */
|
package/dist/session-core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createSessionCore } from "./session-core-
|
|
1
|
+
import { t as createSessionCore } from "./session-core-Bvga6tUS.js";
|
|
2
2
|
export { createSessionCore };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTheme } from "./context.js";
|
|
2
|
-
import { r as TEXT_FAINT } from "./_colors-
|
|
2
|
+
import { r as TEXT_FAINT } from "./_colors-Bfh3-BVE.js";
|
|
3
3
|
import { t as Eyebrow } from "./eyebrow-C6ZFuiz6.js";
|
|
4
|
-
import { n as
|
|
4
|
+
import { n as truncate, r as tryParseJSON } from "./_utils-CsqbIVGI.js";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import { createContext, memo, useContext, useMemo, useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"react-markdown": "^10.1.0",
|
|
23
23
|
"remark-gfm": "^4.0.1",
|
|
24
24
|
"use-sync-external-store": "^1.6.0",
|
|
25
|
-
"@alexkroman1/aai": "5.
|
|
25
|
+
"@alexkroman1/aai": "5.2.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^19.0.0",
|