@guuey/agent-client 0.3.1 → 0.4.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/README.md CHANGED
@@ -34,7 +34,11 @@ import { createWebAdapters } from "@guuey/agent-client";
34
34
 
35
35
  export function Chat({ endpointUrl, appId }: { endpointUrl: string; appId: string }) {
36
36
  const adapters = createWebAdapters({ getAccessToken: async () => myToken });
37
- const { messages, send, isStreaming } = useAgentInvoke({ endpointUrl, appId, adapters });
37
+ const { messages, send, status, activeTool, error } = useAgentInvoke({
38
+ endpointUrl,
39
+ appId,
40
+ adapters,
41
+ });
38
42
 
39
43
  return (
40
44
  <>
@@ -43,7 +47,10 @@ export function Chat({ endpointUrl, appId }: { endpointUrl: string; appId: strin
43
47
  {m.text}
44
48
  </p>
45
49
  ))}
46
- <button disabled={isStreaming} onClick={() => send("hello")}>
50
+ {status === "connecting" && <p>Waking your agent…</p>}
51
+ {status === "using-tool" && <p>Using {activeTool}…</p>}
52
+ {error && <p role="alert">{error}</p>}
53
+ <button disabled={status !== "ready"} onClick={() => send("hello")}>
47
54
  Send
48
55
  </button>
49
56
  </>
@@ -51,6 +58,12 @@ export function Chat({ endpointUrl, appId }: { endpointUrl: string; appId: strin
51
58
  }
52
59
  ```
53
60
 
61
+ `status` walks the turn lifecycle — `ready` → `connecting` → `thinking` /
62
+ `using-tool` (with `activeTool` naming the tool) / `responding` → back to
63
+ `ready`. Failures never occupy `status`; they land in `error` and the
64
+ composer re-enables. The full vocabulary is documented at
65
+ [docs.guuey.com/sdk](https://docs.guuey.com/sdk).
66
+
54
67
  On React Native, supply your own adapters (AsyncStorage + an `expo/fetch`
55
68
  transport) in place of `createWebAdapters` — the hook's contract is identical.
56
69
 
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The pod's error-envelope wire codes, TRANSCRIBED.
3
+ *
4
+ * The source of truth is the runtime's own private module
5
+ * (`backend/services/nocode-runtime/src/error-codes.ts`). This package is
6
+ * published to npm and cannot take a `@guuey-private` dependency, so it keeps
7
+ * its own copy — the same arrangement as {@link GUEST_HEADER} in
8
+ * `./web-adapters.ts` and `@guuey/host`'s mirrored fs-contract constants. The
9
+ * copies are not trusted to prose alone: `agent-client-codes.sync.test.ts` in
10
+ * the runtime package (which can import BOTH) asserts they stay identical, so
11
+ * renaming a code on either side fails that test rather than silently breaking
12
+ * a client branch.
13
+ *
14
+ * WIRE CONTRACT (what these codes appear in):
15
+ *
16
+ * - a pre-stream refusal — `{ "code": …, "message": … }` with an HTTP status,
17
+ * parsed into {@link AgentResponseError};
18
+ * - an in-band failure — `event: error` / `data: { code, message }`, surfaced
19
+ * as `useAgentInvoke`'s `errorCode`.
20
+ *
21
+ * Both channels carry the SAME vocabulary, which is why one mirror serves them.
22
+ */
23
+ export declare const AGENT_ERROR_CODES: {
24
+ /** No usable identity on a surface that requires one. */
25
+ readonly UNAUTHORIZED: "UNAUTHORIZED";
26
+ /** The invoke body did not parse / validate. */
27
+ readonly INVALID_REQUEST: "INVALID_REQUEST";
28
+ /** The builder turned anonymous access off for this agent. */
29
+ readonly GUEST_ACCESS_DISABLED: "GUEST_ACCESS_DISABLED";
30
+ /** The caller (or the app) is out of plan allowance — the upgrade prompt. */
31
+ readonly QUOTA_EXCEEDED: "QUOTA_EXCEEDED";
32
+ /** The app hit its builder-set managed spend cap. */
33
+ readonly MANAGED_SPEND_CAP: "MANAGED_SPEND_CAP";
34
+ /**
35
+ * The pod is at its concurrent-turn cap (scaling S1-F3). A 503 carrying a
36
+ * `Retry-After` hint, and the ONE code {@link fetchStreamTransport} retries
37
+ * by itself — see its docblock for the single-attempt rule.
38
+ */
39
+ readonly POD_SATURATED: "POD_SATURATED";
40
+ /**
41
+ * The pod took SIGTERM and refuses NEW turns while in-flight ones finish.
42
+ * Also a 503 + `Retry-After`, but deliberately NOT auto-retried (the
43
+ * endpoint pull re-routes the next request; retrying into the same pod is
44
+ * the one thing guaranteed not to help).
45
+ */
46
+ readonly DRAINING: "DRAINING";
47
+ /** Refused for this caller — e.g. the link-prompt dismiss route's byo-only rule. */
48
+ readonly FORBIDDEN: "FORBIDDEN";
49
+ /** The turn ran past the pod's wall-clock budget. */
50
+ readonly TIMEOUT: "TIMEOUT";
51
+ /** A guuey-side dependency failed (not the agent's own code). */
52
+ readonly PLATFORM_ERROR: "PLATFORM_ERROR";
53
+ /** Unclassified pod failure. */
54
+ readonly INTERNAL: "INTERNAL";
55
+ };
56
+ /** One of the pod's wire codes — see {@link AGENT_ERROR_CODES}. */
57
+ export type AgentErrorCode = (typeof AGENT_ERROR_CODES)[keyof typeof AGENT_ERROR_CODES];
58
+ //# sourceMappingURL=error-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB;IAC5B,yDAAyD;;IAEzD,gDAAgD;;IAEhD,8DAA8D;;IAE9D,6EAA6E;;IAE7E,qDAAqD;;IAErD;;;;OAIG;;IAEH;;;;;OAKG;;IAEH,oFAAoF;;IAEpF,qDAAqD;;IAErD,iEAAiE;;IAEjE,gCAAgC;;CAExB,CAAC;AAEX,mEAAmE;AACnE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The pod's error-envelope wire codes, TRANSCRIBED.
3
+ *
4
+ * The source of truth is the runtime's own private module
5
+ * (`backend/services/nocode-runtime/src/error-codes.ts`). This package is
6
+ * published to npm and cannot take a `@guuey-private` dependency, so it keeps
7
+ * its own copy — the same arrangement as {@link GUEST_HEADER} in
8
+ * `./web-adapters.ts` and `@guuey/host`'s mirrored fs-contract constants. The
9
+ * copies are not trusted to prose alone: `agent-client-codes.sync.test.ts` in
10
+ * the runtime package (which can import BOTH) asserts they stay identical, so
11
+ * renaming a code on either side fails that test rather than silently breaking
12
+ * a client branch.
13
+ *
14
+ * WIRE CONTRACT (what these codes appear in):
15
+ *
16
+ * - a pre-stream refusal — `{ "code": …, "message": … }` with an HTTP status,
17
+ * parsed into {@link AgentResponseError};
18
+ * - an in-band failure — `event: error` / `data: { code, message }`, surfaced
19
+ * as `useAgentInvoke`'s `errorCode`.
20
+ *
21
+ * Both channels carry the SAME vocabulary, which is why one mirror serves them.
22
+ */
23
+ export const AGENT_ERROR_CODES = {
24
+ /** No usable identity on a surface that requires one. */
25
+ UNAUTHORIZED: "UNAUTHORIZED",
26
+ /** The invoke body did not parse / validate. */
27
+ INVALID_REQUEST: "INVALID_REQUEST",
28
+ /** The builder turned anonymous access off for this agent. */
29
+ GUEST_ACCESS_DISABLED: "GUEST_ACCESS_DISABLED",
30
+ /** The caller (or the app) is out of plan allowance — the upgrade prompt. */
31
+ QUOTA_EXCEEDED: "QUOTA_EXCEEDED",
32
+ /** The app hit its builder-set managed spend cap. */
33
+ MANAGED_SPEND_CAP: "MANAGED_SPEND_CAP",
34
+ /**
35
+ * The pod is at its concurrent-turn cap (scaling S1-F3). A 503 carrying a
36
+ * `Retry-After` hint, and the ONE code {@link fetchStreamTransport} retries
37
+ * by itself — see its docblock for the single-attempt rule.
38
+ */
39
+ POD_SATURATED: "POD_SATURATED",
40
+ /**
41
+ * The pod took SIGTERM and refuses NEW turns while in-flight ones finish.
42
+ * Also a 503 + `Retry-After`, but deliberately NOT auto-retried (the
43
+ * endpoint pull re-routes the next request; retrying into the same pod is
44
+ * the one thing guaranteed not to help).
45
+ */
46
+ DRAINING: "DRAINING",
47
+ /** Refused for this caller — e.g. the link-prompt dismiss route's byo-only rule. */
48
+ FORBIDDEN: "FORBIDDEN",
49
+ /** The turn ran past the pod's wall-clock budget. */
50
+ TIMEOUT: "TIMEOUT",
51
+ /** A guuey-side dependency failed (not the agent's own code). */
52
+ PLATFORM_ERROR: "PLATFORM_ERROR",
53
+ /** Unclassified pod failure. */
54
+ INTERNAL: "INTERNAL",
55
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Error types the transports throw and the hook branches on.
3
+ *
4
+ * Its own module (rather than living in `./web-adapters.ts`) so `useAgentInvoke`
5
+ * — which must stay platform-agnostic — can `instanceof`-narrow a caught error
6
+ * without pulling the web adapter bundle (`fetch`, the history reader,
7
+ * `@guuey/mcp-apps-host`) into a React-Native build.
8
+ */
9
+ /**
10
+ * Thrown when the pod returns a non-2xx status on `/agent/invoke` (before any
11
+ * SSE stream opens). Carries the pod's structured `{ code, message }` when
12
+ * present — e.g. a `QUOTA_EXCEEDED` 429 whose message ("…reached its plan
13
+ * generation limit…") the chat UI should surface — falling back to the bare
14
+ * status for non-JSON failures. See `AGENT_ERROR_CODES` for the vocabulary.
15
+ */
16
+ export declare class AgentResponseError extends Error {
17
+ readonly status: number;
18
+ readonly code?: string | undefined;
19
+ /**
20
+ * The response's `Retry-After` hint in whole seconds, when it sent a
21
+ * parseable one. The pod attaches it to its two 503 refusals
22
+ * (`POD_SATURATED`, `DRAINING`) and exposes the header across origins via
23
+ * `Access-Control-Expose-Headers`, so a browser client can actually read
24
+ * it. `undefined` when the header was absent, malformed, or in the
25
+ * HTTP-date form the pod never emits.
26
+ */
27
+ readonly retryAfterSeconds?: number | undefined;
28
+ constructor(message: string, status: number, code?: string | undefined,
29
+ /**
30
+ * The response's `Retry-After` hint in whole seconds, when it sent a
31
+ * parseable one. The pod attaches it to its two 503 refusals
32
+ * (`POD_SATURATED`, `DRAINING`) and exposes the header across origins via
33
+ * `Access-Control-Expose-Headers`, so a browser client can actually read
34
+ * it. `undefined` when the header was absent, malformed, or in the
35
+ * HTTP-date form the pod never emits.
36
+ */
37
+ retryAfterSeconds?: number | undefined);
38
+ }
39
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAGzC,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM;gBAXnC,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,YAAA;IACtB;;;;;;;OAOG;IACM,iBAAiB,CAAC,EAAE,MAAM,YAAA;CAKtC"}
package/dist/errors.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Error types the transports throw and the hook branches on.
3
+ *
4
+ * Its own module (rather than living in `./web-adapters.ts`) so `useAgentInvoke`
5
+ * — which must stay platform-agnostic — can `instanceof`-narrow a caught error
6
+ * without pulling the web adapter bundle (`fetch`, the history reader,
7
+ * `@guuey/mcp-apps-host`) into a React-Native build.
8
+ */
9
+ /**
10
+ * Thrown when the pod returns a non-2xx status on `/agent/invoke` (before any
11
+ * SSE stream opens). Carries the pod's structured `{ code, message }` when
12
+ * present — e.g. a `QUOTA_EXCEEDED` 429 whose message ("…reached its plan
13
+ * generation limit…") the chat UI should surface — falling back to the bare
14
+ * status for non-JSON failures. See `AGENT_ERROR_CODES` for the vocabulary.
15
+ */
16
+ export class AgentResponseError extends Error {
17
+ status;
18
+ code;
19
+ retryAfterSeconds;
20
+ constructor(message, status, code,
21
+ /**
22
+ * The response's `Retry-After` hint in whole seconds, when it sent a
23
+ * parseable one. The pod attaches it to its two 503 refusals
24
+ * (`POD_SATURATED`, `DRAINING`) and exposes the header across origins via
25
+ * `Access-Control-Expose-Headers`, so a browser client can actually read
26
+ * it. `undefined` when the header was absent, malformed, or in the
27
+ * HTTP-date form the pod never emits.
28
+ */
29
+ retryAfterSeconds) {
30
+ super(message);
31
+ this.status = status;
32
+ this.code = code;
33
+ this.retryAfterSeconds = retryAfterSeconds;
34
+ this.name = "AgentResponseError";
35
+ }
36
+ }
package/dist/history.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * has its own copy today and can migrate onto this later.
12
12
  */
13
13
  import type { AgMessage, JsonValue } from "@silverprotocol/core";
14
- import type { AgentMessage, HistoryCard, HistoryLoadResult } from "./types";
14
+ import type { AgentMessage, HistoryCard, HistoryLoadResult } from "./types.js";
15
15
  /** One row of `GET /v1/threads/:id/messages`. */
16
16
  export interface ThreadHistoryRow {
17
17
  seq: number;
@@ -1 +1 @@
1
- {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5E,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACjC;AAOD;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,SAA6B;CAIjD;AAeD,qEAAqE;AACrE,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAOpF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,WAAW,EAAE,CAOhF;AAED,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,OAAO,EACP,QAAQ,EACR,WAAW,EACX,YAAoB,EACpB,SAAiB,GAClB,EAAE,yBAAyB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBxD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK1E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAE7E"}
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/E,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACjC;AAOD;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,SAA6B;CAIjD;AAeD,qEAAqE;AACrE,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE,CAOpF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,WAAW,EAAE,CAOhF;AAED,MAAM,WAAW,yBAAyB;IACxC,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,OAAO,EACP,QAAQ,EACR,WAAW,EACX,YAAoB,EACpB,SAAiB,GAClB,EAAE,yBAAyB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBxD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK1E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAE7E"}
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
- export { parseSseEvents, extractAssistantText, reduceAssistantText, stringField, parseConsentRequest, parseLinkRequest, type ParsedSseEvent, } from "./sse";
2
- export { dismissLinkPrompt } from "./link-prompt";
3
- export { createUiResourceReader, type CreateUiResourceReaderOptions, createWebAdapters, localStorageThreadStore, webGenerateId, fetchStreamTransport, AgentResponseError, type CreateWebAdaptersOptions, } from "./web-adapters";
4
- export { fetchThreadHistory, threadHistoryRowsToMessages, threadHistoryRowsToCards, HistoryUnauthorizedError, type ThreadHistoryRow, type ThreadHistoryFetchOptions, } from "./history";
5
- export { ingestMessageFrame } from "./blocks";
6
- export { sortHistoryCards, toolNameFor } from "./history";
1
+ export { parseSseEvents, extractAssistantText, reduceAssistantText, stringField, parseConsentRequest, parseLinkRequest, type ParsedSseEvent, } from "./sse.js";
2
+ export { dismissLinkPrompt } from "./link-prompt.js";
3
+ export { createUiActionRelay, type CreateUiActionRelayOptions, createUiResourceReader, type CreateUiResourceReaderOptions, createWebAdapters, localStorageThreadStore, webGenerateId, fetchStreamTransport, type CreateWebAdaptersOptions, } from "./web-adapters.js";
4
+ export { withSaturationRetry, parseRetryAfterSeconds, type SaturationRetryOptions, } from "./saturation-retry.js";
5
+ export { AgentResponseError } from "./errors.js";
6
+ export { AGENT_ERROR_CODES, type AgentErrorCode } from "./error-codes.js";
7
+ export { fetchThreadHistory, threadHistoryRowsToMessages, threadHistoryRowsToCards, HistoryUnauthorizedError, type ThreadHistoryRow, type ThreadHistoryFetchOptions, } from "./history.js";
8
+ export { ingestMessageFrame } from "./blocks.js";
9
+ export { sortHistoryCards, toolNameFor } from "./history.js";
7
10
  export type { AgEvent, AgReduceResult, AgMessage, AgBlock } from "@silverprotocol/core";
8
- export type { AgentMessage, HistoryCard, ProfileConsentRequest, ProfileLinkRequest, ThreadIdStore, GenerateId, InvokeRequest, InvokeTransport, AgentInvokeAdapters, AgentInvokeHistoryAdapter, AgentInvokeStatus, HistoryLoadResult, UseAgentInvokeOptions, UseAgentInvokeReturn, } from "./types";
11
+ export type { AgentMessage, HistoryCard, ProfileConsentRequest, ProfileLinkRequest, ThreadIdStore, GenerateId, InvokeRequest, InvokeTransport, AgentInvokeAdapters, AgentInvokeHistoryAdapter, AgentInvokeStatus, HistoryLoadResult, UseAgentInvokeOptions, UseAgentInvokeReturn, } from "./types.js";
9
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,cAAc,GACpB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,iBAAiB,EACjB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,wBAAwB,GAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAK9C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAI1D,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACxF,YAAY,EACV,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,cAAc,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,iBAAiB,EACjB,uBAAuB,EACvB,aAAa,EACb,oBAAoB,EACpB,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EACL,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAKjD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAI7D,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACxF,YAAY,EACV,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,UAAU,EACV,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,21 @@
1
- export { parseSseEvents, extractAssistantText, reduceAssistantText, stringField, parseConsentRequest, parseLinkRequest, } from "./sse";
2
- export { dismissLinkPrompt } from "./link-prompt";
3
- export { createUiResourceReader, createWebAdapters, localStorageThreadStore, webGenerateId, fetchStreamTransport, AgentResponseError, } from "./web-adapters";
4
- export { fetchThreadHistory, threadHistoryRowsToMessages, threadHistoryRowsToCards, HistoryUnauthorizedError, } from "./history";
5
- export { ingestMessageFrame } from "./blocks";
1
+ export { parseSseEvents, extractAssistantText, reduceAssistantText, stringField, parseConsentRequest, parseLinkRequest, } from "./sse.js";
2
+ export { dismissLinkPrompt } from "./link-prompt.js";
3
+ export { createUiActionRelay, createUiResourceReader, createWebAdapters, localStorageThreadStore, webGenerateId, fetchStreamTransport, } from "./web-adapters.js";
4
+ // The `POD_SATURATED` single-retry wrapper, transport-agnostic: a host that
5
+ // brings its own `fetch` (Portal's React-Native transport) wraps it to wear the
6
+ // same semantics as the web transport instead of hand-rolling a second copy.
7
+ // `parseRetryAfterSeconds` ships with it because filling
8
+ // `AgentResponseError.retryAfterSeconds` the same way is what makes the wrapper
9
+ // honour the pod's hint.
10
+ export { withSaturationRetry, parseRetryAfterSeconds, } from "./saturation-retry.js";
11
+ export { AgentResponseError } from "./errors.js";
12
+ // The pod's wire-code vocabulary, mirrored — branch on these instead of
13
+ // re-typing the string literals (see the module docblock for the sync guard).
14
+ export { AGENT_ERROR_CODES } from "./error-codes.js";
15
+ export { fetchThreadHistory, threadHistoryRowsToMessages, threadHistoryRowsToCards, HistoryUnauthorizedError, } from "./history.js";
16
+ export { ingestMessageFrame } from "./blocks.js";
6
17
  // Pure block-walk / resource-narrowing helpers for a block-preserving renderer
7
18
  // (shared by Studio's `AgentBlocks` and Portal-web's agent chat). React-free.
8
19
  // Transcript labeling/ordering helpers (mount narrowing itself moved to
9
20
  // @guuey/mcp-apps-host — the SEP-1865 Host role package; import it directly).
10
- export { sortHistoryCards, toolNameFor } from "./history";
21
+ export { sortHistoryCards, toolNameFor } from "./history.js";
package/dist/react.d.ts CHANGED
@@ -6,6 +6,6 @@
6
6
  * history reader, and the web adapters). Consumers that only need those never
7
7
  * import React at all; consumers that render chat import the hook from here.
8
8
  */
9
- export { useAgentInvoke, applyHistoryResult, type HistoryApplication } from "./useAgentInvoke";
9
+ export { useAgentInvoke, applyHistoryResult, type HistoryApplication } from "./useAgentInvoke.js";
10
10
  export type { AgEvent, AgReduceResult } from "@silverprotocol/core";
11
11
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAI/F,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAIlG,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/react.js CHANGED
@@ -6,4 +6,4 @@
6
6
  * history reader, and the web adapters). Consumers that only need those never
7
7
  * import React at all; consumers that render chat import the hook from here.
8
8
  */
9
- export { useAgentInvoke, applyHistoryResult } from "./useAgentInvoke";
9
+ export { useAgentInvoke, applyHistoryResult } from "./useAgentInvoke.js";
@@ -0,0 +1,60 @@
1
+ import type { InvokeTransport } from "./types.js";
2
+ /**
3
+ * Read `Retry-After` as WHOLE SECONDS, or `undefined`.
4
+ *
5
+ * HTTP also allows an absolute HTTP-date, which is deliberately NOT parsed:
6
+ * the pod only ever emits a delta-seconds integer, and silently mis-reading a
7
+ * date as `NaN` seconds is worse than falling back to the fixed delay.
8
+ *
9
+ * Exported because every transport that builds an {@link AgentResponseError}
10
+ * has to fill `retryAfterSeconds` the same way for {@link withSaturationRetry}
11
+ * to honour the same hint — a second hand-rolled regex in a host adapter is
12
+ * exactly the drift this module exists to prevent.
13
+ */
14
+ export declare function parseRetryAfterSeconds(header: string | null): number | undefined;
15
+ /** Options for {@link withSaturationRetry}. */
16
+ export interface SaturationRetryOptions {
17
+ /**
18
+ * The saturation-retry wait. Injectable so tests drive the retry without a
19
+ * real 15s timer; production uses an abort-aware `setTimeout`.
20
+ */
21
+ sleep?: (ms: number, signal: AbortSignal) => Promise<void>;
22
+ }
23
+ /**
24
+ * Wrap an invoke transport with ONE automatic retry on a saturated pod.
25
+ *
26
+ * ## What retries, and what deliberately does not
27
+ *
28
+ * `POD_SATURATED` (503) means the pod is at its concurrent-turn cap right now
29
+ * — a transient queue state that clears as in-flight turns finish, so a single
30
+ * delayed re-send usually just works. The wait is the pod's own `Retry-After`
31
+ * hint (via {@link AgentResponseError.retryAfterSeconds}), defaulting to 15s
32
+ * when it sent none and capped at 30s.
33
+ *
34
+ * `DRAINING` (also 503 + `Retry-After`) is NOT retried in v1. The refusing pod
35
+ * is shutting down: its readiness probe is already failing and the endpoint
36
+ * pull is in flight, so the useful retry is the one that reaches a DIFFERENT
37
+ * pod — and a wrapped transport re-sends to the same URL. Retrying here would
38
+ * spend the user's 15s to arrive back at the same draining pod (or at a fresh
39
+ * one by luck), which is not a guarantee worth building on. When the retry can
40
+ * be made routing-aware, this is the code to revisit.
41
+ *
42
+ * Exactly ONE retry: a second saturation propagates as
43
+ * {@link AgentResponseError}, so a genuinely overloaded agent surfaces instead
44
+ * of looping. Nothing is retried once a chunk has been yielded — replaying
45
+ * mid-stream would duplicate a partial assistant turn (the same `yielded`
46
+ * guard the widget's `withIdentifiedToken` 401-retry uses). An abort during
47
+ * the wait skips the retry and surfaces the original refusal.
48
+ *
49
+ * The retry is INVISIBLE to `useAgentInvoke`: no frames were yielded, so the
50
+ * turn simply stays in `connecting` for the duration of the wait. There is no
51
+ * `retrying` status by design — the hook's state machine describes the pod's
52
+ * turn lifecycle, not the transport's plumbing.
53
+ *
54
+ * The wrapped transport is re-invoked from scratch for the retry, so a host
55
+ * that resolves identity inside its own generator (Portal's RN transport reads
56
+ * the bearer bridge per attempt) re-reads it on the second try rather than
57
+ * replaying a token that may have expired during the wait.
58
+ */
59
+ export declare function withSaturationRetry(transport: InvokeTransport, options?: SaturationRetryOptions): InvokeTransport;
60
+ //# sourceMappingURL=saturation-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saturation-retry.d.ts","sourceRoot":"","sources":["../src/saturation-retry.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,YAAY,CAAC;AAiBjE;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAMhF;AA4BD,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,eAAe,EAC1B,OAAO,GAAE,sBAA2B,GACnC,eAAe,CAqBjB"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The single `POD_SATURATED` auto-retry, as a transport-agnostic wrapper.
3
+ *
4
+ * Its own module — rather than living inside `./web-adapters.ts`, where it was
5
+ * born — because the behaviour is a property of the POD's refusal vocabulary,
6
+ * not of `fetch`. Every host that speaks `/agent/invoke` wants it, including
7
+ * the ones that cannot import the web adapter bundle: Portal's React-Native
8
+ * transport wraps its own `fetch` call with {@link withSaturationRetry} the
9
+ * same way `fetchStreamTransport` wraps its browser streaming reader, so the
10
+ * two wear byte-identical retry semantics instead of two hand-written copies
11
+ * that drift.
12
+ *
13
+ * This module imports only `./types.js`, `./errors.js` and `./error-codes.js`
14
+ * — all pure — so pulling it in costs a React-Native build nothing.
15
+ */
16
+ import { AGENT_ERROR_CODES } from "./error-codes.js";
17
+ import { AgentResponseError } from "./errors.js";
18
+ /**
19
+ * Fallback wait before the saturation retry when the pod sent no usable
20
+ * `Retry-After` — the same 15s the pod's governor hints today
21
+ * (`GOVERNOR_RETRY_AFTER_SECONDS`), so a stripped header behaves like the
22
+ * normal case rather than hammering.
23
+ */
24
+ const SATURATION_FALLBACK_DELAY_SECONDS = 15;
25
+ /**
26
+ * Ceiling on the honoured hint. A pod that (mis)configures a multi-minute
27
+ * `Retry-After` must not park a chat UI in `connecting` for that long — past
28
+ * this the user is better served by the visible failure they can act on.
29
+ */
30
+ const SATURATION_MAX_DELAY_SECONDS = 30;
31
+ /**
32
+ * Read `Retry-After` as WHOLE SECONDS, or `undefined`.
33
+ *
34
+ * HTTP also allows an absolute HTTP-date, which is deliberately NOT parsed:
35
+ * the pod only ever emits a delta-seconds integer, and silently mis-reading a
36
+ * date as `NaN` seconds is worse than falling back to the fixed delay.
37
+ *
38
+ * Exported because every transport that builds an {@link AgentResponseError}
39
+ * has to fill `retryAfterSeconds` the same way for {@link withSaturationRetry}
40
+ * to honour the same hint — a second hand-rolled regex in a host adapter is
41
+ * exactly the drift this module exists to prevent.
42
+ */
43
+ export function parseRetryAfterSeconds(header) {
44
+ if (header === null)
45
+ return undefined;
46
+ const trimmed = header.trim();
47
+ if (!/^\d+$/.test(trimmed))
48
+ return undefined;
49
+ const seconds = Number(trimmed);
50
+ return Number.isSafeInteger(seconds) ? seconds : undefined;
51
+ }
52
+ /** How long to wait before the single saturation retry, in milliseconds. */
53
+ function saturationDelayMs(retryAfterSeconds) {
54
+ const hinted = retryAfterSeconds ?? SATURATION_FALLBACK_DELAY_SECONDS;
55
+ return Math.min(hinted, SATURATION_MAX_DELAY_SECONDS) * 1000;
56
+ }
57
+ /**
58
+ * Wait `ms`, or resolve early if the turn is aborted — a user who hits stop
59
+ * must not sit through the remainder of a 15s backoff before the UI settles.
60
+ */
61
+ function delay(ms, signal) {
62
+ return new Promise((resolve) => {
63
+ if (signal.aborted) {
64
+ resolve();
65
+ return;
66
+ }
67
+ const finish = () => {
68
+ clearTimeout(timer);
69
+ signal.removeEventListener("abort", finish);
70
+ resolve();
71
+ };
72
+ const timer = setTimeout(finish, ms);
73
+ signal.addEventListener("abort", finish, { once: true });
74
+ });
75
+ }
76
+ /**
77
+ * Wrap an invoke transport with ONE automatic retry on a saturated pod.
78
+ *
79
+ * ## What retries, and what deliberately does not
80
+ *
81
+ * `POD_SATURATED` (503) means the pod is at its concurrent-turn cap right now
82
+ * — a transient queue state that clears as in-flight turns finish, so a single
83
+ * delayed re-send usually just works. The wait is the pod's own `Retry-After`
84
+ * hint (via {@link AgentResponseError.retryAfterSeconds}), defaulting to 15s
85
+ * when it sent none and capped at 30s.
86
+ *
87
+ * `DRAINING` (also 503 + `Retry-After`) is NOT retried in v1. The refusing pod
88
+ * is shutting down: its readiness probe is already failing and the endpoint
89
+ * pull is in flight, so the useful retry is the one that reaches a DIFFERENT
90
+ * pod — and a wrapped transport re-sends to the same URL. Retrying here would
91
+ * spend the user's 15s to arrive back at the same draining pod (or at a fresh
92
+ * one by luck), which is not a guarantee worth building on. When the retry can
93
+ * be made routing-aware, this is the code to revisit.
94
+ *
95
+ * Exactly ONE retry: a second saturation propagates as
96
+ * {@link AgentResponseError}, so a genuinely overloaded agent surfaces instead
97
+ * of looping. Nothing is retried once a chunk has been yielded — replaying
98
+ * mid-stream would duplicate a partial assistant turn (the same `yielded`
99
+ * guard the widget's `withIdentifiedToken` 401-retry uses). An abort during
100
+ * the wait skips the retry and surfaces the original refusal.
101
+ *
102
+ * The retry is INVISIBLE to `useAgentInvoke`: no frames were yielded, so the
103
+ * turn simply stays in `connecting` for the duration of the wait. There is no
104
+ * `retrying` status by design — the hook's state machine describes the pod's
105
+ * turn lifecycle, not the transport's plumbing.
106
+ *
107
+ * The wrapped transport is re-invoked from scratch for the retry, so a host
108
+ * that resolves identity inside its own generator (Portal's RN transport reads
109
+ * the bearer bridge per attempt) re-reads it on the second try rather than
110
+ * replaying a token that may have expired during the wait.
111
+ */
112
+ export function withSaturationRetry(transport, options = {}) {
113
+ return async function* retrying(req) {
114
+ let yielded = false;
115
+ try {
116
+ for await (const chunk of transport(req)) {
117
+ yielded = true;
118
+ yield chunk;
119
+ }
120
+ return;
121
+ }
122
+ catch (err) {
123
+ const saturated = err instanceof AgentResponseError && err.code === AGENT_ERROR_CODES.POD_SATURATED;
124
+ if (!saturated || yielded)
125
+ throw err;
126
+ await (options.sleep ?? delay)(saturationDelayMs(err.retryAfterSeconds), req.signal);
127
+ // Aborted mid-wait: the user is done with this turn. Surface the refusal
128
+ // that caused the wait rather than spending a request that `fetch` would
129
+ // reject on the signal anyway.
130
+ if (req.signal.aborted)
131
+ throw err;
132
+ }
133
+ yield* transport(req);
134
+ };
135
+ }
package/dist/sse.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * platform dependencies — unit-tested in isolation (`sse.test.ts`) and shared
4
4
  * verbatim across web (Studio) and React-Native (Portal).
5
5
  */
6
- import type { ProfileConsentRequest, ProfileLinkRequest } from "./types";
6
+ import type { ProfileConsentRequest, ProfileLinkRequest } from "./types.js";
7
7
  export interface ParsedSseEvent {
8
8
  event: string;
9
9
  data: unknown;
package/dist/sse.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEzE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAqBzF;AAsBD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAU1E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAmC1D;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI1E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,qBAAqB,GAAG,IAAI,CAO/E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAOzE"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAqBzF;AAsBD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAU1E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAmC1D;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAI1E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,qBAAqB,GAAG,IAAI,CAO/E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAOzE"}
package/dist/types.d.ts CHANGED
@@ -148,9 +148,16 @@ export interface UseAgentInvokeOptions {
148
148
  * - `responding` — assistant text is arriving (`text.start`/`text.delta`
149
149
  * silver frames, or bypass text/assistant frames).
150
150
  *
151
- * Failure keeps its own channel ({@link UseAgentInvokeReturn.error}) — there
152
- * is deliberately no `error` status: after any terminal outcome the status
153
- * returns to `ready` so the composer re-enables.
151
+ * Failure keeps its own channel ({@link UseAgentInvokeReturn.error} +
152
+ * {@link UseAgentInvokeReturn.errorCode}) — there is deliberately no `error`
153
+ * status: after any terminal outcome the status returns to `ready` so the
154
+ * composer re-enables.
155
+ *
156
+ * There is likewise no `retrying` state. `fetchStreamTransport` retries a
157
+ * `POD_SATURATED` refusal once by itself, but that happens before any frame is
158
+ * yielded, so the turn stays in `connecting` for the backoff and the hook never
159
+ * learns it happened. This union describes the POD's turn lifecycle; transport
160
+ * plumbing does not belong in it.
154
161
  */
155
162
  export type AgentInvokeStatus = "ready" | "connecting" | "thinking" | "using-tool" | "responding";
156
163
  export interface UseAgentInvokeReturn {
@@ -162,6 +169,25 @@ export interface UseAgentInvokeReturn {
162
169
  /** The active tool's wire name while `status === 'using-tool'`, else null. */
163
170
  activeTool: string | null;
164
171
  error: string | null;
172
+ /**
173
+ * The pod's wire code for the failure in {@link error}, when it carried one
174
+ * — `QUOTA_EXCEEDED`, `POD_SATURATED`, `GUEST_ACCESS_DISABLED`, … (see
175
+ * `AGENT_ERROR_CODES`, and branch on those constants rather than re-typing
176
+ * the literals). `null` when there is no error, or when the failure had no
177
+ * code: a network drop, a host-adapter throw, or an `event: error` frame
178
+ * without one.
179
+ *
180
+ * Both failure channels feed it — the pre-stream refusal (thrown as
181
+ * `AgentResponseError`) and the in-band `event: error` frame — because the
182
+ * two carry the SAME vocabulary; a consumer branches once, not per channel.
183
+ * Set and cleared in lockstep with {@link error}: a new `send()`, `reset()`,
184
+ * or an app switch clears both.
185
+ *
186
+ * It is a `string`, not the `AgentErrorCode` union: the pod may ship a new
187
+ * code before a consumer upgrades this SDK, and a narrowed type would make
188
+ * that unrepresentable rather than merely unhandled.
189
+ */
190
+ errorCode: string | null;
165
191
  threadId: string | null;
166
192
  /** Abort the in-flight turn (the stream stops; partial text is kept). */
167
193
  abort: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { AgentMessage, HistoryLoadResult, UseAgentInvokeOptions, UseAgentInvokeReturn } from "./types";
1
+ import type { AgentMessage, HistoryLoadResult, UseAgentInvokeOptions, UseAgentInvokeReturn } from "./types.js";
2
2
  /** The decision `applyHistoryResult` reaches for a loaded transcript. */
3
3
  export type HistoryApplication = {
4
4
  kind: "seed";
@@ -1 +1 @@
1
- {"version":3,"file":"useAgentInvoke.d.ts","sourceRoot":"","sources":["../src/useAgentInvoke.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAGV,YAAY,EAEZ,iBAAiB,EAGjB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAMjB,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,iBAAiB,EACzB,eAAe,EAAE,YAAY,EAAE,GAC9B,kBAAkB,CAIpB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,oBAAoB,CAqUhF"}
1
+ {"version":3,"file":"useAgentInvoke.d.ts","sourceRoot":"","sources":["../src/useAgentInvoke.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAGV,YAAY,EAEZ,iBAAiB,EAGjB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAMpB,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,iBAAiB,EACzB,eAAe,EAAE,YAAY,EAAE,GAC9B,kBAAkB,CAIpB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,oBAAoB,CAwVhF"}