llm-cli-gateway 2.3.0 → 2.5.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/metrics.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type CliType } from "./session-manager.js";
1
+ import { type ProviderType } from "./session-manager.js";
2
2
  export interface ToolMetricsSnapshot {
3
3
  requestCount: number;
4
4
  successCount: number;
@@ -13,11 +13,11 @@ export interface PerformanceMetricsSnapshot {
13
13
  totalFailures: number;
14
14
  overallSuccessRate: number;
15
15
  overallFailureRate: number;
16
- byTool: Record<CliType, ToolMetricsSnapshot>;
16
+ byTool: Record<ProviderType, ToolMetricsSnapshot>;
17
17
  generatedAt: string;
18
18
  }
19
19
  export declare class PerformanceMetrics {
20
20
  private metrics;
21
- recordRequest(cli: CliType, durationMs: number, success: boolean): void;
21
+ recordRequest(provider: ProviderType, durationMs: number, success: boolean): void;
22
22
  snapshot(): PerformanceMetricsSnapshot;
23
23
  }
package/dist/metrics.js CHANGED
@@ -1,12 +1,12 @@
1
- import { CLI_TYPES } from "./session-manager.js";
2
- const createEmptyMetrics = () => Object.fromEntries(CLI_TYPES.map(cli => [
3
- cli,
1
+ import { PROVIDER_TYPES } from "./session-manager.js";
2
+ const createEmptyMetrics = () => Object.fromEntries(PROVIDER_TYPES.map(provider => [
3
+ provider,
4
4
  { requestCount: 0, successCount: 0, failureCount: 0, totalResponseTimeMs: 0 },
5
5
  ]));
6
6
  export class PerformanceMetrics {
7
7
  metrics = createEmptyMetrics();
8
- recordRequest(cli, durationMs, success) {
9
- const metrics = this.metrics[cli];
8
+ recordRequest(provider, durationMs, success) {
9
+ const metrics = this.metrics[provider];
10
10
  metrics.requestCount += 1;
11
11
  const normalizedDurationMs = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
12
12
  metrics.totalResponseTimeMs += normalizedDurationMs;
@@ -22,12 +22,12 @@ export class PerformanceMetrics {
22
22
  let totalRequests = 0;
23
23
  let totalSuccesses = 0;
24
24
  let totalFailures = 0;
25
- for (const cli of CLI_TYPES) {
26
- const metrics = this.metrics[cli];
25
+ for (const provider of PROVIDER_TYPES) {
26
+ const metrics = this.metrics[provider];
27
27
  const averageResponseTimeMs = metrics.requestCount > 0 ? metrics.totalResponseTimeMs / metrics.requestCount : 0;
28
28
  const successRate = metrics.requestCount > 0 ? metrics.successCount / metrics.requestCount : 0;
29
29
  const failureRate = metrics.requestCount > 0 ? metrics.failureCount / metrics.requestCount : 0;
30
- byTool[cli] = {
30
+ byTool[provider] = {
31
31
  requestCount: metrics.requestCount,
32
32
  successCount: metrics.successCount,
33
33
  failureCount: metrics.failureCount,
@@ -0,0 +1,38 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { Logger } from "./logger.js";
3
+ import { type RemoteOAuthConfig } from "./auth.js";
4
+ export interface OAuthServerOptions {
5
+ protectedPath: string;
6
+ config: RemoteOAuthConfig;
7
+ logger?: Logger;
8
+ }
9
+ export interface OAuthRequestContext {
10
+ req: IncomingMessage;
11
+ res: ServerResponse;
12
+ url: URL;
13
+ baseUrl: string;
14
+ }
15
+ export declare const OAUTH_CODE_TTL_MS: number;
16
+ export declare function generateSecret(bytes?: number): string;
17
+ export declare function hashSecret(secret: string): string;
18
+ export declare function isSecretHash(value: string): boolean;
19
+ export declare function verifySecret(secret: string, encodedHash: string): boolean;
20
+ export declare function redactSecret(value: string | null | undefined): string | null;
21
+ export declare function isLocalHost(host: string): boolean;
22
+ export declare function oauthBaseUrlFromRequest(req: IncomingMessage, config: RemoteOAuthConfig): string | null;
23
+ export declare class OAuthServer {
24
+ private readonly opts;
25
+ private readonly codes;
26
+ private readonly clients;
27
+ constructor(opts: OAuthServerOptions);
28
+ resourceMetadataUrl(baseUrl: string): string;
29
+ isOAuthPath(pathname: string): boolean;
30
+ handle(ctx: OAuthRequestContext): Promise<boolean>;
31
+ private protectedResourceMetadata;
32
+ private authorizationServerMetadata;
33
+ private registrationAllowedByPolicy;
34
+ private handleRegister;
35
+ private handleAuthorize;
36
+ private handleToken;
37
+ private pruneExpiredCodes;
38
+ }
package/dist/oauth.js ADDED
@@ -0,0 +1,441 @@
1
+ import { createHash, randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
2
+ import { URLSearchParams } from "node:url";
3
+ import { issueOAuthAccessToken, timingSafeStringEqual, } from "./auth.js";
4
+ export const OAUTH_CODE_TTL_MS = 5 * 60 * 1000;
5
+ const GENERATED_SECRET_BYTES = 32;
6
+ const SCRYPT_N = 32768;
7
+ const SCRYPT_R = 8;
8
+ const SCRYPT_P = 1;
9
+ const SCRYPT_KEYLEN = 32;
10
+ const SCRYPT_MAXMEM = 64 * 1024 * 1024;
11
+ export function generateSecret(bytes = GENERATED_SECRET_BYTES) {
12
+ return randomBytes(bytes).toString("base64url");
13
+ }
14
+ export function hashSecret(secret) {
15
+ const salt = randomBytes(16);
16
+ const hash = scryptSync(secret, salt, SCRYPT_KEYLEN, {
17
+ N: SCRYPT_N,
18
+ r: SCRYPT_R,
19
+ p: SCRYPT_P,
20
+ maxmem: SCRYPT_MAXMEM,
21
+ });
22
+ return `scrypt:N=${SCRYPT_N},r=${SCRYPT_R},p=${SCRYPT_P}:${salt.toString("base64url")}:${hash.toString("base64url")}`;
23
+ }
24
+ export function isSecretHash(value) {
25
+ return /^scrypt:N=\d+,r=\d+,p=\d+:[A-Za-z0-9_-]+:[A-Za-z0-9_-]+$/.test(value);
26
+ }
27
+ export function verifySecret(secret, encodedHash) {
28
+ const parts = encodedHash.split(":");
29
+ if (parts.length !== 4 || parts[0] !== "scrypt")
30
+ return false;
31
+ const params = Object.fromEntries(parts[1].split(",").map(entry => {
32
+ const [key, value] = entry.split("=");
33
+ return [key, Number(value)];
34
+ }));
35
+ if (!params.N || !params.r || !params.p)
36
+ return false;
37
+ const salt = Buffer.from(parts[2], "base64url");
38
+ const expected = Buffer.from(parts[3], "base64url");
39
+ const actual = scryptSync(secret, salt, expected.length, {
40
+ N: params.N,
41
+ r: params.r,
42
+ p: params.p,
43
+ maxmem: SCRYPT_MAXMEM,
44
+ });
45
+ if (actual.length !== expected.length)
46
+ return false;
47
+ return timingSafeEqual(actual, expected);
48
+ }
49
+ export function redactSecret(value) {
50
+ return value ? "<redacted>" : null;
51
+ }
52
+ function firstHeader(value) {
53
+ return Array.isArray(value) ? value[0] : value;
54
+ }
55
+ function methodNotAllowed(res) {
56
+ res.writeHead(405, { allow: "GET, POST", "content-type": "application/json" });
57
+ res.end(JSON.stringify({ error: "Method not allowed" }));
58
+ }
59
+ function jsonResponse(res, status, body) {
60
+ res.writeHead(status, { "content-type": "application/json" });
61
+ res.end(JSON.stringify(body));
62
+ }
63
+ function isHttpsOrLoopbackUrl(value) {
64
+ try {
65
+ const url = new URL(value);
66
+ if (url.protocol === "https:")
67
+ return true;
68
+ if (url.protocol !== "http:")
69
+ return false;
70
+ return ["localhost", "127.0.0.1", "::1", "[::1]"].includes(url.hostname);
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ export function isLocalHost(host) {
77
+ const hostname = host.split(":")[0]?.toLowerCase() ?? "";
78
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
79
+ }
80
+ export function oauthBaseUrlFromRequest(req, config) {
81
+ if (config.issuer && config.issuer !== "auto") {
82
+ try {
83
+ return new URL(config.issuer).origin;
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ const configured = process.env.LLM_GATEWAY_PUBLIC_URL;
90
+ if (configured) {
91
+ try {
92
+ return new URL(configured).origin;
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ const host = firstHeader(req.headers.host) ?? "127.0.0.1:3333";
99
+ if (!isLocalHost(host))
100
+ return null;
101
+ return `http://${host}`;
102
+ }
103
+ function extractStringArray(value, params, key) {
104
+ const values = Array.isArray(value) ? value : params.getAll(key);
105
+ return values.filter((item) => typeof item === "string" && item.length > 0);
106
+ }
107
+ async function readRawBody(req) {
108
+ return new Promise((resolve, reject) => {
109
+ const chunks = [];
110
+ req.on("data", chunk => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
111
+ req.on("error", reject);
112
+ req.on("end", () => resolve(chunks.length ? Buffer.concat(chunks).toString("utf8") : ""));
113
+ });
114
+ }
115
+ async function readOAuthBody(req) {
116
+ const raw = await readRawBody(req);
117
+ const contentType = firstHeader(req.headers["content-type"]) ?? "";
118
+ if (contentType.includes("application/json")) {
119
+ const parsed = JSON.parse(raw || "{}");
120
+ const params = new URLSearchParams();
121
+ for (const [key, value] of Object.entries(parsed)) {
122
+ if (typeof value === "string")
123
+ params.set(key, value);
124
+ else if (Array.isArray(value)) {
125
+ for (const item of value) {
126
+ if (typeof item === "string")
127
+ params.append(key, item);
128
+ }
129
+ }
130
+ }
131
+ return { params, json: parsed };
132
+ }
133
+ return { params: new URLSearchParams(raw), json: {} };
134
+ }
135
+ function basicClientCredentials(req) {
136
+ const authorization = firstHeader(req.headers.authorization);
137
+ if (!authorization?.startsWith("Basic "))
138
+ return null;
139
+ const raw = Buffer.from(authorization.slice("Basic ".length), "base64").toString("utf8");
140
+ const separator = raw.indexOf(":");
141
+ if (separator < 0)
142
+ return null;
143
+ return {
144
+ clientId: decodeURIComponent(raw.slice(0, separator)),
145
+ clientSecret: decodeURIComponent(raw.slice(separator + 1)),
146
+ };
147
+ }
148
+ function oauthClientSecret(req, params) {
149
+ return params.get("client_secret") ?? basicClientCredentials(req)?.clientSecret ?? null;
150
+ }
151
+ function oauthClientId(req, params) {
152
+ return params.get("client_id") ?? basicClientCredentials(req)?.clientId ?? null;
153
+ }
154
+ function validPkceVerifier(verifier, challenge, method) {
155
+ if (!challenge)
156
+ return true;
157
+ if (!verifier)
158
+ return false;
159
+ if (method === "S256") {
160
+ const digest = createHash("sha256").update(verifier).digest("base64url");
161
+ return timingSafeStringEqual(digest, challenge);
162
+ }
163
+ if (!method || method === "plain") {
164
+ return timingSafeStringEqual(verifier, challenge);
165
+ }
166
+ return false;
167
+ }
168
+ function oauthErrorRedirect(redirectUri, error, state) {
169
+ const target = new URL(redirectUri);
170
+ target.searchParams.set("error", error);
171
+ if (state)
172
+ target.searchParams.set("state", state);
173
+ return target.toString();
174
+ }
175
+ function normalizeScopes(scope) {
176
+ const scopes = (scope ?? "mcp")
177
+ .split(/\s+/)
178
+ .map(item => item.trim())
179
+ .filter(Boolean);
180
+ return [...new Set(scopes.length ? scopes : ["mcp"])];
181
+ }
182
+ function scopesAllowed(requested, client) {
183
+ return requested.every(scope => client.scopes.has(scope));
184
+ }
185
+ function toRuntimeClient(client, allowPublicClients) {
186
+ return {
187
+ clientId: client.clientId,
188
+ clientSecretHash: client.clientSecretHash ?? null,
189
+ redirectUris: new Set(client.allowedRedirectUris),
190
+ scopes: new Set(client.scopes.length ? client.scopes : ["mcp"]),
191
+ issuedAt: Math.floor(Date.now() / 1000),
192
+ publicClient: allowPublicClients && !client.clientSecretHash,
193
+ };
194
+ }
195
+ export class OAuthServer {
196
+ opts;
197
+ codes = new Map();
198
+ clients = new Map();
199
+ constructor(opts) {
200
+ this.opts = opts;
201
+ for (const client of opts.config.clients) {
202
+ this.clients.set(client.clientId, toRuntimeClient(client, opts.config.allowPublicClients));
203
+ }
204
+ }
205
+ resourceMetadataUrl(baseUrl) {
206
+ return `${baseUrl}/.well-known/oauth-protected-resource`;
207
+ }
208
+ isOAuthPath(pathname) {
209
+ return (pathname.startsWith("/.well-known/oauth-protected-resource") ||
210
+ pathname.startsWith("/.well-known/oauth-authorization-server") ||
211
+ pathname === "/.well-known/openid-configuration" ||
212
+ pathname.startsWith("/oauth/"));
213
+ }
214
+ async handle(ctx) {
215
+ const { req, res, url, baseUrl } = ctx;
216
+ if (url.pathname.startsWith("/.well-known/oauth-protected-resource")) {
217
+ if (req.method !== "GET") {
218
+ methodNotAllowed(res);
219
+ return true;
220
+ }
221
+ jsonResponse(res, 200, this.protectedResourceMetadata(baseUrl));
222
+ return true;
223
+ }
224
+ if (url.pathname.startsWith("/.well-known/oauth-authorization-server") ||
225
+ url.pathname === "/.well-known/openid-configuration") {
226
+ if (req.method !== "GET") {
227
+ methodNotAllowed(res);
228
+ return true;
229
+ }
230
+ jsonResponse(res, 200, this.authorizationServerMetadata(baseUrl));
231
+ return true;
232
+ }
233
+ if (url.pathname === "/oauth/register") {
234
+ await this.handleRegister(req, res);
235
+ return true;
236
+ }
237
+ if (url.pathname === "/oauth/authorize") {
238
+ await this.handleAuthorize(req, res);
239
+ return true;
240
+ }
241
+ if (url.pathname === "/oauth/token") {
242
+ await this.handleToken(req, res);
243
+ return true;
244
+ }
245
+ return false;
246
+ }
247
+ protectedResourceMetadata(baseUrl) {
248
+ return {
249
+ resource: `${baseUrl}${this.opts.protectedPath}`,
250
+ authorization_servers: [baseUrl],
251
+ scopes_supported: ["mcp", "workspace:admin"],
252
+ bearer_methods_supported: ["header"],
253
+ };
254
+ }
255
+ authorizationServerMetadata(baseUrl) {
256
+ return {
257
+ issuer: baseUrl,
258
+ authorization_endpoint: `${baseUrl}/oauth/authorize`,
259
+ token_endpoint: `${baseUrl}/oauth/token`,
260
+ registration_endpoint: `${baseUrl}/oauth/register`,
261
+ response_types_supported: ["code"],
262
+ grant_types_supported: ["authorization_code"],
263
+ token_endpoint_auth_methods_supported: this.opts.config.allowPublicClients
264
+ ? ["client_secret_post", "client_secret_basic", "none"]
265
+ : ["client_secret_post", "client_secret_basic"],
266
+ code_challenge_methods_supported: this.opts.config.allowPlainPkce
267
+ ? ["S256", "plain"]
268
+ : ["S256"],
269
+ scopes_supported: ["mcp", "workspace:admin"],
270
+ };
271
+ }
272
+ registrationAllowedByPolicy(req, params) {
273
+ const policy = this.opts.config.registrationPolicy;
274
+ if (policy === "open_dev") {
275
+ const host = firstHeader(req.headers.host) ?? "";
276
+ return isLocalHost(host) || process.env.LLM_GATEWAY_OAUTH_OPEN_DEV === "1";
277
+ }
278
+ if (policy === "static_clients")
279
+ return false;
280
+ const supplied = params.get("shared_secret") ?? params.get("registration_secret");
281
+ if (!supplied || supplied.includes("?"))
282
+ return false;
283
+ const hash = this.opts.config.sharedSecret?.enabled
284
+ ? this.opts.config.sharedSecret.secretHash
285
+ : null;
286
+ return Boolean(hash && verifySecret(supplied, hash));
287
+ }
288
+ async handleRegister(req, res) {
289
+ if (req.method !== "POST") {
290
+ methodNotAllowed(res);
291
+ return;
292
+ }
293
+ const { params, json } = await readOAuthBody(req);
294
+ if (new URL(req.url ?? "/", "http://localhost").searchParams.has("shared_secret")) {
295
+ jsonResponse(res, 400, { error: "invalid_request" });
296
+ return;
297
+ }
298
+ if (!this.registrationAllowedByPolicy(req, params)) {
299
+ jsonResponse(res, 403, { error: "invalid_client" });
300
+ return;
301
+ }
302
+ const redirectUris = extractStringArray(json.redirect_uris, params, "redirect_uris");
303
+ if (redirectUris.length === 0 || redirectUris.some(uri => !isHttpsOrLoopbackUrl(uri))) {
304
+ jsonResponse(res, 400, { error: "invalid_redirect_uri" });
305
+ return;
306
+ }
307
+ const clientId = `llm-cli-gateway-${randomUUID()}`;
308
+ const clientSecret = this.opts.config.allowPublicClients ? null : generateSecret();
309
+ const issuedAt = Math.floor(Date.now() / 1000);
310
+ this.clients.set(clientId, {
311
+ clientId,
312
+ clientSecretHash: clientSecret ? hashSecret(clientSecret) : null,
313
+ redirectUris: new Set(redirectUris),
314
+ scopes: new Set(["mcp"]),
315
+ issuedAt,
316
+ publicClient: !clientSecret,
317
+ });
318
+ jsonResponse(res, 201, {
319
+ client_id: clientId,
320
+ ...(clientSecret ? { client_secret: clientSecret } : {}),
321
+ client_id_issued_at: issuedAt,
322
+ grant_types: ["authorization_code"],
323
+ response_types: ["code"],
324
+ redirect_uris: redirectUris,
325
+ token_endpoint_auth_method: clientSecret ? "client_secret_post" : "none",
326
+ scope: "mcp",
327
+ });
328
+ }
329
+ async handleAuthorize(req, res) {
330
+ if (req.method !== "GET" && req.method !== "POST") {
331
+ methodNotAllowed(res);
332
+ return;
333
+ }
334
+ const params = req.method === "POST"
335
+ ? (await readOAuthBody(req)).params
336
+ : new URL(req.url ?? "/", "http://localhost").searchParams;
337
+ if (params.has("shared_secret")) {
338
+ jsonResponse(res, 400, { error: "invalid_request" });
339
+ return;
340
+ }
341
+ const responseType = params.get("response_type");
342
+ const clientId = params.get("client_id") ?? "";
343
+ const redirectUri = params.get("redirect_uri");
344
+ const state = params.get("state");
345
+ if (!redirectUri) {
346
+ jsonResponse(res, 400, { error: "invalid_request" });
347
+ return;
348
+ }
349
+ const client = this.clients.get(clientId);
350
+ if (!client || !client.redirectUris.has(redirectUri)) {
351
+ jsonResponse(res, 400, { error: "invalid_request" });
352
+ return;
353
+ }
354
+ const method = params.get("code_challenge_method");
355
+ const codeChallenge = params.get("code_challenge");
356
+ if (responseType !== "code" ||
357
+ (this.opts.config.requirePkce && !codeChallenge) ||
358
+ (codeChallenge &&
359
+ method !== "S256" &&
360
+ !(this.opts.config.allowPlainPkce && method === "plain"))) {
361
+ res.writeHead(302, {
362
+ location: oauthErrorRedirect(redirectUri, "invalid_request", state),
363
+ });
364
+ res.end();
365
+ return;
366
+ }
367
+ const requestedScopes = normalizeScopes(params.get("scope"));
368
+ if (!scopesAllowed(requestedScopes, client)) {
369
+ res.writeHead(302, {
370
+ location: oauthErrorRedirect(redirectUri, "invalid_scope", state),
371
+ });
372
+ res.end();
373
+ return;
374
+ }
375
+ this.pruneExpiredCodes();
376
+ const code = randomUUID();
377
+ this.codes.set(code, {
378
+ clientId,
379
+ redirectUri,
380
+ scope: requestedScopes.join(" "),
381
+ codeChallenge,
382
+ codeChallengeMethod: method,
383
+ expiresAt: Date.now() + OAUTH_CODE_TTL_MS,
384
+ });
385
+ const target = new URL(redirectUri);
386
+ target.searchParams.set("code", code);
387
+ if (state)
388
+ target.searchParams.set("state", state);
389
+ res.writeHead(302, { location: target.toString() });
390
+ res.end();
391
+ }
392
+ async handleToken(req, res) {
393
+ if (req.method !== "POST") {
394
+ methodNotAllowed(res);
395
+ return;
396
+ }
397
+ if (new URL(req.url ?? "/", "http://localhost").searchParams.has("client_secret")) {
398
+ jsonResponse(res, 400, { error: "invalid_request" });
399
+ return;
400
+ }
401
+ const { params } = await readOAuthBody(req);
402
+ const code = params.get("code") ?? "";
403
+ const entry = this.codes.get(code);
404
+ const clientId = oauthClientId(req, params);
405
+ const client = clientId ? this.clients.get(clientId) : undefined;
406
+ const clientSecret = oauthClientSecret(req, params);
407
+ const secretOk = client?.publicClient ||
408
+ Boolean(client?.clientSecretHash &&
409
+ clientSecret &&
410
+ verifySecret(clientSecret, client.clientSecretHash));
411
+ if (params.get("grant_type") !== "authorization_code" ||
412
+ !entry ||
413
+ entry.expiresAt < Date.now() ||
414
+ !client ||
415
+ client.clientId !== entry.clientId ||
416
+ !secretOk ||
417
+ params.get("redirect_uri") !== entry.redirectUri ||
418
+ !validPkceVerifier(params.get("code_verifier"), entry.codeChallenge, entry.codeChallengeMethod)) {
419
+ jsonResponse(res, 400, { error: "invalid_grant" });
420
+ return;
421
+ }
422
+ this.codes.delete(code);
423
+ const token = issueOAuthAccessToken({
424
+ clientId: client.clientId,
425
+ scopes: normalizeScopes(entry.scope),
426
+ ttlSeconds: this.opts.config.tokenTtlSeconds,
427
+ });
428
+ jsonResponse(res, 200, {
429
+ access_token: token.accessToken,
430
+ token_type: "Bearer",
431
+ expires_in: token.expiresIn,
432
+ scope: token.scope,
433
+ });
434
+ }
435
+ pruneExpiredCodes(now = Date.now()) {
436
+ for (const [code, entry] of this.codes) {
437
+ if (entry.expiresAt < now)
438
+ this.codes.delete(code);
439
+ }
440
+ }
441
+ }
@@ -0,0 +1,7 @@
1
+ export interface GatewayRequestContext {
2
+ authKind?: "disabled" | "gateway_bearer" | "oauth";
3
+ authScopes: string[];
4
+ authClientId?: string;
5
+ }
6
+ export declare function runWithRequestContext<T>(context: GatewayRequestContext, callback: () => T | Promise<T>): T | Promise<T>;
7
+ export declare function getRequestContext(): GatewayRequestContext | undefined;
@@ -0,0 +1,8 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const requestContext = new AsyncLocalStorage();
3
+ export function runWithRequestContext(context, callback) {
4
+ return requestContext.run(context, callback);
5
+ }
6
+ export function getRequestContext() {
7
+ return requestContext.getStore();
8
+ }
@@ -98,44 +98,44 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
98
98
  effort: z.ZodOptional<z.ZodEnum<["low", "medium", "high", "xhigh", "max"]>>;
99
99
  excludeDynamicSystemPromptSections: z.ZodOptional<z.ZodBoolean>;
100
100
  }, "strip", z.ZodTypeAny, {
101
- agent?: string | undefined;
102
101
  agents?: Record<string, Record<string, unknown>> | undefined;
102
+ agent?: string | undefined;
103
103
  forkSession?: boolean | undefined;
104
104
  systemPrompt?: string | undefined;
105
105
  appendSystemPrompt?: string | undefined;
106
106
  maxBudgetUsd?: number | undefined;
107
107
  maxTurns?: number | undefined;
108
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
108
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
109
109
  excludeDynamicSystemPromptSections?: boolean | undefined;
110
110
  }, {
111
- agent?: string | undefined;
112
111
  agents?: Record<string, Record<string, unknown>> | undefined;
112
+ agent?: string | undefined;
113
113
  forkSession?: boolean | undefined;
114
114
  systemPrompt?: string | undefined;
115
115
  appendSystemPrompt?: string | undefined;
116
116
  maxBudgetUsd?: number | undefined;
117
117
  maxTurns?: number | undefined;
118
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
118
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
119
119
  excludeDynamicSystemPromptSections?: boolean | undefined;
120
120
  }>, {
121
- agent?: string | undefined;
122
121
  agents?: Record<string, Record<string, unknown>> | undefined;
122
+ agent?: string | undefined;
123
123
  forkSession?: boolean | undefined;
124
124
  systemPrompt?: string | undefined;
125
125
  appendSystemPrompt?: string | undefined;
126
126
  maxBudgetUsd?: number | undefined;
127
127
  maxTurns?: number | undefined;
128
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
128
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
129
129
  excludeDynamicSystemPromptSections?: boolean | undefined;
130
130
  }, {
131
- agent?: string | undefined;
132
131
  agents?: Record<string, Record<string, unknown>> | undefined;
132
+ agent?: string | undefined;
133
133
  forkSession?: boolean | undefined;
134
134
  systemPrompt?: string | undefined;
135
135
  appendSystemPrompt?: string | undefined;
136
136
  maxBudgetUsd?: number | undefined;
137
137
  maxTurns?: number | undefined;
138
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
138
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
139
139
  excludeDynamicSystemPromptSections?: boolean | undefined;
140
140
  }>;
141
141
  export declare const CLAUDE_AGENT_DEFINITION_SCHEMA: z.ZodObject<{