@alexkroman1/aai-ui 5.0.0 → 5.1.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.
@@ -1,4 +1,4 @@
1
- import{i as e}from"./index-0-DXv-S4.js";import{t}from"./_module-url-BX0RuRU2.js";var n=t(`
1
+ import{i as e}from"./index-22Wylv4z.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-0-DXv-S4.js"></script>
9
+ <script type="module" crossorigin src="./assets/index-22Wylv4z.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="./assets/index-CRfdZPH1.css">
11
11
  </head>
12
12
  <body>
@@ -1,4 +1,4 @@
1
- import { r as fetchClientConfig, t as createSessionCore } from "./session-core-Bjkr4PAP.js";
1
+ import { r as fetchClientConfig, t as createSessionCore } from "./session-core-CwCaFzL8.js";
2
2
  import { SessionProvider, ThemeProvider } from "./context.js";
3
3
  import { t as ChatView } from "./chat-view-CW-tZCMm.js";
4
4
  import { n as ToolConfigContext } from "./tool-call-block-DIxpG8GM.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-Bjkr4PAP.js";
1
+ import { n as buildAgentUrl, r as fetchClientConfig, t as createSessionCore } from "./session-core-CwCaFzL8.js";
2
2
  import { SessionProvider, ThemeProvider, useSession, useSessionSelector, useTheme } from "./context.js";
3
3
  import { Button } from "./components/button.js";
4
4
  import { t as ChatView } from "./chat-view-CW-tZCMm.js";
@@ -8,28 +8,49 @@ import ReconnectingWebSocket from "partysocket/ws";
8
8
  *
9
9
  * `GET client-config` (relative to the agent's base URL — see
10
10
  * `sdk/client-config.ts` in `@alexkroman1/aai`) gives the default client the
11
- * agent's display name and greeting before any connection exists. Every
12
- * failure path — network error, 404 from an older server, malformed body —
13
- * degrades to the empty default, so this lookup can never break an existing
14
- * agent.
11
+ * agent's display name and greeting before any connection exists. For that
12
+ * use every failure path — network error, 404 from an older server,
13
+ * malformed body — degrades to the empty default (`fetchClientConfig`), so
14
+ * the lookup can never break an existing agent.
15
+ *
16
+ * The session's broker decision needs the opposite: `loadClientConfig`
17
+ * keeps "the lookup failed" (`null`) distinct from "the server answered and
18
+ * named no sessionUrl" (`{}`). See its doc comment.
15
19
  */
16
20
  /** Resolve a relative endpoint path against the agent's base URL. */
17
21
  function buildAgentUrl(platformUrl, endpointPath) {
18
22
  return new URL(endpointPath, platformUrl.endsWith("/") ? platformUrl : `${platformUrl}/`);
19
23
  }
20
24
  const AGENT_DEFAULT = {};
21
- /** Fetch the agent's client config; any failure yields the agent default. */
22
- async function fetchClientConfig(platformUrl, fetchFn) {
25
+ /**
26
+ * Fetch the agent's client config, reporting `null` when the lookup did not
27
+ * produce an answer (network error, non-2xx, unparsable body).
28
+ *
29
+ * The distinction from `fetchClientConfig` matters for exactly one caller:
30
+ * the session's per-attempt broker decision. A config that ARRIVED and named
31
+ * no `sessionUrl` means "this server is not a broker" (`aai dev`, an older
32
+ * server) — a durable fact worth latching. A lookup that FAILED means
33
+ * nothing about the server, and treating the two alike is how a single 503
34
+ * (a sandbox mid-boot, or one that failed to start) pinned a session to the
35
+ * platform's `/:slug/websocket` — a WebSocket redirect browsers don't
36
+ * follow, so every retry failed with no re-brokering even after the agent
37
+ * recovered.
38
+ */
39
+ async function loadClientConfig(platformUrl, fetchFn) {
23
40
  const doFetch = fetchFn ?? ((input, init) => globalThis.fetch(input, init));
24
41
  try {
25
42
  const resp = await doFetch(buildAgentUrl(platformUrl, CLIENT_CONFIG_PATH).href);
26
- if (!resp.ok) return AGENT_DEFAULT;
43
+ if (!resp.ok) return null;
27
44
  const parsed = ClientConfigResponseSchema.safeParse(await resp.json());
28
- return parsed.success ? parsed.data : AGENT_DEFAULT;
45
+ return parsed.success ? parsed.data : null;
29
46
  } catch {
30
- return AGENT_DEFAULT;
47
+ return null;
31
48
  }
32
49
  }
50
+ /** Fetch the agent's client config; any failure yields the agent default. */
51
+ async function fetchClientConfig(platformUrl, fetchFn) {
52
+ return await loadClientConfig(platformUrl, fetchFn) ?? AGENT_DEFAULT;
53
+ }
33
54
  //#endregion
34
55
  //#region session-core-audio-setup.ts
35
56
  /**
@@ -636,13 +657,9 @@ function createSessionCore(options) {
636
657
  * greeting-suppression fallback for a server whose config carried no id.
637
658
  */
638
659
  async function currentWsUrl() {
639
- const cfg = serverIsBroker === false ? {} : await fetchClientConfig(options.platformUrl);
640
- serverIsBroker = cfg.sessionUrl !== void 0;
641
- const url = cfg.sessionUrl ? buildBrokeredWsUrl(cfg.sessionUrl, hasConnected, sessionId) : buildWsUrl(options.platformUrl, hasConnected, sessionId);
642
- const display = new URL(url);
643
- display.search = "";
644
- if (display.toString() !== currentSnapshot.apiUrl) updateState({ apiUrl: display.toString() });
645
- return url.toString();
660
+ const cfg = serverIsBroker === false ? null : await loadClientConfig(options.platformUrl);
661
+ if (cfg) serverIsBroker = cfg.sessionUrl !== void 0;
662
+ return (cfg?.sessionUrl ? buildBrokeredWsUrl(cfg.sessionUrl, hasConnected, sessionId) : buildWsUrl(options.platformUrl, hasConnected, sessionId)).toString();
646
663
  }
647
664
  /** Open a socket: an injected constructor as-is (tests — connects to the
648
665
  * same-origin path, no brokering), or partysocket's reconnecting
@@ -29,9 +29,13 @@ export type SessionSnapshot = {
29
29
  /** True while the microphone is live and streaming to the server. */
30
30
  readonly recording: boolean;
31
31
  /**
32
- * The WebSocket URL a program can connect to directly (the same endpoint
33
- * this session uses), e.g. `wss://host/my-agent/websocket`. Derived from
34
- * `platformUrl` at construction — available before connecting.
32
+ * The WebSocket URL a program can connect to directly — the long-living
33
+ * platform endpoint, e.g. `wss://host/my-agent/websocket`. Derived from
34
+ * `platformUrl` at construction — available before connecting — and never
35
+ * replaced by the brokered sandbox tunnel URL the session may actually be
36
+ * connected to: that URL is ephemeral (it dies when the sandbox is
37
+ * replaced), while the platform endpoint is stable and upgrades
38
+ * programmatic clients to the current sandbox endpoint itself.
35
39
  */
36
40
  readonly apiUrl: string;
37
41
  /**
@@ -1,2 +1,2 @@
1
- import { t as createSessionCore } from "./session-core-Bjkr4PAP.js";
1
+ import { t as createSessionCore } from "./session-core-CwCaFzL8.js";
2
2
  export { createSessionCore };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexkroman1/aai-ui",
3
- "version": "5.0.0",
3
+ "version": "5.1.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.0.0"
25
+ "@alexkroman1/aai": "5.1.0"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react": "^19.0.0",