@anuma/agent-runtime 6.33.1 → 6.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -376,10 +376,6 @@ async function runAgentRequest(opts) {
376
376
  model: opts.agent.model.default,
377
377
  token: grant.bearer,
378
378
  tools,
379
- // X-Anuma-Surface drives portal auth/grant keying (OAuth client_id + first-party
380
- // grant surface) — keep it. X-Anuma-Feature is the provenance header the portal
381
- // records into requests.feature (#1353); without it, agent-runtime LLM traffic
382
- // lands feature=null and can't be told apart from chat/background in prod.
383
379
  headers: { "X-Anuma-Surface": "agent", "X-Anuma-Feature": "agent" },
384
380
  ...opts.portalBaseUrl ? { baseUrl: opts.portalBaseUrl } : void 0,
385
381
  ...opts.transport ? { transport: opts.transport } : void 0,
package/dist/index.d.mts CHANGED
@@ -3,33 +3,18 @@ export { ConnectorTokenGetterOpts } from '@anuma/sdk/tools';
3
3
  import { LlmapiMessage } from '@anuma/sdk';
4
4
  import { ToolConfig, StreamingTransport, ApiType, AutoExecutedToolResult } from '@anuma/sdk/server';
5
5
 
6
- /**
7
- * Public types for `@anuma/agent-runtime`.
8
- *
9
- * Mirrors the contract in `.claude-docs/connecters/agent-runtime-spec.md`.
10
- * These types are the contract between the SDK / portal vault and any
11
- * server-side consumer (Haven, Sentinel, future SMS handler).
12
- */
13
-
14
- /**
15
- * Parsed result of an incoming bearer token. Returned by
16
- * {@link extractGrantContext}.
17
- */
6
+ /** Parsed result of an incoming bearer token, returned by {@link extractGrantContext}. */
18
7
  interface GrantContext {
19
- /** Wallet address — primary user identifier on the portal. */
8
+ /** Wallet address; the primary user identifier on the portal. */
20
9
  userAddress: string;
21
- /** OAuth `client_id` that owns the bearer (e.g. `"haven_v1"`). */
10
+ /** OAuth `client_id` that owns the bearer, e.g. `"haven_v1"`. */
22
11
  clientId: string;
23
12
  /** Scopes the user granted to this client. */
24
13
  scopes: string[];
25
- /** Bearer token verbatim — for relaying to the portal. */
14
+ /** Bearer token verbatim, for relaying to the portal. */
26
15
  bearer: string;
27
16
  }
28
- /**
29
- * Discriminated result of a mint call. Failures are returned, never
30
- * thrown — transport errors (5xx / network) raise from {@link PortalClient}
31
- * directly.
32
- */
17
+ /** Result of a mint call; HTTP failures, including 5xx after retries, are returned and network errors throw; `expiresAt` is unix ms. */
33
18
  type MintResult = {
34
19
  ok: true;
35
20
  accessToken: string;
@@ -38,11 +23,9 @@ type MintResult = {
38
23
  ok: false;
39
24
  error: MintError;
40
25
  };
41
- /** Variants of `MintResult.error`. Re-exported from the SDK so consumers
42
- * importing only `@anuma/agent-runtime` get the union without a second
43
- * import. */
26
+ /** Variants of `MintResult.error`, re-exported from `@anuma/sdk/tools`. */
44
27
  type MintError = ConnectorMintError;
45
- /** Returned by {@link PortalClient.listConnectors}. */
28
+ /** Returned by {@link PortalClient.listConnectors}; `connectedAt` is unix ms. */
46
29
  interface ConnectorInfo {
47
30
  oauthApp: string;
48
31
  externalAccount?: string;
@@ -51,19 +34,13 @@ interface ConnectorInfo {
51
34
  }
52
35
  /** Argument shape for {@link PortalClient.createConnectTicket}. */
53
36
  interface ConnectTicketOpts {
54
- /** Logical provider (e.g. `"gmail"`, `"github"`) — mapped to the portal
55
- * `oauth_app` internally and used to build the connect URL. */
37
+ /** Logical provider, e.g. `"gmail"` or `"github"`. */
56
38
  provider: string;
57
- /**
58
- * Scopes requested for the connect flow, passed VERBATIM upstream
59
- * ("upstream-flavored"): Google needs full
60
- * `https://www.googleapis.com/auth/...` URLs. An empty array falls back to
61
- * the provider's default scope union on the portal side.
62
- */
39
+ /** Scopes passed verbatim upstream (Google needs full `https://www.googleapis.com/auth/...` URLs); an empty array uses the provider's default scopes. */
63
40
  requestedScopes: string[];
64
41
  returnTo: string;
65
42
  }
66
- /** Result of a ticket-mint call. */
43
+ /** Result of a ticket-mint call; `expiresAt` is unix ms. */
67
44
  interface ConnectTicket {
68
45
  ticketId: string;
69
46
  expiresAt: number;
@@ -71,28 +48,27 @@ interface ConnectTicket {
71
48
  }
72
49
  /** Typed wrapper over the portal HTTP API. */
73
50
  interface PortalClient {
74
- /** Mint a fresh upstream access token for a logical provider. `access`
75
- * defaults to the provider's standard level (e.g. gmail `read`, github
76
- * `repo`). */
51
+ /** Mint an upstream access token for a logical provider; `access` defaults to the provider's standard level. */
77
52
  mintConnectorToken(provider: string, access?: string): Promise<MintResult>;
78
- /** List the user's currently-connected connectors. */
53
+ /** List the user's connected connectors. */
79
54
  listConnectors(): Promise<ConnectorInfo[]>;
80
- /** Mint a connect ticket so the user can be redirected to a connect flow. */
55
+ /** Mint a connect ticket for redirecting the user to a connect flow. */
81
56
  createConnectTicket(opts: ConnectTicketOpts): Promise<ConnectTicket>;
82
57
  }
58
+ /** Options for {@link createPortalClient}. */
83
59
  interface PortalClientOpts {
84
- /** Defaults to `process.env.ANUMA_PORTAL_URL` then the production portal. */
60
+ /** @defaultValue `process.env.ANUMA_PORTAL_URL`, then the production portal */
85
61
  baseUrl?: string;
86
- /** Defaults to `globalThis.fetch`. */
62
+ /** @defaultValue `globalThis.fetch` */
87
63
  fetchImpl?: typeof fetch;
88
- /** Per-request timeout. @default 5000 */
64
+ /** Per-request timeout. @defaultValue 5000 */
89
65
  timeoutMs?: number;
90
- /** Max retry attempts on 5xx / network errors. @default 3 */
66
+ /** Max attempts on 5xx and network errors. @defaultValue 3 */
91
67
  maxRetries?: number;
92
- /** Initial backoff before the second attempt. @default 100 */
68
+ /** Initial backoff before the second attempt. @defaultValue 100 */
93
69
  retryBaseMs?: number;
94
70
  }
95
- /** Structurally-typed incoming request. Any HTTP framework satisfies this. */
71
+ /** Structurally typed incoming request; any HTTP framework satisfies it. */
96
72
  interface IncomingRequest {
97
73
  headers: {
98
74
  authorization?: string;
@@ -100,17 +76,7 @@ interface IncomingRequest {
100
76
  [key: string]: string | string[] | undefined;
101
77
  };
102
78
  }
103
- /**
104
- * Structured tool error lifted from a tool-result message after the loop
105
- * completes. Connector errors carry the canonical
106
- * `__anuma_connector_error_v1` payload; other tool failures may surface
107
- * here in the future.
108
- */
109
- /**
110
- * Open shape so future tool-execution errors can lift into the same union
111
- * without breaking consumers. Connector errors populate `provider`; other
112
- * errors carry a `message`.
113
- */
79
+ /** Structured tool error; connector errors populate `provider`, others carry `message`. */
114
80
  interface ToolErrorInfo {
115
81
  code: string;
116
82
  provider?: string;
@@ -124,153 +90,68 @@ interface ToolError {
124
90
  error: ToolErrorInfo;
125
91
  }
126
92
 
127
- /**
128
- * Error subclasses thrown by `@anuma/agent-runtime`.
129
- *
130
- * - {@link AuthError} comes out of `extractGrantContext` when the bearer is
131
- * missing, malformed, expired, or already revoked.
132
- */
133
93
  /** Discriminant for {@link AuthError}. */
134
94
  type AuthErrorSubtype = "missing_bearer" | "invalid_bearer" | "expired" | "revoked";
95
+ /** Thrown by `extractGrantContext` when the bearer is missing, malformed, expired, or revoked. */
135
96
  declare class AuthError extends Error {
136
97
  readonly subtype: AuthErrorSubtype;
137
98
  constructor(subtype: AuthErrorSubtype, message?: string);
138
99
  }
139
100
 
140
- /**
141
- * Pull the bearer off an incoming request, validate it against the portal,
142
- * and return the parsed grant.
143
- *
144
- * In v1 the portal validates by exposing `GET /api/v1/me`, which returns
145
- * `{ user_address, client_id, scopes }`. A later portal version may switch
146
- * to issuing signed JWTs and let `extractGrantContext` do local decode —
147
- * the consumer signature stays the same.
148
- */
149
-
150
101
  type ExtractGrantContextOpts = Pick<PortalClientOpts, "baseUrl" | "fetchImpl" | "timeoutMs">;
102
+ /** Validate the request's bearer against the portal and return the parsed grant. @throws {@link AuthError} when the bearer is missing, malformed, expired, or revoked. */
151
103
  declare function extractGrantContext(req: IncomingRequest, opts?: ExtractGrantContextOpts): Promise<GrantContext>;
152
104
 
153
- /**
154
- * Typed HTTP client over the portal API.
155
- *
156
- * Retries on 5xx / network errors with exponential backoff + jitter
157
- * (default 3 attempts, base 100ms). Never retries 4xx — those become
158
- * `MintResult.ok=false` (for mint) or thrown errors (for the bookkeeping
159
- * endpoints `listConnectors` / `createConnectTicket`).
160
- *
161
- * Surface is duck-typed against `PortalClient` so test stubs can satisfy
162
- * the same contract.
163
- */
164
-
105
+ /** Create a {@link PortalClient} that retries 5xx and network errors with jittered exponential backoff and never retries 4xx. */
165
106
  declare function createPortalClient(bearer: string, opts?: PortalClientOpts): PortalClient;
166
107
 
167
- /**
168
- * Convenience wrapper that re-exports the SDK's
169
- * `createConnectorTokenGetter` with the same per-instance cache semantics.
170
- *
171
- * The wrapper exists so consumers importing only `@anuma/agent-runtime`
172
- * get the helper as part of a single import surface, without also
173
- * importing `@anuma/sdk/tools` directly. The behavior is identical.
174
- */
175
-
176
108
  declare function createConnectorTokenGetter(client: PortalClient, provider: string, opts?: ConnectorTokenGetterOpts): () => Promise<string | null>;
177
109
 
178
- /**
179
- * `runAgentRequest` — the single function a server-side agent host calls
180
- * per inbound request.
181
- *
182
- * Wires the four pieces together:
183
- * extractGrantContext → createPortalClient → toolFactories → runToolLoop
184
- *
185
- * After the loop returns, walks the auto-executed tool results, lifts any
186
- * payload carrying the canonical `__anuma_connector_error_v1` marker into
187
- * `AgentResponse.toolErrors`. The marker shape is the load-bearing contract
188
- * — every connector tool factory uses `buildConnectorErrorResult` to emit
189
- * it, and the parser keys solely on that marker so it can't false-positive
190
- * on tools that legitimately return JSON.
191
- */
192
-
193
110
  /** Minimal slice of `AgentConfig` this runtime depends on. */
194
111
  interface AgentConfigLike {
195
- /** Model selection — at least `default` must be present. */
196
112
  model: {
197
113
  default: string;
198
114
  };
199
- /** System prompt threaded into the loop. */
200
115
  prompt: string;
201
116
  }
117
+ /** Options for {@link runAgentRequest}. */
202
118
  interface AgentRequestOpts {
203
- /** Inbound request — only `headers.authorization` is read. */
119
+ /** Inbound request; only `headers.authorization` is read. */
204
120
  request: IncomingRequest;
205
- /** Agent configuration (haven, sentinel, …). */
206
121
  agent: AgentConfigLike;
207
- /** Conversation history including the user turn. */
208
122
  messages: LlmapiMessage[];
209
- /** Tool factories that receive the portal client and return `ToolConfig[]`. */
123
+ /** Factories that receive the portal client and return `ToolConfig[]`. */
210
124
  toolFactories?: Array<(portalClient: PortalClient) => ToolConfig[]>;
211
- /** Override portal client opts (test injection). */
125
+ /** Overrides for the portal client, for test injection. */
212
126
  portalClientOpts?: PortalClientOpts;
213
- /**
214
- * Override the streaming transport runToolLoop uses to talk to the
215
- * portal's chat completion API. Production code never sets this — it's
216
- * the injection point e2e tests use to stub LLM behavior without a real
217
- * portal in the loop. Forwarded verbatim to runToolLoop's
218
- * `transport` option.
219
- */
127
+ /** Streaming transport override forwarded to `runToolLoop`, for tests. */
220
128
  transport?: StreamingTransport;
221
- /**
222
- * Optional portal base URL forwarded to runToolLoop for chat completions.
223
- * Defaults to runToolLoop's own default. Setting this without a stub
224
- * `transport` will hit the real portal.
225
- */
129
+ /** Portal base URL for chat completions; without a stub `transport` this hits the real portal. */
226
130
  portalBaseUrl?: string;
227
- /**
228
- * Optional override for the LLM API strategy ("responses" | "completions" | "auto").
229
- * Production callers don't set this — the default ("auto") picks the right
230
- * endpoint for the model. Tests use "completions" with the stub transport
231
- * to feed OpenAI-style streaming chunks.
232
- */
131
+ /** LLM API strategy. @defaultValue `"auto"` */
233
132
  apiType?: ApiType;
234
133
  }
235
- /** Minimal usage summary lifted off the LLM response. */
134
+ /** Token usage lifted off the LLM response. */
236
135
  interface UsageSummary {
237
136
  inputTokens?: number;
238
137
  outputTokens?: number;
239
138
  totalTokens?: number;
240
139
  }
140
+ /** Result of {@link runAgentRequest}. */
241
141
  interface AgentResponse {
242
- /**
243
- * Conversation messages after the loop completes: the input messages,
244
- * followed by tool-result messages for each auto-executed tool, followed
245
- * by the final assistant message. Synthesized — `runToolLoop` doesn't
246
- * expose the full message history directly.
247
- */
142
+ /** Input messages, then an assistant `tool_calls` message and tool-result messages when tools ran, then the final assistant message if present. */
248
143
  messages: LlmapiMessage[];
249
- /** Structured tool errors lifted from the post-loop parser. */
144
+ /** Connector errors lifted from tool results. */
250
145
  toolErrors: ToolError[];
251
- /** Token usage summary if the response carried one. */
252
146
  usage?: UsageSummary;
253
- /** Grant context, surfaced for logging / multi-tenant context propagation. */
147
+ /** Grant context, for logging and tenant propagation. */
254
148
  grant: GrantContext;
255
149
  }
256
- /**
257
- * Walk the loop's tool results, lift entries that carry the
258
- * `__anuma_connector_error_v1` marker into structured `ToolError`s.
259
- *
260
- * Each `AutoExecutedToolResult.result` is what the executor returned.
261
- * Connector tool factories return the JSON string produced by
262
- * `buildConnectorErrorResult`, so we JSON.parse strings and inspect for
263
- * the marker. Non-string results (objects, arrays, errors) skip the
264
- * parser entirely — they can't be connector errors.
265
- */
150
+ /** Lift tool results carrying the `__anuma_connector_error_v1` marker into structured `ToolError`s. */
266
151
  declare function extractConnectorToolErrors(toolResults: AutoExecutedToolResult[] | undefined): ToolError[];
267
- /**
268
- * Default `requestAccess` passed to connector tool factories from inside
269
- * `runAgentRequest`. Server agents cannot drive interactive OAuth — they
270
- * have no surface to bounce the user through. The factory falls back to
271
- * emitting the canonical connector error JSON when this throws.
272
- */
152
+ /** Default `requestAccess` for server agents: always throws, since they cannot drive interactive OAuth. */
273
153
  declare function denyInteractive(): Promise<string | null>;
154
+ /** Handle one inbound agent request: validate the bearer, build the portal client and tools, run `runToolLoop`, and lift connector errors. @throws Error when the tool loop fails at the transport level. */
274
155
  declare function runAgentRequest(opts: AgentRequestOpts): Promise<AgentResponse>;
275
156
 
276
157
  export { type AgentConfigLike, type AgentRequestOpts, type AgentResponse, AuthError, type AuthErrorSubtype, type ConnectTicket, type ConnectTicketOpts, type ConnectorInfo, type ExtractGrantContextOpts, type GrantContext, type IncomingRequest, type MintError, type MintResult, type PortalClient, type PortalClientOpts, type ToolError, type ToolErrorInfo, type UsageSummary, createConnectorTokenGetter, createPortalClient, denyInteractive, extractConnectorToolErrors, extractGrantContext, runAgentRequest };
package/dist/index.d.ts CHANGED
@@ -3,33 +3,18 @@ export { ConnectorTokenGetterOpts } from '@anuma/sdk/tools';
3
3
  import { LlmapiMessage } from '@anuma/sdk';
4
4
  import { ToolConfig, StreamingTransport, ApiType, AutoExecutedToolResult } from '@anuma/sdk/server';
5
5
 
6
- /**
7
- * Public types for `@anuma/agent-runtime`.
8
- *
9
- * Mirrors the contract in `.claude-docs/connecters/agent-runtime-spec.md`.
10
- * These types are the contract between the SDK / portal vault and any
11
- * server-side consumer (Haven, Sentinel, future SMS handler).
12
- */
13
-
14
- /**
15
- * Parsed result of an incoming bearer token. Returned by
16
- * {@link extractGrantContext}.
17
- */
6
+ /** Parsed result of an incoming bearer token, returned by {@link extractGrantContext}. */
18
7
  interface GrantContext {
19
- /** Wallet address — primary user identifier on the portal. */
8
+ /** Wallet address; the primary user identifier on the portal. */
20
9
  userAddress: string;
21
- /** OAuth `client_id` that owns the bearer (e.g. `"haven_v1"`). */
10
+ /** OAuth `client_id` that owns the bearer, e.g. `"haven_v1"`. */
22
11
  clientId: string;
23
12
  /** Scopes the user granted to this client. */
24
13
  scopes: string[];
25
- /** Bearer token verbatim — for relaying to the portal. */
14
+ /** Bearer token verbatim, for relaying to the portal. */
26
15
  bearer: string;
27
16
  }
28
- /**
29
- * Discriminated result of a mint call. Failures are returned, never
30
- * thrown — transport errors (5xx / network) raise from {@link PortalClient}
31
- * directly.
32
- */
17
+ /** Result of a mint call; HTTP failures, including 5xx after retries, are returned and network errors throw; `expiresAt` is unix ms. */
33
18
  type MintResult = {
34
19
  ok: true;
35
20
  accessToken: string;
@@ -38,11 +23,9 @@ type MintResult = {
38
23
  ok: false;
39
24
  error: MintError;
40
25
  };
41
- /** Variants of `MintResult.error`. Re-exported from the SDK so consumers
42
- * importing only `@anuma/agent-runtime` get the union without a second
43
- * import. */
26
+ /** Variants of `MintResult.error`, re-exported from `@anuma/sdk/tools`. */
44
27
  type MintError = ConnectorMintError;
45
- /** Returned by {@link PortalClient.listConnectors}. */
28
+ /** Returned by {@link PortalClient.listConnectors}; `connectedAt` is unix ms. */
46
29
  interface ConnectorInfo {
47
30
  oauthApp: string;
48
31
  externalAccount?: string;
@@ -51,19 +34,13 @@ interface ConnectorInfo {
51
34
  }
52
35
  /** Argument shape for {@link PortalClient.createConnectTicket}. */
53
36
  interface ConnectTicketOpts {
54
- /** Logical provider (e.g. `"gmail"`, `"github"`) — mapped to the portal
55
- * `oauth_app` internally and used to build the connect URL. */
37
+ /** Logical provider, e.g. `"gmail"` or `"github"`. */
56
38
  provider: string;
57
- /**
58
- * Scopes requested for the connect flow, passed VERBATIM upstream
59
- * ("upstream-flavored"): Google needs full
60
- * `https://www.googleapis.com/auth/...` URLs. An empty array falls back to
61
- * the provider's default scope union on the portal side.
62
- */
39
+ /** Scopes passed verbatim upstream (Google needs full `https://www.googleapis.com/auth/...` URLs); an empty array uses the provider's default scopes. */
63
40
  requestedScopes: string[];
64
41
  returnTo: string;
65
42
  }
66
- /** Result of a ticket-mint call. */
43
+ /** Result of a ticket-mint call; `expiresAt` is unix ms. */
67
44
  interface ConnectTicket {
68
45
  ticketId: string;
69
46
  expiresAt: number;
@@ -71,28 +48,27 @@ interface ConnectTicket {
71
48
  }
72
49
  /** Typed wrapper over the portal HTTP API. */
73
50
  interface PortalClient {
74
- /** Mint a fresh upstream access token for a logical provider. `access`
75
- * defaults to the provider's standard level (e.g. gmail `read`, github
76
- * `repo`). */
51
+ /** Mint an upstream access token for a logical provider; `access` defaults to the provider's standard level. */
77
52
  mintConnectorToken(provider: string, access?: string): Promise<MintResult>;
78
- /** List the user's currently-connected connectors. */
53
+ /** List the user's connected connectors. */
79
54
  listConnectors(): Promise<ConnectorInfo[]>;
80
- /** Mint a connect ticket so the user can be redirected to a connect flow. */
55
+ /** Mint a connect ticket for redirecting the user to a connect flow. */
81
56
  createConnectTicket(opts: ConnectTicketOpts): Promise<ConnectTicket>;
82
57
  }
58
+ /** Options for {@link createPortalClient}. */
83
59
  interface PortalClientOpts {
84
- /** Defaults to `process.env.ANUMA_PORTAL_URL` then the production portal. */
60
+ /** @defaultValue `process.env.ANUMA_PORTAL_URL`, then the production portal */
85
61
  baseUrl?: string;
86
- /** Defaults to `globalThis.fetch`. */
62
+ /** @defaultValue `globalThis.fetch` */
87
63
  fetchImpl?: typeof fetch;
88
- /** Per-request timeout. @default 5000 */
64
+ /** Per-request timeout. @defaultValue 5000 */
89
65
  timeoutMs?: number;
90
- /** Max retry attempts on 5xx / network errors. @default 3 */
66
+ /** Max attempts on 5xx and network errors. @defaultValue 3 */
91
67
  maxRetries?: number;
92
- /** Initial backoff before the second attempt. @default 100 */
68
+ /** Initial backoff before the second attempt. @defaultValue 100 */
93
69
  retryBaseMs?: number;
94
70
  }
95
- /** Structurally-typed incoming request. Any HTTP framework satisfies this. */
71
+ /** Structurally typed incoming request; any HTTP framework satisfies it. */
96
72
  interface IncomingRequest {
97
73
  headers: {
98
74
  authorization?: string;
@@ -100,17 +76,7 @@ interface IncomingRequest {
100
76
  [key: string]: string | string[] | undefined;
101
77
  };
102
78
  }
103
- /**
104
- * Structured tool error lifted from a tool-result message after the loop
105
- * completes. Connector errors carry the canonical
106
- * `__anuma_connector_error_v1` payload; other tool failures may surface
107
- * here in the future.
108
- */
109
- /**
110
- * Open shape so future tool-execution errors can lift into the same union
111
- * without breaking consumers. Connector errors populate `provider`; other
112
- * errors carry a `message`.
113
- */
79
+ /** Structured tool error; connector errors populate `provider`, others carry `message`. */
114
80
  interface ToolErrorInfo {
115
81
  code: string;
116
82
  provider?: string;
@@ -124,153 +90,68 @@ interface ToolError {
124
90
  error: ToolErrorInfo;
125
91
  }
126
92
 
127
- /**
128
- * Error subclasses thrown by `@anuma/agent-runtime`.
129
- *
130
- * - {@link AuthError} comes out of `extractGrantContext` when the bearer is
131
- * missing, malformed, expired, or already revoked.
132
- */
133
93
  /** Discriminant for {@link AuthError}. */
134
94
  type AuthErrorSubtype = "missing_bearer" | "invalid_bearer" | "expired" | "revoked";
95
+ /** Thrown by `extractGrantContext` when the bearer is missing, malformed, expired, or revoked. */
135
96
  declare class AuthError extends Error {
136
97
  readonly subtype: AuthErrorSubtype;
137
98
  constructor(subtype: AuthErrorSubtype, message?: string);
138
99
  }
139
100
 
140
- /**
141
- * Pull the bearer off an incoming request, validate it against the portal,
142
- * and return the parsed grant.
143
- *
144
- * In v1 the portal validates by exposing `GET /api/v1/me`, which returns
145
- * `{ user_address, client_id, scopes }`. A later portal version may switch
146
- * to issuing signed JWTs and let `extractGrantContext` do local decode —
147
- * the consumer signature stays the same.
148
- */
149
-
150
101
  type ExtractGrantContextOpts = Pick<PortalClientOpts, "baseUrl" | "fetchImpl" | "timeoutMs">;
102
+ /** Validate the request's bearer against the portal and return the parsed grant. @throws {@link AuthError} when the bearer is missing, malformed, expired, or revoked. */
151
103
  declare function extractGrantContext(req: IncomingRequest, opts?: ExtractGrantContextOpts): Promise<GrantContext>;
152
104
 
153
- /**
154
- * Typed HTTP client over the portal API.
155
- *
156
- * Retries on 5xx / network errors with exponential backoff + jitter
157
- * (default 3 attempts, base 100ms). Never retries 4xx — those become
158
- * `MintResult.ok=false` (for mint) or thrown errors (for the bookkeeping
159
- * endpoints `listConnectors` / `createConnectTicket`).
160
- *
161
- * Surface is duck-typed against `PortalClient` so test stubs can satisfy
162
- * the same contract.
163
- */
164
-
105
+ /** Create a {@link PortalClient} that retries 5xx and network errors with jittered exponential backoff and never retries 4xx. */
165
106
  declare function createPortalClient(bearer: string, opts?: PortalClientOpts): PortalClient;
166
107
 
167
- /**
168
- * Convenience wrapper that re-exports the SDK's
169
- * `createConnectorTokenGetter` with the same per-instance cache semantics.
170
- *
171
- * The wrapper exists so consumers importing only `@anuma/agent-runtime`
172
- * get the helper as part of a single import surface, without also
173
- * importing `@anuma/sdk/tools` directly. The behavior is identical.
174
- */
175
-
176
108
  declare function createConnectorTokenGetter(client: PortalClient, provider: string, opts?: ConnectorTokenGetterOpts): () => Promise<string | null>;
177
109
 
178
- /**
179
- * `runAgentRequest` — the single function a server-side agent host calls
180
- * per inbound request.
181
- *
182
- * Wires the four pieces together:
183
- * extractGrantContext → createPortalClient → toolFactories → runToolLoop
184
- *
185
- * After the loop returns, walks the auto-executed tool results, lifts any
186
- * payload carrying the canonical `__anuma_connector_error_v1` marker into
187
- * `AgentResponse.toolErrors`. The marker shape is the load-bearing contract
188
- * — every connector tool factory uses `buildConnectorErrorResult` to emit
189
- * it, and the parser keys solely on that marker so it can't false-positive
190
- * on tools that legitimately return JSON.
191
- */
192
-
193
110
  /** Minimal slice of `AgentConfig` this runtime depends on. */
194
111
  interface AgentConfigLike {
195
- /** Model selection — at least `default` must be present. */
196
112
  model: {
197
113
  default: string;
198
114
  };
199
- /** System prompt threaded into the loop. */
200
115
  prompt: string;
201
116
  }
117
+ /** Options for {@link runAgentRequest}. */
202
118
  interface AgentRequestOpts {
203
- /** Inbound request — only `headers.authorization` is read. */
119
+ /** Inbound request; only `headers.authorization` is read. */
204
120
  request: IncomingRequest;
205
- /** Agent configuration (haven, sentinel, …). */
206
121
  agent: AgentConfigLike;
207
- /** Conversation history including the user turn. */
208
122
  messages: LlmapiMessage[];
209
- /** Tool factories that receive the portal client and return `ToolConfig[]`. */
123
+ /** Factories that receive the portal client and return `ToolConfig[]`. */
210
124
  toolFactories?: Array<(portalClient: PortalClient) => ToolConfig[]>;
211
- /** Override portal client opts (test injection). */
125
+ /** Overrides for the portal client, for test injection. */
212
126
  portalClientOpts?: PortalClientOpts;
213
- /**
214
- * Override the streaming transport runToolLoop uses to talk to the
215
- * portal's chat completion API. Production code never sets this — it's
216
- * the injection point e2e tests use to stub LLM behavior without a real
217
- * portal in the loop. Forwarded verbatim to runToolLoop's
218
- * `transport` option.
219
- */
127
+ /** Streaming transport override forwarded to `runToolLoop`, for tests. */
220
128
  transport?: StreamingTransport;
221
- /**
222
- * Optional portal base URL forwarded to runToolLoop for chat completions.
223
- * Defaults to runToolLoop's own default. Setting this without a stub
224
- * `transport` will hit the real portal.
225
- */
129
+ /** Portal base URL for chat completions; without a stub `transport` this hits the real portal. */
226
130
  portalBaseUrl?: string;
227
- /**
228
- * Optional override for the LLM API strategy ("responses" | "completions" | "auto").
229
- * Production callers don't set this — the default ("auto") picks the right
230
- * endpoint for the model. Tests use "completions" with the stub transport
231
- * to feed OpenAI-style streaming chunks.
232
- */
131
+ /** LLM API strategy. @defaultValue `"auto"` */
233
132
  apiType?: ApiType;
234
133
  }
235
- /** Minimal usage summary lifted off the LLM response. */
134
+ /** Token usage lifted off the LLM response. */
236
135
  interface UsageSummary {
237
136
  inputTokens?: number;
238
137
  outputTokens?: number;
239
138
  totalTokens?: number;
240
139
  }
140
+ /** Result of {@link runAgentRequest}. */
241
141
  interface AgentResponse {
242
- /**
243
- * Conversation messages after the loop completes: the input messages,
244
- * followed by tool-result messages for each auto-executed tool, followed
245
- * by the final assistant message. Synthesized — `runToolLoop` doesn't
246
- * expose the full message history directly.
247
- */
142
+ /** Input messages, then an assistant `tool_calls` message and tool-result messages when tools ran, then the final assistant message if present. */
248
143
  messages: LlmapiMessage[];
249
- /** Structured tool errors lifted from the post-loop parser. */
144
+ /** Connector errors lifted from tool results. */
250
145
  toolErrors: ToolError[];
251
- /** Token usage summary if the response carried one. */
252
146
  usage?: UsageSummary;
253
- /** Grant context, surfaced for logging / multi-tenant context propagation. */
147
+ /** Grant context, for logging and tenant propagation. */
254
148
  grant: GrantContext;
255
149
  }
256
- /**
257
- * Walk the loop's tool results, lift entries that carry the
258
- * `__anuma_connector_error_v1` marker into structured `ToolError`s.
259
- *
260
- * Each `AutoExecutedToolResult.result` is what the executor returned.
261
- * Connector tool factories return the JSON string produced by
262
- * `buildConnectorErrorResult`, so we JSON.parse strings and inspect for
263
- * the marker. Non-string results (objects, arrays, errors) skip the
264
- * parser entirely — they can't be connector errors.
265
- */
150
+ /** Lift tool results carrying the `__anuma_connector_error_v1` marker into structured `ToolError`s. */
266
151
  declare function extractConnectorToolErrors(toolResults: AutoExecutedToolResult[] | undefined): ToolError[];
267
- /**
268
- * Default `requestAccess` passed to connector tool factories from inside
269
- * `runAgentRequest`. Server agents cannot drive interactive OAuth — they
270
- * have no surface to bounce the user through. The factory falls back to
271
- * emitting the canonical connector error JSON when this throws.
272
- */
152
+ /** Default `requestAccess` for server agents: always throws, since they cannot drive interactive OAuth. */
273
153
  declare function denyInteractive(): Promise<string | null>;
154
+ /** Handle one inbound agent request: validate the bearer, build the portal client and tools, run `runToolLoop`, and lift connector errors. @throws Error when the tool loop fails at the transport level. */
274
155
  declare function runAgentRequest(opts: AgentRequestOpts): Promise<AgentResponse>;
275
156
 
276
157
  export { type AgentConfigLike, type AgentRequestOpts, type AgentResponse, AuthError, type AuthErrorSubtype, type ConnectTicket, type ConnectTicketOpts, type ConnectorInfo, type ExtractGrantContextOpts, type GrantContext, type IncomingRequest, type MintError, type MintResult, type PortalClient, type PortalClientOpts, type ToolError, type ToolErrorInfo, type UsageSummary, createConnectorTokenGetter, createPortalClient, denyInteractive, extractConnectorToolErrors, extractGrantContext, runAgentRequest };
package/dist/index.mjs CHANGED
@@ -348,10 +348,6 @@ async function runAgentRequest(opts) {
348
348
  model: opts.agent.model.default,
349
349
  token: grant.bearer,
350
350
  tools,
351
- // X-Anuma-Surface drives portal auth/grant keying (OAuth client_id + first-party
352
- // grant surface) — keep it. X-Anuma-Feature is the provenance header the portal
353
- // records into requests.feature (#1353); without it, agent-runtime LLM traffic
354
- // lands feature=null and can't be told apart from chat/background in prod.
355
351
  headers: { "X-Anuma-Surface": "agent", "X-Anuma-Feature": "agent" },
356
352
  ...opts.portalBaseUrl ? { baseUrl: opts.portalBaseUrl } : void 0,
357
353
  ...opts.transport ? { transport: opts.transport } : void 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/agent-runtime",
3
- "version": "6.33.1",
3
+ "version": "6.34.0",
4
4
  "description": "Server-side runtime contract for Anuma agents — extractGrantContext, PortalClient, runAgentRequest.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -30,13 +30,13 @@
30
30
  "access": "public"
31
31
  },
32
32
  "peerDependencies": {
33
- "@anuma/sdk": "6.33.1"
33
+ "@anuma/sdk": "6.34.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsup": "^8.5.1",
37
37
  "typescript": "^5.9.3",
38
38
  "vitest": "^4.1.11",
39
- "@anuma/sdk": "6.33.1"
39
+ "@anuma/sdk": "6.34.0"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsup",