@alexkroman1/aai-ui 0.16.0 → 0.17.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.
Files changed (86) hide show
  1. package/dist/agent-state-labels.d.ts +8 -3
  2. package/dist/{chat-view-DIwPoAEG.js → chat-view-W6KcdjJY.js} +40 -30
  3. package/dist/{client-config-C7fQrioM.js → client-config-CzvWmw4X.js} +7 -12
  4. package/dist/client-config.d.ts +29 -10
  5. package/dist/components/_form-readiness.d.ts +2 -1
  6. package/dist/components/audio-result.d.ts +2 -0
  7. package/dist/components/bullet-list.d.ts +1 -0
  8. package/dist/components/button.d.ts +2 -2
  9. package/dist/components/chat-view.js +1 -1
  10. package/dist/components/console-shell.d.ts +8 -5
  11. package/dist/components/controls.d.ts +1 -0
  12. package/dist/components/conversation-view.d.ts +1 -0
  13. package/dist/components/facts.d.ts +1 -0
  14. package/dist/components/form-fields.d.ts +8 -8
  15. package/dist/components/form-types.d.ts +16 -2
  16. package/dist/components/form.d.ts +9 -4
  17. package/dist/components/markdown.d.ts +1 -0
  18. package/dist/components/message-list.d.ts +1 -0
  19. package/dist/components/message-list.js +1 -1
  20. package/dist/components/session-controls.d.ts +7 -2
  21. package/dist/components/session-error-banner.d.ts +1 -0
  22. package/dist/components/session-state-dot.d.ts +20 -7
  23. package/dist/components/sidebar-layout.d.ts +2 -2
  24. package/dist/components/tool-call-block.d.ts +3 -3
  25. package/dist/components/tool-call-row.d.ts +1 -0
  26. package/dist/components/tool-config-context.d.ts +2 -1
  27. package/dist/components/url-chips.d.ts +4 -3
  28. package/dist/components/workflow-fields.d.ts +2 -1
  29. package/dist/components/workflow-pending-note.d.ts +1 -0
  30. package/dist/components/workflow-run-error.d.ts +1 -0
  31. package/dist/components/workflow-run-panel.d.ts +1 -0
  32. package/dist/context.d.ts +8 -7
  33. package/dist/context.js +2 -2
  34. package/dist/default-client/assets/{audio-DzwGxdv4.js → audio-Ct7JpSNT.js} +1 -1
  35. package/dist/default-client/assets/{capture-processor-CXCWxCO8.js → capture-processor-Cx1AdMHL.js} +1 -1
  36. package/dist/default-client/assets/index-BlUYCTB5.js +126 -0
  37. package/dist/default-client/assets/{playback-processor-DXHfyQD9.js → playback-processor-CCwTknSu.js} +1 -1
  38. package/dist/default-client/index.html +1 -1
  39. package/dist/define-client.d.ts +2 -0
  40. package/dist/define-client.js +4 -4
  41. package/dist/inbox-protocol.d.ts +14 -4
  42. package/dist/inbox.d.ts +1 -0
  43. package/dist/index.d.ts +3 -3
  44. package/dist/index.js +61 -19
  45. package/dist/internal.js +1 -1
  46. package/dist/linked-client.d.ts +2 -0
  47. package/dist/{message-list-DHZcLhRA.js → message-list-BsaBkBgo.js} +21 -10
  48. package/dist/page.d.ts +2 -0
  49. package/dist/phone.d.ts +1 -0
  50. package/dist/route-fetch.d.ts +1 -0
  51. package/dist/session/audio-setup.d.ts +1 -1
  52. package/dist/session/audio-state.d.ts +6 -6
  53. package/dist/session/index.js +1 -1
  54. package/dist/session/messages.d.ts +1 -9
  55. package/dist/session/preconnect.d.ts +1 -1
  56. package/dist/session/types.d.ts +4 -0
  57. package/dist/{session-CYdjRvbl.js → session-3lgPYNNO.js} +25 -14
  58. package/dist/stored-value.d.ts +2 -0
  59. package/dist/types.d.ts +48 -4
  60. package/dist/use-client-runs.d.ts +2 -0
  61. package/dist/use-conversation-log.d.ts +2 -0
  62. package/dist/use-conversation.d.ts +24 -9
  63. package/dist/use-copy.d.ts +1 -0
  64. package/dist/use-download-url.d.ts +6 -1
  65. package/dist/use-flash.d.ts +1 -0
  66. package/dist/use-inbox.d.ts +2 -0
  67. package/dist/use-push-to-talk.d.ts +6 -1
  68. package/dist/use-route-mutation.d.ts +3 -0
  69. package/dist/use-route.d.ts +2 -0
  70. package/dist/use-session-controls.d.ts +1 -0
  71. package/dist/use-tap-to-talk.d.ts +5 -2
  72. package/dist/use-user-transcript.d.ts +5 -1
  73. package/dist/use-workflow-form.d.ts +8 -1
  74. package/dist/use-workflow-progress.d.ts +5 -0
  75. package/dist/use-workflow-run.d.ts +5 -0
  76. package/dist/use-workflow-runs.d.ts +10 -2
  77. package/dist/use-workflow-stream.d.ts +25 -3
  78. package/dist/use-workflows.d.ts +10 -2
  79. package/dist/workflow-client.d.ts +5 -0
  80. package/dist/workflow-field-kind.d.ts +8 -4
  81. package/dist/worklets/capture-processor.d.ts +3 -3
  82. package/dist/worklets/capture-processor.js +2 -2
  83. package/dist/worklets/playback-processor.d.ts +3 -3
  84. package/dist/worklets/playback-processor.js +2 -2
  85. package/package.json +2 -2
  86. package/dist/default-client/assets/index-BOTLwsNO.js +0 -126
