@alexkroman1/aai-ui 6.5.0 → 6.5.1
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/{_utils-CsqbIVGI.js → _utils-B6498_bm.js} +13 -1
- package/dist/_utils.d.ts +10 -0
- package/dist/_workflow-files.d.ts +16 -0
- package/dist/audio.js +15 -7
- package/dist/{chat-view-CK61bWWx.js → chat-view-ByQFf94G.js} +2 -2
- package/dist/components/button.js +30 -25
- 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/tool-call-block.js +1 -1
- package/dist/{controls-Cy_YVfsa.js → controls-CjG91QJ4.js} +1 -1
- package/dist/default-client/assets/audio-CoVe8N48.js +1 -0
- package/dist/default-client/assets/index-CepvxbNU.js +293 -0
- package/dist/default-client/index.html +1 -1
- package/dist/define-client.js +5 -5
- package/dist/hooks.js +4 -3
- package/dist/index.js +69 -20
- package/dist/{message-list-BwA3rdPi.js → message-list-CpPV7dGx.js} +1 -1
- package/dist/{session-core-ClKdVgRU.js → session-core-CAfYmUbg.js} +33 -23
- package/dist/session-core-reconnect.d.ts +6 -6
- package/dist/session-core.js +1 -1
- package/dist/{tool-call-block-CrLN7xlI.js → tool-call-block-D6pTEPrT.js} +5 -4
- package/dist/worklets/capture-processor.js +3 -4
- package/dist/worklets/playback-processor.js +3 -4
- package/package.json +2 -2
- package/dist/default-client/assets/audio-fO7SVU64.js +0 -1
- package/dist/default-client/assets/index-aXDcAQ6M.js +0 -293
|
@@ -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-CepvxbNU.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="./assets/client-audio-constants-Ck0IJO4c.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="./assets/index-BZlePk3y.css">
|
|
12
12
|
</head>
|
package/dist/define-client.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { r as fetchClientConfig, t as createSessionCore } from "./session-core-
|
|
1
|
+
import { r as fetchClientConfig, t as createSessionCore } from "./session-core-CAfYmUbg.js";
|
|
2
2
|
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
3
|
-
import { t as ChatView } from "./chat-view-
|
|
4
|
-
import { t as pageBaseUrl } from "./_utils-
|
|
5
|
-
import { n as ToolConfigContext } from "./tool-call-block-
|
|
3
|
+
import { t as ChatView } from "./chat-view-ByQFf94G.js";
|
|
4
|
+
import { n as setPageTitle, t as pageBaseUrl } from "./_utils-B6498_bm.js";
|
|
5
|
+
import { n as ToolConfigContext } from "./tool-call-block-D6pTEPrT.js";
|
|
6
6
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
7
7
|
import { StartScreen } from "./components/start-screen.js";
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -165,7 +165,7 @@ function client(config) {
|
|
|
165
165
|
resumeSessionId: config.resumeSessionId,
|
|
166
166
|
WebSocket: config.WebSocket
|
|
167
167
|
});
|
|
168
|
-
|
|
168
|
+
setPageTitle(config.name);
|
|
169
169
|
const rootNode = config.component ? createElement(config.component) : createElement(DefaultRoot, {
|
|
170
170
|
platformUrl,
|
|
171
171
|
name: config.name,
|
package/dist/hooks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useSessionSelector } from "./context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as tryParseJSON } from "./_utils-B6498_bm.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). */
|
|
@@ -44,8 +44,9 @@ function processToolCallTail(toolCalls, cursor, isSettled, onNew) {
|
|
|
44
44
|
* and invokes `fire` once per tool call reaching `status`.
|
|
45
45
|
*/
|
|
46
46
|
function useToolCallEffect(status, args, fire) {
|
|
47
|
-
const
|
|
48
|
-
const
|
|
47
|
+
const first = args[0];
|
|
48
|
+
const filterName = typeof first === "string" ? first : null;
|
|
49
|
+
const callback = filterName === null ? first : args[1];
|
|
49
50
|
const toolCalls = useSessionSelector((s) => s.toolCalls);
|
|
50
51
|
const cursorRef = useRef({
|
|
51
52
|
seq: 0,
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { i as loadClientConfig, n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-
|
|
2
|
-
import { n as Markdown, r as AutoScroll, t as MessageList } from "./message-list-
|
|
1
|
+
import { i as loadClientConfig, n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-CAfYmUbg.js";
|
|
2
|
+
import { n as Markdown, r as AutoScroll, t as MessageList } from "./message-list-CpPV7dGx.js";
|
|
3
3
|
import { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme } from "./context.js";
|
|
4
4
|
import { r as inkTint } from "./_colors-CcAi2FOU.js";
|
|
5
5
|
import { Button } from "./components/button.js";
|
|
6
|
-
import { t as ChatView } from "./chat-view-
|
|
7
|
-
import { t as pageBaseUrl } from "./_utils-
|
|
8
|
-
import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-
|
|
9
|
-
import { n as ToolConfigContext, r as ToolCallRow } from "./tool-call-block-
|
|
6
|
+
import { t as ChatView } from "./chat-view-ByQFf94G.js";
|
|
7
|
+
import { n as setPageTitle, t as pageBaseUrl } from "./_utils-B6498_bm.js";
|
|
8
|
+
import { i as UiUrlChip, n as ApiUrlChip, r as SessionUrlChips, t as Controls } from "./controls-CjG91QJ4.js";
|
|
9
|
+
import { n as ToolConfigContext, r as ToolCallRow } from "./tool-call-block-D6pTEPrT.js";
|
|
10
10
|
import { SidebarLayout } from "./components/sidebar-layout.js";
|
|
11
11
|
import { StartScreen } from "./components/start-screen.js";
|
|
12
12
|
import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
|
|
@@ -526,6 +526,7 @@ function UploadProgressBar({ upload, className }) {
|
|
|
526
526
|
if (!upload) return null;
|
|
527
527
|
const { name, index, count, loaded, total, fraction } = upload;
|
|
528
528
|
const percent = fraction === void 0 ? void 0 : Math.round(fraction * 100);
|
|
529
|
+
const faint = inkTint(theme.text, theme.surface, 65);
|
|
529
530
|
return /* @__PURE__ */ jsxs("div", {
|
|
530
531
|
className: clsx(className ?? "flex flex-col gap-1.5"),
|
|
531
532
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -533,11 +534,11 @@ function UploadProgressBar({ upload, className }) {
|
|
|
533
534
|
children: [/* @__PURE__ */ jsx("span", {
|
|
534
535
|
id: labelId,
|
|
535
536
|
className: "truncate",
|
|
536
|
-
style: { color:
|
|
537
|
+
style: { color: faint },
|
|
537
538
|
children: count > 1 ? `Uploading ${name} (${index} of ${count})` : `Uploading ${name}`
|
|
538
539
|
}), /* @__PURE__ */ jsx("span", {
|
|
539
540
|
className: "shrink-0 tabular-nums",
|
|
540
|
-
style: { color:
|
|
541
|
+
style: { color: faint },
|
|
541
542
|
children: total === void 0 ? formatBytes(loaded) : `${formatBytes(loaded)} of ${formatBytes(total)}`
|
|
542
543
|
})]
|
|
543
544
|
}), /* @__PURE__ */ jsx("div", {
|
|
@@ -649,6 +650,25 @@ function filesOf(value) {
|
|
|
649
650
|
const files = value.filter((one) => one instanceof File);
|
|
650
651
|
return files.length > 0 && files.length === value.length ? files : [];
|
|
651
652
|
}
|
|
653
|
+
/**
|
|
654
|
+
* The input properties still carrying a `File` — i.e. the ones that CANNOT survive
|
|
655
|
+
* being sent.
|
|
656
|
+
*
|
|
657
|
+
* A run input is JSON, and `JSON.stringify(new File(…))` is `{}` — no `toJSON`, no
|
|
658
|
+
* own enumerable properties. So a File left in a payload does not fail to send: it
|
|
659
|
+
* arrives as an empty object, and the workflow rejects it against whatever its own
|
|
660
|
+
* schema says the property should be. Measured in production as
|
|
661
|
+
* `Invalid input for workflow "transcribe": recording: Invalid input` — a message
|
|
662
|
+
* about a type, on a form where the user had picked a perfectly good file.
|
|
663
|
+
*
|
|
664
|
+
* Exported beside {@link filesOf} because it is the same question asked at the
|
|
665
|
+
* other end: that one decides which fields to UPLOAD, this one checks that none
|
|
666
|
+
* were missed. Both hooks are the callers.
|
|
667
|
+
*/
|
|
668
|
+
function fileFields(input) {
|
|
669
|
+
if (!isRecord(input)) return [];
|
|
670
|
+
return Object.entries(input).filter(([, value]) => filesOf(value).length > 0).map(([key]) => key);
|
|
671
|
+
}
|
|
652
672
|
//#endregion
|
|
653
673
|
//#region _repeat-until.ts
|
|
654
674
|
/**
|
|
@@ -1137,10 +1157,10 @@ function useWorkflowSubmit(workflow, opts = {}) {
|
|
|
1137
1157
|
const [startError, setStartError] = useState(void 0);
|
|
1138
1158
|
const [upload, setUpload] = useState(void 0);
|
|
1139
1159
|
const getClient = useWorkflowApiRef(api);
|
|
1140
|
-
const tracked = useWorkflowRun(runId, {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
});
|
|
1160
|
+
const tracked = useWorkflowRun(runId, omitUndefined({
|
|
1161
|
+
api,
|
|
1162
|
+
intervalMs
|
|
1163
|
+
}));
|
|
1144
1164
|
return {
|
|
1145
1165
|
submit: useCallback(async (input) => {
|
|
1146
1166
|
const client = getClient();
|
|
@@ -1247,7 +1267,8 @@ function SchemaField({ name, property, required, upload = false }) {
|
|
|
1247
1267
|
...hint,
|
|
1248
1268
|
...defaults
|
|
1249
1269
|
});
|
|
1250
|
-
|
|
1270
|
+
const type = typeOf(property);
|
|
1271
|
+
switch (type) {
|
|
1251
1272
|
case "boolean": return /* @__PURE__ */ jsx(CheckboxField, {
|
|
1252
1273
|
name,
|
|
1253
1274
|
label,
|
|
@@ -1259,7 +1280,7 @@ function SchemaField({ name, property, required, upload = false }) {
|
|
|
1259
1280
|
name,
|
|
1260
1281
|
label,
|
|
1261
1282
|
required,
|
|
1262
|
-
step:
|
|
1283
|
+
step: type === "integer" ? 1 : "any",
|
|
1263
1284
|
...hint,
|
|
1264
1285
|
...defaults
|
|
1265
1286
|
});
|
|
@@ -1546,7 +1567,7 @@ function useWorkflowProgress(runId, opts = {}) {
|
|
|
1546
1567
|
* @public
|
|
1547
1568
|
*/
|
|
1548
1569
|
function WorkflowProgress({ runId, api, className, placeholder }) {
|
|
1549
|
-
const { progress, streaming, supported } = useWorkflowProgress(runId,
|
|
1570
|
+
const { progress, streaming, supported } = useWorkflowProgress(runId, omitUndefined({ api }));
|
|
1550
1571
|
if (!supported || progress.length === 0) return placeholder ?? null;
|
|
1551
1572
|
return /* @__PURE__ */ jsxs("pre", {
|
|
1552
1573
|
className: clsx(className ?? "whitespace-pre-wrap border-l pl-4 text-xs opacity-70"),
|
|
@@ -1610,7 +1631,7 @@ function WorkflowProgress({ runId, api, className, placeholder }) {
|
|
|
1610
1631
|
*/
|
|
1611
1632
|
function page(config) {
|
|
1612
1633
|
const container = resolveContainer(config.target);
|
|
1613
|
-
|
|
1634
|
+
setPageTitle(config.name);
|
|
1614
1635
|
return mountRoot(container, createElement(ThemeProvider, { value: config.theme }, createElement(config.component)));
|
|
1615
1636
|
}
|
|
1616
1637
|
//#endregion
|
|
@@ -1869,10 +1890,10 @@ function useWorkflowStream(workflow, opts = {}) {
|
|
|
1869
1890
|
const [startError, setStartError] = useState(void 0);
|
|
1870
1891
|
const [upload, setUpload] = useState(void 0);
|
|
1871
1892
|
const getClient = useWorkflowApiRef(api);
|
|
1872
|
-
const tracked = useWorkflowRun(runId, {
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
});
|
|
1893
|
+
const tracked = useWorkflowRun(runId, omitUndefined({
|
|
1894
|
+
api,
|
|
1895
|
+
intervalMs
|
|
1896
|
+
}));
|
|
1876
1897
|
return {
|
|
1877
1898
|
submit: useCallback(async (input) => {
|
|
1878
1899
|
const client = getClient();
|
|
@@ -1888,6 +1909,7 @@ function useWorkflowStream(workflow, opts = {}) {
|
|
|
1888
1909
|
...input,
|
|
1889
1910
|
[field]: id
|
|
1890
1911
|
} : input;
|
|
1912
|
+
assertSendable(workflow, payload, field);
|
|
1891
1913
|
started = await client.start(workflow, payload, omitUndefined({ key }));
|
|
1892
1914
|
setRunId(started);
|
|
1893
1915
|
if (!chosen) return;
|
|
@@ -1926,6 +1948,33 @@ function useWorkflowStream(workflow, opts = {}) {
|
|
|
1926
1948
|
error: startError ?? tracked.error
|
|
1927
1949
|
};
|
|
1928
1950
|
}
|
|
1951
|
+
/**
|
|
1952
|
+
* Refuse a payload carrying a `File`, before a run is started over it.
|
|
1953
|
+
*
|
|
1954
|
+
* A File cannot be SENT: a run input is JSON and `JSON.stringify(new File(…))` is
|
|
1955
|
+
* `{}` (see `fileFields`). So without this the run starts, rejects its own input,
|
|
1956
|
+
* and reports a type error about a property the user filled in correctly — which is
|
|
1957
|
+
* what production did, five times: `Invalid input for workflow "transcribe":
|
|
1958
|
+
* recording: Invalid input`, from a page whose file picker was working.
|
|
1959
|
+
*
|
|
1960
|
+
* The reachable cause is a workflow whose listing declares no `uploads` for the
|
|
1961
|
+
* property the form put a file in — one built before the declaration existed, or a
|
|
1962
|
+
* page pointing at the wrong workflow — so the message names BOTH halves: the
|
|
1963
|
+
* property that carries a file, and the one (if any) the workflow says is its
|
|
1964
|
+
* upload. A message naming only one of them leaves the reader guessing which end
|
|
1965
|
+
* to change.
|
|
1966
|
+
*
|
|
1967
|
+
* A throw rather than a silent repair: this hook cannot know whether the right fix
|
|
1968
|
+
* is to declare the property or to stop sending the file, and guessing either way
|
|
1969
|
+
* would start a run the caller did not mean.
|
|
1970
|
+
*/
|
|
1971
|
+
function assertSendable(workflow, payload, field) {
|
|
1972
|
+
const unsendable = fileFields(payload);
|
|
1973
|
+
if (unsendable.length === 0) return;
|
|
1974
|
+
const carries = unsendable.length === 1 ? "carries a file" : "carry files";
|
|
1975
|
+
const declares = field === void 0 ? "" : ` (it declares "${field}")`;
|
|
1976
|
+
throw new Error(`Cannot start "${workflow}": ${unsendable.join(", ")} ${carries} the workflow does not declare as an upload${declares}. Add the property to \`workflow({ uploads: [...] })\`, or submit an upload id.`);
|
|
1977
|
+
}
|
|
1929
1978
|
/** A fresh upload id: a capability, so it is random rather than derived. */
|
|
1930
1979
|
function randomUploadId() {
|
|
1931
1980
|
return crypto.randomUUID().replaceAll("-", "");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSessionSelector, useTheme } from "./context.js";
|
|
2
2
|
import { i as primaryTint, r as inkTint } from "./_colors-CcAi2FOU.js";
|
|
3
|
-
import { t as ToolCallBlock } from "./tool-call-block-
|
|
3
|
+
import { t as ToolCallBlock } from "./tool-call-block-D6pTEPrT.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { StickToBottom } from "use-stick-to-bottom";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -232,12 +232,6 @@ function openReconnectingSocket(urlProvider) {
|
|
|
232
232
|
return new ReconnectingWebSocket(urlProvider, void 0, RECONNECT_OPTIONS);
|
|
233
233
|
}
|
|
234
234
|
/**
|
|
235
|
-
* True while `socket` is a reconnecting socket that will retry after the
|
|
236
|
-
* close event currently being handled. partysocket schedules the retry
|
|
237
|
-
* *before* dispatching `close`, so `retryCount` already names the attempt
|
|
238
|
-
* just scheduled — at `maxRetries` it has given up.
|
|
239
|
-
*/
|
|
240
|
-
/**
|
|
241
235
|
* Force a fresh connection attempt on a reconnecting socket, reporting
|
|
242
236
|
* whether it was one. Used for a failure partysocket cannot see: a socket it
|
|
243
237
|
* considers open and healthy, whose peer never completed OUR handshake.
|
|
@@ -249,6 +243,12 @@ function forceReconnect(socket) {
|
|
|
249
243
|
socket.reconnect();
|
|
250
244
|
return true;
|
|
251
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* True while `socket` is a reconnecting socket that will retry after the
|
|
248
|
+
* close event currently being handled. partysocket schedules the retry
|
|
249
|
+
* *before* dispatching `close`, so `retryCount` already names the attempt
|
|
250
|
+
* just scheduled — at `maxRetries` it has given up.
|
|
251
|
+
*/
|
|
252
252
|
function reconnectPending(socket) {
|
|
253
253
|
return socket instanceof ReconnectingWebSocket && socket.shouldReconnect && socket.retryCount < RECONNECT_OPTIONS.maxRetries;
|
|
254
254
|
}
|
|
@@ -706,16 +706,15 @@ function createMessageHandlers(deps) {
|
|
|
706
706
|
case "tool.completed": {
|
|
707
707
|
const tcs = getSnapshot().toolCalls;
|
|
708
708
|
const idx = tcs.findIndex((tc) => tc.callId === e.toolCallId);
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
709
|
+
const existing = tcs[idx];
|
|
710
|
+
if (!existing) break;
|
|
711
|
+
const updated = [...tcs];
|
|
712
|
+
updated[idx] = {
|
|
713
|
+
...existing,
|
|
714
|
+
status: "done",
|
|
715
|
+
result: e.result
|
|
716
|
+
};
|
|
717
|
+
updateState({ toolCalls: updated });
|
|
719
718
|
break;
|
|
720
719
|
}
|
|
721
720
|
case "reply.completed":
|
|
@@ -765,7 +764,7 @@ function createMessageHandlers(deps) {
|
|
|
765
764
|
handleErrorEvent(e);
|
|
766
765
|
break;
|
|
767
766
|
case "session.timed-out":
|
|
768
|
-
|
|
767
|
+
conn.retiredByServer = true;
|
|
769
768
|
break;
|
|
770
769
|
default: break;
|
|
771
770
|
}
|
|
@@ -949,13 +948,24 @@ function createSessionCore(options) {
|
|
|
949
948
|
function resetState() {
|
|
950
949
|
updateState(CLEARED_SESSION_STATE);
|
|
951
950
|
}
|
|
951
|
+
/**
|
|
952
|
+
* The socket, when there is one and it can carry a frame.
|
|
953
|
+
*
|
|
954
|
+
* Returning the socket rather than a boolean because every caller needs it
|
|
955
|
+
* next, and a predicate does not narrow `conn.ws` across the call. One
|
|
956
|
+
* spelling of the readiness test, which four call sites used to repeat.
|
|
957
|
+
*/
|
|
958
|
+
function openSocket() {
|
|
959
|
+
return conn.ws?.readyState === WS_OPEN ? conn.ws : null;
|
|
960
|
+
}
|
|
952
961
|
function sendJson(msg) {
|
|
953
|
-
|
|
962
|
+
openSocket()?.send(JSON.stringify(msg));
|
|
954
963
|
}
|
|
955
964
|
function sendAudio(bytes) {
|
|
956
|
-
|
|
957
|
-
if (
|
|
958
|
-
|
|
965
|
+
const ws = openSocket();
|
|
966
|
+
if (!ws) return;
|
|
967
|
+
if (ws.bufferedAmount > MIC_SEND_MAX_BUFFERED_BYTES) return;
|
|
968
|
+
ws.send(bytes);
|
|
959
969
|
}
|
|
960
970
|
const { handleMessage, settleWhenAudioDrained } = createMessageHandlers({
|
|
961
971
|
getSnapshot,
|
|
@@ -1090,7 +1100,7 @@ function createSessionCore(options) {
|
|
|
1090
1100
|
}, { signal: sig });
|
|
1091
1101
|
}
|
|
1092
1102
|
function cancel() {
|
|
1093
|
-
if (!
|
|
1103
|
+
if (!openSocket()) return;
|
|
1094
1104
|
conn.turn.bump();
|
|
1095
1105
|
conn.voiceIO?.flush();
|
|
1096
1106
|
updateState({ state: "listening" });
|
|
@@ -1099,7 +1109,7 @@ function createSessionCore(options) {
|
|
|
1099
1109
|
function reset() {
|
|
1100
1110
|
conn.turn.bump();
|
|
1101
1111
|
conn.voiceIO?.flush();
|
|
1102
|
-
if (
|
|
1112
|
+
if (openSocket()) {
|
|
1103
1113
|
sendJson({ type: "reset" });
|
|
1104
1114
|
return;
|
|
1105
1115
|
}
|
|
@@ -6,12 +6,6 @@ import type { WebSocketConstructor } from "./types.ts";
|
|
|
6
6
|
* session started with.
|
|
7
7
|
*/
|
|
8
8
|
export declare function openReconnectingSocket(urlProvider: () => Promise<string>): InstanceType<WebSocketConstructor>;
|
|
9
|
-
/**
|
|
10
|
-
* True while `socket` is a reconnecting socket that will retry after the
|
|
11
|
-
* close event currently being handled. partysocket schedules the retry
|
|
12
|
-
* *before* dispatching `close`, so `retryCount` already names the attempt
|
|
13
|
-
* just scheduled — at `maxRetries` it has given up.
|
|
14
|
-
*/
|
|
15
9
|
/**
|
|
16
10
|
* Force a fresh connection attempt on a reconnecting socket, reporting
|
|
17
11
|
* whether it was one. Used for a failure partysocket cannot see: a socket it
|
|
@@ -20,4 +14,10 @@ export declare function openReconnectingSocket(urlProvider: () => Promise<string
|
|
|
20
14
|
* reconnect machinery — the caller then treats the failure as terminal.
|
|
21
15
|
*/
|
|
22
16
|
export declare function forceReconnect(socket: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* True while `socket` is a reconnecting socket that will retry after the
|
|
19
|
+
* close event currently being handled. partysocket schedules the retry
|
|
20
|
+
* *before* dispatching `close`, so `retryCount` already names the attempt
|
|
21
|
+
* just scheduled — at `maxRetries` it has given up.
|
|
22
|
+
*/
|
|
23
23
|
export declare function reconnectPending(socket: unknown): boolean;
|
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-CAfYmUbg.js";
|
|
2
2
|
export { createSessionCore };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useTheme } from "./context.js";
|
|
2
2
|
import { r as inkTint } from "./_colors-CcAi2FOU.js";
|
|
3
3
|
import { t as Eyebrow } from "./eyebrow-C6ZFuiz6.js";
|
|
4
|
-
import {
|
|
4
|
+
import { i as tryParseJSON, r as truncate } from "./_utils-B6498_bm.js";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { createContext, memo, useContext, useMemo, useState } from "react";
|
|
@@ -40,6 +40,7 @@ function ToolCallRow({ title, detail, pending = false, icon, variant = "default"
|
|
|
40
40
|
const theme = useTheme();
|
|
41
41
|
const sizes = VARIANT_CLASSES[variant];
|
|
42
42
|
const canExpand = children != null;
|
|
43
|
+
const faint = inkTint(theme.text, theme.bg, 65);
|
|
43
44
|
return /* @__PURE__ */ jsxs("div", {
|
|
44
45
|
className: clsx("flex flex-col rounded-md border overflow-hidden", className),
|
|
45
46
|
style: {
|
|
@@ -60,7 +61,7 @@ function ToolCallRow({ title, detail, pending = false, icon, variant = "default"
|
|
|
60
61
|
children: icon
|
|
61
62
|
}) : /* @__PURE__ */ jsx(Eyebrow, {
|
|
62
63
|
className: "shrink-0",
|
|
63
|
-
style: { color:
|
|
64
|
+
style: { color: faint },
|
|
64
65
|
children: "Tool"
|
|
65
66
|
}),
|
|
66
67
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -70,12 +71,12 @@ function ToolCallRow({ title, detail, pending = false, icon, variant = "default"
|
|
|
70
71
|
}),
|
|
71
72
|
/* @__PURE__ */ jsx("span", {
|
|
72
73
|
className: clsx("font-aai-mono truncate flex-1 min-w-0", sizes.title),
|
|
73
|
-
style: { color:
|
|
74
|
+
style: { color: faint },
|
|
74
75
|
children: detail
|
|
75
76
|
}),
|
|
76
77
|
canExpand && /* @__PURE__ */ jsx("span", {
|
|
77
78
|
className: clsx("shrink-0 transition-transform duration-150", sizes.chevron, isOpen && "rotate-90"),
|
|
78
|
-
style: { color:
|
|
79
|
+
style: { color: faint },
|
|
79
80
|
children: "▶"
|
|
80
81
|
})
|
|
81
82
|
]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { MIC_BUFFER_SECONDS, MIC_SILENCE_PROBE_MS } from "../types.js";
|
|
2
2
|
import { t as workletModuleUrl } from "../_module-url-C_4gRVL0.js";
|
|
3
3
|
//#region worklets/capture-processor.ts
|
|
4
|
-
|
|
4
|
+
/** Raw worklet source — exported so tests can evaluate the processor directly. */
|
|
5
|
+
const captureProcessorSource = `
|
|
5
6
|
class CaptureProcessor extends AudioWorkletProcessor {
|
|
6
7
|
constructor(options) {
|
|
7
8
|
super();
|
|
@@ -91,8 +92,6 @@ class CaptureProcessor extends AudioWorkletProcessor {
|
|
|
91
92
|
|
|
92
93
|
registerProcessor('capture-processor', CaptureProcessor);
|
|
93
94
|
`;
|
|
94
|
-
|
|
95
|
-
const captureProcessorSource = CaptureProcessorWorklet;
|
|
96
|
-
var capture_processor_default = workletModuleUrl(CaptureProcessorWorklet);
|
|
95
|
+
var capture_processor_default = workletModuleUrl(captureProcessorSource);
|
|
97
96
|
//#endregion
|
|
98
97
|
export { captureProcessorSource, capture_processor_default as default };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { PLAYBACK_BUFFER_SECONDS, PLAYBACK_CONCEAL_FADE_MS, PLAYBACK_CONCEAL_FLOOR, PLAYBACK_FILL_MS, PLAYBACK_PROGRESS_INTERVAL_MS } from "../types.js";
|
|
2
2
|
import { t as workletModuleUrl } from "../_module-url-C_4gRVL0.js";
|
|
3
3
|
//#region worklets/playback-processor.ts
|
|
4
|
-
|
|
4
|
+
/** Raw worklet source — exported so tests can evaluate the processor directly. */
|
|
5
|
+
const playbackProcessorSource = `
|
|
5
6
|
class PlaybackProcessor extends AudioWorkletProcessor {
|
|
6
7
|
constructor(options) {
|
|
7
8
|
super();
|
|
@@ -315,8 +316,6 @@ class PlaybackProcessor extends AudioWorkletProcessor {
|
|
|
315
316
|
|
|
316
317
|
registerProcessor('playback-processor', PlaybackProcessor);
|
|
317
318
|
`;
|
|
318
|
-
|
|
319
|
-
const playbackProcessorSource = PlaybackProcessorWorklet;
|
|
320
|
-
var playback_processor_default = workletModuleUrl(PlaybackProcessorWorklet);
|
|
319
|
+
var playback_processor_default = workletModuleUrl(playbackProcessorSource);
|
|
321
320
|
//#endregion
|
|
322
321
|
export { playback_processor_default as default, playbackProcessorSource };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexkroman1/aai-ui",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"remark-gfm": "^4.0.1",
|
|
30
30
|
"use-stick-to-bottom": "^1.1.6",
|
|
31
31
|
"use-sync-external-store": "^1.6.0",
|
|
32
|
-
"@alexkroman1/aai": "6.5.
|
|
32
|
+
"@alexkroman1/aai": "6.5.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"react": "^19.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e,s as t}from"./client-audio-constants-Ck0IJO4c.js";var n={echoCancellation:!0,noiseSuppression:!1,autoGainControl:!1,voiceIsolation:!1};function r(e,t,n){if(e!==t)throw Error(`Browser refused the ${n} sample rate: asked for ${t} Hz, got ${e} Hz`)}function i(e){e.then(e=>{for(let t of e.getTracks())t.stop()}).catch(()=>{})}function a(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 o(o){let{sttSampleRate:s,ttsSampleRate:c,captureWorkletSrc:l,playbackWorkletSrc:u,onMicData:d,onError:f,onPlaybackStats:p,onPlaybackProgress:m,onMicSilent:h}=o,g=new AudioContext({sampleRate:c,latencyHint:`playback`}),_=s===c,v=_?g:new AudioContext({sampleRate:s,latencyHint:`interactive`});async function y(){let e=_?[g]:[g,v];await Promise.all(e.map(e=>e.close().catch(e=>{console.warn(`AudioContext close failed:`,e)})))}let b=navigator.mediaDevices.getUserMedia({audio:{deviceId:{ideal:`default`},...n}}),x;try{[x]=await Promise.all([b,g.resume(),v.resume(),v.audioWorklet.addModule(l),g.audioWorklet.addModule(u)]),r(v.sampleRate,s,`capture`),r(g.sampleRate,c,`playback`)}catch(e){throw i(b),await y(),e}let S=v.createMediaStreamSource(x),C=a(v,d,h);S.connect(C.node),C.node.onprocessorerror=()=>{let e=Error(`Audio capture worklet crashed`);console.error(`[aai-ui]`,e.message),f?.(e)},C.start();let w=null,T=null,E=0,D=null,O=new AbortController;function k(){T?.(),T=null,D=null}function A(e){e.stats&&e.stats.concealedSamples>0&&p?.(e.stats),e.reason!==`interrupt`&&(D===null||e.turn===D)&&k()}function j(){if(w)return w;let e=new AudioWorkletNode(g,`playback-processor`);return e.connect(g.destination),e.port.onmessage=e=>{e.data.event===`stop`?A(e.data):e.data.event===`progress`&&m?.(e.data.bufferedMs)},e.onprocessorerror=()=>{let e=Error(`Audio playback worklet crashed`);console.error(`[aai-ui]`,e.message),k(),f?.(e)},w=e,e}let M={enqueue(e){O.signal.aborted||e.byteLength!==0&&j().port.postMessage({event:`write`,buffer:new Uint8Array(e)},[e])},done(){if(!w)return Promise.resolve();let n=++E;if(w.port.postMessage({event:`done`,turn:n}),g.state!==`running`)return D=null,Promise.resolve();let{promise:r,resolve:i}=Promise.withResolvers();T?.();let a=()=>{clearInterval(o),clearTimeout(s),T===a&&(T=null,D=null),i()},o=setInterval(()=>{g.state!==`running`&&a()},t),s=setTimeout(a,e);return T=a,D=n,r},flush(){w&&(k(),w.port.postMessage({event:`interrupt`}))},async close(){if(!O.signal.aborted){O.abort(),await C.stop(),S.disconnect(),C.node.disconnect(),w&&w.disconnect();for(let e of x.getTracks())e.stop();await y()}},async[Symbol.asyncDispose](){await M.close()}};return M}export{o as createVoiceIO};
|