@skydiveai/pi-server 0.1.0-beta.165

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Create, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @skydiveai/pi-server
2
+
3
+ Serve a [pi coding agent](https://github.com/earendil-works) over standard
4
+ LLM API protocols. Platform-agnostic: you supply a `SessionFactory` that
5
+ builds the pi session per request, and compose the handlers into your own
6
+ HTTP server.
7
+
8
+ Protocols:
9
+
10
+ - OpenAI Chat Completions (`POST /v1/chat/completions`, plus mid-turn
11
+ steering via `POST /v1/chat/completions/{id}/steer`)
12
+ - OpenAI Responses (`POST /v1/responses`)
13
+ - Anthropic Messages (`POST /v1/messages`)
14
+ - Google A2A (executor + request-origin-derived agent card)
15
+
16
+ All handlers are web-standard `(Request) => Response | null` functions —
17
+ null means "not mine", so they compose. `webHandlerToMiddleware` /
18
+ `mountAt` / `chainMiddleware` bridge them onto node:http or express
19
+ servers without this package depending on either.
20
+
21
+ Configuration is injection-only: session construction (`createSession`),
22
+ per-turn hooks (`onSessionSetup`, `postPrompt`), forwarded header
23
+ prefixes, and prewarm paths are all options with no platform defaults.
24
+ `@earendil-works/pi-coding-agent` is an exact-pinned peer dependency.
25
+
26
+ See `src/protocols/PROTOCOL.md` for the wire-format reference.
@@ -0,0 +1,545 @@
1
+ import { Logger, Logger as Logger$1 } from "pino";
2
+ import { Api, KnownProvider, Model } from "@earendil-works/pi-ai";
3
+ import { z } from "zod";
4
+ import { SessionManager, ToolDefinition, createAgentSession } from "@earendil-works/pi-coding-agent";
5
+ import { AgentExecutor } from "@a2a-js/sdk/server";
6
+ import { AgentCard } from "@a2a-js/sdk";
7
+ import { IncomingMessage, ServerResponse } from "node:http";
8
+
9
+ //#region src/constants.d.ts
10
+ declare const DEFAULT_PROVIDER = "anthropic";
11
+ declare const DEFAULT_MODEL = "claude-opus-4-7";
12
+ declare const DEFAULT_THINKING_LEVEL = "medium";
13
+ declare const VALID_THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh"];
14
+ declare const PI_AGENT_DIR: string;
15
+ //#endregion
16
+ //#region src/logger.d.ts
17
+ declare const logger: Logger;
18
+ type TraceContext = {
19
+ traceId: string;
20
+ spanId: string;
21
+ parentSpanId: string | null;
22
+ flags: string; /** Full `traceparent` header value to forward to downstreams. */
23
+ traceparent: string;
24
+ };
25
+ declare function newTraceContext(): TraceContext;
26
+ /**
27
+ * Parse an incoming `traceparent` and mint a child span id under the same
28
+ * trace id. The parent span id is preserved so logs can stitch caller and
29
+ * callee. Returns a fresh root context if the header is missing or malformed.
30
+ */
31
+ declare function deriveTraceContext(headerValue: unknown): TraceContext;
32
+ /**
33
+ * Build a per-request child logger pre-bound with trace context. Every event
34
+ * emitted from `req` should go through this logger so it auto-inherits
35
+ * `trace_id`/`span_id`/`parent_span_id`.
36
+ */
37
+ declare function requestLogger(request: Request): {
38
+ log: Logger;
39
+ trace: TraceContext;
40
+ };
41
+ //#endregion
42
+ //#region src/session-registry.d.ts
43
+ type SessionRegistry = {
44
+ get(id: string): AssistantSession | null;
45
+ set(id: string, session: AssistantSession): void;
46
+ delete(id: string): void;
47
+ };
48
+ declare function createMapSessionRegistry(): SessionRegistry;
49
+ //#endregion
50
+ //#region src/protocols/shared.d.ts
51
+ type AssistantSession = Awaited<ReturnType<typeof createAgentSession>>['session'];
52
+ type PostPromptCallback = (args: {
53
+ session: AssistantSession;
54
+ log: Logger$1;
55
+ }) => Promise<void>;
56
+ /**
57
+ * Synchronous hook invoked once per chat request, immediately after
58
+ * `createAgentSession` and before the first `session.prompt(...)` call.
59
+ * Used to install agent-loop callbacks (e.g. `shouldStopAfterTurn`) that
60
+ * pi-coding-agent's `AgentSession` does not surface directly.
61
+ */
62
+ type SessionSetupCallback = (args: {
63
+ session: AssistantSession;
64
+ log: Logger$1;
65
+ }) => void;
66
+ type AgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
67
+ /**
68
+ * Everything a session build needs, resolved by the protocol handlers
69
+ * from the incoming request. The factory implementation lives in the
70
+ * agent's harness workspace (their index.ts) so session policy — skills
71
+ * paths, system prompt handling, steering modes — is theirs to edit.
72
+ */
73
+ type CreateSessionArgs = {
74
+ cwd: string;
75
+ sessionId: string;
76
+ perRequestApiKeys: Partial<Record<KnownProvider, string>>;
77
+ systemPromptOverride: (() => string | undefined) | null; /** Per-request env from the x-shell-env header, if present. */
78
+ shellEnv: Record<string, string> | null;
79
+ model: AgentSessionOptions['model'];
80
+ thinkingLevel: AgentSessionOptions['thinkingLevel'] | null;
81
+ log: Logger$1;
82
+ /**
83
+ * Platform hook (tool-update auto-stop) — call with the created
84
+ * session BEFORE session.bindExtensions().
85
+ */
86
+ onSessionSetup: SessionSetupCallback;
87
+ /**
88
+ * Protocol-supplied work that needs the session manager before the
89
+ * agent session exists (preloading conversation history). Run it
90
+ * concurrently with resource loading.
91
+ */
92
+ prepare: ((args: {
93
+ sessionManager: SessionManager;
94
+ }) => Promise<void>) | null;
95
+ };
96
+ type SessionFactory = (args: CreateSessionArgs) => Promise<{
97
+ session: AssistantSession;
98
+ sessionManager: SessionManager;
99
+ }>;
100
+ type SharedHandlerOptions = {
101
+ cwd?: string;
102
+ createSession: SessionFactory;
103
+ onSessionSetup?: SessionSetupCallback;
104
+ postPrompt?: PostPromptCallback;
105
+ passthroughHeaderPrefixes?: string[];
106
+ };
107
+ //#endregion
108
+ //#region src/protocols/a2a.d.ts
109
+ type A2AOptions = SharedHandlerOptions & {
110
+ agentCard?: Partial<{
111
+ name: string;
112
+ description: string;
113
+ version: string;
114
+ /**
115
+ * Fixed public endpoint URL for the card. When unset, the served
116
+ * card derives it from each request's origin (x-forwarded-* aware),
117
+ * so the card advertises whatever public host reached it.
118
+ */
119
+ url: string;
120
+ skills: Array<{
121
+ id: string;
122
+ name: string;
123
+ description: string;
124
+ }>;
125
+ }>;
126
+ };
127
+ declare function createAgentExecutor(options: A2AOptions): AgentExecutor;
128
+ declare function buildAgentCard(baseUrl: string, overrides: A2AOptions['agentCard']): AgentCard;
129
+ //#endregion
130
+ //#region src/protocols/anthropic-messages.d.ts
131
+ type AnthropicMessagesOptions = SharedHandlerOptions & {
132
+ defaultModel?: string;
133
+ sessionRegistry?: SessionRegistry;
134
+ };
135
+ //#endregion
136
+ //#region src/protocols/chat-completions.d.ts
137
+ type ChatCompletionsOptions = SharedHandlerOptions & {
138
+ getTools?: (request: Request) => Promise<ToolDefinition[]> | ToolDefinition[];
139
+ defaultModel?: string;
140
+ sessionRegistry?: SessionRegistry;
141
+ };
142
+ //#endregion
143
+ //#region src/protocols/responses.d.ts
144
+ type ResponsesOptions = SharedHandlerOptions & {
145
+ defaultModel?: string;
146
+ sessionRegistry?: SessionRegistry;
147
+ };
148
+ //#endregion
149
+ //#region src/protocols/index.d.ts
150
+ type ProtocolName = 'chat-completions' | 'messages' | 'responses';
151
+ type ProtocolHandler = (request: Request) => Promise<Response | null>;
152
+ type ProtocolsOptions = {
153
+ cwd?: string;
154
+ /**
155
+ * Builds the pi agent session for every request. The implementation
156
+ * lives in the agent's harness workspace — session policy (skills
157
+ * paths, system prompt handling, steering modes) is theirs to edit.
158
+ */
159
+ createSession: SessionFactory;
160
+ onSessionSetup?: SessionSetupCallback;
161
+ postPrompt?: PostPromptCallback;
162
+ /**
163
+ * Incoming request header prefixes forwarded to the upstream model
164
+ * call (e.g. for proxy routing hints). None by default.
165
+ */
166
+ passthroughHeaderPrefixes?: string[];
167
+ /**
168
+ * Paths served by the prewarm handler (runs a 1-token chat completion
169
+ * in-process so first real requests skip cold-start). Disabled when
170
+ * empty.
171
+ */
172
+ prewarmPaths?: string[];
173
+ only?: ProtocolName[];
174
+ exclude?: ProtocolName[];
175
+ chatCompletions?: Partial<ChatCompletionsOptions>;
176
+ messages?: Partial<AnthropicMessagesOptions>;
177
+ responses?: Partial<ResponsesOptions>;
178
+ };
179
+ /**
180
+ * Build the individual protocol handlers, each returning null for
181
+ * requests it doesn't recognize. An in-memory session registry backs
182
+ * chat-completions steering unless deliberately overridden.
183
+ */
184
+ declare function createProtocolHandlers(options: ProtocolsOptions): {
185
+ prewarm: (request: Request) => Promise<Response | null>;
186
+ chatCompletions: (request: Request) => Promise<Response | null>;
187
+ messages: (request: Request) => Promise<Response | null>;
188
+ responses: (request: Request) => Promise<Response | null>;
189
+ };
190
+ /** Chain handlers; null when none matched. */
191
+ declare function composeHandlers(handlers: ProtocolHandler[]): ProtocolHandler;
192
+ declare function createProtocols(options: ProtocolsOptions): (request: Request) => Promise<Response>;
193
+ //#endregion
194
+ //#region src/protocols/prewarm.d.ts
195
+ declare function createPrewarm({
196
+ paths,
197
+ chatCompletions
198
+ }: {
199
+ paths: string[];
200
+ chatCompletions: (request: Request) => Promise<Response | null>;
201
+ }): (request: Request) => Promise<Response | null>;
202
+ //#endregion
203
+ //#region src/model-spec.d.ts
204
+ /**
205
+ * Runtime mirror of pi-ai's `KnownProvider` union (which is type-only). The
206
+ * `satisfies` keeps every member valid against the type; new pi-ai providers
207
+ * are admitted by adding them here.
208
+ */
209
+ declare const KNOWN_PI_PROVIDERS: readonly ["amazon-bedrock", "anthropic", "google", "google-vertex", "openai", "azure-openai-responses", "openai-codex", "deepseek", "github-copilot", "xai", "groq", "cerebras", "openrouter", "vercel-ai-gateway", "zai", "mistral", "minimax", "minimax-cn", "moonshotai", "moonshotai-cn", "huggingface", "fireworks", "opencode", "opencode-go", "kimi-coding", "cloudflare-workers-ai", "cloudflare-ai-gateway", "xiaomi", "xiaomi-token-plan-cn", "xiaomi-token-plan-ams", "xiaomi-token-plan-sgp"];
210
+ declare const modelSpecSchema: z.ZodDiscriminatedUnion<"api", [z.ZodObject<{
211
+ api: z.ZodLiteral<"openai-completions">;
212
+ compat: z.ZodOptional<z.ZodObject<{
213
+ supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
214
+ requiresThinkingAsText: z.ZodOptional<z.ZodBoolean>;
215
+ thinkingFormat: z.ZodOptional<z.ZodEnum<["openai", "openrouter", "deepseek", "zai", "qwen", "qwen-chat-template"]>>;
216
+ supportsStrictMode: z.ZodOptional<z.ZodBoolean>;
217
+ maxTokensField: z.ZodOptional<z.ZodEnum<["max_completion_tokens", "max_tokens"]>>;
218
+ cacheControlFormat: z.ZodOptional<z.ZodLiteral<"anthropic">>;
219
+ }, "strip", z.ZodTypeAny, {
220
+ supportsReasoningEffort?: boolean | undefined;
221
+ requiresThinkingAsText?: boolean | undefined;
222
+ thinkingFormat?: "openai" | "deepseek" | "openrouter" | "zai" | "qwen" | "qwen-chat-template" | undefined;
223
+ supportsStrictMode?: boolean | undefined;
224
+ maxTokensField?: "max_completion_tokens" | "max_tokens" | undefined;
225
+ cacheControlFormat?: "anthropic" | undefined;
226
+ }, {
227
+ supportsReasoningEffort?: boolean | undefined;
228
+ requiresThinkingAsText?: boolean | undefined;
229
+ thinkingFormat?: "openai" | "deepseek" | "openrouter" | "zai" | "qwen" | "qwen-chat-template" | undefined;
230
+ supportsStrictMode?: boolean | undefined;
231
+ maxTokensField?: "max_completion_tokens" | "max_tokens" | undefined;
232
+ cacheControlFormat?: "anthropic" | undefined;
233
+ }>>; /** Exact model id the serving endpoint expects. */
234
+ id: z.ZodString; /** Display name shown in pi surfaces and session logs. */
235
+ name: z.ZodString; /** pi-ai provider key — also the auth-storage key for `apiKey`. */
236
+ provider: z.ZodEnum<["amazon-bedrock", "anthropic", "google", "google-vertex", "openai", "azure-openai-responses", "openai-codex", "deepseek", "github-copilot", "xai", "groq", "cerebras", "openrouter", "vercel-ai-gateway", "zai", "mistral", "minimax", "minimax-cn", "moonshotai", "moonshotai-cn", "huggingface", "fireworks", "opencode", "opencode-go", "kimi-coding", "cloudflare-workers-ai", "cloudflare-ai-gateway", "xiaomi", "xiaomi-token-plan-cn", "xiaomi-token-plan-ams", "xiaomi-token-plan-sgp"]>; /** Provider API root, e.g. "https://openrouter.ai/api/v1". */
237
+ baseUrl: z.ZodString;
238
+ reasoning: z.ZodBoolean;
239
+ thinkingLevelMap: z.ZodOptional<z.ZodObject<{
240
+ off: z.ZodOptional<z.ZodNullable<z.ZodString>>;
241
+ minimal: z.ZodOptional<z.ZodNullable<z.ZodString>>;
242
+ low: z.ZodOptional<z.ZodNullable<z.ZodString>>;
243
+ medium: z.ZodOptional<z.ZodNullable<z.ZodString>>;
244
+ high: z.ZodOptional<z.ZodNullable<z.ZodString>>;
245
+ xhigh: z.ZodOptional<z.ZodNullable<z.ZodString>>;
246
+ }, "strip", z.ZodTypeAny, {
247
+ medium?: string | null | undefined;
248
+ off?: string | null | undefined;
249
+ minimal?: string | null | undefined;
250
+ low?: string | null | undefined;
251
+ high?: string | null | undefined;
252
+ xhigh?: string | null | undefined;
253
+ }, {
254
+ medium?: string | null | undefined;
255
+ off?: string | null | undefined;
256
+ minimal?: string | null | undefined;
257
+ low?: string | null | undefined;
258
+ high?: string | null | undefined;
259
+ xhigh?: string | null | undefined;
260
+ }>>;
261
+ input: z.ZodArray<z.ZodEnum<["text", "image"]>, "atleastone">;
262
+ contextWindow: z.ZodNumber;
263
+ maxTokens: z.ZodNumber;
264
+ /**
265
+ * Optional runtime API key for `provider`, installed as a per-request key
266
+ * so the model registry's auth lookup succeeds. Deployments that resolve
267
+ * real credentials elsewhere (e.g. at an egress proxy) can pass whatever
268
+ * placeholder that layer recognizes — the value is opaque to this server.
269
+ */
270
+ apiKey: z.ZodOptional<z.ZodString>;
271
+ }, "strip", z.ZodTypeAny, {
272
+ api: "openai-completions";
273
+ id: string;
274
+ name: string;
275
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
276
+ baseUrl: string;
277
+ reasoning: boolean;
278
+ input: ["text" | "image", ...("text" | "image")[]];
279
+ contextWindow: number;
280
+ maxTokens: number;
281
+ compat?: {
282
+ supportsReasoningEffort?: boolean | undefined;
283
+ requiresThinkingAsText?: boolean | undefined;
284
+ thinkingFormat?: "openai" | "deepseek" | "openrouter" | "zai" | "qwen" | "qwen-chat-template" | undefined;
285
+ supportsStrictMode?: boolean | undefined;
286
+ maxTokensField?: "max_completion_tokens" | "max_tokens" | undefined;
287
+ cacheControlFormat?: "anthropic" | undefined;
288
+ } | undefined;
289
+ thinkingLevelMap?: {
290
+ medium?: string | null | undefined;
291
+ off?: string | null | undefined;
292
+ minimal?: string | null | undefined;
293
+ low?: string | null | undefined;
294
+ high?: string | null | undefined;
295
+ xhigh?: string | null | undefined;
296
+ } | undefined;
297
+ apiKey?: string | undefined;
298
+ }, {
299
+ api: "openai-completions";
300
+ id: string;
301
+ name: string;
302
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
303
+ baseUrl: string;
304
+ reasoning: boolean;
305
+ input: ["text" | "image", ...("text" | "image")[]];
306
+ contextWindow: number;
307
+ maxTokens: number;
308
+ compat?: {
309
+ supportsReasoningEffort?: boolean | undefined;
310
+ requiresThinkingAsText?: boolean | undefined;
311
+ thinkingFormat?: "openai" | "deepseek" | "openrouter" | "zai" | "qwen" | "qwen-chat-template" | undefined;
312
+ supportsStrictMode?: boolean | undefined;
313
+ maxTokensField?: "max_completion_tokens" | "max_tokens" | undefined;
314
+ cacheControlFormat?: "anthropic" | undefined;
315
+ } | undefined;
316
+ thinkingLevelMap?: {
317
+ medium?: string | null | undefined;
318
+ off?: string | null | undefined;
319
+ minimal?: string | null | undefined;
320
+ low?: string | null | undefined;
321
+ high?: string | null | undefined;
322
+ xhigh?: string | null | undefined;
323
+ } | undefined;
324
+ apiKey?: string | undefined;
325
+ }>, z.ZodObject<{
326
+ api: z.ZodLiteral<"anthropic-messages">;
327
+ compat: z.ZodOptional<z.ZodObject<{
328
+ supportsEagerToolInputStreaming: z.ZodOptional<z.ZodBoolean>;
329
+ supportsLongCacheRetention: z.ZodOptional<z.ZodBoolean>;
330
+ }, "strip", z.ZodTypeAny, {
331
+ supportsEagerToolInputStreaming?: boolean | undefined;
332
+ supportsLongCacheRetention?: boolean | undefined;
333
+ }, {
334
+ supportsEagerToolInputStreaming?: boolean | undefined;
335
+ supportsLongCacheRetention?: boolean | undefined;
336
+ }>>; /** Exact model id the serving endpoint expects. */
337
+ id: z.ZodString; /** Display name shown in pi surfaces and session logs. */
338
+ name: z.ZodString; /** pi-ai provider key — also the auth-storage key for `apiKey`. */
339
+ provider: z.ZodEnum<["amazon-bedrock", "anthropic", "google", "google-vertex", "openai", "azure-openai-responses", "openai-codex", "deepseek", "github-copilot", "xai", "groq", "cerebras", "openrouter", "vercel-ai-gateway", "zai", "mistral", "minimax", "minimax-cn", "moonshotai", "moonshotai-cn", "huggingface", "fireworks", "opencode", "opencode-go", "kimi-coding", "cloudflare-workers-ai", "cloudflare-ai-gateway", "xiaomi", "xiaomi-token-plan-cn", "xiaomi-token-plan-ams", "xiaomi-token-plan-sgp"]>; /** Provider API root, e.g. "https://openrouter.ai/api/v1". */
340
+ baseUrl: z.ZodString;
341
+ reasoning: z.ZodBoolean;
342
+ thinkingLevelMap: z.ZodOptional<z.ZodObject<{
343
+ off: z.ZodOptional<z.ZodNullable<z.ZodString>>;
344
+ minimal: z.ZodOptional<z.ZodNullable<z.ZodString>>;
345
+ low: z.ZodOptional<z.ZodNullable<z.ZodString>>;
346
+ medium: z.ZodOptional<z.ZodNullable<z.ZodString>>;
347
+ high: z.ZodOptional<z.ZodNullable<z.ZodString>>;
348
+ xhigh: z.ZodOptional<z.ZodNullable<z.ZodString>>;
349
+ }, "strip", z.ZodTypeAny, {
350
+ medium?: string | null | undefined;
351
+ off?: string | null | undefined;
352
+ minimal?: string | null | undefined;
353
+ low?: string | null | undefined;
354
+ high?: string | null | undefined;
355
+ xhigh?: string | null | undefined;
356
+ }, {
357
+ medium?: string | null | undefined;
358
+ off?: string | null | undefined;
359
+ minimal?: string | null | undefined;
360
+ low?: string | null | undefined;
361
+ high?: string | null | undefined;
362
+ xhigh?: string | null | undefined;
363
+ }>>;
364
+ input: z.ZodArray<z.ZodEnum<["text", "image"]>, "atleastone">;
365
+ contextWindow: z.ZodNumber;
366
+ maxTokens: z.ZodNumber;
367
+ /**
368
+ * Optional runtime API key for `provider`, installed as a per-request key
369
+ * so the model registry's auth lookup succeeds. Deployments that resolve
370
+ * real credentials elsewhere (e.g. at an egress proxy) can pass whatever
371
+ * placeholder that layer recognizes — the value is opaque to this server.
372
+ */
373
+ apiKey: z.ZodOptional<z.ZodString>;
374
+ }, "strip", z.ZodTypeAny, {
375
+ api: "anthropic-messages";
376
+ id: string;
377
+ name: string;
378
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
379
+ baseUrl: string;
380
+ reasoning: boolean;
381
+ input: ["text" | "image", ...("text" | "image")[]];
382
+ contextWindow: number;
383
+ maxTokens: number;
384
+ compat?: {
385
+ supportsEagerToolInputStreaming?: boolean | undefined;
386
+ supportsLongCacheRetention?: boolean | undefined;
387
+ } | undefined;
388
+ thinkingLevelMap?: {
389
+ medium?: string | null | undefined;
390
+ off?: string | null | undefined;
391
+ minimal?: string | null | undefined;
392
+ low?: string | null | undefined;
393
+ high?: string | null | undefined;
394
+ xhigh?: string | null | undefined;
395
+ } | undefined;
396
+ apiKey?: string | undefined;
397
+ }, {
398
+ api: "anthropic-messages";
399
+ id: string;
400
+ name: string;
401
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
402
+ baseUrl: string;
403
+ reasoning: boolean;
404
+ input: ["text" | "image", ...("text" | "image")[]];
405
+ contextWindow: number;
406
+ maxTokens: number;
407
+ compat?: {
408
+ supportsEagerToolInputStreaming?: boolean | undefined;
409
+ supportsLongCacheRetention?: boolean | undefined;
410
+ } | undefined;
411
+ thinkingLevelMap?: {
412
+ medium?: string | null | undefined;
413
+ off?: string | null | undefined;
414
+ minimal?: string | null | undefined;
415
+ low?: string | null | undefined;
416
+ high?: string | null | undefined;
417
+ xhigh?: string | null | undefined;
418
+ } | undefined;
419
+ apiKey?: string | undefined;
420
+ }>]>;
421
+ type ModelSpec = z.infer<typeof modelSpecSchema>;
422
+ /**
423
+ * Parse a request-body `x_model`. Null when absent or invalid — never a
424
+ * request rejection, so a malformed spec degrades to the legacy body-model
425
+ * resolution instead of failing the turn.
426
+ */
427
+ declare function parseModelSpec(input: unknown, log: Logger): ModelSpec | null;
428
+ declare function buildModelFromSpec(spec: ModelSpec): {
429
+ compat?: {
430
+ supportsReasoningEffort?: boolean | undefined;
431
+ requiresThinkingAsText?: boolean | undefined;
432
+ thinkingFormat?: "openai" | "deepseek" | "openrouter" | "zai" | "qwen" | "qwen-chat-template" | undefined;
433
+ supportsStrictMode?: boolean | undefined;
434
+ maxTokensField?: "max_completion_tokens" | "max_tokens" | undefined;
435
+ cacheControlFormat?: "anthropic" | undefined;
436
+ } | undefined;
437
+ api: "openai-completions";
438
+ input: ["text" | "image", ...("text" | "image")[]];
439
+ cost: {
440
+ input: number;
441
+ output: number;
442
+ cacheRead: number;
443
+ cacheWrite: number;
444
+ };
445
+ contextWindow: number;
446
+ maxTokens: number;
447
+ thinkingLevelMap?: {
448
+ medium?: string | null | undefined;
449
+ off?: string | null | undefined;
450
+ minimal?: string | null | undefined;
451
+ low?: string | null | undefined;
452
+ high?: string | null | undefined;
453
+ xhigh?: string | null | undefined;
454
+ } | undefined;
455
+ id: string;
456
+ name: string;
457
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
458
+ baseUrl: string;
459
+ reasoning: boolean;
460
+ } | {
461
+ compat?: {
462
+ supportsEagerToolInputStreaming?: boolean | undefined;
463
+ supportsLongCacheRetention?: boolean | undefined;
464
+ } | undefined;
465
+ api: "anthropic-messages";
466
+ input: ["text" | "image", ...("text" | "image")[]];
467
+ cost: {
468
+ input: number;
469
+ output: number;
470
+ cacheRead: number;
471
+ cacheWrite: number;
472
+ };
473
+ contextWindow: number;
474
+ maxTokens: number;
475
+ thinkingLevelMap?: {
476
+ medium?: string | null | undefined;
477
+ off?: string | null | undefined;
478
+ minimal?: string | null | undefined;
479
+ low?: string | null | undefined;
480
+ high?: string | null | undefined;
481
+ xhigh?: string | null | undefined;
482
+ } | undefined;
483
+ id: string;
484
+ name: string;
485
+ provider: "anthropic" | "amazon-bedrock" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" | "opencode-go" | "kimi-coding" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
486
+ baseUrl: string;
487
+ reasoning: boolean;
488
+ };
489
+ /**
490
+ * Resolve the model a request should run on: a valid `x_model` wins,
491
+ * anything else falls back to registry resolution of the body model. Shared
492
+ * by every transport so they honor the spec identically.
493
+ */
494
+ declare function resolveRequestModel({
495
+ modelInput,
496
+ modelSpecInput,
497
+ defaultModel,
498
+ log
499
+ }: {
500
+ modelInput: unknown;
501
+ modelSpecInput: unknown;
502
+ defaultModel: string | undefined;
503
+ log: Logger;
504
+ }): {
505
+ model: Model<Api>;
506
+ modelSpec: ModelSpec | null;
507
+ };
508
+ /**
509
+ * Install the spec's runtime API key as the per-request key for its
510
+ * provider. A caller-supplied key for the same provider (request headers)
511
+ * always wins.
512
+ */
513
+ declare function withSpecApiKey(keys: Partial<Record<KnownProvider, string>>, modelSpec: ModelSpec | null): Partial<Record<KnownProvider, string>>;
514
+ //#endregion
515
+ //#region src/express.d.ts
516
+ type WebHandler = (request: Request) => Promise<Response | null>;
517
+ type Middleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void;
518
+ declare function requestUrl(req: IncomingMessage): string;
519
+ declare function requestHeaders(req: IncomingMessage): Headers;
520
+ /**
521
+ * Mountable middleware for a web-standard handler. A null result calls
522
+ * next() so unmatched requests fall through to whatever the caller
523
+ * mounts after it.
524
+ */
525
+ declare function webHandlerToMiddleware(handler: WebHandler): Middleware;
526
+ /**
527
+ * Path-scope a middleware the way express mounting does: skip (next())
528
+ * unless the request path matches the prefix, and present a
529
+ * mount-relative req.url to the inner middleware. Lets express-style
530
+ * handlers that expect `app.use('/a2a', h)` participate in a composed
531
+ * catch-all.
532
+ */
533
+ declare function mountAt(prefix: string, middleware: Middleware): Middleware;
534
+ /** Run middlewares in order; each next() advances to the following one. */
535
+ declare function chainMiddleware(middlewares: Middleware[]): Middleware;
536
+ //#endregion
537
+ //#region src/trace-context.d.ts
538
+ declare function runInTraceContext<T>(fn: () => T): T;
539
+ /** No-op when called outside `runInTraceContext`. */
540
+ declare function setCurrentTraceparent(tp: string): void;
541
+ declare function getCurrentTraceparent(): string | null;
542
+ /** Extract the trace id (second segment) from a `traceparent` value. */
543
+ declare function parseTraceId(traceparent: string | null): string | null;
544
+ //#endregion
545
+ export { type A2AOptions, type AnthropicMessagesOptions, type ChatCompletionsOptions, type CreateSessionArgs, DEFAULT_MODEL, DEFAULT_PROVIDER, DEFAULT_THINKING_LEVEL, KNOWN_PI_PROVIDERS, type Middleware, type ModelSpec, PI_AGENT_DIR, type PostPromptCallback, type ProtocolHandler, type ProtocolsOptions, type ResponsesOptions, type SessionFactory, type SessionSetupCallback, type TraceContext, VALID_THINKING_LEVELS, type WebHandler, buildAgentCard, buildModelFromSpec, chainMiddleware, composeHandlers, createAgentExecutor, createMapSessionRegistry, createPrewarm, createProtocolHandlers, createProtocols, deriveTraceContext, getCurrentTraceparent, logger, modelSpecSchema, mountAt, newTraceContext, parseModelSpec, parseTraceId, requestHeaders, requestLogger, requestUrl, resolveRequestModel, runInTraceContext, setCurrentTraceparent, webHandlerToMiddleware, withSpecApiKey };