@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 +0 -4
- package/dist/index.d.mts +39 -158
- package/dist/index.d.ts +39 -158
- package/dist/index.mjs +0 -4
- package/package.json +3 -3
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
|
|
8
|
+
/** Wallet address; the primary user identifier on the portal. */
|
|
20
9
|
userAddress: string;
|
|
21
|
-
/** OAuth `client_id` that owns the bearer
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
53
|
+
/** List the user's connected connectors. */
|
|
79
54
|
listConnectors(): Promise<ConnectorInfo[]>;
|
|
80
|
-
/** Mint a connect ticket
|
|
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
|
-
/**
|
|
60
|
+
/** @defaultValue `process.env.ANUMA_PORTAL_URL`, then the production portal */
|
|
85
61
|
baseUrl?: string;
|
|
86
|
-
/**
|
|
62
|
+
/** @defaultValue `globalThis.fetch` */
|
|
87
63
|
fetchImpl?: typeof fetch;
|
|
88
|
-
/** Per-request timeout. @
|
|
64
|
+
/** Per-request timeout. @defaultValue 5000 */
|
|
89
65
|
timeoutMs?: number;
|
|
90
|
-
/** Max
|
|
66
|
+
/** Max attempts on 5xx and network errors. @defaultValue 3 */
|
|
91
67
|
maxRetries?: number;
|
|
92
|
-
/** Initial backoff before the second attempt. @
|
|
68
|
+
/** Initial backoff before the second attempt. @defaultValue 100 */
|
|
93
69
|
retryBaseMs?: number;
|
|
94
70
|
}
|
|
95
|
-
/** Structurally
|
|
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
|
|
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
|
-
/**
|
|
123
|
+
/** Factories that receive the portal client and return `ToolConfig[]`. */
|
|
210
124
|
toolFactories?: Array<(portalClient: PortalClient) => ToolConfig[]>;
|
|
211
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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,
|
|
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
|
|
8
|
+
/** Wallet address; the primary user identifier on the portal. */
|
|
20
9
|
userAddress: string;
|
|
21
|
-
/** OAuth `client_id` that owns the bearer
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
53
|
+
/** List the user's connected connectors. */
|
|
79
54
|
listConnectors(): Promise<ConnectorInfo[]>;
|
|
80
|
-
/** Mint a connect ticket
|
|
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
|
-
/**
|
|
60
|
+
/** @defaultValue `process.env.ANUMA_PORTAL_URL`, then the production portal */
|
|
85
61
|
baseUrl?: string;
|
|
86
|
-
/**
|
|
62
|
+
/** @defaultValue `globalThis.fetch` */
|
|
87
63
|
fetchImpl?: typeof fetch;
|
|
88
|
-
/** Per-request timeout. @
|
|
64
|
+
/** Per-request timeout. @defaultValue 5000 */
|
|
89
65
|
timeoutMs?: number;
|
|
90
|
-
/** Max
|
|
66
|
+
/** Max attempts on 5xx and network errors. @defaultValue 3 */
|
|
91
67
|
maxRetries?: number;
|
|
92
|
-
/** Initial backoff before the second attempt. @
|
|
68
|
+
/** Initial backoff before the second attempt. @defaultValue 100 */
|
|
93
69
|
retryBaseMs?: number;
|
|
94
70
|
}
|
|
95
|
-
/** Structurally
|
|
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
|
|
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
|
-
/**
|
|
123
|
+
/** Factories that receive the portal client and return `ToolConfig[]`. */
|
|
210
124
|
toolFactories?: Array<(portalClient: PortalClient) => ToolConfig[]>;
|
|
211
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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,
|
|
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.
|
|
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
|
+
"@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.
|
|
39
|
+
"@anuma/sdk": "6.34.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsup",
|