@@ -1,4 +1,4 @@
1
- import{r as e}from"./index-BOTLwsNO.js";import{t}from"./_module-url-BX0RuRU2.js";var n=`
1
+ import{r as e}from"./index-BlUYCTB5.js";import{t}from"./_module-url-BX0RuRU2.js";var n=`
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:#fafafa;margin:0}</style>
9
- <script type="module" crossorigin src="./assets/index-BOTLwsNO.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-BlUYCTB5.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-_-x5JLLa.css">
11
11
  </head>
12
12
  <body>
@@ -27,6 +27,7 @@ import type { ClientTheme, VoiceSessionOptions } from "./types.ts";
27
27
  * `component`, which invited the identical failure for a combination
28
28
  * {@link mountClient} can simply render.
29
29
  *
30
+ * @input
30
31
  * @public
31
32
  */
32
33
  export type ClientConfig = Pick<VoiceSessionOptions, "onSessionId" | "resumeSessionId" | "location" | "phone" | "client" | "token" | "WebSocket"> & {
@@ -94,6 +95,7 @@ export type ClientConfig = Pick<VoiceSessionOptions, "onSessionId" | "resumeSess
94
95
  *
95
96
  * Implements `Disposable` so it can be used with `using`.
96
97
  *
98
+ * @sealed
97
99
  * @public
98
100
  */
99
101
  export type ClientHandle = {
@@ -1,7 +1,7 @@
1
- import { t as ChatView } from "./chat-view-DIwPoAEG.js";
1
+ import { t as ChatView } from "./chat-view-W6KcdjJY.js";
2
2
  import { n as pageBaseUrl, r as setPageTitle } from "./_utils-Mi-SCFA1.js";
3
- import { n as fetchClientConfig } from "./client-config-C7fQrioM.js";
4
- import { t as createBrowserSession } from "./session-CYdjRvbl.js";
3
+ import { n as fetchClientConfig } from "./client-config-CzvWmw4X.js";
4
+ import { t as createBrowserSession } from "./session-3lgPYNNO.js";
5
5
  import { SessionProvider, ThemeProvider } from "./context.js";
6
6
  import { t as ToolConfigContext } from "./tool-config-context-Es4YUzV2.js";
7
7
  import { SidebarLayout } from "./components/sidebar-layout.js";
@@ -105,7 +105,7 @@ function DefaultRoot({ platformUrl, ...display }) {
105
105
  useEffect(() => {
106
106
  if (!needsLookup) return;
107
107
  let cancelled = false;
108
- fetchClientConfig(platformUrl).then((cfg) => {
108
+ fetchClientConfig({ platformUrl }).then((cfg) => {
109
109
  if (!cancelled) setResolved(cfg);
110
110
  });
111
111
  return () => {
@@ -37,6 +37,7 @@ import { type InboxClientFrame, type InboxServerFrame } from "@alexkroman1/aai/p
37
37
  * One notice from the agent — what a workflow step sent with
38
38
  * `stepNotifyClient`, e.g. a reminder coming due.
39
39
  *
40
+ * @sealed
40
41
  * @public
41
42
  */
42
43
  export type InboxNotice = {
@@ -57,6 +58,11 @@ export type InboxNotice = {
57
58
  * for events: every session bound to the client, this tab's own included —
58
59
  * filter on `sessionId` (`useSessionId()`) to show only the OTHER ones.
59
60
  *
61
+ * `"other"` is a frame this version does not know (`frameType` is the wire
62
+ * `type` it arrived with) — a member from the start so that a frame the server
63
+ * adds later reaches an existing `switch`'s `default`, not a compile error.
64
+ * Ignore it.
65
+ *
60
66
  * @public
61
67
  */
62
68
  export type InboxEvent = {
@@ -69,6 +75,9 @@ export type InboxEvent = {
69
75
  } | {
70
76
  readonly type: "session_ended";
71
77
  readonly sessionId: string;
78
+ } | {
79
+ readonly type: "other";
80
+ readonly frameType: string;
72
81
  };
73
82
  /**
74
83
  * The largest notice taken: 60 s of 16 kHz PCM16, the firmware's
@@ -103,10 +112,11 @@ export type AssemblerOutput = {
103
112
  */
104
113
  export declare function parseNoticeHeader(json: string): NoticeHeader | undefined;
105
114
  /**
106
- * A live-event frame, or undefined for anything else (a notice header, say).
107
- * The wire's live frames are returned as the published {@link InboxEvent}, so
108
- * that view cannot drift from what the server sends without this failing to
109
- * compile.
115
+ * A live-event frame, or undefined for a notice header or a frame that is not
116
+ * one at all. The wire's live frames are returned as the published
117
+ * {@link InboxEvent}, so that view cannot drift from what the server sends
118
+ * without this failing to compile; a well-formed frame of a type this version
119
+ * does not know is `{ type: "other" }`.
110
120
  */
111
121
  export declare function parseInboxEvent(json: string): InboxEvent | undefined;
112
122
  /**
package/dist/inbox.d.ts CHANGED
@@ -44,6 +44,7 @@ export declare const INBOX_RECONNECT_MAX_MS = 30000;
44
44
  /**
45
45
  * Options for {@link createInbox}.
46
46
  *
47
+ * @input
47
48
  * @public
48
49
  */
49
50
  export type CreateInboxOptions = {
package/dist/index.d.ts CHANGED
@@ -63,7 +63,7 @@
63
63
  */
64
64
  export { type ClientRun, type ClientRunStatus, type ClientRunsResponse, errorMessage, } from "@alexkroman1/aai";
65
65
  export { AGENT_STATE_LABELS } from "./agent-state-labels.ts";
66
- export { type ClientConfigResponse, fetchClientConfig, } from "./client-config.ts";
66
+ export { type ClientConfigResponse, type FetchClientConfigOptions, fetchClientConfig, } from "./client-config.ts";
67
67
  export { browserClientId, type SessionIdentity } from "./client-identity.ts";
68
68
  export { useClientTool } from "./client-tool.ts";
69
69
  export { AudioResult, type AudioResultCaptions, type AudioResultProps, } from "./components/audio-result.tsx";
@@ -75,7 +75,7 @@ export { ConsoleShell, type ConsoleShellProps } from "./components/console-shell
75
75
  export { Controls, type ControlsProps } from "./components/controls.tsx";
76
76
  export { ConversationView, type ConversationViewProps, } from "./components/conversation-view.tsx";
77
77
  export { Facts, type FactsProps } from "./components/facts.tsx";
78
- export { CheckboxField, Field, type FieldShell, FileField, type FileReadMode, type FileValue, Form, type FormProps, type FormValues, NumberField, SelectField, SubmitButton, TextAreaField, TextField, } from "./components/form.tsx";
78
+ export { CheckboxField, Field, type FieldShell, FileField, type FileReadMode, type FileValue, Form, type FormProps, type FormValues, isFileValue, NumberField, SelectField, SubmitButton, TextAreaField, TextField, } from "./components/form.tsx";
79
79
  export { Markdown, type MarkdownProps, type MarkdownVariant } from "./components/markdown.tsx";
80
80
  export { MessageList, type MessageListProps } from "./components/message-list.tsx";
81
81
  export { type SessionControlAction, type SessionControlButton, SessionControls, type SessionControlsLabels, type SessionControlsProps, } from "./components/session-controls.tsx";
@@ -106,7 +106,7 @@ export { type RouteFetchOptions, type RouteMethod, routeFetch } from "./route-fe
106
106
  export type { AgentCustomEvent, AgentStateFrame, BrowserSession, browserSessionBrand, SendTextOptions, SessionSnapshot, ToolCallOutcome, UserTurnControls, } from "./session/index.ts";
107
107
  export { createBrowserSession } from "./session/index.ts";
108
108
  export { createStoredValue, type StoredValue, type StoredValueOptions, useStoredValue, } from "./stored-value.ts";
109
- export type { AgentState, ChatMessage, ClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
109
+ export type { AgentState, ChatMessage, ClientTheme, ResolvedClientTheme, SessionError, SessionErrorCode, ToolCallInfo, VoiceSessionOptions, WebSocketConstructor, } from "./types.ts";
110
110
  export { type UseClientRunsOptions, type UseClientRunsResult, useClientRuns, } from "./use-client-runs.ts";
111
111
  export { type ConversationItem, type UseConversationResult, useConversation, } from "./use-conversation.ts";
112
112
  export { type UseConversationLogOptions, type UseConversationLogResult, useConversationLog, } from "./use-conversation-log.ts";
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { a as AGENT_STATE_LABELS, i as SessionErrorBanner, n as ConsoleShell, r as SessionStateDot, t as ChatView } from "./chat-view-DIwPoAEG.js";
1
+ import { a as AGENT_STATE_LABELS, i as SessionErrorBanner, n as ConsoleShell, r as SessionStateDot, t as ChatView } from "./chat-view-W6KcdjJY.js";
2
2
  import { n as pageBaseUrl, r as setPageTitle, t as isTypingTarget } from "./_utils-Mi-SCFA1.js";
3
- import { n as fetchClientConfig, t as buildAgentUrl } from "./client-config-C7fQrioM.js";
4
- import { a as ticketCarriage, c as resolveReported, d as storageSet, f as urlSlot, i as resolveSessionTokenSync, l as storageGet, r as resolveSessionToken, s as browserClientId, t as createBrowserSession, u as storageRemove } from "./session-CYdjRvbl.js";
3
+ import { n as fetchClientConfig, t as buildAgentUrl } from "./client-config-CzvWmw4X.js";
4
+ import { a as ticketCarriage, c as resolveReported, d as storageSet, f as urlSlot, i as resolveSessionTokenSync, l as storageGet, r as resolveSessionToken, s as browserClientId, t as createBrowserSession, u as storageRemove } from "./session-3lgPYNNO.js";
5
5
  import { ThemeProvider, useOptionalSessionCore, useSession, useSessionActions, useSessionCore, useSessionError, useSessionSelector, useSessionStatus, useTheme } from "./context.js";
6
6
  import { a as useAgentState, i as selectAgentState, n as useToolCallStart, r as useToolResult, t as useEvent } from "./hooks-DN4gHYsj.js";
7
- import { a as useConversation, i as interleave, n as Markdown, o as AutoScroll, r as ConversationView, t as MessageList } from "./message-list-DHZcLhRA.js";
7
+ import { a as useConversation, i as interleave, n as Markdown, o as AutoScroll, r as ConversationView, t as MessageList } from "./message-list-BsaBkBgo.js";
8
8
  import { a as inkTint, i as focusRingStyle, n as FOCUS_RING } from "./_colors-CpZO-88A.js";
9
9
  import { Button } from "./components/button.js";
10
10
  import { a as useFlash, i as useCopy } from "./url-chips-oyy_Eiqh.js";
@@ -797,6 +797,27 @@ function FileField({ name, label, hint, className, read = "none", upload = false
797
797
  });
798
798
  }
799
799
  //#endregion
800
+ //#region src/components/form-types.ts
801
+ /**
802
+ * What a form's controls CONTRIBUTE — the types both halves of the form code
803
+ * share, and {@link isFileValue}, the guard that reads one back.
804
+ *
805
+ * Their own module because `form.tsx` (the components) and `_form-values.ts`
806
+ * (the DOM read) both need them, and a type living in one of those would make
807
+ * the pair import each other.
808
+ */
809
+ /**
810
+ * Whether one {@link FormValues} entry is what a {@link FileField} contributed.
811
+ *
812
+ * A field with nothing chosen contributes no key at all, so the absent case is
813
+ * the ordinary one — this is `false` for `undefined`, not an error.
814
+ *
815
+ * @public
816
+ */
817
+ function isFileValue(value) {
818
+ return isRecord(value) && typeof value.name === "string" && typeof value.size === "number" && typeof value.type === "string" && typeof value.lastModified === "number" && (value.content === void 0 || typeof value.content === "string");
819
+ }
820
+ //#endregion
800
821
  //#region src/components/form.tsx
801
822
  /** @jsxImportSource react */
802
823
  /**
@@ -1019,7 +1040,7 @@ const DEFAULT_VARIANT = {
1019
1040
  };
1020
1041
  function defaultButton({ action, label, onClick }) {
1021
1042
  return /* @__PURE__ */ jsx(Button, {
1022
- variant: DEFAULT_VARIANT[action],
1043
+ variant: DEFAULT_VARIANT[action] ?? "secondary",
1023
1044
  onClick,
1024
1045
  children: label
1025
1046
  });
@@ -1339,9 +1360,10 @@ function useWorkflows(options = {}) {
1339
1360
  * studio's SDK-subpath list: mirroring "would just move the drift somewhere
1340
1361
  * new".
1341
1362
  *
1342
- * So a NEW control added to `<WorkflowFields>` is a new member of
1343
- * {@link WorkflowFieldKind}, and every reader of the rule finds out from the
1344
- * type rather than from a table somebody remembered to edit.
1363
+ * So a NEW control added to `<WorkflowFields>` is a new value of
1364
+ * {@link WorkflowFieldKind}. The set is open, so that addition is not a break:
1365
+ * a reader's `switch` keeps a `default` and treats a kind it does not know the
1366
+ * way it treats `"none"`.
1345
1367
  */
1346
1368
  /**
1347
1369
  * A property's declared type, taking the first non-null member of a union.
@@ -1835,7 +1857,7 @@ function WorkflowRunPanel({ run, statusLabels, onClear, api, live, children, cla
1835
1857
  */
1836
1858
  /** The item as the log keeps it: a tool call's `result` dropped. */
1837
1859
  function logItem(item) {
1838
- if (item.kind === "message" || item.toolCall.result === void 0) return item;
1860
+ if (item.kind !== "tool" || item.toolCall.result === void 0) return item;
1839
1861
  const { result: _result, ...toolCall } = item.toolCall;
1840
1862
  return {
1841
1863
  kind: "tool",
@@ -1845,7 +1867,11 @@ function logItem(item) {
1845
1867
  /** One item's identity as a turn — ignoring ids and a tool call going pending → done. */
1846
1868
  function turnKey(item) {
1847
1869
  if (!item) return "";
1848
- return item.kind === "message" ? `m${item.message.role}:${item.message.content}` : `t${item.toolCall.name}:${JSON.stringify(item.toolCall.args)}`;
1870
+ switch (item.kind) {
1871
+ case "message": return `m${item.message.role}:${item.message.content}`;
1872
+ case "tool": return `t${item.toolCall.name}:${JSON.stringify(item.toolCall.args)}`;
1873
+ default: return `o${item.type}`;
1874
+ }
1849
1875
  }
1850
1876
  /** The same turn in the same state — what makes a rewrite a no-op. */
1851
1877
  function sameItem(a, b) {
@@ -1976,11 +2002,15 @@ function parseItem(raw) {
1976
2002
  if (!isRecord(raw)) return void 0;
1977
2003
  if (raw.kind === "message" && isRecord(raw.message)) return parseMessage(raw.message);
1978
2004
  if (raw.kind === "tool" && isRecord(raw.toolCall)) return parseToolCall(raw.toolCall);
2005
+ if (typeof raw.kind === "string" && raw.kind !== "message" && raw.kind !== "tool") return {
2006
+ kind: "other",
2007
+ type: raw.kind === "other" && typeof raw.type === "string" ? raw.type : raw.kind
2008
+ };
1979
2009
  }
1980
2010
  function parseMessage(raw) {
1981
2011
  const { id, role, content } = raw;
1982
2012
  if (typeof id !== "number" || typeof content !== "string") return void 0;
1983
- return role === "user" || role === "assistant" ? message(id, role, content) : void 0;
2013
+ return typeof role === "string" && role !== "" ? message(id, role, content) : void 0;
1984
2014
  }
1985
2015
  function parseToolCall(raw) {
1986
2016
  const { callId, name, args, status, seq, afterMessageId } = raw;
@@ -2055,15 +2085,27 @@ function parseNoticeHeader(json) {
2055
2085
  bytes
2056
2086
  };
2057
2087
  }
2088
+ /** The wire frame types this version knows; anything else is an `"other"` event. */
2089
+ const KNOWN_FRAME_TYPES = /* @__PURE__ */ new Set([
2090
+ "notice",
2091
+ "session_event",
2092
+ "session_ended"
2093
+ ]);
2058
2094
  /**
2059
- * A live-event frame, or undefined for anything else (a notice header, say).
2060
- * The wire's live frames are returned as the published {@link InboxEvent}, so
2061
- * that view cannot drift from what the server sends without this failing to
2062
- * compile.
2095
+ * A live-event frame, or undefined for a notice header or a frame that is not
2096
+ * one at all. The wire's live frames are returned as the published
2097
+ * {@link InboxEvent}, so that view cannot drift from what the server sends
2098
+ * without this failing to compile; a well-formed frame of a type this version
2099
+ * does not know is `{ type: "other" }`.
2063
2100
  */
2064
2101
  function parseInboxEvent(json) {
2065
- const frame = parseServerFrame(json);
2066
- return frame === void 0 || frame.type === "notice" ? void 0 : frame;
2102
+ const raw = safeJsonParse$1(json);
2103
+ if (isRecord(raw) && typeof raw.type === "string" && !KNOWN_FRAME_TYPES.has(raw.type)) return {
2104
+ type: "other",
2105
+ frameType: raw.type
2106
+ };
2107
+ const parsed = InboxServerFrameSchema.safeParse(raw);
2108
+ return !parsed.success || parsed.data.type === "notice" ? void 0 : parsed.data;
2067
2109
  }
2068
2110
  /**
2069
2111
  * The receiving state machine of one socket — see the module doc for its four
@@ -4405,7 +4447,7 @@ function useConversationLog(options = {}) {
4405
4447
  own.current = sessionId;
4406
4448
  const mirrored = useRef(/* @__PURE__ */ new Map());
4407
4449
  const mirror = useCallback((event) => {
4408
- if (event.sessionId === own.current) return;
4450
+ if (event.type === "other" || event.sessionId === own.current) return;
4409
4451
  if (event.type === "session_ended") {
4410
4452
  mirrored.current.delete(event.sessionId);
4411
4453
  return;
@@ -5661,4 +5703,4 @@ function fileAt(input, field) {
5661
5703
  return filesOf(input[field])[0];
5662
5704
  }
5663
5705
  //#endregion
5664
- export { AGENT_STATE_LABELS, AudioResult, AutoScroll, BulletList, Button, ChatView, CheckboxField, ConsoleShell, Controls, ConversationView, Facts, Field, FileField, Form, Markdown, MessageList, NumberField, SelectField, SessionControls, SessionErrorBanner, SessionStateDot, SidebarLayout, StartScreen, SubmitButton, TextAreaField, TextField, ToolCallRow, UploadProgressBar, WORKFLOW_STATUS_LABELS, WorkflowFields, WorkflowPendingNote, WorkflowProgress, WorkflowRunError, WorkflowRunPanel, browserClientId, createBrowserSession, createInbox, createLinkedClient, createStoredValue, createWorkflowApi, errorMessage, fetchClientConfig, fieldKindFor, inboxEventToItem, isTerminal, mountClient, mountPage, phoneE164, routeFetch, selectAgentState, useAgentState, useClientId, useClientRuns, useClientTool, useConversation, useConversationLog, useCopy, useDownloadUrl, useEvent, useFlash, useInbox, usePushToTalk, useRoute, useRouteMutation, useRunKey, useSession, useSessionActions, useSessionControls, useSessionError, useSessionId, useSessionSelector, useSessionStatus, useStoredValue, useTapToTalk, useTheme, useToolCallStart, useToolResult, useUserTranscript, useWorkflowProgress, useWorkflowRun, useWorkflowRuns, useWorkflowStream, useWorkflowSubmit, useWorkflows };
5706
+ export { AGENT_STATE_LABELS, AudioResult, AutoScroll, BulletList, Button, ChatView, CheckboxField, ConsoleShell, Controls, ConversationView, Facts, Field, FileField, Form, Markdown, MessageList, NumberField, SelectField, SessionControls, SessionErrorBanner, SessionStateDot, SidebarLayout, StartScreen, SubmitButton, TextAreaField, TextField, ToolCallRow, UploadProgressBar, WORKFLOW_STATUS_LABELS, WorkflowFields, WorkflowPendingNote, WorkflowProgress, WorkflowRunError, WorkflowRunPanel, browserClientId, createBrowserSession, createInbox, createLinkedClient, createStoredValue, createWorkflowApi, errorMessage, fetchClientConfig, fieldKindFor, inboxEventToItem, isFileValue, isTerminal, mountClient, mountPage, phoneE164, routeFetch, selectAgentState, useAgentState, useClientId, useClientRuns, useClientTool, useConversation, useConversationLog, useCopy, useDownloadUrl, useEvent, useFlash, useInbox, usePushToTalk, useRoute, useRouteMutation, useRunKey, useSession, useSessionActions, useSessionControls, useSessionError, useSessionId, useSessionSelector, useSessionStatus, useStoredValue, useTapToTalk, useTheme, useToolCallStart, useToolResult, useUserTranscript, useWorkflowProgress, useWorkflowRun, useWorkflowRuns, useWorkflowStream, useWorkflowSubmit, useWorkflows };
package/dist/internal.js CHANGED
@@ -1,4 +1,4 @@
1
- import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-C7fQrioM.js";
1
+ import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-CzvWmw4X.js";
2
2
  import { SessionProvider, ThemeProvider } from "./context.js";
3
3
  import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-oyy_Eiqh.js";
4
4
  import { t as TRANSCRIBING_PLACEHOLDER } from "./use-user-transcript-uyHhzy4d.js";
@@ -17,6 +17,7 @@
17
17
  /**
18
18
  * Options for {@link createLinkedClient}.
19
19
  *
20
+ * @input
20
21
  * @public
21
22
  */
22
23
  export type LinkedClientOptions = {
@@ -31,6 +32,7 @@ export type LinkedClientOptions = {
31
32
  /**
32
33
  * Which client a page is — see {@link createLinkedClient}.
33
34
  *
35
+ * @sealed
34
36
  * @public
35
37
  */
36
38
  export type LinkedClient = {
@@ -152,15 +152,20 @@ function isThinking(state, messages, toolCalls) {
152
152
  * const { items, streaming, transcript, thinking } = useConversation();
153
153
  * return (
154
154
  * <div>
155
- * {items.map((item) =>
156
- * item.kind === "message" ? (
157
- * <p key={item.message.id} data-role={item.message.role}>
158
- * {item.message.content}
159
- * </p>
160
- * ) : (
161
- * <code key={item.toolCall.callId}>{item.toolCall.name}</code>
162
- * ),
163
- * )}
155
+ * {items.map((item) => {
156
+ * switch (item.kind) {
157
+ * case "message":
158
+ * return (
159
+ * <p key={item.message.id} data-role={item.message.role}>
160
+ * {item.message.content}
161
+ * </p>
162
+ * );
163
+ * case "tool":
164
+ * return <code key={item.toolCall.callId}>{item.toolCall.name}</code>;
165
+ * default:
166
+ * return null;
167
+ * }
168
+ * })}
164
169
  * {streaming !== null && <p data-role="assistant">{streaming}</p>}
165
170
  * {transcript.speaking && <p data-role="user">{transcript.text}</p>}
166
171
  * {thinking && <p>…</p>}
@@ -280,7 +285,13 @@ function ConversationView({ renderMessage, renderTool = defaultTool, renderStrea
280
285
  const { items, streaming, transcript, thinking } = useConversation();
281
286
  const liveItems = log ? void 0 : items;
282
287
  const rows = useMemo(() => {
283
- const renderItem = (item, key) => item.kind === "message" ? renderKeyed(`${key}m${item.message.id}`, renderMessage(item.message)) : renderKeyed(`${key}t${item.toolCall.callId}`, renderTool(item.toolCall));
288
+ const renderItem = (item, key) => {
289
+ switch (item.kind) {
290
+ case "message": return renderKeyed(`${key}m${item.message.id}`, renderMessage(item.message));
291
+ case "tool": return renderKeyed(`${key}t${item.toolCall.callId}`, renderTool(item.toolCall));
292
+ default: return null;
293
+ }
294
+ };
284
295
  if (!log) return (liveItems ?? []).map((item) => renderItem(item, ""));
285
296
  return logRows(log, renderItem, renderMessage, renderNote, renderSessionHeader);
286
297
  }, [
package/dist/page.d.ts CHANGED
@@ -27,6 +27,7 @@ import type { ClientTheme } from "./types.ts";
27
27
  /**
28
28
  * Configuration for {@link mountPage}.
29
29
  *
30
+ * @input
30
31
  * @public
31
32
  */
32
33
  export type PageConfig = {
@@ -55,6 +56,7 @@ export type PageConfig = {
55
56
  /**
56
57
  * Handle returned by {@link mountPage}. `Disposable`, so `using` works.
57
58
  *
59
+ * @sealed
58
60
  * @public
59
61
  */
60
62
  export type PageHandle = {
package/dist/phone.d.ts CHANGED
@@ -12,6 +12,7 @@
12
12
  /**
13
13
  * Options for {@link phoneE164}.
14
14
  *
15
+ * @input
15
16
  * @public
16
17
  */
17
18
  export type PhoneE164Options = {
@@ -29,6 +29,7 @@ export type RouteMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
29
29
  /**
30
30
  * Options for {@link routeFetch}.
31
31
  *
32
+ * @input
32
33
  * @public
33
34
  */
34
35
  export type RouteFetchOptions = {
@@ -53,5 +53,5 @@ export type AudioPathCallbacks = {
53
53
  * up for a connection nobody wants any more is a live microphone, and no
54
54
  * amount of cancellation upstream releases the device.
55
55
  */
56
- export declare function openAudioPath(config: AudioPathConfig, callbacks: AudioPathCallbacks, preConnect?: Promise<PreConnectCapture | null> | null): Promise<VoiceIO>;
56
+ export declare function openAudioPath(config: AudioPathConfig, callbacks: AudioPathCallbacks, preConnect?: Promise<PreConnectCapture | null> | null, signal?: AbortSignal): Promise<VoiceIO>;
57
57
  export {};
@@ -32,14 +32,14 @@
32
32
  * anywhere; as context of `down`/`starting` they are cleared by entering
33
33
  * `down` rather than by three call sites remembering to.
34
34
  *
35
- * ## What cancellation does NOT do, and the one guard that had to survive
35
+ * ## Cancellation follows the microphone's ownership
36
36
  *
37
37
  * Stopping the `bringUp` actor hides its resolution; it does not close a
38
38
  * microphone the browser has already granted. So `bringUp` checks its own
39
- * `signal` after `openAudioPath` settles and releases what it built. That is
40
- * the single remaining "is this still wanted?" test, and it lives in the
41
- * producer — which owns the value nobody adopted — rather than at the four
42
- * consumer sites that used to re-ask.
39
+ * `signal` after `openAudioPath` settles and releases what it built. The same
40
+ * signal reaches the opening path and the transferred pre-connect capture,
41
+ * so cancellation before the lazy modules load prevents a permission request
42
+ * in the first place. Both checks live with the producer that owns the device.
43
43
  *
44
44
  * ## Effects stay in the session core
45
45
  *
@@ -63,7 +63,7 @@ export type AudioPathEffects = {
63
63
  * hand it a promise they resolve by hand, which is the only way to hold a
64
64
  * bring-up open across the events that abandon it.
65
65
  */
66
- open(config: AudioPathConfig, callbacks: AudioPathCallbacks): Promise<VoiceIO>;
66
+ open(config: AudioPathConfig, callbacks: AudioPathCallbacks, signal: AbortSignal): Promise<VoiceIO>;
67
67
  /** Relay captured microphone audio to the server. */
68
68
  sendMicAudio(pcm16: ArrayBuffer): void;
69
69
  /**
@@ -1,2 +1,2 @@
1
- import { a as ticketCarriage, i as resolveSessionTokenSync, n as CLEARED_SESSION_STATE, o as loadAudioModules, r as resolveSessionToken, t as createBrowserSession } from "../session-CYdjRvbl.js";
1
+ import { a as ticketCarriage, i as resolveSessionTokenSync, n as CLEARED_SESSION_STATE, o as loadAudioModules, r as resolveSessionToken, t as createBrowserSession } from "../session-3lgPYNNO.js";
2
2
  export { CLEARED_SESSION_STATE, createBrowserSession, loadAudioModules, resolveSessionToken, resolveSessionTokenSync, ticketCarriage };
@@ -7,15 +7,7 @@ import { type ConnState, type SessionSnapshot } from "./types.ts";
7
7
  * The empty arrays are safe to share: snapshot collections are never mutated
8
8
  * in place, only replaced.
9
9
  */
10
- export declare const CLEARED_SESSION_STATE: {
11
- messages: never[];
12
- toolCalls: never[];
13
- customEvents: never[];
14
- agentState: null;
15
- userTranscript: null;
16
- agentTranscript: null;
17
- error: null;
18
- };
10
+ export declare const CLEARED_SESSION_STATE: Readonly<Pick<SessionSnapshot, "messages" | "toolCalls" | "customEvents" | "agentState" | "userTranscript" | "agentTranscript" | "error">>;
19
11
  /** Config payload extracted from a `config` server message. */
20
12
  export type SessionConfigMessage = {
21
13
  sampleRate: number;
@@ -40,7 +40,7 @@ export type PreConnectAudio = {
40
40
  */
41
41
  begin(): void;
42
42
  /** Hand the held capture to a bring-up, or `null` when none is held. */
43
- take(): Promise<PreConnectCapture | null> | null;
43
+ take(signal?: AbortSignal): Promise<PreConnectCapture | null> | null;
44
44
  /** Release a held capture: the session is over or starting afresh. */
45
45
  release(): void;
46
46
  };
@@ -15,6 +15,7 @@ import type { AudioPath } from "./audio-state.ts";
15
15
  * Deliberately NOT the DOM `CustomEvent`: it shares nothing with that
16
16
  * interface, and the old name shadowed the global in `.tsx` files.
17
17
  *
18
+ * @sealed
18
19
  * @public
19
20
  */
20
21
  export type AgentCustomEvent = {
@@ -47,6 +48,7 @@ export type AgentStateFrame = Readonly<Record<string, unknown>>;
47
48
  * | `recording` | Is the microphone actually live right now? |
48
49
  * | `state` | What is the agent doing — see {@link AgentState}. |
49
50
  *
51
+ * @sealed
50
52
  * @public
51
53
  */
52
54
  export type SessionSnapshot = {
@@ -179,6 +181,7 @@ export declare const browserSessionBrand: unique symbol;
179
181
  * the session, so a feature one agent in many declares is not three members
180
182
  * every session carries in its autocomplete.
181
183
  *
184
+ * @sealed
182
185
  * @public
183
186
  */
184
187
  export type UserTurnControls = {
@@ -209,6 +212,7 @@ export type ToolCallOutcome = {
209
212
  /**
210
213
  * Options for {@link BrowserSession.sendText}.
211
214
  *
215
+ * @input
212
216
  * @public
213
217
  */
214
218
  export type SendTextOptions = {
@@ -1,8 +1,8 @@
1
1
  import { n as pageBaseUrl } from "./_utils-Mi-SCFA1.js";
2
- import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-C7fQrioM.js";
2
+ import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-CzvWmw4X.js";
3
3
  import { MIC_SEND_MAX_BUFFERED_BYTES } from "./types.js";
4
- import { SessionEventSchema, errorMessage, safeJsonParse } from "@alexkroman1/aai";
5
- import { SESSION_AUTH_PROTOCOL_PREFIX, SESSION_PROTOCOL, lenientParse } from "@alexkroman1/aai/protocol";
4
+ import { errorMessage, safeJsonParse } from "@alexkroman1/aai";
5
+ import { SESSION_AUTH_PROTOCOL_PREFIX, SESSION_PROTOCOL, SessionEventSchema, lenientParse } from "@alexkroman1/aai/protocol";
6
6
  import { CLIENT_ID_RE, MAX_CLIENT_MESSAGES, RESUME_ID_RE, WS_OPEN, createEpoch, toArgsRecord } from "@alexkroman1/aai/internal";
7
7
  import { omitUndefined } from "@alexkroman1/aai/utils";
8
8
  import { and, assign, createActor, fromPromise, not, setup, stateIn } from "xstate";
@@ -213,17 +213,19 @@ function loadAudioModules() {
213
213
  * up for a connection nobody wants any more is a live microphone, and no
214
214
  * amount of cancellation upstream releases the device.
215
215
  */
216
- async function openAudioPath(config, callbacks, preConnect) {
216
+ async function openAudioPath(config, callbacks, preConnect, signal) {
217
217
  const pre = await preConnect ?? void 0;
218
218
  try {
219
- return await openVoiceIO(config, callbacks, pre);
219
+ signal?.throwIfAborted();
220
+ return await openVoiceIO(config, callbacks, pre, signal);
220
221
  } catch (err) {
221
222
  pre?.close();
222
223
  throw err;
223
224
  }
224
225
  }
225
- async function openVoiceIO(config, callbacks, pre) {
226
+ async function openVoiceIO(config, callbacks, pre, signal) {
226
227
  const [{ createVoiceIO }, captureWorklet, playbackWorklet] = await loadAudioModules();
228
+ signal?.throwIfAborted();
227
229
  return createVoiceIO({
228
230
  preConnect: pre,
229
231
  onPreConnectAudio: callbacks.onPreConnectAudio,
@@ -297,7 +299,7 @@ function createAudioEffects(deps) {
297
299
  });
298
300
  }
299
301
  return {
300
- open: (config, callbacks) => (deps.openAudioPath ?? openAudioPath)(config, callbacks, preConnect.take()),
302
+ open: (config, callbacks, signal) => (deps.openAudioPath ?? openAudioPath)(config, callbacks, preConnect.take(signal), signal),
301
303
  sendMicAudio: (pcm16) => {
302
304
  try {
303
305
  mic.sendAudio(pcm16);
@@ -379,14 +381,14 @@ function createAudioEffects(deps) {
379
381
  * anywhere; as context of `down`/`starting` they are cleared by entering
380
382
  * `down` rather than by three call sites remembering to.
381
383
  *
382
- * ## What cancellation does NOT do, and the one guard that had to survive
384
+ * ## Cancellation follows the microphone's ownership
383
385
  *
384
386
  * Stopping the `bringUp` actor hides its resolution; it does not close a
385
387
  * microphone the browser has already granted. So `bringUp` checks its own
386
- * `signal` after `openAudioPath` settles and releases what it built. That is
387
- * the single remaining "is this still wanted?" test, and it lives in the
388
- * producer — which owns the value nobody adopted — rather than at the four
389
- * consumer sites that used to re-ask.
388
+ * `signal` after `openAudioPath` settles and releases what it built. The same
389
+ * signal reaches the opening path and the transferred pre-connect capture,
390
+ * so cancellation before the lazy modules load prevents a permission request
391
+ * in the first place. Both checks live with the producer that owns the device.
390
392
  *
391
393
  * ## Effects stay in the session core
392
394
  *
@@ -438,7 +440,7 @@ bringUp: fromPromise(async ({ input, signal }) => {
438
440
  message
439
441
  });
440
442
  }
441
- });
443
+ }, signal);
442
444
  if (signal.aborted) {
443
445
  input.effects.release(io);
444
446
  throw ABANDONED;
@@ -1651,10 +1653,19 @@ function createPreConnectAudio(enabled) {
1651
1653
  maxSeconds: 10
1652
1654
  })).catch(() => null);
1653
1655
  },
1654
- take() {
1656
+ take(signal) {
1655
1657
  const taken = held;
1658
+ const current = attempt;
1656
1659
  held = null;
1657
1660
  attempt = null;
1661
+ if (taken && current && signal) {
1662
+ const release = () => {
1663
+ current.released = true;
1664
+ };
1665
+ if (signal.aborted) release();
1666
+ else signal.addEventListener("abort", release, { once: true });
1667
+ return taken.finally(() => signal.removeEventListener("abort", release));
1668
+ }
1658
1669
  return taken;
1659
1670
  },
1660
1671
  release() {
@@ -19,6 +19,7 @@
19
19
  /**
20
20
  * Options for {@link createStoredValue}.
21
21
  *
22
+ * @input
22
23
  * @public
23
24
  */
24
25
  export type StoredValueOptions = {
@@ -30,6 +31,7 @@ export type StoredValueOptions = {
30
31
  /**
31
32
  * One remembered string — see {@link createStoredValue}.
32
33
  *
34
+ * @sealed
33
35
  * @public
34
36
  */
35
37
  export type StoredValue = {