agent-framework-js 1.0.1 → 1.1.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/CHANGELOG.md CHANGED
@@ -7,16 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [1.0.1] - 2026-06-21
10
+ ## [1.1.0] - 2026-06-24
11
11
 
12
- ### Fixed
12
+ ### Added
13
13
 
14
- - **`GenerateResponse.usage` is now populated with real token counts** from the
15
- OpenAI-compatible (and therefore Copilot) provider, instead of always being
16
- `undefined`. Non-streaming calls read the `usage` object from the response;
17
- streaming calls send `stream_options: { include_usage: true }` and surface the
18
- trailing usage chunk in the final `done` response. OpenAI's
19
- `prompt_tokens`/`completion_tokens` are mapped to `inputTokens`/`outputTokens`.
14
+ - **Custom HTTP headers & secrets for remote MCP servers** (`mcp` module), matching the `mcp.json`
15
+ HTTP server format. The `remote` transport now accepts `headers` (static record or an async
16
+ callback resolved lazily at connect time, so secrets are never persisted) and an optional `type`
17
+ (`"http"` Streamable HTTP the default or `"sse"` for legacy Server-Sent Events servers).
18
+ Empty header values are dropped and values are redacted in logs/traces. `stdio` transport gained
19
+ an optional `env` for extra process environment variables.
20
20
 
21
21
  ## [1.0.0] - 2026-06-17
22
22
 
package/README.md CHANGED
@@ -83,7 +83,7 @@ Prefer **deep imports** for the smallest bundle: `agent-framework-js/agents`,
83
83
  | Agents | `agents` | text + multimodal input, streaming, reasoning field, threads with compaction |
84
84
  | Providers | `providers` | Copilot + OpenAI-compatible; caller-injected credentials; retry/backoff |
85
85
  | Tools | `tools` | local function tools, JSON-Schema validation, namespacing, enable/disable |
86
- | MCP | `mcp` | remote (HTTP/SSE) everywhere; stdio in Node only |
86
+ | MCP | `mcp` | remote (HTTP/SSE) with custom headers everywhere; stdio in Node only |
87
87
  | Skills | `skills` | progressive disclosure; client-side keyword index |
88
88
  | Workflows | `workflows` | sequential / concurrent / handoff / group; HITL; checkpoints |
89
89
  | Middleware | `middleware` | request/response pipeline |
@@ -130,9 +130,6 @@ function createOpenAICompatibleProvider(options) {
130
130
  model: modelOf(req.model).model,
131
131
  messages: toOpenAIMessages(req.messages),
132
132
  stream,
133
- // Ask the API to emit a trailing usage chunk on streamed responses so the
134
- // final `done` response can surface real token counts (FR usage reporting).
135
- ...stream ? { stream_options: { include_usage: true } } : {},
136
133
  ...wire.tools ? { tools: wire.tools } : {}
137
134
  });
138
135
  }
@@ -170,7 +167,6 @@ function createOpenAICompatibleProvider(options) {
170
167
  if (!choice) throw new chunkMQ2XTH3S_cjs.ProviderError("Provider returned no choices", "malformed");
171
168
  const message = choice.message;
172
169
  const reasoningModel = modelOf(req.model).supportsReasoning;
173
- const usage = parseUsage(json["usage"]);
174
170
  let toolCalls = parseToolCalls(message, wire.nameMap);
175
171
  if ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === "tool_calls") {
176
172
  const assembled = await assembleViaStream(req);
@@ -185,16 +181,14 @@ function createOpenAICompatibleProvider(options) {
185
181
  text: message["content"] ?? assembled.text ?? "",
186
182
  reasoning: reasoningModel ? message["reasoning"] ?? assembled.reasoning ?? void 0 : void 0,
187
183
  reasoningOpaque: reasoningModel ? message["reasoning_opaque"] ?? assembled.reasoningOpaque ?? void 0 : void 0,
188
- toolCalls,
189
- usage: usage ?? assembled.usage
184
+ toolCalls
190
185
  };
191
186
  }
192
187
  return {
193
188
  text: message["content"] ?? "",
194
189
  reasoning: reasoningModel ? message["reasoning"] ?? void 0 : void 0,
195
190
  reasoningOpaque: reasoningModel ? message["reasoning_opaque"] ?? void 0 : void 0,
196
- toolCalls,
197
- usage
191
+ toolCalls
198
192
  };
199
193
  }, options.retry);
200
194
  }
@@ -227,7 +221,6 @@ function createOpenAICompatibleProvider(options) {
227
221
  let text = "";
228
222
  let reasoning = "";
229
223
  let reasoningOpaque = "";
230
- let usage;
231
224
  const toolAccum = /* @__PURE__ */ new Map();
232
225
  for (; ; ) {
233
226
  const { value, done } = await reader.read();
@@ -241,8 +234,6 @@ function createOpenAICompatibleProvider(options) {
241
234
  const data = trimmed.slice(5).trim();
242
235
  if (data === "[DONE]") continue;
243
236
  const parsed = safeJson(data);
244
- const chunkUsage = parseUsage(parsed?.usage);
245
- if (chunkUsage) usage = chunkUsage;
246
237
  const delta = parsed?.choices?.[0]?.delta;
247
238
  if (!delta) continue;
248
239
  if (delta.content) {
@@ -282,8 +273,7 @@ function createOpenAICompatibleProvider(options) {
282
273
  text,
283
274
  reasoning: reasoning || void 0,
284
275
  reasoningOpaque: reasoningOpaque || void 0,
285
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
286
- usage
276
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0
287
277
  }
288
278
  };
289
279
  }
@@ -303,14 +293,6 @@ function safeJson(s) {
303
293
  return void 0;
304
294
  }
305
295
  }
306
- function parseUsage(raw) {
307
- if (!raw || typeof raw !== "object") return void 0;
308
- const u = raw;
309
- const inputTokens = typeof u.prompt_tokens === "number" ? u.prompt_tokens : void 0;
310
- const outputTokens = typeof u.completion_tokens === "number" ? u.completion_tokens : void 0;
311
- if (inputTokens === void 0 && outputTokens === void 0) return void 0;
312
- return { inputTokens, outputTokens };
313
- }
314
296
 
315
297
  // src/providers/copilot.ts
316
298
  var DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
@@ -359,5 +341,5 @@ exports.createOpenAICompatibleProvider = createOpenAICompatibleProvider;
359
341
  exports.providerErrorFromStatus = providerErrorFromStatus;
360
342
  exports.resolveModels = resolveModels;
361
343
  exports.withRetry = withRetry;
362
- //# sourceMappingURL=chunk-UEYT6XMA.cjs.map
363
- //# sourceMappingURL=chunk-UEYT6XMA.cjs.map
344
+ //# sourceMappingURL=chunk-JLPLGU7O.cjs.map
345
+ //# sourceMappingURL=chunk-JLPLGU7O.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/provider.ts","../src/providers/retry.ts","../src/providers/openai-compatible.ts","../src/providers/copilot.ts"],"names":["ValidationError","ProviderError","detectRuntime","RuntimeUnsupportedError"],"mappings":"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","file":"chunk-JLPLGU7O.cjs","sourcesContent":["/**\n * LLM provider abstraction. Agents and workflows depend only on this interface,\n * never on a concrete provider, so new providers can be added without changing\n * agent/workflow code. (FR-007)\n *\n * Credentials are always obtained via a caller-supplied callback and are never\n * bundled, persisted, or logged by the framework. (FR-005a, FR-008)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** A caller-supplied source of credentials. The framework never stores the value. */\nexport interface CredentialSource {\n\t/** Return the current credential (token/api key). May be async. */\n\tgetCredential(): string | Promise<string>;\n}\n\n/**\n * Model configuration for a provider. A provider may expose **one or more** models\n * (e.g. GitHub Copilot offers several; an OpenAI-compatible endpoint is usually one).\n * Supply either a single `capabilities` object or an array via `models`.\n */\nexport interface ModelSelectionOptions {\n\t/** Single-model shorthand. */\n\tcapabilities?: ModelCapabilities;\n\t/** One or more models this provider can use. */\n\tmodels?: ModelCapabilities[];\n\t/** Name of the default model (defaults to the first entry). */\n\tdefaultModel?: string;\n}\n\n/** Resolved model set with a default and a lookup helper. */\nexport interface ResolvedModels {\n\t/** All configured models (at least one). */\n\tmodels: ModelCapabilities[];\n\t/** The default model used when a request does not specify one. */\n\tdefaultModel: ModelCapabilities;\n\t/** Look up a model by name, or return the default when omitted. */\n\tmodelOf(name?: string): ModelCapabilities;\n}\n\n/**\n * Normalize {@link ModelSelectionOptions} into a model list, a default, and a\n * lookup helper. Throws {@link ValidationError} if no model is configured or a\n * named model is missing.\n *\n * @example\n * ```ts\n * const { defaultModel, modelOf } = resolveModels({\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * ```\n */\nexport function resolveModels(options: ModelSelectionOptions): ResolvedModels {\n\tconst models = options.models ?? (options.capabilities ? [options.capabilities] : []);\n\tif (models.length === 0) {\n\t\tthrow new ValidationError(\"Provider requires at least one model (set `capabilities` or `models`)\");\n\t}\n\tconst defaultModel = options.defaultModel\n\t\t? models.find((m) => m.model === options.defaultModel)\n\t\t: models[0];\n\tif (!defaultModel) {\n\t\tthrow new ValidationError(`defaultModel \"${options.defaultModel}\" is not present in models`);\n\t}\n\tconst modelOf = (name?: string): ModelCapabilities => {\n\t\tif (!name) return defaultModel;\n\t\tconst found = models.find((m) => m.model === name);\n\t\tif (!found) {\n\t\t\tthrow new ValidationError(`Model \"${name}\" is not configured for this provider`);\n\t\t}\n\t\treturn found;\n\t};\n\treturn { models, defaultModel, modelOf };\n}\n\n/** A tool description passed to the provider so the model can decide to call it. */\nexport interface ToolSpec {\n\tname: string;\n\tdescription: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/** A request to generate a model response. */\nexport interface GenerateRequest {\n\tmessages: Message[];\n\ttools?: ToolSpec[];\n\t/** Which configured model to use; defaults to the provider's default model. */\n\tmodel?: string;\n\t/** Abort signal to cancel an in-flight request. */\n\tsignal?: AbortSignal;\n}\n\n/** A tool call requested by the model. */\nexport interface ToolCall {\n\tid: string;\n\tname: string;\n\t/** Raw JSON arguments (validated by the tools module before invocation). */\n\targuments: unknown;\n}\n\n/** A complete (non-streaming) model response. */\nexport interface GenerateResponse {\n\t/** Final answer text. */\n\ttext: string;\n\t/** Reasoning/thinking content — only present for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\t/**\n\t * Opaque reasoning blob (e.g. Claude thinking signature) to round-trip on the\n\t * next assistant turn for thinking continuity. Never logged or inspected.\n\t */\n\treasoningOpaque?: string;\n\t/** Tool calls the model wants to make, if any. */\n\ttoolCalls?: ToolCall[];\n\t/** Approximate token usage if reported by the provider. */\n\tusage?: { inputTokens?: number; outputTokens?: number };\n}\n\n/** An incremental streaming chunk. */\nexport type GenerateChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"tool-call\"; toolCall: ToolCall }\n\t| { type: \"done\"; response: GenerateResponse };\n\n/**\n * An LLM backend. Implementations adapt a concrete API (Copilot, OpenAI-compatible)\n * onto this uniform surface.\n */\nexport interface Provider {\n\t/** Stable provider identifier, e.g. `\"openai-compatible\"`. */\n\treadonly name: string;\n\t/** The default model's capability configuration. (FR-007a) */\n\treadonly capabilities: ModelCapabilities;\n\t/** All models this provider is configured with (one or more). */\n\treadonly models: ModelCapabilities[];\n\t/** Look up a configured model by name, or the default when omitted. */\n\tmodel(name?: string): ModelCapabilities;\n\t/** Generate a complete response. */\n\tgenerate(req: GenerateRequest): Promise<GenerateResponse>;\n\t/** Generate a streamed response. */\n\tgenerateStream(req: GenerateRequest): AsyncIterable<GenerateChunk>;\n}\n","/**\n * Exponential-backoff retry for transient provider failures. Transient errors\n * (429 with Retry-After, 5xx, network/timeout) are retried; auth/4xx fail fast.\n * (FR-008a)\n *\n * @packageDocumentation\n */\n\nimport { ProviderError } from \"../core/errors.js\";\n\n/** Retry tuning. All fields have safe defaults. */\nexport interface RetryOptions {\n\t/** Maximum retry attempts after the first try. Default 3. */\n\tmaxRetries?: number;\n\t/** Base delay in ms for backoff. Default 250. */\n\tbaseDelayMs?: number;\n\t/** Maximum delay cap in ms. Default 8000. */\n\tmaxDelayMs?: number;\n}\n\nconst DEFAULTS: Required<RetryOptions> = {\n\tmaxRetries: 3,\n\tbaseDelayMs: 250,\n\tmaxDelayMs: 8000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Run `fn`, retrying transient {@link ProviderError}s with exponential backoff\n * and jitter. Non-transient errors are rethrown immediately (fail fast).\n *\n * @param fn - The operation to attempt. It should throw a {@link ProviderError}.\n * @param opts - Retry tuning.\n * @param retryAfterMs - Optional hook returning a server-specified delay (Retry-After).\n */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\topts?: RetryOptions,\n\tretryAfterMs?: (err: ProviderError) => number | undefined,\n): Promise<T> {\n\tconst cfg = { ...DEFAULTS, ...opts };\n\tlet attempt = 0;\n\n\tfor (; ;) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst isRetryable = err instanceof ProviderError && err.retryable;\n\t\t\tif (!isRetryable || attempt >= cfg.maxRetries) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tconst serverDelay = retryAfterMs?.(err as ProviderError);\n\t\t\tconst backoff = Math.min(cfg.baseDelayMs * 2 ** attempt, cfg.maxDelayMs);\n\t\t\tconst jitter = Math.random() * cfg.baseDelayMs;\n\t\t\tawait sleep(serverDelay ?? backoff + jitter);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\n/** Map an HTTP status to a {@link ProviderError} with the right retry semantics. */\nexport function providerErrorFromStatus(status: number, message: string): ProviderError {\n\tif (status === 429 || status >= 500) {\n\t\treturn new ProviderError(message, \"transient\", { status });\n\t}\n\tif (status === 401 || status === 403) {\n\t\treturn new ProviderError(message, \"auth\", { status });\n\t}\n\treturn new ProviderError(message, \"client\", { status });\n}\n","/**\n * OpenAI-compatible provider. Targets any endpoint speaking the OpenAI\n * `/chat/completions` API, including local servers such as LM Studio via a custom\n * `baseUrl`, and GitHub Copilot (see {@link createCopilotProvider}). (FR-006)\n *\n * Provider compatibility notes (handled here so callers don't have to):\n * - Tool names are sanitized to `^[a-zA-Z0-9_-]+$` on the wire (OpenAI/Copilot\n * reject dotted names like `webiq.browse`) and translated back to the registry\n * key when the model calls them.\n * - Assistant turns that requested tools emit `tool_calls` with `content: null`\n * so strict providers (e.g. Anthropic) can pair each tool result with its call.\n * - Streaming responses accumulate `delta.tool_calls[]` keyed by `index`\n * (fragments may start at a non-zero index when reasoning occupies 0/1).\n * - Some reasoning models report `finish_reason: \"tool_calls\"` from the\n * non-streaming endpoint without a `tool_calls` array; `generate` transparently\n * re-requests in streaming mode and assembles them, failing loud (typed\n * {@link ProviderError}) rather than silently stopping if none materialize.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart, MessageToolCall } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type {\n\tProvider,\n\tCredentialSource,\n\tGenerateRequest,\n\tGenerateResponse,\n\tGenerateChunk,\n\tToolCall,\n\tToolSpec,\n} from \"./provider.js\";\nimport { resolveModels, type ModelSelectionOptions } from \"./provider.js\";\nimport { withRetry, providerErrorFromStatus, type RetryOptions } from \"./retry.js\";\n\n/**\n * Options for {@link createOpenAICompatibleProvider}.\n *\n * Supply a single model via `capabilities`, or multiple via `models` (most\n * OpenAI-compatible endpoints expose one model, but multiple are supported).\n */\nexport interface OpenAICompatibleProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Base URL of the OpenAI-compatible API, e.g. `http://localhost:1234/v1`. */\n\tbaseUrl: string;\n\t/**\n\t * Extra request headers merged into every call (e.g. provider-required\n\t * identification headers). The `authorization` header is always set from\n\t * `getCredential()` and cannot be overridden here.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface OpenAIMessage {\n\trole: string;\n\tcontent: unknown;\n\ttool_calls?: Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }>;\n\ttool_call_id?: string;\n\tname?: string;\n\treasoning_opaque?: string;\n}\n\n/** OpenAI/Copilot require tool names to match `^[a-zA-Z0-9_-]{1,128}$`. */\nconst UNSAFE_TOOL_NAME_CHARS = /[^a-zA-Z0-9_-]/g;\n\n/**\n * Sanitize a (possibly namespaced) tool name for the wire. Dotted MCP names like\n * `webiq.browse` become `webiq_browse`; the original is recovered via the\n * per-request name map when the model calls the tool.\n */\nfunction sanitizeToolName(name: string): string {\n\treturn name.replace(UNSAFE_TOOL_NAME_CHARS, \"_\");\n}\n\nfunction toOpenAIContent(parts: ContentPart[]): unknown {\n\tif (parts.every((p) => p.type === \"text\")) {\n\t\treturn parts.map((p) => (p as { text: string }).text).join(\"\");\n\t}\n\treturn parts.map((p) =>\n\t\tp.type === \"text\"\n\t\t\t? { type: \"text\", text: p.text }\n\t\t\t: { type: \"image_url\", image_url: { url: p.data } },\n\t);\n}\n\nfunction toWireToolCalls(\n\ttoolCalls: MessageToolCall[],\n): Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }> {\n\treturn toolCalls.map((tc) => ({\n\t\tid: tc.id,\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: sanitizeToolName(tc.name),\n\t\t\targuments:\n\t\t\t\ttypeof tc.arguments === \"string\" ? tc.arguments : JSON.stringify(tc.arguments ?? {}),\n\t\t},\n\t}));\n}\n\nfunction toOpenAIMessages(messages: Message[]): OpenAIMessage[] {\n\treturn messages.map((m) => {\n\t\tconst msg: OpenAIMessage = { role: m.role, content: toOpenAIContent(m.parts) };\n\t\tif (m.toolCalls && m.toolCalls.length > 0) {\n\t\t\tmsg.tool_calls = toWireToolCalls(m.toolCalls);\n\t\t\t// Strict providers require `content: null` (not \"\") on an assistant turn\n\t\t\t// that only carries tool calls.\n\t\t\tconst hasText = m.parts.some((p) => p.type === \"text\" && p.text.length > 0);\n\t\t\tif (!hasText) msg.content = null;\n\t\t}\n\t\tif (m.toolCallId) msg.tool_call_id = m.toolCallId;\n\t\tif (m.name) msg.name = sanitizeToolName(m.name);\n\t\tif (m.reasoningOpaque) msg.reasoning_opaque = m.reasoningOpaque;\n\t\treturn msg;\n\t});\n}\n\n/** Wire tool specs plus a map from sanitized name back to the registry key. */\ninterface WireTools {\n\ttools?: Array<{ type: \"function\"; function: { name: string; description: string; parameters: unknown } }>;\n\tnameMap: Map<string, string>;\n}\n\nfunction buildWireTools(specs?: ToolSpec[]): WireTools {\n\tconst nameMap = new Map<string, string>();\n\tif (!specs || specs.length === 0) return { tools: undefined, nameMap };\n\tconst tools = specs.map((t) => {\n\t\tconst wireName = sanitizeToolName(t.name);\n\t\tnameMap.set(wireName, t.name);\n\t\treturn {\n\t\t\ttype: \"function\" as const,\n\t\t\tfunction: { name: wireName, description: t.description, parameters: t.inputSchema },\n\t\t};\n\t});\n\treturn { tools, nameMap };\n}\n\n/**\n * Create an OpenAI-compatible provider (works with LM Studio, vLLM, etc.).\n *\n * @example\n * ```ts\n * const provider = createOpenAICompatibleProvider({\n * baseUrl: \"http://localhost:1234/v1\",\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * capabilities: { model: \"local\", maxInputTokens: 262144, maxOutputTokens: 32000 },\n * });\n * ```\n */\nexport function createOpenAICompatibleProvider(\n\toptions: OpenAICompatibleProviderOptions,\n): Provider {\n\tconst doFetch = options.fetchImpl ?? globalThis.fetch;\n\tconst url = `${options.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\tconst { models, defaultModel, modelOf } = resolveModels(options);\n\n\tasync function authHeaders(): Promise<Record<string, string>> {\n\t\tconst cred = await options.getCredential();\n\t\t// content-type first, then caller headers (may override it), then the\n\t\t// credential-derived authorization which always wins.\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(options.headers ?? {}),\n\t\t};\n\t\tif (cred) headers[\"authorization\"] = `Bearer ${cred}`;\n\t\treturn headers;\n\t}\n\n\tfunction body(req: GenerateRequest, stream: boolean, wire: WireTools): string {\n\t\treturn JSON.stringify({\n\t\t\tmodel: modelOf(req.model).model,\n\t\t\tmessages: toOpenAIMessages(req.messages),\n\t\t\tstream,\n\t\t\t...(wire.tools ? { tools: wire.tools } : {}),\n\t\t});\n\t}\n\n\tfunction parseToolCalls(raw: unknown, nameMap: Map<string, string>): ToolCall[] | undefined {\n\t\tconst calls = (raw as {\n\t\t\ttool_calls?: Array<{ id: string; function: { name: string; arguments: string } }>;\n\t\t})?.tool_calls;\n\t\tif (!calls || calls.length === 0) return undefined;\n\t\treturn calls.map((c) => ({\n\t\t\tid: c.id,\n\t\t\tname: nameMap.get(c.function.name) ?? c.function.name,\n\t\t\targuments: safeJson(c.function.arguments),\n\t\t}));\n\t}\n\n\tasync function generate(req: GenerateRequest): Promise<GenerateResponse> {\n\t\treturn withRetry(async () => {\n\t\t\tconst wire = buildWireTools(req.tools);\n\t\t\tlet res: Response;\n\t\t\ttry {\n\t\t\t\tres = await doFetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: await authHeaders(),\n\t\t\t\t\tbody: body(req, false, wire),\n\t\t\t\t\tsignal: req.signal,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t\t}\n\t\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\n\t\t\tlet json: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tjson = (await res.json()) as Record<string, unknown>;\n\t\t\t} catch {\n\t\t\t\tthrow new ProviderError(\"Malformed provider response\", \"malformed\");\n\t\t\t}\n\t\t\tconst choice = (\n\t\t\t\tjson[\"choices\"] as Array<{ message: Record<string, unknown>; finish_reason?: string }>\n\t\t\t)?.[0];\n\t\t\tif (!choice) throw new ProviderError(\"Provider returned no choices\", \"malformed\");\n\t\t\tconst message = choice.message;\n\t\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\t\tlet toolCalls = parseToolCalls(message, wire.nameMap);\n\n\t\t\t// Bug 4(b): some reasoning models report `finish_reason: \"tool_calls\"` from\n\t\t\t// the non-streaming endpoint without a `tool_calls` array. Re-request in\n\t\t\t// streaming mode and assemble them so the agent loop can proceed.\n\t\t\tif ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === \"tool_calls\") {\n\t\t\t\tconst assembled = await assembleViaStream(req);\n\t\t\t\ttoolCalls = assembled.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t\t\"Provider signaled tool_calls but returned none (even when streamed)\",\n\t\t\t\t\t\t\"malformed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: (message[\"content\"] as string) ?? assembled.text ?? \"\",\n\t\t\t\t\treasoning: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning\"] as string) ?? assembled.reasoning ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? assembled.reasoningOpaque ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\ttoolCalls,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: (message[\"content\"] as string) ?? \"\",\n\t\t\t\treasoning: reasoningModel ? ((message[\"reasoning\"] as string) ?? undefined) : undefined,\n\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t\ttoolCalls,\n\t\t\t};\n\t\t}, options.retry);\n\t}\n\n\t/** Drive a streaming request to completion and return its assembled final response. */\n\tasync function assembleViaStream(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tlet final: GenerateResponse = { text: \"\" };\n\t\tfor await (const chunk of generateStream(req)) {\n\t\t\tif (chunk.type === \"done\") final = chunk.response;\n\t\t}\n\t\treturn final;\n\t}\n\n\tasync function* generateStream(req: GenerateRequest): AsyncIterable<GenerateChunk> {\n\t\tconst wire = buildWireTools(req.tools);\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await doFetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: await authHeaders(),\n\t\t\t\tbody: body(req, true, wire),\n\t\t\t\tsignal: req.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t}\n\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\t\tif (!res.body) throw new ProviderError(\"Provider returned no stream body\", \"malformed\");\n\n\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\tconst reader = res.body.getReader();\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet text = \"\";\n\t\tlet reasoning = \"\";\n\t\tlet reasoningOpaque = \"\";\n\t\t// Accumulate streamed tool-call fragments keyed by their `index` (which may\n\t\t// start at a non-zero value when reasoning deltas occupy the first indices).\n\t\tconst toolAccum = new Map<number, { id?: string; name?: string; args: string }>();\n\n\t\tfor (; ;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst trimmed = line.trim();\n\t\t\t\tif (!trimmed.startsWith(\"data:\")) continue;\n\t\t\t\tconst data = trimmed.slice(5).trim();\n\t\t\t\tif (data === \"[DONE]\") continue;\n\t\t\t\tconst parsed = safeJson(data) as\n\t\t\t\t\t| {\n\t\t\t\t\t\tchoices?: Array<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\treasoning?: string;\n\t\t\t\t\t\t\t\treasoning_opaque?: string;\n\t\t\t\t\t\t\t\ttool_calls?: Array<{\n\t\t\t\t\t\t\t\t\tindex?: number;\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}>;\n\t\t\t\t\t}\n\t\t\t\t\t| undefined;\n\t\t\t\tconst delta = parsed?.choices?.[0]?.delta;\n\t\t\t\tif (!delta) continue;\n\t\t\t\tif (delta.content) {\n\t\t\t\t\ttext += delta.content;\n\t\t\t\t\tyield { type: \"text\", text: delta.content };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning && reasoningModel) {\n\t\t\t\t\treasoning += delta.reasoning;\n\t\t\t\t\tyield { type: \"reasoning\", text: delta.reasoning };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning_opaque && reasoningModel) {\n\t\t\t\t\treasoningOpaque += delta.reasoning_opaque;\n\t\t\t\t}\n\t\t\t\tif (delta.tool_calls) {\n\t\t\t\t\tfor (const frag of delta.tool_calls) {\n\t\t\t\t\t\tconst idx = frag.index ?? 0;\n\t\t\t\t\t\tconst slot = toolAccum.get(idx) ?? { args: \"\" };\n\t\t\t\t\t\tif (frag.id) slot.id = frag.id;\n\t\t\t\t\t\tif (frag.function?.name) slot.name = frag.function.name;\n\t\t\t\t\t\tif (frag.function?.arguments) slot.args += frag.function.arguments;\n\t\t\t\t\t\ttoolAccum.set(idx, slot);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Materialize accumulated tool calls (sorted by stream index) and surface\n\t\t// them both as chunks and in the final `done` response.\n\t\tconst toolCalls: ToolCall[] = [...toolAccum.entries()]\n\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t.filter(([, s]) => s.name)\n\t\t\t.map(([idx, s]) => ({\n\t\t\t\tid: s.id ?? `call_${idx}`,\n\t\t\t\tname: wire.nameMap.get(s.name as string) ?? (s.name as string),\n\t\t\t\targuments: safeJson(s.args) ?? {},\n\t\t\t}));\n\t\tfor (const toolCall of toolCalls) {\n\t\t\tyield { type: \"tool-call\", toolCall };\n\t\t}\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresponse: {\n\t\t\t\ttext,\n\t\t\t\treasoning: reasoning || undefined,\n\t\t\t\treasoningOpaque: reasoningOpaque || undefined,\n\t\t\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tname: \"openai-compatible\",\n\t\tcapabilities: defaultModel,\n\t\tmodels,\n\t\tmodel: modelOf,\n\t\tgenerate,\n\t\tgenerateStream,\n\t};\n}\n\nfunction safeJson(s: string): unknown {\n\ttry {\n\t\treturn JSON.parse(s);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n","/**\n * GitHub Copilot provider. (FR-005)\n *\n * Copilot's chat API is OpenAI-compatible, so this provider configures the shared\n * OpenAI-compatible transport with Copilot's endpoint and the caller-supplied\n * credential (a Copilot/GitHub token). The token is obtained via callback and is\n * never bundled, persisted, or logged. (FR-005a)\n *\n * In a frontend-only deployment the end user supplies their own token (it stays\n * client-side); in a backend deployment the developer may supply it, or the user\n * sends it per request over SSL/TLS and the backend must not log or persist it.\n *\n * Note: the Copilot API (`api.githubcopilot.com`) sends no CORS headers, so it\n * cannot be called directly from a browser. A browser deployment must route through\n * a backend/proxy (set `baseUrl` to it); constructing this provider in a browser\n * against the default host throws {@link RuntimeUnsupportedError}.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, CredentialSource, ModelSelectionOptions } from \"./provider.js\";\nimport type { RetryOptions } from \"./retry.js\";\nimport { createOpenAICompatibleProvider } from \"./openai-compatible.js\";\nimport { detectRuntime } from \"../core/runtime.js\";\nimport { RuntimeUnsupportedError } from \"../core/errors.js\";\n\n/** Default Copilot-compatible chat completions base URL. */\nconst DEFAULT_COPILOT_BASE_URL = \"https://api.githubcopilot.com\";\n\n/**\n * Headers `api.githubcopilot.com` requires on every request. Omitting any of\n * these causes the API to reject the call with HTTP 400. They are sent by default\n * and can be overridden per option via `headers`.\n */\nconst COPILOT_DEFAULT_HEADERS: Record<string, string> = {\n\t\"Editor-Version\": \"vscode/1.95.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.20.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n\t\"Openai-Intent\": \"conversation-panel\",\n};\n\n/**\n * Options for {@link createCopilotProvider}.\n *\n * GitHub Copilot exposes several models, so configure them via `models` (with an\n * optional `defaultModel`). A single `capabilities` object is also accepted.\n */\nexport interface CopilotProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Override the Copilot base URL if needed. */\n\tbaseUrl?: string;\n\t/**\n\t * Extra/override request headers. Merged over the required Copilot defaults\n\t * (`Editor-Version`, `Editor-Plugin-Version`, `Copilot-Integration-Id`,\n\t * `Openai-Intent`), so you can adjust them without losing the others.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Create a GitHub Copilot provider.\n *\n * @example Single model\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken, // never logged or persisted\n * capabilities: { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * });\n * ```\n *\n * @example Multiple models\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken,\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * // Pick a model per request: provider.generate({ messages, model: \"o3-mini\" })\n * ```\n *\n * @throws {RuntimeUnsupportedError} when constructed in a browser against the\n * default Copilot host. `api.githubcopilot.com` does not send CORS headers, so a\n * browser cannot call it directly — host a small backend/proxy and point `baseUrl`\n * at it (which lifts this guard), or run the provider server-side (Node/edge).\n */\nexport function createCopilotProvider(options: CopilotProviderOptions): Provider {\n\tconst baseUrl = options.baseUrl ?? DEFAULT_COPILOT_BASE_URL;\n\n\t// Frontend-only guard: the Copilot API has no CORS support, so a browser must\n\t// route through a backend/proxy. Setting a custom `baseUrl` (your proxy) is the\n\t// supported opt-in and lifts this guard. Edge/Node (server-side) are unaffected.\n\tconst usingDefaultHost = baseUrl === DEFAULT_COPILOT_BASE_URL;\n\tif (usingDefaultHost && detectRuntime().isBrowser) {\n\t\tthrow new RuntimeUnsupportedError(\n\t\t\t\"GitHub Copilot directly from a browser (the Copilot API sends no CORS headers)\",\n\t\t\t{\n\t\t\t\treason: \"cors\",\n\t\t\t\tremedy:\n\t\t\t\t\t\"Run a lightweight backend/proxy (e.g. a Vite dev-server proxy or a small server route) \" +\n\t\t\t\t\t\"that forwards to https://api.githubcopilot.com, then set `baseUrl` to your proxy URL. \" +\n\t\t\t\t\t\"Alternatively, run the Copilot provider server-side (Node or an edge function).\",\n\t\t\t},\n\t\t);\n\t}\n\n\tconst inner = createOpenAICompatibleProvider({\n\t\tbaseUrl,\n\t\tgetCredential: options.getCredential,\n\t\tcapabilities: options.capabilities,\n\t\tmodels: options.models,\n\t\tdefaultModel: options.defaultModel,\n\t\t// Copilot rejects calls missing its identification headers; defaults are\n\t\t// applied here and remain overridable via `options.headers`.\n\t\theaders: { ...COPILOT_DEFAULT_HEADERS, ...(options.headers ?? {}) },\n\t\tretry: options.retry,\n\t\tfetchImpl: options.fetchImpl,\n\t});\n\t// Preserve the provider contract but report the Copilot name.\n\treturn {\n\t\tname: \"copilot\",\n\t\tcapabilities: inner.capabilities,\n\t\tmodels: inner.models,\n\t\tmodel: inner.model.bind(inner),\n\t\tgenerate: inner.generate.bind(inner),\n\t\tgenerateStream: inner.generateStream.bind(inner),\n\t};\n}\n"]}
@@ -23,17 +23,47 @@ function mcpToolToTool(serverId, def, client) {
23
23
  }
24
24
 
25
25
  // src/mcp/connection.ts
26
+ async function resolveHeaders(headers) {
27
+ if (!headers) return void 0;
28
+ const resolved = typeof headers === "function" ? await headers() : headers;
29
+ const entries = Object.entries(resolved).filter(
30
+ ([, v]) => v != null && v !== ""
31
+ );
32
+ return entries.length ? Object.fromEntries(entries) : void 0;
33
+ }
34
+ function headerEventSourceInit(headers) {
35
+ return {
36
+ fetch: (url, init) => fetch(url, {
37
+ ...init,
38
+ headers: { ...init?.headers, ...headers }
39
+ })
40
+ };
41
+ }
26
42
  async function createTransport(config) {
27
43
  if (config.transport.kind === "stdio") {
28
44
  chunkN64ZFATA_cjs.requireCapability("canSpawnProcess", "MCP stdio transport");
29
45
  const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
30
46
  return new StdioClientTransport({
31
47
  command: config.transport.command,
32
- args: config.transport.args ?? []
48
+ args: config.transport.args ?? [],
49
+ ...config.transport.env ? { env: config.transport.env } : {}
50
+ });
51
+ }
52
+ const headers = await resolveHeaders(config.transport.headers);
53
+ const url = new URL(config.transport.url);
54
+ if (config.transport.type === "sse") {
55
+ const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js');
56
+ return new SSEClientTransport(url, {
57
+ ...headers ? {
58
+ requestInit: { headers },
59
+ eventSourceInit: headerEventSourceInit(headers)
60
+ } : {}
33
61
  });
34
62
  }
35
63
  const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');
36
- return new StreamableHTTPClientTransport(new URL(config.transport.url));
64
+ return new StreamableHTTPClientTransport(url, {
65
+ ...headers ? { requestInit: { headers } } : {}
66
+ });
37
67
  }
38
68
  async function connectMCP(config) {
39
69
  let client;
@@ -68,5 +98,5 @@ async function connectMCP(config) {
68
98
 
69
99
  exports.connectMCP = connectMCP;
70
100
  exports.mcpToolToTool = mcpToolToTool;
71
- //# sourceMappingURL=chunk-U3ULJMNH.cjs.map
72
- //# sourceMappingURL=chunk-U3ULJMNH.cjs.map
101
+ //# sourceMappingURL=chunk-SUTW6P6O.cjs.map
102
+ //# sourceMappingURL=chunk-SUTW6P6O.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/adapter.ts","../src/mcp/connection.ts"],"names":["MCPError","requireCapability"],"mappings":"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","file":"chunk-SUTW6P6O.cjs","sourcesContent":["/**\n * Adapts MCP-provided tools onto the framework's uniform {@link Tool} contract,\n * namespaced by the connection id so collisions are impossible. (FR-014, FR-014a)\n *\n * @packageDocumentation\n */\n\nimport type { Tool } from \"../tools/tool.js\";\nimport { MCPError } from \"../core/errors.js\";\n\ninterface MCPToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Wrap an MCP tool definition as a framework tool. Invocation calls back through\n * the MCP client; failures surface as typed {@link MCPError}/tool errors.\n */\nexport function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool {\n\treturn {\n\t\tname: def.name,\n\t\tdescription: def.description ?? \"\",\n\t\tinputSchema: def.inputSchema,\n\t\tsource: serverId,\n\t\tenabled: true,\n\t\tasync run(args: unknown): Promise<unknown> {\n\t\t\ttry {\n\t\t\t\tconst result = await client.callTool({ name: def.name, arguments: args });\n\t\t\t\treturn result.content ?? result;\n\t\t\t} catch (e) {\n\t\t\t\tthrow new MCPError(`MCP tool \"${def.name}\" failed: ${(e as Error).message}`, serverId);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * MCP (Model Context Protocol) integration. Connects to MCP servers and exposes\n * their tools through the framework's uniform tool interface.\n *\n * Remote transport (HTTP/SSE) works in all runtimes; stdio (spawning a server\n * process) works only where process spawning is permitted (Node). Requesting\n * stdio elsewhere throws a typed {@link RuntimeUnsupportedError}. (FR-013, FR-013a,\n * FR-013b, FR-030a)\n *\n * The `@modelcontextprotocol/sdk` package is an optional peer dependency and is\n * loaded lazily so browser bundles that do not use MCP pay no cost.\n *\n * @packageDocumentation\n */\n\nimport { MCPError } from \"../core/errors.js\";\nimport { requireCapability } from \"../core/runtime.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport { mcpToolToTool } from \"./adapter.js\";\n\n/**\n * Custom HTTP headers for a remote MCP connection. Mirrors the `headers` object\n * of an `mcp.json` HTTP server entry and is the standard way to pass secrets\n * such as `Authorization: Bearer …` or `X-API-Key` tokens.\n *\n * It may be a static record or a (possibly async) callback that returns the\n * headers. The callback form keeps the security model intact: secrets are\n * resolved lazily at connect time (e.g. minting a fresh bearer token) and are\n * never persisted on the config object. Empty/`null`/`undefined` values are\n * dropped so blank auth headers are never sent.\n */\nexport type MCPHeaders =\n\t| Record<string, string>\n\t| (() => Record<string, string> | Promise<Record<string, string>>);\n\n/** Transport options for an MCP connection. */\nexport type MCPTransport =\n\t| {\n\t\t\tkind: \"remote\";\n\t\t\turl: string;\n\t\t\t/**\n\t\t\t * Wire transport for the remote endpoint. Defaults to `\"http\"`\n\t\t\t * (Streamable HTTP, the `\"http\"`/`\"streamable-http\"` type in `mcp.json`).\n\t\t\t * Use `\"sse\"` for legacy Server-Sent Events servers. (FR-013a)\n\t\t\t */\n\t\t\ttype?: \"http\" | \"sse\";\n\t\t\t/** Custom request headers (auth tokens, API keys, content versions, …). */\n\t\t\theaders?: MCPHeaders;\n\t }\n\t| {\n\t\t\tkind: \"stdio\";\n\t\t\tcommand: string;\n\t\t\targs?: string[];\n\t\t\t/** Extra environment variables for the spawned server process. */\n\t\t\tenv?: Record<string, string>;\n\t };\n\n/** Configuration for connecting to an MCP server. */\nexport interface MCPConnectionConfig {\n\t/** Connection id; becomes the namespace prefix for discovered tools. (FR-014a) */\n\tid: string;\n\ttransport: MCPTransport;\n\t/** Whether the connection's tools are enabled. Defaults to true. */\n\tenabled?: boolean;\n}\n\n/** A live connection to an MCP server. */\nexport interface MCPConnection {\n\treadonly id: string;\n\tconnect(): Promise<void>;\n\tlistTools(): Promise<Tool[]>;\n\tclose(): Promise<void>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyClient = any;\n\n/**\n * Resolve {@link MCPHeaders} into a plain record at connect time, invoking the\n * callback form if provided and stripping empty values so we never transmit a\n * blank `Authorization`/`X-API-Key` header. Returns `undefined` when there are\n * no usable headers so the transport is constructed without a `requestInit`.\n */\nasync function resolveHeaders(\n\theaders?: MCPHeaders,\n): Promise<Record<string, string> | undefined> {\n\tif (!headers) return undefined;\n\tconst resolved = typeof headers === \"function\" ? await headers() : headers;\n\tconst entries = Object.entries(resolved).filter(\n\t\t([, v]) => v != null && v !== \"\",\n\t);\n\treturn entries.length ? Object.fromEntries(entries) : undefined;\n}\n\n/**\n * Build an `EventSourceInit` that injects custom headers onto the initial SSE\n * stream request. The legacy SSE transport only attaches `requestInit` headers\n * to the follow-up POST messages, so without this the auth header would be\n * missing from the GET that opens the stream.\n */\nfunction headerEventSourceInit(headers: Record<string, string>): {\n\tfetch: (url: string | URL, init?: RequestInit) => Promise<Response>;\n} {\n\treturn {\n\t\tfetch: (url, init) =>\n\t\t\tfetch(url, {\n\t\t\t\t...init,\n\t\t\t\theaders: { ...(init?.headers as Record<string, string>), ...headers },\n\t\t\t}),\n\t};\n}\n\nasync function createTransport(config: MCPConnectionConfig): Promise<AnyClient> {\n\tif (config.transport.kind === \"stdio\") {\n\t\t// Gate on runtime capability before attempting to spawn. (FR-013b, FR-030a)\n\t\trequireCapability(\"canSpawnProcess\", \"MCP stdio transport\");\n\t\tconst { StdioClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/stdio.js\"\n\t\t);\n\t\treturn new StdioClientTransport({\n\t\t\tcommand: config.transport.command,\n\t\t\targs: config.transport.args ?? [],\n\t\t\t...(config.transport.env ? { env: config.transport.env } : {}),\n\t\t});\n\t}\n\n\tconst headers = await resolveHeaders(config.transport.headers);\n\tconst url = new URL(config.transport.url);\n\n\t// Legacy Server-Sent Events transport. (FR-013a)\n\tif (config.transport.type === \"sse\") {\n\t\tconst { SSEClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/sse.js\"\n\t\t);\n\t\treturn new SSEClientTransport(url, {\n\t\t\t...(headers\n\t\t\t\t? {\n\t\t\t\t\t\trequestInit: { headers },\n\t\t\t\t\t\teventSourceInit: headerEventSourceInit(headers),\n\t\t\t\t }\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\t// Default: Streamable HTTP (the \"http\"/\"streamable-http\" type in mcp.json).\n\tconst { StreamableHTTPClientTransport } = await import(\n\t\t\"@modelcontextprotocol/sdk/client/streamableHttp.js\"\n\t);\n\treturn new StreamableHTTPClientTransport(url, {\n\t\t...(headers ? { requestInit: { headers } } : {}),\n\t});\n}\n\n/**\n * Connect to an MCP server.\n *\n * @example\n * ```ts\n * // Remote HTTP server with bearer auth (mirrors an mcp.json HTTP entry).\n * const mcp = await connectMCP({\n * id: \"docs\",\n * transport: {\n * kind: \"remote\",\n * url: \"https://api.example.com/mcp\",\n * headers: { Authorization: \"Bearer your-api-token-here\" },\n * },\n * });\n * const tools = await mcp.listTools(); // namespaced as docs.<tool>\n * ```\n */\nexport async function connectMCP(config: MCPConnectionConfig): Promise<MCPConnection> {\n\tlet client: AnyClient | undefined;\n\n\tasync function connect(): Promise<void> {\n\t\ttry {\n\t\t\tconst { Client } = await import(\"@modelcontextprotocol/sdk/client/index.js\");\n\t\t\tconst transport = await createTransport(config);\n\t\t\tclient = new Client({ name: \"agent-framework-js\", version: \"0.1.0\" }, { capabilities: {} });\n\t\t\tawait client.connect(transport);\n\t\t} catch (e) {\n\t\t\t// Preserve typed runtime errors; wrap everything else as an MCP error.\n\t\t\tif ((e as Error).name === \"RuntimeUnsupportedError\") throw e;\n\t\t\tthrow new MCPError(`Failed to connect to MCP server: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function listTools(): Promise<Tool[]> {\n\t\tif (!client) throw new MCPError(\"Not connected\", config.id);\n\t\ttry {\n\t\t\tconst result = await client.listTools();\n\t\t\treturn (result.tools ?? []).map((t: { name: string; description?: string; inputSchema: Record<string, unknown> }) =>\n\t\t\t\tmcpToolToTool(config.id, t, client),\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthrow new MCPError(`Failed to list tools: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function close(): Promise<void> {\n\t\tawait client?.close?.();\n\t\tclient = undefined;\n\t}\n\n\treturn { id: config.id, connect, listTools, close };\n}\n"]}
@@ -21,17 +21,47 @@ function mcpToolToTool(serverId, def, client) {
21
21
  }
22
22
 
23
23
  // src/mcp/connection.ts
24
+ async function resolveHeaders(headers) {
25
+ if (!headers) return void 0;
26
+ const resolved = typeof headers === "function" ? await headers() : headers;
27
+ const entries = Object.entries(resolved).filter(
28
+ ([, v]) => v != null && v !== ""
29
+ );
30
+ return entries.length ? Object.fromEntries(entries) : void 0;
31
+ }
32
+ function headerEventSourceInit(headers) {
33
+ return {
34
+ fetch: (url, init) => fetch(url, {
35
+ ...init,
36
+ headers: { ...init?.headers, ...headers }
37
+ })
38
+ };
39
+ }
24
40
  async function createTransport(config) {
25
41
  if (config.transport.kind === "stdio") {
26
42
  requireCapability("canSpawnProcess", "MCP stdio transport");
27
43
  const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
28
44
  return new StdioClientTransport({
29
45
  command: config.transport.command,
30
- args: config.transport.args ?? []
46
+ args: config.transport.args ?? [],
47
+ ...config.transport.env ? { env: config.transport.env } : {}
48
+ });
49
+ }
50
+ const headers = await resolveHeaders(config.transport.headers);
51
+ const url = new URL(config.transport.url);
52
+ if (config.transport.type === "sse") {
53
+ const { SSEClientTransport } = await import('@modelcontextprotocol/sdk/client/sse.js');
54
+ return new SSEClientTransport(url, {
55
+ ...headers ? {
56
+ requestInit: { headers },
57
+ eventSourceInit: headerEventSourceInit(headers)
58
+ } : {}
31
59
  });
32
60
  }
33
61
  const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js');
34
- return new StreamableHTTPClientTransport(new URL(config.transport.url));
62
+ return new StreamableHTTPClientTransport(url, {
63
+ ...headers ? { requestInit: { headers } } : {}
64
+ });
35
65
  }
36
66
  async function connectMCP(config) {
37
67
  let client;
@@ -65,5 +95,5 @@ async function connectMCP(config) {
65
95
  }
66
96
 
67
97
  export { connectMCP, mcpToolToTool };
68
- //# sourceMappingURL=chunk-QYG4HLIC.js.map
69
- //# sourceMappingURL=chunk-QYG4HLIC.js.map
98
+ //# sourceMappingURL=chunk-YVFQNJIU.js.map
99
+ //# sourceMappingURL=chunk-YVFQNJIU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/adapter.ts","../src/mcp/connection.ts"],"names":[],"mappings":"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","file":"chunk-YVFQNJIU.js","sourcesContent":["/**\n * Adapts MCP-provided tools onto the framework's uniform {@link Tool} contract,\n * namespaced by the connection id so collisions are impossible. (FR-014, FR-014a)\n *\n * @packageDocumentation\n */\n\nimport type { Tool } from \"../tools/tool.js\";\nimport { MCPError } from \"../core/errors.js\";\n\ninterface MCPToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Wrap an MCP tool definition as a framework tool. Invocation calls back through\n * the MCP client; failures surface as typed {@link MCPError}/tool errors.\n */\nexport function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool {\n\treturn {\n\t\tname: def.name,\n\t\tdescription: def.description ?? \"\",\n\t\tinputSchema: def.inputSchema,\n\t\tsource: serverId,\n\t\tenabled: true,\n\t\tasync run(args: unknown): Promise<unknown> {\n\t\t\ttry {\n\t\t\t\tconst result = await client.callTool({ name: def.name, arguments: args });\n\t\t\t\treturn result.content ?? result;\n\t\t\t} catch (e) {\n\t\t\t\tthrow new MCPError(`MCP tool \"${def.name}\" failed: ${(e as Error).message}`, serverId);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * MCP (Model Context Protocol) integration. Connects to MCP servers and exposes\n * their tools through the framework's uniform tool interface.\n *\n * Remote transport (HTTP/SSE) works in all runtimes; stdio (spawning a server\n * process) works only where process spawning is permitted (Node). Requesting\n * stdio elsewhere throws a typed {@link RuntimeUnsupportedError}. (FR-013, FR-013a,\n * FR-013b, FR-030a)\n *\n * The `@modelcontextprotocol/sdk` package is an optional peer dependency and is\n * loaded lazily so browser bundles that do not use MCP pay no cost.\n *\n * @packageDocumentation\n */\n\nimport { MCPError } from \"../core/errors.js\";\nimport { requireCapability } from \"../core/runtime.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport { mcpToolToTool } from \"./adapter.js\";\n\n/**\n * Custom HTTP headers for a remote MCP connection. Mirrors the `headers` object\n * of an `mcp.json` HTTP server entry and is the standard way to pass secrets\n * such as `Authorization: Bearer …` or `X-API-Key` tokens.\n *\n * It may be a static record or a (possibly async) callback that returns the\n * headers. The callback form keeps the security model intact: secrets are\n * resolved lazily at connect time (e.g. minting a fresh bearer token) and are\n * never persisted on the config object. Empty/`null`/`undefined` values are\n * dropped so blank auth headers are never sent.\n */\nexport type MCPHeaders =\n\t| Record<string, string>\n\t| (() => Record<string, string> | Promise<Record<string, string>>);\n\n/** Transport options for an MCP connection. */\nexport type MCPTransport =\n\t| {\n\t\t\tkind: \"remote\";\n\t\t\turl: string;\n\t\t\t/**\n\t\t\t * Wire transport for the remote endpoint. Defaults to `\"http\"`\n\t\t\t * (Streamable HTTP, the `\"http\"`/`\"streamable-http\"` type in `mcp.json`).\n\t\t\t * Use `\"sse\"` for legacy Server-Sent Events servers. (FR-013a)\n\t\t\t */\n\t\t\ttype?: \"http\" | \"sse\";\n\t\t\t/** Custom request headers (auth tokens, API keys, content versions, …). */\n\t\t\theaders?: MCPHeaders;\n\t }\n\t| {\n\t\t\tkind: \"stdio\";\n\t\t\tcommand: string;\n\t\t\targs?: string[];\n\t\t\t/** Extra environment variables for the spawned server process. */\n\t\t\tenv?: Record<string, string>;\n\t };\n\n/** Configuration for connecting to an MCP server. */\nexport interface MCPConnectionConfig {\n\t/** Connection id; becomes the namespace prefix for discovered tools. (FR-014a) */\n\tid: string;\n\ttransport: MCPTransport;\n\t/** Whether the connection's tools are enabled. Defaults to true. */\n\tenabled?: boolean;\n}\n\n/** A live connection to an MCP server. */\nexport interface MCPConnection {\n\treadonly id: string;\n\tconnect(): Promise<void>;\n\tlistTools(): Promise<Tool[]>;\n\tclose(): Promise<void>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyClient = any;\n\n/**\n * Resolve {@link MCPHeaders} into a plain record at connect time, invoking the\n * callback form if provided and stripping empty values so we never transmit a\n * blank `Authorization`/`X-API-Key` header. Returns `undefined` when there are\n * no usable headers so the transport is constructed without a `requestInit`.\n */\nasync function resolveHeaders(\n\theaders?: MCPHeaders,\n): Promise<Record<string, string> | undefined> {\n\tif (!headers) return undefined;\n\tconst resolved = typeof headers === \"function\" ? await headers() : headers;\n\tconst entries = Object.entries(resolved).filter(\n\t\t([, v]) => v != null && v !== \"\",\n\t);\n\treturn entries.length ? Object.fromEntries(entries) : undefined;\n}\n\n/**\n * Build an `EventSourceInit` that injects custom headers onto the initial SSE\n * stream request. The legacy SSE transport only attaches `requestInit` headers\n * to the follow-up POST messages, so without this the auth header would be\n * missing from the GET that opens the stream.\n */\nfunction headerEventSourceInit(headers: Record<string, string>): {\n\tfetch: (url: string | URL, init?: RequestInit) => Promise<Response>;\n} {\n\treturn {\n\t\tfetch: (url, init) =>\n\t\t\tfetch(url, {\n\t\t\t\t...init,\n\t\t\t\theaders: { ...(init?.headers as Record<string, string>), ...headers },\n\t\t\t}),\n\t};\n}\n\nasync function createTransport(config: MCPConnectionConfig): Promise<AnyClient> {\n\tif (config.transport.kind === \"stdio\") {\n\t\t// Gate on runtime capability before attempting to spawn. (FR-013b, FR-030a)\n\t\trequireCapability(\"canSpawnProcess\", \"MCP stdio transport\");\n\t\tconst { StdioClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/stdio.js\"\n\t\t);\n\t\treturn new StdioClientTransport({\n\t\t\tcommand: config.transport.command,\n\t\t\targs: config.transport.args ?? [],\n\t\t\t...(config.transport.env ? { env: config.transport.env } : {}),\n\t\t});\n\t}\n\n\tconst headers = await resolveHeaders(config.transport.headers);\n\tconst url = new URL(config.transport.url);\n\n\t// Legacy Server-Sent Events transport. (FR-013a)\n\tif (config.transport.type === \"sse\") {\n\t\tconst { SSEClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/sse.js\"\n\t\t);\n\t\treturn new SSEClientTransport(url, {\n\t\t\t...(headers\n\t\t\t\t? {\n\t\t\t\t\t\trequestInit: { headers },\n\t\t\t\t\t\teventSourceInit: headerEventSourceInit(headers),\n\t\t\t\t }\n\t\t\t\t: {}),\n\t\t});\n\t}\n\n\t// Default: Streamable HTTP (the \"http\"/\"streamable-http\" type in mcp.json).\n\tconst { StreamableHTTPClientTransport } = await import(\n\t\t\"@modelcontextprotocol/sdk/client/streamableHttp.js\"\n\t);\n\treturn new StreamableHTTPClientTransport(url, {\n\t\t...(headers ? { requestInit: { headers } } : {}),\n\t});\n}\n\n/**\n * Connect to an MCP server.\n *\n * @example\n * ```ts\n * // Remote HTTP server with bearer auth (mirrors an mcp.json HTTP entry).\n * const mcp = await connectMCP({\n * id: \"docs\",\n * transport: {\n * kind: \"remote\",\n * url: \"https://api.example.com/mcp\",\n * headers: { Authorization: \"Bearer your-api-token-here\" },\n * },\n * });\n * const tools = await mcp.listTools(); // namespaced as docs.<tool>\n * ```\n */\nexport async function connectMCP(config: MCPConnectionConfig): Promise<MCPConnection> {\n\tlet client: AnyClient | undefined;\n\n\tasync function connect(): Promise<void> {\n\t\ttry {\n\t\t\tconst { Client } = await import(\"@modelcontextprotocol/sdk/client/index.js\");\n\t\t\tconst transport = await createTransport(config);\n\t\t\tclient = new Client({ name: \"agent-framework-js\", version: \"0.1.0\" }, { capabilities: {} });\n\t\t\tawait client.connect(transport);\n\t\t} catch (e) {\n\t\t\t// Preserve typed runtime errors; wrap everything else as an MCP error.\n\t\t\tif ((e as Error).name === \"RuntimeUnsupportedError\") throw e;\n\t\t\tthrow new MCPError(`Failed to connect to MCP server: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function listTools(): Promise<Tool[]> {\n\t\tif (!client) throw new MCPError(\"Not connected\", config.id);\n\t\ttry {\n\t\t\tconst result = await client.listTools();\n\t\t\treturn (result.tools ?? []).map((t: { name: string; description?: string; inputSchema: Record<string, unknown> }) =>\n\t\t\t\tmcpToolToTool(config.id, t, client),\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthrow new MCPError(`Failed to list tools: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function close(): Promise<void> {\n\t\tawait client?.close?.();\n\t\tclient = undefined;\n\t}\n\n\treturn { id: config.id, connect, listTools, close };\n}\n"]}
@@ -128,9 +128,6 @@ function createOpenAICompatibleProvider(options) {
128
128
  model: modelOf(req.model).model,
129
129
  messages: toOpenAIMessages(req.messages),
130
130
  stream,
131
- // Ask the API to emit a trailing usage chunk on streamed responses so the
132
- // final `done` response can surface real token counts (FR usage reporting).
133
- ...stream ? { stream_options: { include_usage: true } } : {},
134
131
  ...wire.tools ? { tools: wire.tools } : {}
135
132
  });
136
133
  }
@@ -168,7 +165,6 @@ function createOpenAICompatibleProvider(options) {
168
165
  if (!choice) throw new ProviderError("Provider returned no choices", "malformed");
169
166
  const message = choice.message;
170
167
  const reasoningModel = modelOf(req.model).supportsReasoning;
171
- const usage = parseUsage(json["usage"]);
172
168
  let toolCalls = parseToolCalls(message, wire.nameMap);
173
169
  if ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === "tool_calls") {
174
170
  const assembled = await assembleViaStream(req);
@@ -183,16 +179,14 @@ function createOpenAICompatibleProvider(options) {
183
179
  text: message["content"] ?? assembled.text ?? "",
184
180
  reasoning: reasoningModel ? message["reasoning"] ?? assembled.reasoning ?? void 0 : void 0,
185
181
  reasoningOpaque: reasoningModel ? message["reasoning_opaque"] ?? assembled.reasoningOpaque ?? void 0 : void 0,
186
- toolCalls,
187
- usage: usage ?? assembled.usage
182
+ toolCalls
188
183
  };
189
184
  }
190
185
  return {
191
186
  text: message["content"] ?? "",
192
187
  reasoning: reasoningModel ? message["reasoning"] ?? void 0 : void 0,
193
188
  reasoningOpaque: reasoningModel ? message["reasoning_opaque"] ?? void 0 : void 0,
194
- toolCalls,
195
- usage
189
+ toolCalls
196
190
  };
197
191
  }, options.retry);
198
192
  }
@@ -225,7 +219,6 @@ function createOpenAICompatibleProvider(options) {
225
219
  let text = "";
226
220
  let reasoning = "";
227
221
  let reasoningOpaque = "";
228
- let usage;
229
222
  const toolAccum = /* @__PURE__ */ new Map();
230
223
  for (; ; ) {
231
224
  const { value, done } = await reader.read();
@@ -239,8 +232,6 @@ function createOpenAICompatibleProvider(options) {
239
232
  const data = trimmed.slice(5).trim();
240
233
  if (data === "[DONE]") continue;
241
234
  const parsed = safeJson(data);
242
- const chunkUsage = parseUsage(parsed?.usage);
243
- if (chunkUsage) usage = chunkUsage;
244
235
  const delta = parsed?.choices?.[0]?.delta;
245
236
  if (!delta) continue;
246
237
  if (delta.content) {
@@ -280,8 +271,7 @@ function createOpenAICompatibleProvider(options) {
280
271
  text,
281
272
  reasoning: reasoning || void 0,
282
273
  reasoningOpaque: reasoningOpaque || void 0,
283
- toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
284
- usage
274
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0
285
275
  }
286
276
  };
287
277
  }
@@ -301,14 +291,6 @@ function safeJson(s) {
301
291
  return void 0;
302
292
  }
303
293
  }
304
- function parseUsage(raw) {
305
- if (!raw || typeof raw !== "object") return void 0;
306
- const u = raw;
307
- const inputTokens = typeof u.prompt_tokens === "number" ? u.prompt_tokens : void 0;
308
- const outputTokens = typeof u.completion_tokens === "number" ? u.completion_tokens : void 0;
309
- if (inputTokens === void 0 && outputTokens === void 0) return void 0;
310
- return { inputTokens, outputTokens };
311
- }
312
294
 
313
295
  // src/providers/copilot.ts
314
296
  var DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
@@ -353,5 +335,5 @@ function createCopilotProvider(options) {
353
335
  }
354
336
 
355
337
  export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry };
356
- //# sourceMappingURL=chunk-K7ZWLHKU.js.map
357
- //# sourceMappingURL=chunk-K7ZWLHKU.js.map
338
+ //# sourceMappingURL=chunk-YVJGF4HQ.js.map
339
+ //# sourceMappingURL=chunk-YVJGF4HQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/provider.ts","../src/providers/retry.ts","../src/providers/openai-compatible.ts","../src/providers/copilot.ts"],"names":[],"mappings":"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","file":"chunk-YVJGF4HQ.js","sourcesContent":["/**\n * LLM provider abstraction. Agents and workflows depend only on this interface,\n * never on a concrete provider, so new providers can be added without changing\n * agent/workflow code. (FR-007)\n *\n * Credentials are always obtained via a caller-supplied callback and are never\n * bundled, persisted, or logged by the framework. (FR-005a, FR-008)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** A caller-supplied source of credentials. The framework never stores the value. */\nexport interface CredentialSource {\n\t/** Return the current credential (token/api key). May be async. */\n\tgetCredential(): string | Promise<string>;\n}\n\n/**\n * Model configuration for a provider. A provider may expose **one or more** models\n * (e.g. GitHub Copilot offers several; an OpenAI-compatible endpoint is usually one).\n * Supply either a single `capabilities` object or an array via `models`.\n */\nexport interface ModelSelectionOptions {\n\t/** Single-model shorthand. */\n\tcapabilities?: ModelCapabilities;\n\t/** One or more models this provider can use. */\n\tmodels?: ModelCapabilities[];\n\t/** Name of the default model (defaults to the first entry). */\n\tdefaultModel?: string;\n}\n\n/** Resolved model set with a default and a lookup helper. */\nexport interface ResolvedModels {\n\t/** All configured models (at least one). */\n\tmodels: ModelCapabilities[];\n\t/** The default model used when a request does not specify one. */\n\tdefaultModel: ModelCapabilities;\n\t/** Look up a model by name, or return the default when omitted. */\n\tmodelOf(name?: string): ModelCapabilities;\n}\n\n/**\n * Normalize {@link ModelSelectionOptions} into a model list, a default, and a\n * lookup helper. Throws {@link ValidationError} if no model is configured or a\n * named model is missing.\n *\n * @example\n * ```ts\n * const { defaultModel, modelOf } = resolveModels({\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * ```\n */\nexport function resolveModels(options: ModelSelectionOptions): ResolvedModels {\n\tconst models = options.models ?? (options.capabilities ? [options.capabilities] : []);\n\tif (models.length === 0) {\n\t\tthrow new ValidationError(\"Provider requires at least one model (set `capabilities` or `models`)\");\n\t}\n\tconst defaultModel = options.defaultModel\n\t\t? models.find((m) => m.model === options.defaultModel)\n\t\t: models[0];\n\tif (!defaultModel) {\n\t\tthrow new ValidationError(`defaultModel \"${options.defaultModel}\" is not present in models`);\n\t}\n\tconst modelOf = (name?: string): ModelCapabilities => {\n\t\tif (!name) return defaultModel;\n\t\tconst found = models.find((m) => m.model === name);\n\t\tif (!found) {\n\t\t\tthrow new ValidationError(`Model \"${name}\" is not configured for this provider`);\n\t\t}\n\t\treturn found;\n\t};\n\treturn { models, defaultModel, modelOf };\n}\n\n/** A tool description passed to the provider so the model can decide to call it. */\nexport interface ToolSpec {\n\tname: string;\n\tdescription: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/** A request to generate a model response. */\nexport interface GenerateRequest {\n\tmessages: Message[];\n\ttools?: ToolSpec[];\n\t/** Which configured model to use; defaults to the provider's default model. */\n\tmodel?: string;\n\t/** Abort signal to cancel an in-flight request. */\n\tsignal?: AbortSignal;\n}\n\n/** A tool call requested by the model. */\nexport interface ToolCall {\n\tid: string;\n\tname: string;\n\t/** Raw JSON arguments (validated by the tools module before invocation). */\n\targuments: unknown;\n}\n\n/** A complete (non-streaming) model response. */\nexport interface GenerateResponse {\n\t/** Final answer text. */\n\ttext: string;\n\t/** Reasoning/thinking content — only present for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\t/**\n\t * Opaque reasoning blob (e.g. Claude thinking signature) to round-trip on the\n\t * next assistant turn for thinking continuity. Never logged or inspected.\n\t */\n\treasoningOpaque?: string;\n\t/** Tool calls the model wants to make, if any. */\n\ttoolCalls?: ToolCall[];\n\t/** Approximate token usage if reported by the provider. */\n\tusage?: { inputTokens?: number; outputTokens?: number };\n}\n\n/** An incremental streaming chunk. */\nexport type GenerateChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"tool-call\"; toolCall: ToolCall }\n\t| { type: \"done\"; response: GenerateResponse };\n\n/**\n * An LLM backend. Implementations adapt a concrete API (Copilot, OpenAI-compatible)\n * onto this uniform surface.\n */\nexport interface Provider {\n\t/** Stable provider identifier, e.g. `\"openai-compatible\"`. */\n\treadonly name: string;\n\t/** The default model's capability configuration. (FR-007a) */\n\treadonly capabilities: ModelCapabilities;\n\t/** All models this provider is configured with (one or more). */\n\treadonly models: ModelCapabilities[];\n\t/** Look up a configured model by name, or the default when omitted. */\n\tmodel(name?: string): ModelCapabilities;\n\t/** Generate a complete response. */\n\tgenerate(req: GenerateRequest): Promise<GenerateResponse>;\n\t/** Generate a streamed response. */\n\tgenerateStream(req: GenerateRequest): AsyncIterable<GenerateChunk>;\n}\n","/**\n * Exponential-backoff retry for transient provider failures. Transient errors\n * (429 with Retry-After, 5xx, network/timeout) are retried; auth/4xx fail fast.\n * (FR-008a)\n *\n * @packageDocumentation\n */\n\nimport { ProviderError } from \"../core/errors.js\";\n\n/** Retry tuning. All fields have safe defaults. */\nexport interface RetryOptions {\n\t/** Maximum retry attempts after the first try. Default 3. */\n\tmaxRetries?: number;\n\t/** Base delay in ms for backoff. Default 250. */\n\tbaseDelayMs?: number;\n\t/** Maximum delay cap in ms. Default 8000. */\n\tmaxDelayMs?: number;\n}\n\nconst DEFAULTS: Required<RetryOptions> = {\n\tmaxRetries: 3,\n\tbaseDelayMs: 250,\n\tmaxDelayMs: 8000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Run `fn`, retrying transient {@link ProviderError}s with exponential backoff\n * and jitter. Non-transient errors are rethrown immediately (fail fast).\n *\n * @param fn - The operation to attempt. It should throw a {@link ProviderError}.\n * @param opts - Retry tuning.\n * @param retryAfterMs - Optional hook returning a server-specified delay (Retry-After).\n */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\topts?: RetryOptions,\n\tretryAfterMs?: (err: ProviderError) => number | undefined,\n): Promise<T> {\n\tconst cfg = { ...DEFAULTS, ...opts };\n\tlet attempt = 0;\n\n\tfor (; ;) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst isRetryable = err instanceof ProviderError && err.retryable;\n\t\t\tif (!isRetryable || attempt >= cfg.maxRetries) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tconst serverDelay = retryAfterMs?.(err as ProviderError);\n\t\t\tconst backoff = Math.min(cfg.baseDelayMs * 2 ** attempt, cfg.maxDelayMs);\n\t\t\tconst jitter = Math.random() * cfg.baseDelayMs;\n\t\t\tawait sleep(serverDelay ?? backoff + jitter);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\n/** Map an HTTP status to a {@link ProviderError} with the right retry semantics. */\nexport function providerErrorFromStatus(status: number, message: string): ProviderError {\n\tif (status === 429 || status >= 500) {\n\t\treturn new ProviderError(message, \"transient\", { status });\n\t}\n\tif (status === 401 || status === 403) {\n\t\treturn new ProviderError(message, \"auth\", { status });\n\t}\n\treturn new ProviderError(message, \"client\", { status });\n}\n","/**\n * OpenAI-compatible provider. Targets any endpoint speaking the OpenAI\n * `/chat/completions` API, including local servers such as LM Studio via a custom\n * `baseUrl`, and GitHub Copilot (see {@link createCopilotProvider}). (FR-006)\n *\n * Provider compatibility notes (handled here so callers don't have to):\n * - Tool names are sanitized to `^[a-zA-Z0-9_-]+$` on the wire (OpenAI/Copilot\n * reject dotted names like `webiq.browse`) and translated back to the registry\n * key when the model calls them.\n * - Assistant turns that requested tools emit `tool_calls` with `content: null`\n * so strict providers (e.g. Anthropic) can pair each tool result with its call.\n * - Streaming responses accumulate `delta.tool_calls[]` keyed by `index`\n * (fragments may start at a non-zero index when reasoning occupies 0/1).\n * - Some reasoning models report `finish_reason: \"tool_calls\"` from the\n * non-streaming endpoint without a `tool_calls` array; `generate` transparently\n * re-requests in streaming mode and assembles them, failing loud (typed\n * {@link ProviderError}) rather than silently stopping if none materialize.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart, MessageToolCall } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type {\n\tProvider,\n\tCredentialSource,\n\tGenerateRequest,\n\tGenerateResponse,\n\tGenerateChunk,\n\tToolCall,\n\tToolSpec,\n} from \"./provider.js\";\nimport { resolveModels, type ModelSelectionOptions } from \"./provider.js\";\nimport { withRetry, providerErrorFromStatus, type RetryOptions } from \"./retry.js\";\n\n/**\n * Options for {@link createOpenAICompatibleProvider}.\n *\n * Supply a single model via `capabilities`, or multiple via `models` (most\n * OpenAI-compatible endpoints expose one model, but multiple are supported).\n */\nexport interface OpenAICompatibleProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Base URL of the OpenAI-compatible API, e.g. `http://localhost:1234/v1`. */\n\tbaseUrl: string;\n\t/**\n\t * Extra request headers merged into every call (e.g. provider-required\n\t * identification headers). The `authorization` header is always set from\n\t * `getCredential()` and cannot be overridden here.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface OpenAIMessage {\n\trole: string;\n\tcontent: unknown;\n\ttool_calls?: Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }>;\n\ttool_call_id?: string;\n\tname?: string;\n\treasoning_opaque?: string;\n}\n\n/** OpenAI/Copilot require tool names to match `^[a-zA-Z0-9_-]{1,128}$`. */\nconst UNSAFE_TOOL_NAME_CHARS = /[^a-zA-Z0-9_-]/g;\n\n/**\n * Sanitize a (possibly namespaced) tool name for the wire. Dotted MCP names like\n * `webiq.browse` become `webiq_browse`; the original is recovered via the\n * per-request name map when the model calls the tool.\n */\nfunction sanitizeToolName(name: string): string {\n\treturn name.replace(UNSAFE_TOOL_NAME_CHARS, \"_\");\n}\n\nfunction toOpenAIContent(parts: ContentPart[]): unknown {\n\tif (parts.every((p) => p.type === \"text\")) {\n\t\treturn parts.map((p) => (p as { text: string }).text).join(\"\");\n\t}\n\treturn parts.map((p) =>\n\t\tp.type === \"text\"\n\t\t\t? { type: \"text\", text: p.text }\n\t\t\t: { type: \"image_url\", image_url: { url: p.data } },\n\t);\n}\n\nfunction toWireToolCalls(\n\ttoolCalls: MessageToolCall[],\n): Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }> {\n\treturn toolCalls.map((tc) => ({\n\t\tid: tc.id,\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: sanitizeToolName(tc.name),\n\t\t\targuments:\n\t\t\t\ttypeof tc.arguments === \"string\" ? tc.arguments : JSON.stringify(tc.arguments ?? {}),\n\t\t},\n\t}));\n}\n\nfunction toOpenAIMessages(messages: Message[]): OpenAIMessage[] {\n\treturn messages.map((m) => {\n\t\tconst msg: OpenAIMessage = { role: m.role, content: toOpenAIContent(m.parts) };\n\t\tif (m.toolCalls && m.toolCalls.length > 0) {\n\t\t\tmsg.tool_calls = toWireToolCalls(m.toolCalls);\n\t\t\t// Strict providers require `content: null` (not \"\") on an assistant turn\n\t\t\t// that only carries tool calls.\n\t\t\tconst hasText = m.parts.some((p) => p.type === \"text\" && p.text.length > 0);\n\t\t\tif (!hasText) msg.content = null;\n\t\t}\n\t\tif (m.toolCallId) msg.tool_call_id = m.toolCallId;\n\t\tif (m.name) msg.name = sanitizeToolName(m.name);\n\t\tif (m.reasoningOpaque) msg.reasoning_opaque = m.reasoningOpaque;\n\t\treturn msg;\n\t});\n}\n\n/** Wire tool specs plus a map from sanitized name back to the registry key. */\ninterface WireTools {\n\ttools?: Array<{ type: \"function\"; function: { name: string; description: string; parameters: unknown } }>;\n\tnameMap: Map<string, string>;\n}\n\nfunction buildWireTools(specs?: ToolSpec[]): WireTools {\n\tconst nameMap = new Map<string, string>();\n\tif (!specs || specs.length === 0) return { tools: undefined, nameMap };\n\tconst tools = specs.map((t) => {\n\t\tconst wireName = sanitizeToolName(t.name);\n\t\tnameMap.set(wireName, t.name);\n\t\treturn {\n\t\t\ttype: \"function\" as const,\n\t\t\tfunction: { name: wireName, description: t.description, parameters: t.inputSchema },\n\t\t};\n\t});\n\treturn { tools, nameMap };\n}\n\n/**\n * Create an OpenAI-compatible provider (works with LM Studio, vLLM, etc.).\n *\n * @example\n * ```ts\n * const provider = createOpenAICompatibleProvider({\n * baseUrl: \"http://localhost:1234/v1\",\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * capabilities: { model: \"local\", maxInputTokens: 262144, maxOutputTokens: 32000 },\n * });\n * ```\n */\nexport function createOpenAICompatibleProvider(\n\toptions: OpenAICompatibleProviderOptions,\n): Provider {\n\tconst doFetch = options.fetchImpl ?? globalThis.fetch;\n\tconst url = `${options.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\tconst { models, defaultModel, modelOf } = resolveModels(options);\n\n\tasync function authHeaders(): Promise<Record<string, string>> {\n\t\tconst cred = await options.getCredential();\n\t\t// content-type first, then caller headers (may override it), then the\n\t\t// credential-derived authorization which always wins.\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(options.headers ?? {}),\n\t\t};\n\t\tif (cred) headers[\"authorization\"] = `Bearer ${cred}`;\n\t\treturn headers;\n\t}\n\n\tfunction body(req: GenerateRequest, stream: boolean, wire: WireTools): string {\n\t\treturn JSON.stringify({\n\t\t\tmodel: modelOf(req.model).model,\n\t\t\tmessages: toOpenAIMessages(req.messages),\n\t\t\tstream,\n\t\t\t...(wire.tools ? { tools: wire.tools } : {}),\n\t\t});\n\t}\n\n\tfunction parseToolCalls(raw: unknown, nameMap: Map<string, string>): ToolCall[] | undefined {\n\t\tconst calls = (raw as {\n\t\t\ttool_calls?: Array<{ id: string; function: { name: string; arguments: string } }>;\n\t\t})?.tool_calls;\n\t\tif (!calls || calls.length === 0) return undefined;\n\t\treturn calls.map((c) => ({\n\t\t\tid: c.id,\n\t\t\tname: nameMap.get(c.function.name) ?? c.function.name,\n\t\t\targuments: safeJson(c.function.arguments),\n\t\t}));\n\t}\n\n\tasync function generate(req: GenerateRequest): Promise<GenerateResponse> {\n\t\treturn withRetry(async () => {\n\t\t\tconst wire = buildWireTools(req.tools);\n\t\t\tlet res: Response;\n\t\t\ttry {\n\t\t\t\tres = await doFetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: await authHeaders(),\n\t\t\t\t\tbody: body(req, false, wire),\n\t\t\t\t\tsignal: req.signal,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t\t}\n\t\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\n\t\t\tlet json: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tjson = (await res.json()) as Record<string, unknown>;\n\t\t\t} catch {\n\t\t\t\tthrow new ProviderError(\"Malformed provider response\", \"malformed\");\n\t\t\t}\n\t\t\tconst choice = (\n\t\t\t\tjson[\"choices\"] as Array<{ message: Record<string, unknown>; finish_reason?: string }>\n\t\t\t)?.[0];\n\t\t\tif (!choice) throw new ProviderError(\"Provider returned no choices\", \"malformed\");\n\t\t\tconst message = choice.message;\n\t\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\t\tlet toolCalls = parseToolCalls(message, wire.nameMap);\n\n\t\t\t// Bug 4(b): some reasoning models report `finish_reason: \"tool_calls\"` from\n\t\t\t// the non-streaming endpoint without a `tool_calls` array. Re-request in\n\t\t\t// streaming mode and assemble them so the agent loop can proceed.\n\t\t\tif ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === \"tool_calls\") {\n\t\t\t\tconst assembled = await assembleViaStream(req);\n\t\t\t\ttoolCalls = assembled.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t\t\"Provider signaled tool_calls but returned none (even when streamed)\",\n\t\t\t\t\t\t\"malformed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: (message[\"content\"] as string) ?? assembled.text ?? \"\",\n\t\t\t\t\treasoning: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning\"] as string) ?? assembled.reasoning ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? assembled.reasoningOpaque ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\ttoolCalls,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: (message[\"content\"] as string) ?? \"\",\n\t\t\t\treasoning: reasoningModel ? ((message[\"reasoning\"] as string) ?? undefined) : undefined,\n\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t\ttoolCalls,\n\t\t\t};\n\t\t}, options.retry);\n\t}\n\n\t/** Drive a streaming request to completion and return its assembled final response. */\n\tasync function assembleViaStream(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tlet final: GenerateResponse = { text: \"\" };\n\t\tfor await (const chunk of generateStream(req)) {\n\t\t\tif (chunk.type === \"done\") final = chunk.response;\n\t\t}\n\t\treturn final;\n\t}\n\n\tasync function* generateStream(req: GenerateRequest): AsyncIterable<GenerateChunk> {\n\t\tconst wire = buildWireTools(req.tools);\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await doFetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: await authHeaders(),\n\t\t\t\tbody: body(req, true, wire),\n\t\t\t\tsignal: req.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t}\n\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\t\tif (!res.body) throw new ProviderError(\"Provider returned no stream body\", \"malformed\");\n\n\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\tconst reader = res.body.getReader();\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet text = \"\";\n\t\tlet reasoning = \"\";\n\t\tlet reasoningOpaque = \"\";\n\t\t// Accumulate streamed tool-call fragments keyed by their `index` (which may\n\t\t// start at a non-zero value when reasoning deltas occupy the first indices).\n\t\tconst toolAccum = new Map<number, { id?: string; name?: string; args: string }>();\n\n\t\tfor (; ;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst trimmed = line.trim();\n\t\t\t\tif (!trimmed.startsWith(\"data:\")) continue;\n\t\t\t\tconst data = trimmed.slice(5).trim();\n\t\t\t\tif (data === \"[DONE]\") continue;\n\t\t\t\tconst parsed = safeJson(data) as\n\t\t\t\t\t| {\n\t\t\t\t\t\tchoices?: Array<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\treasoning?: string;\n\t\t\t\t\t\t\t\treasoning_opaque?: string;\n\t\t\t\t\t\t\t\ttool_calls?: Array<{\n\t\t\t\t\t\t\t\t\tindex?: number;\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}>;\n\t\t\t\t\t}\n\t\t\t\t\t| undefined;\n\t\t\t\tconst delta = parsed?.choices?.[0]?.delta;\n\t\t\t\tif (!delta) continue;\n\t\t\t\tif (delta.content) {\n\t\t\t\t\ttext += delta.content;\n\t\t\t\t\tyield { type: \"text\", text: delta.content };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning && reasoningModel) {\n\t\t\t\t\treasoning += delta.reasoning;\n\t\t\t\t\tyield { type: \"reasoning\", text: delta.reasoning };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning_opaque && reasoningModel) {\n\t\t\t\t\treasoningOpaque += delta.reasoning_opaque;\n\t\t\t\t}\n\t\t\t\tif (delta.tool_calls) {\n\t\t\t\t\tfor (const frag of delta.tool_calls) {\n\t\t\t\t\t\tconst idx = frag.index ?? 0;\n\t\t\t\t\t\tconst slot = toolAccum.get(idx) ?? { args: \"\" };\n\t\t\t\t\t\tif (frag.id) slot.id = frag.id;\n\t\t\t\t\t\tif (frag.function?.name) slot.name = frag.function.name;\n\t\t\t\t\t\tif (frag.function?.arguments) slot.args += frag.function.arguments;\n\t\t\t\t\t\ttoolAccum.set(idx, slot);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Materialize accumulated tool calls (sorted by stream index) and surface\n\t\t// them both as chunks and in the final `done` response.\n\t\tconst toolCalls: ToolCall[] = [...toolAccum.entries()]\n\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t.filter(([, s]) => s.name)\n\t\t\t.map(([idx, s]) => ({\n\t\t\t\tid: s.id ?? `call_${idx}`,\n\t\t\t\tname: wire.nameMap.get(s.name as string) ?? (s.name as string),\n\t\t\t\targuments: safeJson(s.args) ?? {},\n\t\t\t}));\n\t\tfor (const toolCall of toolCalls) {\n\t\t\tyield { type: \"tool-call\", toolCall };\n\t\t}\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresponse: {\n\t\t\t\ttext,\n\t\t\t\treasoning: reasoning || undefined,\n\t\t\t\treasoningOpaque: reasoningOpaque || undefined,\n\t\t\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tname: \"openai-compatible\",\n\t\tcapabilities: defaultModel,\n\t\tmodels,\n\t\tmodel: modelOf,\n\t\tgenerate,\n\t\tgenerateStream,\n\t};\n}\n\nfunction safeJson(s: string): unknown {\n\ttry {\n\t\treturn JSON.parse(s);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n","/**\n * GitHub Copilot provider. (FR-005)\n *\n * Copilot's chat API is OpenAI-compatible, so this provider configures the shared\n * OpenAI-compatible transport with Copilot's endpoint and the caller-supplied\n * credential (a Copilot/GitHub token). The token is obtained via callback and is\n * never bundled, persisted, or logged. (FR-005a)\n *\n * In a frontend-only deployment the end user supplies their own token (it stays\n * client-side); in a backend deployment the developer may supply it, or the user\n * sends it per request over SSL/TLS and the backend must not log or persist it.\n *\n * Note: the Copilot API (`api.githubcopilot.com`) sends no CORS headers, so it\n * cannot be called directly from a browser. A browser deployment must route through\n * a backend/proxy (set `baseUrl` to it); constructing this provider in a browser\n * against the default host throws {@link RuntimeUnsupportedError}.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, CredentialSource, ModelSelectionOptions } from \"./provider.js\";\nimport type { RetryOptions } from \"./retry.js\";\nimport { createOpenAICompatibleProvider } from \"./openai-compatible.js\";\nimport { detectRuntime } from \"../core/runtime.js\";\nimport { RuntimeUnsupportedError } from \"../core/errors.js\";\n\n/** Default Copilot-compatible chat completions base URL. */\nconst DEFAULT_COPILOT_BASE_URL = \"https://api.githubcopilot.com\";\n\n/**\n * Headers `api.githubcopilot.com` requires on every request. Omitting any of\n * these causes the API to reject the call with HTTP 400. They are sent by default\n * and can be overridden per option via `headers`.\n */\nconst COPILOT_DEFAULT_HEADERS: Record<string, string> = {\n\t\"Editor-Version\": \"vscode/1.95.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.20.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n\t\"Openai-Intent\": \"conversation-panel\",\n};\n\n/**\n * Options for {@link createCopilotProvider}.\n *\n * GitHub Copilot exposes several models, so configure them via `models` (with an\n * optional `defaultModel`). A single `capabilities` object is also accepted.\n */\nexport interface CopilotProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Override the Copilot base URL if needed. */\n\tbaseUrl?: string;\n\t/**\n\t * Extra/override request headers. Merged over the required Copilot defaults\n\t * (`Editor-Version`, `Editor-Plugin-Version`, `Copilot-Integration-Id`,\n\t * `Openai-Intent`), so you can adjust them without losing the others.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Create a GitHub Copilot provider.\n *\n * @example Single model\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken, // never logged or persisted\n * capabilities: { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * });\n * ```\n *\n * @example Multiple models\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken,\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * // Pick a model per request: provider.generate({ messages, model: \"o3-mini\" })\n * ```\n *\n * @throws {RuntimeUnsupportedError} when constructed in a browser against the\n * default Copilot host. `api.githubcopilot.com` does not send CORS headers, so a\n * browser cannot call it directly — host a small backend/proxy and point `baseUrl`\n * at it (which lifts this guard), or run the provider server-side (Node/edge).\n */\nexport function createCopilotProvider(options: CopilotProviderOptions): Provider {\n\tconst baseUrl = options.baseUrl ?? DEFAULT_COPILOT_BASE_URL;\n\n\t// Frontend-only guard: the Copilot API has no CORS support, so a browser must\n\t// route through a backend/proxy. Setting a custom `baseUrl` (your proxy) is the\n\t// supported opt-in and lifts this guard. Edge/Node (server-side) are unaffected.\n\tconst usingDefaultHost = baseUrl === DEFAULT_COPILOT_BASE_URL;\n\tif (usingDefaultHost && detectRuntime().isBrowser) {\n\t\tthrow new RuntimeUnsupportedError(\n\t\t\t\"GitHub Copilot directly from a browser (the Copilot API sends no CORS headers)\",\n\t\t\t{\n\t\t\t\treason: \"cors\",\n\t\t\t\tremedy:\n\t\t\t\t\t\"Run a lightweight backend/proxy (e.g. a Vite dev-server proxy or a small server route) \" +\n\t\t\t\t\t\"that forwards to https://api.githubcopilot.com, then set `baseUrl` to your proxy URL. \" +\n\t\t\t\t\t\"Alternatively, run the Copilot provider server-side (Node or an edge function).\",\n\t\t\t},\n\t\t);\n\t}\n\n\tconst inner = createOpenAICompatibleProvider({\n\t\tbaseUrl,\n\t\tgetCredential: options.getCredential,\n\t\tcapabilities: options.capabilities,\n\t\tmodels: options.models,\n\t\tdefaultModel: options.defaultModel,\n\t\t// Copilot rejects calls missing its identification headers; defaults are\n\t\t// applied here and remain overridable via `options.headers`.\n\t\theaders: { ...COPILOT_DEFAULT_HEADERS, ...(options.headers ?? {}) },\n\t\tretry: options.retry,\n\t\tfetchImpl: options.fetchImpl,\n\t});\n\t// Preserve the provider contract but report the Copilot name.\n\treturn {\n\t\tname: \"copilot\",\n\t\tcapabilities: inner.capabilities,\n\t\tmodels: inner.models,\n\t\tmodel: inner.model.bind(inner),\n\t\tgenerate: inner.generate.bind(inner),\n\t\tgenerateStream: inner.generateStream.bind(inner),\n\t};\n}\n"]}
package/dist/index.cjs CHANGED
@@ -7,13 +7,13 @@ var chunkJ2YO7BBV_cjs = require('./chunk-J2YO7BBV.cjs');
7
7
  var chunkYKSNVWGX_cjs = require('./chunk-YKSNVWGX.cjs');
8
8
  var chunkWSMYH2IN_cjs = require('./chunk-WSMYH2IN.cjs');
9
9
  var chunkTAMJ5HSR_cjs = require('./chunk-TAMJ5HSR.cjs');
10
- var chunkU3ULJMNH_cjs = require('./chunk-U3ULJMNH.cjs');
11
10
  var chunkKEI3EALJ_cjs = require('./chunk-KEI3EALJ.cjs');
12
11
  var chunkFSDMBWQV_cjs = require('./chunk-FSDMBWQV.cjs');
13
12
  var chunkV6O6SYAN_cjs = require('./chunk-V6O6SYAN.cjs');
13
+ var chunkSUTW6P6O_cjs = require('./chunk-SUTW6P6O.cjs');
14
14
  var chunk5KC6X2T5_cjs = require('./chunk-5KC6X2T5.cjs');
15
15
  var chunkI55OVD23_cjs = require('./chunk-I55OVD23.cjs');
16
- var chunkUEYT6XMA_cjs = require('./chunk-UEYT6XMA.cjs');
16
+ var chunkJLPLGU7O_cjs = require('./chunk-JLPLGU7O.cjs');
17
17
  var chunkN64ZFATA_cjs = require('./chunk-N64ZFATA.cjs');
18
18
  var chunkMQ2XTH3S_cjs = require('./chunk-MQ2XTH3S.cjs');
19
19
  var chunkIJASUMIQ_cjs = require('./chunk-IJASUMIQ.cjs');
@@ -104,14 +104,6 @@ Object.defineProperty(exports, "validateArgs", {
104
104
  enumerable: true,
105
105
  get: function () { return chunkTAMJ5HSR_cjs.validateArgs; }
106
106
  });
107
- Object.defineProperty(exports, "connectMCP", {
108
- enumerable: true,
109
- get: function () { return chunkU3ULJMNH_cjs.connectMCP; }
110
- });
111
- Object.defineProperty(exports, "mcpToolToTool", {
112
- enumerable: true,
113
- get: function () { return chunkU3ULJMNH_cjs.mcpToolToTool; }
114
- });
115
107
  Object.defineProperty(exports, "useMiddleware", {
116
108
  enumerable: true,
117
109
  get: function () { return chunkKEI3EALJ_cjs.useMiddleware; }
@@ -136,6 +128,14 @@ Object.defineProperty(exports, "withSpan", {
136
128
  enumerable: true,
137
129
  get: function () { return chunkV6O6SYAN_cjs.withSpan; }
138
130
  });
131
+ Object.defineProperty(exports, "connectMCP", {
132
+ enumerable: true,
133
+ get: function () { return chunkSUTW6P6O_cjs.connectMCP; }
134
+ });
135
+ Object.defineProperty(exports, "mcpToolToTool", {
136
+ enumerable: true,
137
+ get: function () { return chunkSUTW6P6O_cjs.mcpToolToTool; }
138
+ });
139
139
  Object.defineProperty(exports, "ThreadPersistence", {
140
140
  enumerable: true,
141
141
  get: function () { return chunk5KC6X2T5_cjs.ThreadPersistence; }
@@ -170,23 +170,23 @@ Object.defineProperty(exports, "textMessage", {
170
170
  });
171
171
  Object.defineProperty(exports, "createCopilotProvider", {
172
172
  enumerable: true,
173
- get: function () { return chunkUEYT6XMA_cjs.createCopilotProvider; }
173
+ get: function () { return chunkJLPLGU7O_cjs.createCopilotProvider; }
174
174
  });
175
175
  Object.defineProperty(exports, "createOpenAICompatibleProvider", {
176
176
  enumerable: true,
177
- get: function () { return chunkUEYT6XMA_cjs.createOpenAICompatibleProvider; }
177
+ get: function () { return chunkJLPLGU7O_cjs.createOpenAICompatibleProvider; }
178
178
  });
179
179
  Object.defineProperty(exports, "providerErrorFromStatus", {
180
180
  enumerable: true,
181
- get: function () { return chunkUEYT6XMA_cjs.providerErrorFromStatus; }
181
+ get: function () { return chunkJLPLGU7O_cjs.providerErrorFromStatus; }
182
182
  });
183
183
  Object.defineProperty(exports, "resolveModels", {
184
184
  enumerable: true,
185
- get: function () { return chunkUEYT6XMA_cjs.resolveModels; }
185
+ get: function () { return chunkJLPLGU7O_cjs.resolveModels; }
186
186
  });
187
187
  Object.defineProperty(exports, "withRetry", {
188
188
  enumerable: true,
189
- get: function () { return chunkUEYT6XMA_cjs.withRetry; }
189
+ get: function () { return chunkJLPLGU7O_cjs.withRetry; }
190
190
  });
191
191
  Object.defineProperty(exports, "detectRuntime", {
192
192
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -8,7 +8,7 @@ export { validateArgs } from './tools/index.cjs';
8
8
  export { T as ToolRegistry, a as ToolResult, n as namespacedName } from './registry-BCkSIe0E.cjs';
9
9
  export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, M as Middleware, d as MiddlewareContext, N as Next, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, i as composeMiddleware, j as createAgent, r as runLoop } from './index-b1oTo3Lv.cjs';
10
10
  export { T as Thread, a as ThreadOptions, e as estimateTokens } from './thread-BzwE1OnJ.cjs';
11
- export { MCPConnection, MCPConnectionConfig, MCPTransport, connectMCP, mcpToolToTool } from './mcp/index.cjs';
11
+ export { MCPConnection, MCPConnectionConfig, MCPHeaders, MCPTransport, connectMCP, mcpToolToTool } from './mcp/index.cjs';
12
12
  export { SkillIndex } from './skills/index.cjs';
13
13
  export { BranchResult, CHECKPOINT_VERSION, Checkpoint, FailurePolicy, PatternHooks, StepResult, Workflow, WorkflowConfig, WorkflowContext, WorkflowEvent, WorkflowPattern, WorkflowState, WorkflowStatus, createCheckpoint, createWorkflow, restoreCheckpoint, runBounded, serializeCheckpoint, stepConcurrent, stepGroup, stepHandoff, stepSequential } from './workflows/index.cjs';
14
14
  export { useMiddleware } from './middleware/index.cjs';
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export { validateArgs } from './tools/index.js';
8
8
  export { T as ToolRegistry, a as ToolResult, n as namespacedName } from './registry-D-CmT0gk.js';
9
9
  export { A as Agent, a as AgentConfig, b as AgentInput, G as GenerateFn, L as LoopOptions, c as LoopResult, M as Middleware, d as MiddlewareContext, N as Next, R as RunChunk, e as RunOptions, f as RunResult, g as RunStatus, h as buildMessages, i as composeMiddleware, j as createAgent, r as runLoop } from './index-C22fqyZQ.js';
10
10
  export { T as Thread, a as ThreadOptions, e as estimateTokens } from './thread-COljUAtD.js';
11
- export { MCPConnection, MCPConnectionConfig, MCPTransport, connectMCP, mcpToolToTool } from './mcp/index.js';
11
+ export { MCPConnection, MCPConnectionConfig, MCPHeaders, MCPTransport, connectMCP, mcpToolToTool } from './mcp/index.js';
12
12
  export { SkillIndex } from './skills/index.js';
13
13
  export { BranchResult, CHECKPOINT_VERSION, Checkpoint, FailurePolicy, PatternHooks, StepResult, Workflow, WorkflowConfig, WorkflowContext, WorkflowEvent, WorkflowPattern, WorkflowState, WorkflowStatus, createCheckpoint, createWorkflow, restoreCheckpoint, runBounded, serializeCheckpoint, stepConcurrent, stepGroup, stepHandoff, stepSequential } from './workflows/index.js';
14
14
  export { useMiddleware } from './middleware/index.js';
package/dist/index.js CHANGED
@@ -5,13 +5,13 @@ export { loadAgentDefinition } from './chunk-DZFJ5MIF.js';
5
5
  export { buildMessages, createAgent, runLoop } from './chunk-IEX6XUZV.js';
6
6
  export { SkillIndex, defineSkill, loadSource } from './chunk-YCBDEEAV.js';
7
7
  export { ToolRegistry, namespacedName, validateArgs } from './chunk-HGEPXJDG.js';
8
- export { connectMCP, mcpToolToTool } from './chunk-QYG4HLIC.js';
9
8
  export { useMiddleware } from './chunk-IUKD54F7.js';
10
9
  export { composeMiddleware } from './chunk-7ZXUIHLH.js';
11
10
  export { configureObservability, isObservabilityEnabled, resetObservability, withSpan } from './chunk-5PDJOBTD.js';
11
+ export { connectMCP, mcpToolToTool } from './chunk-YVFQNJIU.js';
12
12
  export { ThreadPersistence, createBrowserStore, createMemoryStore } from './chunk-3KU76DCP.js';
13
13
  export { Thread, estimateTokens, hasImage, messageText, textMessage } from './chunk-LC54DGGR.js';
14
- export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry } from './chunk-K7ZWLHKU.js';
14
+ export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry } from './chunk-YVJGF4HQ.js';
15
15
  export { detectRuntime, requireCapability, resetRuntimeCache } from './chunk-QXAJ4DUJ.js';
16
16
  export { CheckpointError, FrameworkError, MCPError, ProviderError, RuntimeUnsupportedError, ToolError, ValidationError } from './chunk-IXV4UIF5.js';
17
17
  export { REDACTED, redact } from './chunk-DEABART4.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkU3ULJMNH_cjs = require('../chunk-U3ULJMNH.cjs');
3
+ var chunkSUTW6P6O_cjs = require('../chunk-SUTW6P6O.cjs');
4
4
  require('../chunk-N64ZFATA.cjs');
5
5
  require('../chunk-MQ2XTH3S.cjs');
6
6
  require('../chunk-IJASUMIQ.cjs');
@@ -9,11 +9,11 @@ require('../chunk-IJASUMIQ.cjs');
9
9
 
10
10
  Object.defineProperty(exports, "connectMCP", {
11
11
  enumerable: true,
12
- get: function () { return chunkU3ULJMNH_cjs.connectMCP; }
12
+ get: function () { return chunkSUTW6P6O_cjs.connectMCP; }
13
13
  });
14
14
  Object.defineProperty(exports, "mcpToolToTool", {
15
15
  enumerable: true,
16
- get: function () { return chunkU3ULJMNH_cjs.mcpToolToTool; }
16
+ get: function () { return chunkSUTW6P6O_cjs.mcpToolToTool; }
17
17
  });
18
18
  //# sourceMappingURL=index.cjs.map
19
19
  //# sourceMappingURL=index.cjs.map
@@ -16,14 +16,36 @@ import '../types-AlvjoTyS.cjs';
16
16
  * @packageDocumentation
17
17
  */
18
18
 
19
+ /**
20
+ * Custom HTTP headers for a remote MCP connection. Mirrors the `headers` object
21
+ * of an `mcp.json` HTTP server entry and is the standard way to pass secrets
22
+ * such as `Authorization: Bearer …` or `X-API-Key` tokens.
23
+ *
24
+ * It may be a static record or a (possibly async) callback that returns the
25
+ * headers. The callback form keeps the security model intact: secrets are
26
+ * resolved lazily at connect time (e.g. minting a fresh bearer token) and are
27
+ * never persisted on the config object. Empty/`null`/`undefined` values are
28
+ * dropped so blank auth headers are never sent.
29
+ */
30
+ type MCPHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
19
31
  /** Transport options for an MCP connection. */
20
32
  type MCPTransport = {
21
33
  kind: "remote";
22
34
  url: string;
35
+ /**
36
+ * Wire transport for the remote endpoint. Defaults to `"http"`
37
+ * (Streamable HTTP, the `"http"`/`"streamable-http"` type in `mcp.json`).
38
+ * Use `"sse"` for legacy Server-Sent Events servers. (FR-013a)
39
+ */
40
+ type?: "http" | "sse";
41
+ /** Custom request headers (auth tokens, API keys, content versions, …). */
42
+ headers?: MCPHeaders;
23
43
  } | {
24
44
  kind: "stdio";
25
45
  command: string;
26
46
  args?: string[];
47
+ /** Extra environment variables for the spawned server process. */
48
+ env?: Record<string, string>;
27
49
  };
28
50
  /** Configuration for connecting to an MCP server. */
29
51
  interface MCPConnectionConfig {
@@ -45,7 +67,15 @@ interface MCPConnection {
45
67
  *
46
68
  * @example
47
69
  * ```ts
48
- * const mcp = await connectMCP({ id: "docs", transport: { kind: "remote", url: "https://mcp.example.com" } });
70
+ * // Remote HTTP server with bearer auth (mirrors an mcp.json HTTP entry).
71
+ * const mcp = await connectMCP({
72
+ * id: "docs",
73
+ * transport: {
74
+ * kind: "remote",
75
+ * url: "https://api.example.com/mcp",
76
+ * headers: { Authorization: "Bearer your-api-token-here" },
77
+ * },
78
+ * });
49
79
  * const tools = await mcp.listTools(); // namespaced as docs.<tool>
50
80
  * ```
51
81
  */
@@ -69,4 +99,4 @@ interface MCPToolDef {
69
99
  */
70
100
  declare function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool;
71
101
 
72
- export { type MCPConnection, type MCPConnectionConfig, type MCPTransport, connectMCP, mcpToolToTool };
102
+ export { type MCPConnection, type MCPConnectionConfig, type MCPHeaders, type MCPTransport, connectMCP, mcpToolToTool };
@@ -16,14 +16,36 @@ import '../types-AlvjoTyS.js';
16
16
  * @packageDocumentation
17
17
  */
18
18
 
19
+ /**
20
+ * Custom HTTP headers for a remote MCP connection. Mirrors the `headers` object
21
+ * of an `mcp.json` HTTP server entry and is the standard way to pass secrets
22
+ * such as `Authorization: Bearer …` or `X-API-Key` tokens.
23
+ *
24
+ * It may be a static record or a (possibly async) callback that returns the
25
+ * headers. The callback form keeps the security model intact: secrets are
26
+ * resolved lazily at connect time (e.g. minting a fresh bearer token) and are
27
+ * never persisted on the config object. Empty/`null`/`undefined` values are
28
+ * dropped so blank auth headers are never sent.
29
+ */
30
+ type MCPHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
19
31
  /** Transport options for an MCP connection. */
20
32
  type MCPTransport = {
21
33
  kind: "remote";
22
34
  url: string;
35
+ /**
36
+ * Wire transport for the remote endpoint. Defaults to `"http"`
37
+ * (Streamable HTTP, the `"http"`/`"streamable-http"` type in `mcp.json`).
38
+ * Use `"sse"` for legacy Server-Sent Events servers. (FR-013a)
39
+ */
40
+ type?: "http" | "sse";
41
+ /** Custom request headers (auth tokens, API keys, content versions, …). */
42
+ headers?: MCPHeaders;
23
43
  } | {
24
44
  kind: "stdio";
25
45
  command: string;
26
46
  args?: string[];
47
+ /** Extra environment variables for the spawned server process. */
48
+ env?: Record<string, string>;
27
49
  };
28
50
  /** Configuration for connecting to an MCP server. */
29
51
  interface MCPConnectionConfig {
@@ -45,7 +67,15 @@ interface MCPConnection {
45
67
  *
46
68
  * @example
47
69
  * ```ts
48
- * const mcp = await connectMCP({ id: "docs", transport: { kind: "remote", url: "https://mcp.example.com" } });
70
+ * // Remote HTTP server with bearer auth (mirrors an mcp.json HTTP entry).
71
+ * const mcp = await connectMCP({
72
+ * id: "docs",
73
+ * transport: {
74
+ * kind: "remote",
75
+ * url: "https://api.example.com/mcp",
76
+ * headers: { Authorization: "Bearer your-api-token-here" },
77
+ * },
78
+ * });
49
79
  * const tools = await mcp.listTools(); // namespaced as docs.<tool>
50
80
  * ```
51
81
  */
@@ -69,4 +99,4 @@ interface MCPToolDef {
69
99
  */
70
100
  declare function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool;
71
101
 
72
- export { type MCPConnection, type MCPConnectionConfig, type MCPTransport, connectMCP, mcpToolToTool };
102
+ export { type MCPConnection, type MCPConnectionConfig, type MCPHeaders, type MCPTransport, connectMCP, mcpToolToTool };
package/dist/mcp/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { connectMCP, mcpToolToTool } from '../chunk-QYG4HLIC.js';
1
+ export { connectMCP, mcpToolToTool } from '../chunk-YVFQNJIU.js';
2
2
  import '../chunk-QXAJ4DUJ.js';
3
3
  import '../chunk-IXV4UIF5.js';
4
4
  import '../chunk-DEABART4.js';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkUEYT6XMA_cjs = require('../chunk-UEYT6XMA.cjs');
3
+ var chunkJLPLGU7O_cjs = require('../chunk-JLPLGU7O.cjs');
4
4
  require('../chunk-N64ZFATA.cjs');
5
5
  require('../chunk-MQ2XTH3S.cjs');
6
6
  require('../chunk-IJASUMIQ.cjs');
@@ -9,23 +9,23 @@ require('../chunk-IJASUMIQ.cjs');
9
9
 
10
10
  Object.defineProperty(exports, "createCopilotProvider", {
11
11
  enumerable: true,
12
- get: function () { return chunkUEYT6XMA_cjs.createCopilotProvider; }
12
+ get: function () { return chunkJLPLGU7O_cjs.createCopilotProvider; }
13
13
  });
14
14
  Object.defineProperty(exports, "createOpenAICompatibleProvider", {
15
15
  enumerable: true,
16
- get: function () { return chunkUEYT6XMA_cjs.createOpenAICompatibleProvider; }
16
+ get: function () { return chunkJLPLGU7O_cjs.createOpenAICompatibleProvider; }
17
17
  });
18
18
  Object.defineProperty(exports, "providerErrorFromStatus", {
19
19
  enumerable: true,
20
- get: function () { return chunkUEYT6XMA_cjs.providerErrorFromStatus; }
20
+ get: function () { return chunkJLPLGU7O_cjs.providerErrorFromStatus; }
21
21
  });
22
22
  Object.defineProperty(exports, "resolveModels", {
23
23
  enumerable: true,
24
- get: function () { return chunkUEYT6XMA_cjs.resolveModels; }
24
+ get: function () { return chunkJLPLGU7O_cjs.resolveModels; }
25
25
  });
26
26
  Object.defineProperty(exports, "withRetry", {
27
27
  enumerable: true,
28
- get: function () { return chunkUEYT6XMA_cjs.withRetry; }
28
+ get: function () { return chunkJLPLGU7O_cjs.withRetry; }
29
29
  });
30
30
  //# sourceMappingURL=index.cjs.map
31
31
  //# sourceMappingURL=index.cjs.map
@@ -1,4 +1,4 @@
1
- export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry } from '../chunk-K7ZWLHKU.js';
1
+ export { createCopilotProvider, createOpenAICompatibleProvider, providerErrorFromStatus, resolveModels, withRetry } from '../chunk-YVJGF4HQ.js';
2
2
  import '../chunk-QXAJ4DUJ.js';
3
3
  import '../chunk-IXV4UIF5.js';
4
4
  import '../chunk-DEABART4.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-framework-js",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Modular, tree-shakeable JavaScript/TypeScript agent framework for no-backend deployments (browser, edge, Node). Agents, tools, MCP, skills, multi-agent workflows, middleware, persistence, and OpenTelemetry observability.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/provider.ts","../src/providers/retry.ts","../src/providers/openai-compatible.ts","../src/providers/copilot.ts"],"names":[],"mappings":"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","file":"chunk-K7ZWLHKU.js","sourcesContent":["/**\n * LLM provider abstraction. Agents and workflows depend only on this interface,\n * never on a concrete provider, so new providers can be added without changing\n * agent/workflow code. (FR-007)\n *\n * Credentials are always obtained via a caller-supplied callback and are never\n * bundled, persisted, or logged by the framework. (FR-005a, FR-008)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** A caller-supplied source of credentials. The framework never stores the value. */\nexport interface CredentialSource {\n\t/** Return the current credential (token/api key). May be async. */\n\tgetCredential(): string | Promise<string>;\n}\n\n/**\n * Model configuration for a provider. A provider may expose **one or more** models\n * (e.g. GitHub Copilot offers several; an OpenAI-compatible endpoint is usually one).\n * Supply either a single `capabilities` object or an array via `models`.\n */\nexport interface ModelSelectionOptions {\n\t/** Single-model shorthand. */\n\tcapabilities?: ModelCapabilities;\n\t/** One or more models this provider can use. */\n\tmodels?: ModelCapabilities[];\n\t/** Name of the default model (defaults to the first entry). */\n\tdefaultModel?: string;\n}\n\n/** Resolved model set with a default and a lookup helper. */\nexport interface ResolvedModels {\n\t/** All configured models (at least one). */\n\tmodels: ModelCapabilities[];\n\t/** The default model used when a request does not specify one. */\n\tdefaultModel: ModelCapabilities;\n\t/** Look up a model by name, or return the default when omitted. */\n\tmodelOf(name?: string): ModelCapabilities;\n}\n\n/**\n * Normalize {@link ModelSelectionOptions} into a model list, a default, and a\n * lookup helper. Throws {@link ValidationError} if no model is configured or a\n * named model is missing.\n *\n * @example\n * ```ts\n * const { defaultModel, modelOf } = resolveModels({\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * ```\n */\nexport function resolveModels(options: ModelSelectionOptions): ResolvedModels {\n\tconst models = options.models ?? (options.capabilities ? [options.capabilities] : []);\n\tif (models.length === 0) {\n\t\tthrow new ValidationError(\"Provider requires at least one model (set `capabilities` or `models`)\");\n\t}\n\tconst defaultModel = options.defaultModel\n\t\t? models.find((m) => m.model === options.defaultModel)\n\t\t: models[0];\n\tif (!defaultModel) {\n\t\tthrow new ValidationError(`defaultModel \"${options.defaultModel}\" is not present in models`);\n\t}\n\tconst modelOf = (name?: string): ModelCapabilities => {\n\t\tif (!name) return defaultModel;\n\t\tconst found = models.find((m) => m.model === name);\n\t\tif (!found) {\n\t\t\tthrow new ValidationError(`Model \"${name}\" is not configured for this provider`);\n\t\t}\n\t\treturn found;\n\t};\n\treturn { models, defaultModel, modelOf };\n}\n\n/** A tool description passed to the provider so the model can decide to call it. */\nexport interface ToolSpec {\n\tname: string;\n\tdescription: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/** A request to generate a model response. */\nexport interface GenerateRequest {\n\tmessages: Message[];\n\ttools?: ToolSpec[];\n\t/** Which configured model to use; defaults to the provider's default model. */\n\tmodel?: string;\n\t/** Abort signal to cancel an in-flight request. */\n\tsignal?: AbortSignal;\n}\n\n/** A tool call requested by the model. */\nexport interface ToolCall {\n\tid: string;\n\tname: string;\n\t/** Raw JSON arguments (validated by the tools module before invocation). */\n\targuments: unknown;\n}\n\n/** A complete (non-streaming) model response. */\nexport interface GenerateResponse {\n\t/** Final answer text. */\n\ttext: string;\n\t/** Reasoning/thinking content — only present for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\t/**\n\t * Opaque reasoning blob (e.g. Claude thinking signature) to round-trip on the\n\t * next assistant turn for thinking continuity. Never logged or inspected.\n\t */\n\treasoningOpaque?: string;\n\t/** Tool calls the model wants to make, if any. */\n\ttoolCalls?: ToolCall[];\n\t/** Approximate token usage if reported by the provider. */\n\tusage?: { inputTokens?: number; outputTokens?: number };\n}\n\n/** An incremental streaming chunk. */\nexport type GenerateChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"tool-call\"; toolCall: ToolCall }\n\t| { type: \"done\"; response: GenerateResponse };\n\n/**\n * An LLM backend. Implementations adapt a concrete API (Copilot, OpenAI-compatible)\n * onto this uniform surface.\n */\nexport interface Provider {\n\t/** Stable provider identifier, e.g. `\"openai-compatible\"`. */\n\treadonly name: string;\n\t/** The default model's capability configuration. (FR-007a) */\n\treadonly capabilities: ModelCapabilities;\n\t/** All models this provider is configured with (one or more). */\n\treadonly models: ModelCapabilities[];\n\t/** Look up a configured model by name, or the default when omitted. */\n\tmodel(name?: string): ModelCapabilities;\n\t/** Generate a complete response. */\n\tgenerate(req: GenerateRequest): Promise<GenerateResponse>;\n\t/** Generate a streamed response. */\n\tgenerateStream(req: GenerateRequest): AsyncIterable<GenerateChunk>;\n}\n","/**\n * Exponential-backoff retry for transient provider failures. Transient errors\n * (429 with Retry-After, 5xx, network/timeout) are retried; auth/4xx fail fast.\n * (FR-008a)\n *\n * @packageDocumentation\n */\n\nimport { ProviderError } from \"../core/errors.js\";\n\n/** Retry tuning. All fields have safe defaults. */\nexport interface RetryOptions {\n\t/** Maximum retry attempts after the first try. Default 3. */\n\tmaxRetries?: number;\n\t/** Base delay in ms for backoff. Default 250. */\n\tbaseDelayMs?: number;\n\t/** Maximum delay cap in ms. Default 8000. */\n\tmaxDelayMs?: number;\n}\n\nconst DEFAULTS: Required<RetryOptions> = {\n\tmaxRetries: 3,\n\tbaseDelayMs: 250,\n\tmaxDelayMs: 8000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Run `fn`, retrying transient {@link ProviderError}s with exponential backoff\n * and jitter. Non-transient errors are rethrown immediately (fail fast).\n *\n * @param fn - The operation to attempt. It should throw a {@link ProviderError}.\n * @param opts - Retry tuning.\n * @param retryAfterMs - Optional hook returning a server-specified delay (Retry-After).\n */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\topts?: RetryOptions,\n\tretryAfterMs?: (err: ProviderError) => number | undefined,\n): Promise<T> {\n\tconst cfg = { ...DEFAULTS, ...opts };\n\tlet attempt = 0;\n\n\tfor (; ;) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst isRetryable = err instanceof ProviderError && err.retryable;\n\t\t\tif (!isRetryable || attempt >= cfg.maxRetries) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tconst serverDelay = retryAfterMs?.(err as ProviderError);\n\t\t\tconst backoff = Math.min(cfg.baseDelayMs * 2 ** attempt, cfg.maxDelayMs);\n\t\t\tconst jitter = Math.random() * cfg.baseDelayMs;\n\t\t\tawait sleep(serverDelay ?? backoff + jitter);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\n/** Map an HTTP status to a {@link ProviderError} with the right retry semantics. */\nexport function providerErrorFromStatus(status: number, message: string): ProviderError {\n\tif (status === 429 || status >= 500) {\n\t\treturn new ProviderError(message, \"transient\", { status });\n\t}\n\tif (status === 401 || status === 403) {\n\t\treturn new ProviderError(message, \"auth\", { status });\n\t}\n\treturn new ProviderError(message, \"client\", { status });\n}\n","/**\n * OpenAI-compatible provider. Targets any endpoint speaking the OpenAI\n * `/chat/completions` API, including local servers such as LM Studio via a custom\n * `baseUrl`, and GitHub Copilot (see {@link createCopilotProvider}). (FR-006)\n *\n * Provider compatibility notes (handled here so callers don't have to):\n * - Tool names are sanitized to `^[a-zA-Z0-9_-]+$` on the wire (OpenAI/Copilot\n * reject dotted names like `webiq.browse`) and translated back to the registry\n * key when the model calls them.\n * - Assistant turns that requested tools emit `tool_calls` with `content: null`\n * so strict providers (e.g. Anthropic) can pair each tool result with its call.\n * - Streaming responses accumulate `delta.tool_calls[]` keyed by `index`\n * (fragments may start at a non-zero index when reasoning occupies 0/1).\n * - Some reasoning models report `finish_reason: \"tool_calls\"` from the\n * non-streaming endpoint without a `tool_calls` array; `generate` transparently\n * re-requests in streaming mode and assembles them, failing loud (typed\n * {@link ProviderError}) rather than silently stopping if none materialize.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart, MessageToolCall } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type {\n\tProvider,\n\tCredentialSource,\n\tGenerateRequest,\n\tGenerateResponse,\n\tGenerateChunk,\n\tToolCall,\n\tToolSpec,\n} from \"./provider.js\";\nimport { resolveModels, type ModelSelectionOptions } from \"./provider.js\";\nimport { withRetry, providerErrorFromStatus, type RetryOptions } from \"./retry.js\";\n\n/**\n * Options for {@link createOpenAICompatibleProvider}.\n *\n * Supply a single model via `capabilities`, or multiple via `models` (most\n * OpenAI-compatible endpoints expose one model, but multiple are supported).\n */\nexport interface OpenAICompatibleProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Base URL of the OpenAI-compatible API, e.g. `http://localhost:1234/v1`. */\n\tbaseUrl: string;\n\t/**\n\t * Extra request headers merged into every call (e.g. provider-required\n\t * identification headers). The `authorization` header is always set from\n\t * `getCredential()` and cannot be overridden here.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface OpenAIMessage {\n\trole: string;\n\tcontent: unknown;\n\ttool_calls?: Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }>;\n\ttool_call_id?: string;\n\tname?: string;\n\treasoning_opaque?: string;\n}\n\n/** OpenAI/Copilot require tool names to match `^[a-zA-Z0-9_-]{1,128}$`. */\nconst UNSAFE_TOOL_NAME_CHARS = /[^a-zA-Z0-9_-]/g;\n\n/**\n * Sanitize a (possibly namespaced) tool name for the wire. Dotted MCP names like\n * `webiq.browse` become `webiq_browse`; the original is recovered via the\n * per-request name map when the model calls the tool.\n */\nfunction sanitizeToolName(name: string): string {\n\treturn name.replace(UNSAFE_TOOL_NAME_CHARS, \"_\");\n}\n\nfunction toOpenAIContent(parts: ContentPart[]): unknown {\n\tif (parts.every((p) => p.type === \"text\")) {\n\t\treturn parts.map((p) => (p as { text: string }).text).join(\"\");\n\t}\n\treturn parts.map((p) =>\n\t\tp.type === \"text\"\n\t\t\t? { type: \"text\", text: p.text }\n\t\t\t: { type: \"image_url\", image_url: { url: p.data } },\n\t);\n}\n\nfunction toWireToolCalls(\n\ttoolCalls: MessageToolCall[],\n): Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }> {\n\treturn toolCalls.map((tc) => ({\n\t\tid: tc.id,\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: sanitizeToolName(tc.name),\n\t\t\targuments:\n\t\t\t\ttypeof tc.arguments === \"string\" ? tc.arguments : JSON.stringify(tc.arguments ?? {}),\n\t\t},\n\t}));\n}\n\nfunction toOpenAIMessages(messages: Message[]): OpenAIMessage[] {\n\treturn messages.map((m) => {\n\t\tconst msg: OpenAIMessage = { role: m.role, content: toOpenAIContent(m.parts) };\n\t\tif (m.toolCalls && m.toolCalls.length > 0) {\n\t\t\tmsg.tool_calls = toWireToolCalls(m.toolCalls);\n\t\t\t// Strict providers require `content: null` (not \"\") on an assistant turn\n\t\t\t// that only carries tool calls.\n\t\t\tconst hasText = m.parts.some((p) => p.type === \"text\" && p.text.length > 0);\n\t\t\tif (!hasText) msg.content = null;\n\t\t}\n\t\tif (m.toolCallId) msg.tool_call_id = m.toolCallId;\n\t\tif (m.name) msg.name = sanitizeToolName(m.name);\n\t\tif (m.reasoningOpaque) msg.reasoning_opaque = m.reasoningOpaque;\n\t\treturn msg;\n\t});\n}\n\n/** Wire tool specs plus a map from sanitized name back to the registry key. */\ninterface WireTools {\n\ttools?: Array<{ type: \"function\"; function: { name: string; description: string; parameters: unknown } }>;\n\tnameMap: Map<string, string>;\n}\n\nfunction buildWireTools(specs?: ToolSpec[]): WireTools {\n\tconst nameMap = new Map<string, string>();\n\tif (!specs || specs.length === 0) return { tools: undefined, nameMap };\n\tconst tools = specs.map((t) => {\n\t\tconst wireName = sanitizeToolName(t.name);\n\t\tnameMap.set(wireName, t.name);\n\t\treturn {\n\t\t\ttype: \"function\" as const,\n\t\t\tfunction: { name: wireName, description: t.description, parameters: t.inputSchema },\n\t\t};\n\t});\n\treturn { tools, nameMap };\n}\n\n/**\n * Create an OpenAI-compatible provider (works with LM Studio, vLLM, etc.).\n *\n * @example\n * ```ts\n * const provider = createOpenAICompatibleProvider({\n * baseUrl: \"http://localhost:1234/v1\",\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * capabilities: { model: \"local\", maxInputTokens: 262144, maxOutputTokens: 32000 },\n * });\n * ```\n */\nexport function createOpenAICompatibleProvider(\n\toptions: OpenAICompatibleProviderOptions,\n): Provider {\n\tconst doFetch = options.fetchImpl ?? globalThis.fetch;\n\tconst url = `${options.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\tconst { models, defaultModel, modelOf } = resolveModels(options);\n\n\tasync function authHeaders(): Promise<Record<string, string>> {\n\t\tconst cred = await options.getCredential();\n\t\t// content-type first, then caller headers (may override it), then the\n\t\t// credential-derived authorization which always wins.\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(options.headers ?? {}),\n\t\t};\n\t\tif (cred) headers[\"authorization\"] = `Bearer ${cred}`;\n\t\treturn headers;\n\t}\n\n\tfunction body(req: GenerateRequest, stream: boolean, wire: WireTools): string {\n\t\treturn JSON.stringify({\n\t\t\tmodel: modelOf(req.model).model,\n\t\t\tmessages: toOpenAIMessages(req.messages),\n\t\t\tstream,\n\t\t\t// Ask the API to emit a trailing usage chunk on streamed responses so the\n\t\t\t// final `done` response can surface real token counts (FR usage reporting).\n\t\t\t...(stream ? { stream_options: { include_usage: true } } : {}),\n\t\t\t...(wire.tools ? { tools: wire.tools } : {}),\n\t\t});\n\t}\n\n\tfunction parseToolCalls(raw: unknown, nameMap: Map<string, string>): ToolCall[] | undefined {\n\t\tconst calls = (raw as {\n\t\t\ttool_calls?: Array<{ id: string; function: { name: string; arguments: string } }>;\n\t\t})?.tool_calls;\n\t\tif (!calls || calls.length === 0) return undefined;\n\t\treturn calls.map((c) => ({\n\t\t\tid: c.id,\n\t\t\tname: nameMap.get(c.function.name) ?? c.function.name,\n\t\t\targuments: safeJson(c.function.arguments),\n\t\t}));\n\t}\n\n\tasync function generate(req: GenerateRequest): Promise<GenerateResponse> {\n\t\treturn withRetry(async () => {\n\t\t\tconst wire = buildWireTools(req.tools);\n\t\t\tlet res: Response;\n\t\t\ttry {\n\t\t\t\tres = await doFetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: await authHeaders(),\n\t\t\t\t\tbody: body(req, false, wire),\n\t\t\t\t\tsignal: req.signal,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t\t}\n\t\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\n\t\t\tlet json: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tjson = (await res.json()) as Record<string, unknown>;\n\t\t\t} catch {\n\t\t\t\tthrow new ProviderError(\"Malformed provider response\", \"malformed\");\n\t\t\t}\n\t\t\tconst choice = (\n\t\t\t\tjson[\"choices\"] as Array<{ message: Record<string, unknown>; finish_reason?: string }>\n\t\t\t)?.[0];\n\t\t\tif (!choice) throw new ProviderError(\"Provider returned no choices\", \"malformed\");\n\t\t\tconst message = choice.message;\n\t\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\t\tconst usage = parseUsage(json[\"usage\"]);\n\t\t\tlet toolCalls = parseToolCalls(message, wire.nameMap);\n\n\t\t\t// Bug 4(b): some reasoning models report `finish_reason: \"tool_calls\"` from\n\t\t\t// the non-streaming endpoint without a `tool_calls` array. Re-request in\n\t\t\t// streaming mode and assemble them so the agent loop can proceed.\n\t\t\tif ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === \"tool_calls\") {\n\t\t\t\tconst assembled = await assembleViaStream(req);\n\t\t\t\ttoolCalls = assembled.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t\t\"Provider signaled tool_calls but returned none (even when streamed)\",\n\t\t\t\t\t\t\"malformed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: (message[\"content\"] as string) ?? assembled.text ?? \"\",\n\t\t\t\t\treasoning: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning\"] as string) ?? assembled.reasoning ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? assembled.reasoningOpaque ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\tusage: usage ?? assembled.usage,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: (message[\"content\"] as string) ?? \"\",\n\t\t\t\treasoning: reasoningModel ? ((message[\"reasoning\"] as string) ?? undefined) : undefined,\n\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t\ttoolCalls,\n\t\t\t\tusage,\n\t\t\t};\n\t\t}, options.retry);\n\t}\n\n\t/** Drive a streaming request to completion and return its assembled final response. */\n\tasync function assembleViaStream(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tlet final: GenerateResponse = { text: \"\" };\n\t\tfor await (const chunk of generateStream(req)) {\n\t\t\tif (chunk.type === \"done\") final = chunk.response;\n\t\t}\n\t\treturn final;\n\t}\n\n\tasync function* generateStream(req: GenerateRequest): AsyncIterable<GenerateChunk> {\n\t\tconst wire = buildWireTools(req.tools);\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await doFetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: await authHeaders(),\n\t\t\t\tbody: body(req, true, wire),\n\t\t\t\tsignal: req.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t}\n\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\t\tif (!res.body) throw new ProviderError(\"Provider returned no stream body\", \"malformed\");\n\n\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\tconst reader = res.body.getReader();\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet text = \"\";\n\t\tlet reasoning = \"\";\n\t\tlet reasoningOpaque = \"\";\n\t\t// Trailing usage chunk (sent once near the end when `include_usage` is set).\n\t\tlet usage: { inputTokens?: number; outputTokens?: number } | undefined;\n\t\t// Accumulate streamed tool-call fragments keyed by their `index` (which may\n\t\t// start at a non-zero value when reasoning deltas occupy the first indices).\n\t\tconst toolAccum = new Map<number, { id?: string; name?: string; args: string }>();\n\n\t\tfor (; ;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst trimmed = line.trim();\n\t\t\t\tif (!trimmed.startsWith(\"data:\")) continue;\n\t\t\t\tconst data = trimmed.slice(5).trim();\n\t\t\t\tif (data === \"[DONE]\") continue;\n\t\t\t\tconst parsed = safeJson(data) as\n\t\t\t\t\t| {\n\t\t\t\t\t\tchoices?: Array<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\treasoning?: string;\n\t\t\t\t\t\t\t\treasoning_opaque?: string;\n\t\t\t\t\t\t\t\ttool_calls?: Array<{\n\t\t\t\t\t\t\t\t\tindex?: number;\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}>;\n\t\t\t\t\t\tusage?: unknown;\n\t\t\t\t\t}\n\t\t\t\t\t| undefined;\n\t\t\t\t// The usage chunk arrives with an empty `choices` array, so parse it\n\t\t\t\t// before bailing on a missing delta.\n\t\t\t\tconst chunkUsage = parseUsage(parsed?.usage);\n\t\t\t\tif (chunkUsage) usage = chunkUsage;\n\t\t\t\tconst delta = parsed?.choices?.[0]?.delta;\n\t\t\t\tif (!delta) continue;\n\t\t\t\tif (delta.content) {\n\t\t\t\t\ttext += delta.content;\n\t\t\t\t\tyield { type: \"text\", text: delta.content };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning && reasoningModel) {\n\t\t\t\t\treasoning += delta.reasoning;\n\t\t\t\t\tyield { type: \"reasoning\", text: delta.reasoning };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning_opaque && reasoningModel) {\n\t\t\t\t\treasoningOpaque += delta.reasoning_opaque;\n\t\t\t\t}\n\t\t\t\tif (delta.tool_calls) {\n\t\t\t\t\tfor (const frag of delta.tool_calls) {\n\t\t\t\t\t\tconst idx = frag.index ?? 0;\n\t\t\t\t\t\tconst slot = toolAccum.get(idx) ?? { args: \"\" };\n\t\t\t\t\t\tif (frag.id) slot.id = frag.id;\n\t\t\t\t\t\tif (frag.function?.name) slot.name = frag.function.name;\n\t\t\t\t\t\tif (frag.function?.arguments) slot.args += frag.function.arguments;\n\t\t\t\t\t\ttoolAccum.set(idx, slot);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Materialize accumulated tool calls (sorted by stream index) and surface\n\t\t// them both as chunks and in the final `done` response.\n\t\tconst toolCalls: ToolCall[] = [...toolAccum.entries()]\n\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t.filter(([, s]) => s.name)\n\t\t\t.map(([idx, s]) => ({\n\t\t\t\tid: s.id ?? `call_${idx}`,\n\t\t\t\tname: wire.nameMap.get(s.name as string) ?? (s.name as string),\n\t\t\t\targuments: safeJson(s.args) ?? {},\n\t\t\t}));\n\t\tfor (const toolCall of toolCalls) {\n\t\t\tyield { type: \"tool-call\", toolCall };\n\t\t}\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresponse: {\n\t\t\t\ttext,\n\t\t\t\treasoning: reasoning || undefined,\n\t\t\t\treasoningOpaque: reasoningOpaque || undefined,\n\t\t\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\t\t\tusage,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tname: \"openai-compatible\",\n\t\tcapabilities: defaultModel,\n\t\tmodels,\n\t\tmodel: modelOf,\n\t\tgenerate,\n\t\tgenerateStream,\n\t};\n}\n\nfunction safeJson(s: string): unknown {\n\ttry {\n\t\treturn JSON.parse(s);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Normalize an OpenAI-style `usage` object (`prompt_tokens` / `completion_tokens`)\n * into the framework's `{ inputTokens, outputTokens }` shape. Returns `undefined`\n * when no usable counts are present so callers can fall back to estimation.\n */\nfunction parseUsage(raw: unknown): { inputTokens?: number; outputTokens?: number } | undefined {\n\tif (!raw || typeof raw !== \"object\") return undefined;\n\tconst u = raw as { prompt_tokens?: unknown; completion_tokens?: unknown };\n\tconst inputTokens = typeof u.prompt_tokens === \"number\" ? u.prompt_tokens : undefined;\n\tconst outputTokens = typeof u.completion_tokens === \"number\" ? u.completion_tokens : undefined;\n\tif (inputTokens === undefined && outputTokens === undefined) return undefined;\n\treturn { inputTokens, outputTokens };\n}\n","/**\n * GitHub Copilot provider. (FR-005)\n *\n * Copilot's chat API is OpenAI-compatible, so this provider configures the shared\n * OpenAI-compatible transport with Copilot's endpoint and the caller-supplied\n * credential (a Copilot/GitHub token). The token is obtained via callback and is\n * never bundled, persisted, or logged. (FR-005a)\n *\n * In a frontend-only deployment the end user supplies their own token (it stays\n * client-side); in a backend deployment the developer may supply it, or the user\n * sends it per request over SSL/TLS and the backend must not log or persist it.\n *\n * Note: the Copilot API (`api.githubcopilot.com`) sends no CORS headers, so it\n * cannot be called directly from a browser. A browser deployment must route through\n * a backend/proxy (set `baseUrl` to it); constructing this provider in a browser\n * against the default host throws {@link RuntimeUnsupportedError}.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, CredentialSource, ModelSelectionOptions } from \"./provider.js\";\nimport type { RetryOptions } from \"./retry.js\";\nimport { createOpenAICompatibleProvider } from \"./openai-compatible.js\";\nimport { detectRuntime } from \"../core/runtime.js\";\nimport { RuntimeUnsupportedError } from \"../core/errors.js\";\n\n/** Default Copilot-compatible chat completions base URL. */\nconst DEFAULT_COPILOT_BASE_URL = \"https://api.githubcopilot.com\";\n\n/**\n * Headers `api.githubcopilot.com` requires on every request. Omitting any of\n * these causes the API to reject the call with HTTP 400. They are sent by default\n * and can be overridden per option via `headers`.\n */\nconst COPILOT_DEFAULT_HEADERS: Record<string, string> = {\n\t\"Editor-Version\": \"vscode/1.95.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.20.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n\t\"Openai-Intent\": \"conversation-panel\",\n};\n\n/**\n * Options for {@link createCopilotProvider}.\n *\n * GitHub Copilot exposes several models, so configure them via `models` (with an\n * optional `defaultModel`). A single `capabilities` object is also accepted.\n */\nexport interface CopilotProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Override the Copilot base URL if needed. */\n\tbaseUrl?: string;\n\t/**\n\t * Extra/override request headers. Merged over the required Copilot defaults\n\t * (`Editor-Version`, `Editor-Plugin-Version`, `Copilot-Integration-Id`,\n\t * `Openai-Intent`), so you can adjust them without losing the others.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Create a GitHub Copilot provider.\n *\n * @example Single model\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken, // never logged or persisted\n * capabilities: { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * });\n * ```\n *\n * @example Multiple models\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken,\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * // Pick a model per request: provider.generate({ messages, model: \"o3-mini\" })\n * ```\n *\n * @throws {RuntimeUnsupportedError} when constructed in a browser against the\n * default Copilot host. `api.githubcopilot.com` does not send CORS headers, so a\n * browser cannot call it directly — host a small backend/proxy and point `baseUrl`\n * at it (which lifts this guard), or run the provider server-side (Node/edge).\n */\nexport function createCopilotProvider(options: CopilotProviderOptions): Provider {\n\tconst baseUrl = options.baseUrl ?? DEFAULT_COPILOT_BASE_URL;\n\n\t// Frontend-only guard: the Copilot API has no CORS support, so a browser must\n\t// route through a backend/proxy. Setting a custom `baseUrl` (your proxy) is the\n\t// supported opt-in and lifts this guard. Edge/Node (server-side) are unaffected.\n\tconst usingDefaultHost = baseUrl === DEFAULT_COPILOT_BASE_URL;\n\tif (usingDefaultHost && detectRuntime().isBrowser) {\n\t\tthrow new RuntimeUnsupportedError(\n\t\t\t\"GitHub Copilot directly from a browser (the Copilot API sends no CORS headers)\",\n\t\t\t{\n\t\t\t\treason: \"cors\",\n\t\t\t\tremedy:\n\t\t\t\t\t\"Run a lightweight backend/proxy (e.g. a Vite dev-server proxy or a small server route) \" +\n\t\t\t\t\t\"that forwards to https://api.githubcopilot.com, then set `baseUrl` to your proxy URL. \" +\n\t\t\t\t\t\"Alternatively, run the Copilot provider server-side (Node or an edge function).\",\n\t\t\t},\n\t\t);\n\t}\n\n\tconst inner = createOpenAICompatibleProvider({\n\t\tbaseUrl,\n\t\tgetCredential: options.getCredential,\n\t\tcapabilities: options.capabilities,\n\t\tmodels: options.models,\n\t\tdefaultModel: options.defaultModel,\n\t\t// Copilot rejects calls missing its identification headers; defaults are\n\t\t// applied here and remain overridable via `options.headers`.\n\t\theaders: { ...COPILOT_DEFAULT_HEADERS, ...(options.headers ?? {}) },\n\t\tretry: options.retry,\n\t\tfetchImpl: options.fetchImpl,\n\t});\n\t// Preserve the provider contract but report the Copilot name.\n\treturn {\n\t\tname: \"copilot\",\n\t\tcapabilities: inner.capabilities,\n\t\tmodels: inner.models,\n\t\tmodel: inner.model.bind(inner),\n\t\tgenerate: inner.generate.bind(inner),\n\t\tgenerateStream: inner.generateStream.bind(inner),\n\t};\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/adapter.ts","../src/mcp/connection.ts"],"names":[],"mappings":"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","file":"chunk-QYG4HLIC.js","sourcesContent":["/**\n * Adapts MCP-provided tools onto the framework's uniform {@link Tool} contract,\n * namespaced by the connection id so collisions are impossible. (FR-014, FR-014a)\n *\n * @packageDocumentation\n */\n\nimport type { Tool } from \"../tools/tool.js\";\nimport { MCPError } from \"../core/errors.js\";\n\ninterface MCPToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Wrap an MCP tool definition as a framework tool. Invocation calls back through\n * the MCP client; failures surface as typed {@link MCPError}/tool errors.\n */\nexport function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool {\n\treturn {\n\t\tname: def.name,\n\t\tdescription: def.description ?? \"\",\n\t\tinputSchema: def.inputSchema,\n\t\tsource: serverId,\n\t\tenabled: true,\n\t\tasync run(args: unknown): Promise<unknown> {\n\t\t\ttry {\n\t\t\t\tconst result = await client.callTool({ name: def.name, arguments: args });\n\t\t\t\treturn result.content ?? result;\n\t\t\t} catch (e) {\n\t\t\t\tthrow new MCPError(`MCP tool \"${def.name}\" failed: ${(e as Error).message}`, serverId);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * MCP (Model Context Protocol) integration. Connects to MCP servers and exposes\n * their tools through the framework's uniform tool interface.\n *\n * Remote transport (HTTP/SSE) works in all runtimes; stdio (spawning a server\n * process) works only where process spawning is permitted (Node). Requesting\n * stdio elsewhere throws a typed {@link RuntimeUnsupportedError}. (FR-013, FR-013a,\n * FR-013b, FR-030a)\n *\n * The `@modelcontextprotocol/sdk` package is an optional peer dependency and is\n * loaded lazily so browser bundles that do not use MCP pay no cost.\n *\n * @packageDocumentation\n */\n\nimport { MCPError } from \"../core/errors.js\";\nimport { requireCapability } from \"../core/runtime.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport { mcpToolToTool } from \"./adapter.js\";\n\n/** Transport options for an MCP connection. */\nexport type MCPTransport =\n\t| { kind: \"remote\"; url: string }\n\t| { kind: \"stdio\"; command: string; args?: string[] };\n\n/** Configuration for connecting to an MCP server. */\nexport interface MCPConnectionConfig {\n\t/** Connection id; becomes the namespace prefix for discovered tools. (FR-014a) */\n\tid: string;\n\ttransport: MCPTransport;\n\t/** Whether the connection's tools are enabled. Defaults to true. */\n\tenabled?: boolean;\n}\n\n/** A live connection to an MCP server. */\nexport interface MCPConnection {\n\treadonly id: string;\n\tconnect(): Promise<void>;\n\tlistTools(): Promise<Tool[]>;\n\tclose(): Promise<void>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyClient = any;\n\nasync function createTransport(config: MCPConnectionConfig): Promise<AnyClient> {\n\tif (config.transport.kind === \"stdio\") {\n\t\t// Gate on runtime capability before attempting to spawn. (FR-013b, FR-030a)\n\t\trequireCapability(\"canSpawnProcess\", \"MCP stdio transport\");\n\t\tconst { StdioClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/stdio.js\"\n\t\t);\n\t\treturn new StdioClientTransport({\n\t\t\tcommand: config.transport.command,\n\t\t\targs: config.transport.args ?? [],\n\t\t});\n\t}\n\tconst { StreamableHTTPClientTransport } = await import(\n\t\t\"@modelcontextprotocol/sdk/client/streamableHttp.js\"\n\t);\n\treturn new StreamableHTTPClientTransport(new URL(config.transport.url));\n}\n\n/**\n * Connect to an MCP server.\n *\n * @example\n * ```ts\n * const mcp = await connectMCP({ id: \"docs\", transport: { kind: \"remote\", url: \"https://mcp.example.com\" } });\n * const tools = await mcp.listTools(); // namespaced as docs.<tool>\n * ```\n */\nexport async function connectMCP(config: MCPConnectionConfig): Promise<MCPConnection> {\n\tlet client: AnyClient | undefined;\n\n\tasync function connect(): Promise<void> {\n\t\ttry {\n\t\t\tconst { Client } = await import(\"@modelcontextprotocol/sdk/client/index.js\");\n\t\t\tconst transport = await createTransport(config);\n\t\t\tclient = new Client({ name: \"agent-framework-js\", version: \"0.1.0\" }, { capabilities: {} });\n\t\t\tawait client.connect(transport);\n\t\t} catch (e) {\n\t\t\t// Preserve typed runtime errors; wrap everything else as an MCP error.\n\t\t\tif ((e as Error).name === \"RuntimeUnsupportedError\") throw e;\n\t\t\tthrow new MCPError(`Failed to connect to MCP server: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function listTools(): Promise<Tool[]> {\n\t\tif (!client) throw new MCPError(\"Not connected\", config.id);\n\t\ttry {\n\t\t\tconst result = await client.listTools();\n\t\t\treturn (result.tools ?? []).map((t: { name: string; description?: string; inputSchema: Record<string, unknown> }) =>\n\t\t\t\tmcpToolToTool(config.id, t, client),\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthrow new MCPError(`Failed to list tools: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function close(): Promise<void> {\n\t\tawait client?.close?.();\n\t\tclient = undefined;\n\t}\n\n\treturn { id: config.id, connect, listTools, close };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/adapter.ts","../src/mcp/connection.ts"],"names":["MCPError","requireCapability"],"mappings":"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","file":"chunk-U3ULJMNH.cjs","sourcesContent":["/**\n * Adapts MCP-provided tools onto the framework's uniform {@link Tool} contract,\n * namespaced by the connection id so collisions are impossible. (FR-014, FR-014a)\n *\n * @packageDocumentation\n */\n\nimport type { Tool } from \"../tools/tool.js\";\nimport { MCPError } from \"../core/errors.js\";\n\ninterface MCPToolDef {\n\tname: string;\n\tdescription?: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Wrap an MCP tool definition as a framework tool. Invocation calls back through\n * the MCP client; failures surface as typed {@link MCPError}/tool errors.\n */\nexport function mcpToolToTool(serverId: string, def: MCPToolDef, client: any): Tool {\n\treturn {\n\t\tname: def.name,\n\t\tdescription: def.description ?? \"\",\n\t\tinputSchema: def.inputSchema,\n\t\tsource: serverId,\n\t\tenabled: true,\n\t\tasync run(args: unknown): Promise<unknown> {\n\t\t\ttry {\n\t\t\t\tconst result = await client.callTool({ name: def.name, arguments: args });\n\t\t\t\treturn result.content ?? result;\n\t\t\t} catch (e) {\n\t\t\t\tthrow new MCPError(`MCP tool \"${def.name}\" failed: ${(e as Error).message}`, serverId);\n\t\t\t}\n\t\t},\n\t};\n}\n","/**\n * MCP (Model Context Protocol) integration. Connects to MCP servers and exposes\n * their tools through the framework's uniform tool interface.\n *\n * Remote transport (HTTP/SSE) works in all runtimes; stdio (spawning a server\n * process) works only where process spawning is permitted (Node). Requesting\n * stdio elsewhere throws a typed {@link RuntimeUnsupportedError}. (FR-013, FR-013a,\n * FR-013b, FR-030a)\n *\n * The `@modelcontextprotocol/sdk` package is an optional peer dependency and is\n * loaded lazily so browser bundles that do not use MCP pay no cost.\n *\n * @packageDocumentation\n */\n\nimport { MCPError } from \"../core/errors.js\";\nimport { requireCapability } from \"../core/runtime.js\";\nimport type { Tool } from \"../tools/tool.js\";\nimport { mcpToolToTool } from \"./adapter.js\";\n\n/** Transport options for an MCP connection. */\nexport type MCPTransport =\n\t| { kind: \"remote\"; url: string }\n\t| { kind: \"stdio\"; command: string; args?: string[] };\n\n/** Configuration for connecting to an MCP server. */\nexport interface MCPConnectionConfig {\n\t/** Connection id; becomes the namespace prefix for discovered tools. (FR-014a) */\n\tid: string;\n\ttransport: MCPTransport;\n\t/** Whether the connection's tools are enabled. Defaults to true. */\n\tenabled?: boolean;\n}\n\n/** A live connection to an MCP server. */\nexport interface MCPConnection {\n\treadonly id: string;\n\tconnect(): Promise<void>;\n\tlistTools(): Promise<Tool[]>;\n\tclose(): Promise<void>;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyClient = any;\n\nasync function createTransport(config: MCPConnectionConfig): Promise<AnyClient> {\n\tif (config.transport.kind === \"stdio\") {\n\t\t// Gate on runtime capability before attempting to spawn. (FR-013b, FR-030a)\n\t\trequireCapability(\"canSpawnProcess\", \"MCP stdio transport\");\n\t\tconst { StdioClientTransport } = await import(\n\t\t\t\"@modelcontextprotocol/sdk/client/stdio.js\"\n\t\t);\n\t\treturn new StdioClientTransport({\n\t\t\tcommand: config.transport.command,\n\t\t\targs: config.transport.args ?? [],\n\t\t});\n\t}\n\tconst { StreamableHTTPClientTransport } = await import(\n\t\t\"@modelcontextprotocol/sdk/client/streamableHttp.js\"\n\t);\n\treturn new StreamableHTTPClientTransport(new URL(config.transport.url));\n}\n\n/**\n * Connect to an MCP server.\n *\n * @example\n * ```ts\n * const mcp = await connectMCP({ id: \"docs\", transport: { kind: \"remote\", url: \"https://mcp.example.com\" } });\n * const tools = await mcp.listTools(); // namespaced as docs.<tool>\n * ```\n */\nexport async function connectMCP(config: MCPConnectionConfig): Promise<MCPConnection> {\n\tlet client: AnyClient | undefined;\n\n\tasync function connect(): Promise<void> {\n\t\ttry {\n\t\t\tconst { Client } = await import(\"@modelcontextprotocol/sdk/client/index.js\");\n\t\t\tconst transport = await createTransport(config);\n\t\t\tclient = new Client({ name: \"agent-framework-js\", version: \"0.1.0\" }, { capabilities: {} });\n\t\t\tawait client.connect(transport);\n\t\t} catch (e) {\n\t\t\t// Preserve typed runtime errors; wrap everything else as an MCP error.\n\t\t\tif ((e as Error).name === \"RuntimeUnsupportedError\") throw e;\n\t\t\tthrow new MCPError(`Failed to connect to MCP server: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function listTools(): Promise<Tool[]> {\n\t\tif (!client) throw new MCPError(\"Not connected\", config.id);\n\t\ttry {\n\t\t\tconst result = await client.listTools();\n\t\t\treturn (result.tools ?? []).map((t: { name: string; description?: string; inputSchema: Record<string, unknown> }) =>\n\t\t\t\tmcpToolToTool(config.id, t, client),\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tthrow new MCPError(`Failed to list tools: ${(e as Error).message}`, config.id);\n\t\t}\n\t}\n\n\tasync function close(): Promise<void> {\n\t\tawait client?.close?.();\n\t\tclient = undefined;\n\t}\n\n\treturn { id: config.id, connect, listTools, close };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/provider.ts","../src/providers/retry.ts","../src/providers/openai-compatible.ts","../src/providers/copilot.ts"],"names":["ValidationError","ProviderError","detectRuntime","RuntimeUnsupportedError"],"mappings":"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","file":"chunk-UEYT6XMA.cjs","sourcesContent":["/**\n * LLM provider abstraction. Agents and workflows depend only on this interface,\n * never on a concrete provider, so new providers can be added without changing\n * agent/workflow code. (FR-007)\n *\n * Credentials are always obtained via a caller-supplied callback and are never\n * bundled, persisted, or logged by the framework. (FR-005a, FR-008)\n *\n * @packageDocumentation\n */\n\nimport type { Message, ModelCapabilities } from \"../core/types.js\";\nimport { ValidationError } from \"../core/errors.js\";\n\n/** A caller-supplied source of credentials. The framework never stores the value. */\nexport interface CredentialSource {\n\t/** Return the current credential (token/api key). May be async. */\n\tgetCredential(): string | Promise<string>;\n}\n\n/**\n * Model configuration for a provider. A provider may expose **one or more** models\n * (e.g. GitHub Copilot offers several; an OpenAI-compatible endpoint is usually one).\n * Supply either a single `capabilities` object or an array via `models`.\n */\nexport interface ModelSelectionOptions {\n\t/** Single-model shorthand. */\n\tcapabilities?: ModelCapabilities;\n\t/** One or more models this provider can use. */\n\tmodels?: ModelCapabilities[];\n\t/** Name of the default model (defaults to the first entry). */\n\tdefaultModel?: string;\n}\n\n/** Resolved model set with a default and a lookup helper. */\nexport interface ResolvedModels {\n\t/** All configured models (at least one). */\n\tmodels: ModelCapabilities[];\n\t/** The default model used when a request does not specify one. */\n\tdefaultModel: ModelCapabilities;\n\t/** Look up a model by name, or return the default when omitted. */\n\tmodelOf(name?: string): ModelCapabilities;\n}\n\n/**\n * Normalize {@link ModelSelectionOptions} into a model list, a default, and a\n * lookup helper. Throws {@link ValidationError} if no model is configured or a\n * named model is missing.\n *\n * @example\n * ```ts\n * const { defaultModel, modelOf } = resolveModels({\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * ```\n */\nexport function resolveModels(options: ModelSelectionOptions): ResolvedModels {\n\tconst models = options.models ?? (options.capabilities ? [options.capabilities] : []);\n\tif (models.length === 0) {\n\t\tthrow new ValidationError(\"Provider requires at least one model (set `capabilities` or `models`)\");\n\t}\n\tconst defaultModel = options.defaultModel\n\t\t? models.find((m) => m.model === options.defaultModel)\n\t\t: models[0];\n\tif (!defaultModel) {\n\t\tthrow new ValidationError(`defaultModel \"${options.defaultModel}\" is not present in models`);\n\t}\n\tconst modelOf = (name?: string): ModelCapabilities => {\n\t\tif (!name) return defaultModel;\n\t\tconst found = models.find((m) => m.model === name);\n\t\tif (!found) {\n\t\t\tthrow new ValidationError(`Model \"${name}\" is not configured for this provider`);\n\t\t}\n\t\treturn found;\n\t};\n\treturn { models, defaultModel, modelOf };\n}\n\n/** A tool description passed to the provider so the model can decide to call it. */\nexport interface ToolSpec {\n\tname: string;\n\tdescription: string;\n\tinputSchema: Record<string, unknown>;\n}\n\n/** A request to generate a model response. */\nexport interface GenerateRequest {\n\tmessages: Message[];\n\ttools?: ToolSpec[];\n\t/** Which configured model to use; defaults to the provider's default model. */\n\tmodel?: string;\n\t/** Abort signal to cancel an in-flight request. */\n\tsignal?: AbortSignal;\n}\n\n/** A tool call requested by the model. */\nexport interface ToolCall {\n\tid: string;\n\tname: string;\n\t/** Raw JSON arguments (validated by the tools module before invocation). */\n\targuments: unknown;\n}\n\n/** A complete (non-streaming) model response. */\nexport interface GenerateResponse {\n\t/** Final answer text. */\n\ttext: string;\n\t/** Reasoning/thinking content — only present for reasoning-capable models. (FR-003a) */\n\treasoning?: string;\n\t/**\n\t * Opaque reasoning blob (e.g. Claude thinking signature) to round-trip on the\n\t * next assistant turn for thinking continuity. Never logged or inspected.\n\t */\n\treasoningOpaque?: string;\n\t/** Tool calls the model wants to make, if any. */\n\ttoolCalls?: ToolCall[];\n\t/** Approximate token usage if reported by the provider. */\n\tusage?: { inputTokens?: number; outputTokens?: number };\n}\n\n/** An incremental streaming chunk. */\nexport type GenerateChunk =\n\t| { type: \"text\"; text: string }\n\t| { type: \"reasoning\"; text: string }\n\t| { type: \"tool-call\"; toolCall: ToolCall }\n\t| { type: \"done\"; response: GenerateResponse };\n\n/**\n * An LLM backend. Implementations adapt a concrete API (Copilot, OpenAI-compatible)\n * onto this uniform surface.\n */\nexport interface Provider {\n\t/** Stable provider identifier, e.g. `\"openai-compatible\"`. */\n\treadonly name: string;\n\t/** The default model's capability configuration. (FR-007a) */\n\treadonly capabilities: ModelCapabilities;\n\t/** All models this provider is configured with (one or more). */\n\treadonly models: ModelCapabilities[];\n\t/** Look up a configured model by name, or the default when omitted. */\n\tmodel(name?: string): ModelCapabilities;\n\t/** Generate a complete response. */\n\tgenerate(req: GenerateRequest): Promise<GenerateResponse>;\n\t/** Generate a streamed response. */\n\tgenerateStream(req: GenerateRequest): AsyncIterable<GenerateChunk>;\n}\n","/**\n * Exponential-backoff retry for transient provider failures. Transient errors\n * (429 with Retry-After, 5xx, network/timeout) are retried; auth/4xx fail fast.\n * (FR-008a)\n *\n * @packageDocumentation\n */\n\nimport { ProviderError } from \"../core/errors.js\";\n\n/** Retry tuning. All fields have safe defaults. */\nexport interface RetryOptions {\n\t/** Maximum retry attempts after the first try. Default 3. */\n\tmaxRetries?: number;\n\t/** Base delay in ms for backoff. Default 250. */\n\tbaseDelayMs?: number;\n\t/** Maximum delay cap in ms. Default 8000. */\n\tmaxDelayMs?: number;\n}\n\nconst DEFAULTS: Required<RetryOptions> = {\n\tmaxRetries: 3,\n\tbaseDelayMs: 250,\n\tmaxDelayMs: 8000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((r) => setTimeout(r, ms));\n}\n\n/**\n * Run `fn`, retrying transient {@link ProviderError}s with exponential backoff\n * and jitter. Non-transient errors are rethrown immediately (fail fast).\n *\n * @param fn - The operation to attempt. It should throw a {@link ProviderError}.\n * @param opts - Retry tuning.\n * @param retryAfterMs - Optional hook returning a server-specified delay (Retry-After).\n */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\topts?: RetryOptions,\n\tretryAfterMs?: (err: ProviderError) => number | undefined,\n): Promise<T> {\n\tconst cfg = { ...DEFAULTS, ...opts };\n\tlet attempt = 0;\n\n\tfor (; ;) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst isRetryable = err instanceof ProviderError && err.retryable;\n\t\t\tif (!isRetryable || attempt >= cfg.maxRetries) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tconst serverDelay = retryAfterMs?.(err as ProviderError);\n\t\t\tconst backoff = Math.min(cfg.baseDelayMs * 2 ** attempt, cfg.maxDelayMs);\n\t\t\tconst jitter = Math.random() * cfg.baseDelayMs;\n\t\t\tawait sleep(serverDelay ?? backoff + jitter);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\n/** Map an HTTP status to a {@link ProviderError} with the right retry semantics. */\nexport function providerErrorFromStatus(status: number, message: string): ProviderError {\n\tif (status === 429 || status >= 500) {\n\t\treturn new ProviderError(message, \"transient\", { status });\n\t}\n\tif (status === 401 || status === 403) {\n\t\treturn new ProviderError(message, \"auth\", { status });\n\t}\n\treturn new ProviderError(message, \"client\", { status });\n}\n","/**\n * OpenAI-compatible provider. Targets any endpoint speaking the OpenAI\n * `/chat/completions` API, including local servers such as LM Studio via a custom\n * `baseUrl`, and GitHub Copilot (see {@link createCopilotProvider}). (FR-006)\n *\n * Provider compatibility notes (handled here so callers don't have to):\n * - Tool names are sanitized to `^[a-zA-Z0-9_-]+$` on the wire (OpenAI/Copilot\n * reject dotted names like `webiq.browse`) and translated back to the registry\n * key when the model calls them.\n * - Assistant turns that requested tools emit `tool_calls` with `content: null`\n * so strict providers (e.g. Anthropic) can pair each tool result with its call.\n * - Streaming responses accumulate `delta.tool_calls[]` keyed by `index`\n * (fragments may start at a non-zero index when reasoning occupies 0/1).\n * - Some reasoning models report `finish_reason: \"tool_calls\"` from the\n * non-streaming endpoint without a `tool_calls` array; `generate` transparently\n * re-requests in streaming mode and assembles them, failing loud (typed\n * {@link ProviderError}) rather than silently stopping if none materialize.\n *\n * @packageDocumentation\n */\n\nimport type { Message, ContentPart, MessageToolCall } from \"../core/types.js\";\nimport { ProviderError } from \"../core/errors.js\";\nimport type {\n\tProvider,\n\tCredentialSource,\n\tGenerateRequest,\n\tGenerateResponse,\n\tGenerateChunk,\n\tToolCall,\n\tToolSpec,\n} from \"./provider.js\";\nimport { resolveModels, type ModelSelectionOptions } from \"./provider.js\";\nimport { withRetry, providerErrorFromStatus, type RetryOptions } from \"./retry.js\";\n\n/**\n * Options for {@link createOpenAICompatibleProvider}.\n *\n * Supply a single model via `capabilities`, or multiple via `models` (most\n * OpenAI-compatible endpoints expose one model, but multiple are supported).\n */\nexport interface OpenAICompatibleProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Base URL of the OpenAI-compatible API, e.g. `http://localhost:1234/v1`. */\n\tbaseUrl: string;\n\t/**\n\t * Extra request headers merged into every call (e.g. provider-required\n\t * identification headers). The `authorization` header is always set from\n\t * `getCredential()` and cannot be overridden here.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\ninterface OpenAIMessage {\n\trole: string;\n\tcontent: unknown;\n\ttool_calls?: Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }>;\n\ttool_call_id?: string;\n\tname?: string;\n\treasoning_opaque?: string;\n}\n\n/** OpenAI/Copilot require tool names to match `^[a-zA-Z0-9_-]{1,128}$`. */\nconst UNSAFE_TOOL_NAME_CHARS = /[^a-zA-Z0-9_-]/g;\n\n/**\n * Sanitize a (possibly namespaced) tool name for the wire. Dotted MCP names like\n * `webiq.browse` become `webiq_browse`; the original is recovered via the\n * per-request name map when the model calls the tool.\n */\nfunction sanitizeToolName(name: string): string {\n\treturn name.replace(UNSAFE_TOOL_NAME_CHARS, \"_\");\n}\n\nfunction toOpenAIContent(parts: ContentPart[]): unknown {\n\tif (parts.every((p) => p.type === \"text\")) {\n\t\treturn parts.map((p) => (p as { text: string }).text).join(\"\");\n\t}\n\treturn parts.map((p) =>\n\t\tp.type === \"text\"\n\t\t\t? { type: \"text\", text: p.text }\n\t\t\t: { type: \"image_url\", image_url: { url: p.data } },\n\t);\n}\n\nfunction toWireToolCalls(\n\ttoolCalls: MessageToolCall[],\n): Array<{ id: string; type: \"function\"; function: { name: string; arguments: string } }> {\n\treturn toolCalls.map((tc) => ({\n\t\tid: tc.id,\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: sanitizeToolName(tc.name),\n\t\t\targuments:\n\t\t\t\ttypeof tc.arguments === \"string\" ? tc.arguments : JSON.stringify(tc.arguments ?? {}),\n\t\t},\n\t}));\n}\n\nfunction toOpenAIMessages(messages: Message[]): OpenAIMessage[] {\n\treturn messages.map((m) => {\n\t\tconst msg: OpenAIMessage = { role: m.role, content: toOpenAIContent(m.parts) };\n\t\tif (m.toolCalls && m.toolCalls.length > 0) {\n\t\t\tmsg.tool_calls = toWireToolCalls(m.toolCalls);\n\t\t\t// Strict providers require `content: null` (not \"\") on an assistant turn\n\t\t\t// that only carries tool calls.\n\t\t\tconst hasText = m.parts.some((p) => p.type === \"text\" && p.text.length > 0);\n\t\t\tif (!hasText) msg.content = null;\n\t\t}\n\t\tif (m.toolCallId) msg.tool_call_id = m.toolCallId;\n\t\tif (m.name) msg.name = sanitizeToolName(m.name);\n\t\tif (m.reasoningOpaque) msg.reasoning_opaque = m.reasoningOpaque;\n\t\treturn msg;\n\t});\n}\n\n/** Wire tool specs plus a map from sanitized name back to the registry key. */\ninterface WireTools {\n\ttools?: Array<{ type: \"function\"; function: { name: string; description: string; parameters: unknown } }>;\n\tnameMap: Map<string, string>;\n}\n\nfunction buildWireTools(specs?: ToolSpec[]): WireTools {\n\tconst nameMap = new Map<string, string>();\n\tif (!specs || specs.length === 0) return { tools: undefined, nameMap };\n\tconst tools = specs.map((t) => {\n\t\tconst wireName = sanitizeToolName(t.name);\n\t\tnameMap.set(wireName, t.name);\n\t\treturn {\n\t\t\ttype: \"function\" as const,\n\t\t\tfunction: { name: wireName, description: t.description, parameters: t.inputSchema },\n\t\t};\n\t});\n\treturn { tools, nameMap };\n}\n\n/**\n * Create an OpenAI-compatible provider (works with LM Studio, vLLM, etc.).\n *\n * @example\n * ```ts\n * const provider = createOpenAICompatibleProvider({\n * baseUrl: \"http://localhost:1234/v1\",\n * getCredential: () => process.env.LMSTUDIO_KEY ?? \"\",\n * capabilities: { model: \"local\", maxInputTokens: 262144, maxOutputTokens: 32000 },\n * });\n * ```\n */\nexport function createOpenAICompatibleProvider(\n\toptions: OpenAICompatibleProviderOptions,\n): Provider {\n\tconst doFetch = options.fetchImpl ?? globalThis.fetch;\n\tconst url = `${options.baseUrl.replace(/\\/$/, \"\")}/chat/completions`;\n\tconst { models, defaultModel, modelOf } = resolveModels(options);\n\n\tasync function authHeaders(): Promise<Record<string, string>> {\n\t\tconst cred = await options.getCredential();\n\t\t// content-type first, then caller headers (may override it), then the\n\t\t// credential-derived authorization which always wins.\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"content-type\": \"application/json\",\n\t\t\t...(options.headers ?? {}),\n\t\t};\n\t\tif (cred) headers[\"authorization\"] = `Bearer ${cred}`;\n\t\treturn headers;\n\t}\n\n\tfunction body(req: GenerateRequest, stream: boolean, wire: WireTools): string {\n\t\treturn JSON.stringify({\n\t\t\tmodel: modelOf(req.model).model,\n\t\t\tmessages: toOpenAIMessages(req.messages),\n\t\t\tstream,\n\t\t\t// Ask the API to emit a trailing usage chunk on streamed responses so the\n\t\t\t// final `done` response can surface real token counts (FR usage reporting).\n\t\t\t...(stream ? { stream_options: { include_usage: true } } : {}),\n\t\t\t...(wire.tools ? { tools: wire.tools } : {}),\n\t\t});\n\t}\n\n\tfunction parseToolCalls(raw: unknown, nameMap: Map<string, string>): ToolCall[] | undefined {\n\t\tconst calls = (raw as {\n\t\t\ttool_calls?: Array<{ id: string; function: { name: string; arguments: string } }>;\n\t\t})?.tool_calls;\n\t\tif (!calls || calls.length === 0) return undefined;\n\t\treturn calls.map((c) => ({\n\t\t\tid: c.id,\n\t\t\tname: nameMap.get(c.function.name) ?? c.function.name,\n\t\t\targuments: safeJson(c.function.arguments),\n\t\t}));\n\t}\n\n\tasync function generate(req: GenerateRequest): Promise<GenerateResponse> {\n\t\treturn withRetry(async () => {\n\t\t\tconst wire = buildWireTools(req.tools);\n\t\t\tlet res: Response;\n\t\t\ttry {\n\t\t\t\tres = await doFetch(url, {\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\theaders: await authHeaders(),\n\t\t\t\t\tbody: body(req, false, wire),\n\t\t\t\t\tsignal: req.signal,\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t\t}\n\t\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\n\t\t\tlet json: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tjson = (await res.json()) as Record<string, unknown>;\n\t\t\t} catch {\n\t\t\t\tthrow new ProviderError(\"Malformed provider response\", \"malformed\");\n\t\t\t}\n\t\t\tconst choice = (\n\t\t\t\tjson[\"choices\"] as Array<{ message: Record<string, unknown>; finish_reason?: string }>\n\t\t\t)?.[0];\n\t\t\tif (!choice) throw new ProviderError(\"Provider returned no choices\", \"malformed\");\n\t\t\tconst message = choice.message;\n\t\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\t\tconst usage = parseUsage(json[\"usage\"]);\n\t\t\tlet toolCalls = parseToolCalls(message, wire.nameMap);\n\n\t\t\t// Bug 4(b): some reasoning models report `finish_reason: \"tool_calls\"` from\n\t\t\t// the non-streaming endpoint without a `tool_calls` array. Re-request in\n\t\t\t// streaming mode and assemble them so the agent loop can proceed.\n\t\t\tif ((!toolCalls || toolCalls.length === 0) && choice.finish_reason === \"tool_calls\") {\n\t\t\t\tconst assembled = await assembleViaStream(req);\n\t\t\t\ttoolCalls = assembled.toolCalls;\n\t\t\t\tif (!toolCalls || toolCalls.length === 0) {\n\t\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t\t\"Provider signaled tool_calls but returned none (even when streamed)\",\n\t\t\t\t\t\t\"malformed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\ttext: (message[\"content\"] as string) ?? assembled.text ?? \"\",\n\t\t\t\t\treasoning: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning\"] as string) ?? assembled.reasoning ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? assembled.reasoningOpaque ?? undefined)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\ttoolCalls,\n\t\t\t\t\tusage: usage ?? assembled.usage,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: (message[\"content\"] as string) ?? \"\",\n\t\t\t\treasoning: reasoningModel ? ((message[\"reasoning\"] as string) ?? undefined) : undefined,\n\t\t\t\treasoningOpaque: reasoningModel\n\t\t\t\t\t? ((message[\"reasoning_opaque\"] as string) ?? undefined)\n\t\t\t\t\t: undefined,\n\t\t\t\ttoolCalls,\n\t\t\t\tusage,\n\t\t\t};\n\t\t}, options.retry);\n\t}\n\n\t/** Drive a streaming request to completion and return its assembled final response. */\n\tasync function assembleViaStream(req: GenerateRequest): Promise<GenerateResponse> {\n\t\tlet final: GenerateResponse = { text: \"\" };\n\t\tfor await (const chunk of generateStream(req)) {\n\t\t\tif (chunk.type === \"done\") final = chunk.response;\n\t\t}\n\t\treturn final;\n\t}\n\n\tasync function* generateStream(req: GenerateRequest): AsyncIterable<GenerateChunk> {\n\t\tconst wire = buildWireTools(req.tools);\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await doFetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: await authHeaders(),\n\t\t\t\tbody: body(req, true, wire),\n\t\t\t\tsignal: req.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tthrow new ProviderError(`Network error: ${(e as Error).message}`, \"transient\");\n\t\t}\n\t\tif (!res.ok) throw providerErrorFromStatus(res.status, `Provider returned ${res.status}`);\n\t\tif (!res.body) throw new ProviderError(\"Provider returned no stream body\", \"malformed\");\n\n\t\tconst reasoningModel = modelOf(req.model).supportsReasoning;\n\t\tconst reader = res.body.getReader();\n\t\tconst decoder = new TextDecoder();\n\t\tlet buffer = \"\";\n\t\tlet text = \"\";\n\t\tlet reasoning = \"\";\n\t\tlet reasoningOpaque = \"\";\n\t\t// Trailing usage chunk (sent once near the end when `include_usage` is set).\n\t\tlet usage: { inputTokens?: number; outputTokens?: number } | undefined;\n\t\t// Accumulate streamed tool-call fragments keyed by their `index` (which may\n\t\t// start at a non-zero value when reasoning deltas occupy the first indices).\n\t\tconst toolAccum = new Map<number, { id?: string; name?: string; args: string }>();\n\n\t\tfor (; ;) {\n\t\t\tconst { value, done } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\tbuffer = lines.pop() ?? \"\";\n\t\t\tfor (const line of lines) {\n\t\t\t\tconst trimmed = line.trim();\n\t\t\t\tif (!trimmed.startsWith(\"data:\")) continue;\n\t\t\t\tconst data = trimmed.slice(5).trim();\n\t\t\t\tif (data === \"[DONE]\") continue;\n\t\t\t\tconst parsed = safeJson(data) as\n\t\t\t\t\t| {\n\t\t\t\t\t\tchoices?: Array<{\n\t\t\t\t\t\t\tdelta?: {\n\t\t\t\t\t\t\t\tcontent?: string;\n\t\t\t\t\t\t\t\treasoning?: string;\n\t\t\t\t\t\t\t\treasoning_opaque?: string;\n\t\t\t\t\t\t\t\ttool_calls?: Array<{\n\t\t\t\t\t\t\t\t\tindex?: number;\n\t\t\t\t\t\t\t\t\tid?: string;\n\t\t\t\t\t\t\t\t\tfunction?: { name?: string; arguments?: string };\n\t\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}>;\n\t\t\t\t\t\tusage?: unknown;\n\t\t\t\t\t}\n\t\t\t\t\t| undefined;\n\t\t\t\t// The usage chunk arrives with an empty `choices` array, so parse it\n\t\t\t\t// before bailing on a missing delta.\n\t\t\t\tconst chunkUsage = parseUsage(parsed?.usage);\n\t\t\t\tif (chunkUsage) usage = chunkUsage;\n\t\t\t\tconst delta = parsed?.choices?.[0]?.delta;\n\t\t\t\tif (!delta) continue;\n\t\t\t\tif (delta.content) {\n\t\t\t\t\ttext += delta.content;\n\t\t\t\t\tyield { type: \"text\", text: delta.content };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning && reasoningModel) {\n\t\t\t\t\treasoning += delta.reasoning;\n\t\t\t\t\tyield { type: \"reasoning\", text: delta.reasoning };\n\t\t\t\t}\n\t\t\t\tif (delta.reasoning_opaque && reasoningModel) {\n\t\t\t\t\treasoningOpaque += delta.reasoning_opaque;\n\t\t\t\t}\n\t\t\t\tif (delta.tool_calls) {\n\t\t\t\t\tfor (const frag of delta.tool_calls) {\n\t\t\t\t\t\tconst idx = frag.index ?? 0;\n\t\t\t\t\t\tconst slot = toolAccum.get(idx) ?? { args: \"\" };\n\t\t\t\t\t\tif (frag.id) slot.id = frag.id;\n\t\t\t\t\t\tif (frag.function?.name) slot.name = frag.function.name;\n\t\t\t\t\t\tif (frag.function?.arguments) slot.args += frag.function.arguments;\n\t\t\t\t\t\ttoolAccum.set(idx, slot);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Materialize accumulated tool calls (sorted by stream index) and surface\n\t\t// them both as chunks and in the final `done` response.\n\t\tconst toolCalls: ToolCall[] = [...toolAccum.entries()]\n\t\t\t.sort((a, b) => a[0] - b[0])\n\t\t\t.filter(([, s]) => s.name)\n\t\t\t.map(([idx, s]) => ({\n\t\t\t\tid: s.id ?? `call_${idx}`,\n\t\t\t\tname: wire.nameMap.get(s.name as string) ?? (s.name as string),\n\t\t\t\targuments: safeJson(s.args) ?? {},\n\t\t\t}));\n\t\tfor (const toolCall of toolCalls) {\n\t\t\tyield { type: \"tool-call\", toolCall };\n\t\t}\n\t\tyield {\n\t\t\ttype: \"done\",\n\t\t\tresponse: {\n\t\t\t\ttext,\n\t\t\t\treasoning: reasoning || undefined,\n\t\t\t\treasoningOpaque: reasoningOpaque || undefined,\n\t\t\t\ttoolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n\t\t\t\tusage,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tname: \"openai-compatible\",\n\t\tcapabilities: defaultModel,\n\t\tmodels,\n\t\tmodel: modelOf,\n\t\tgenerate,\n\t\tgenerateStream,\n\t};\n}\n\nfunction safeJson(s: string): unknown {\n\ttry {\n\t\treturn JSON.parse(s);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Normalize an OpenAI-style `usage` object (`prompt_tokens` / `completion_tokens`)\n * into the framework's `{ inputTokens, outputTokens }` shape. Returns `undefined`\n * when no usable counts are present so callers can fall back to estimation.\n */\nfunction parseUsage(raw: unknown): { inputTokens?: number; outputTokens?: number } | undefined {\n\tif (!raw || typeof raw !== \"object\") return undefined;\n\tconst u = raw as { prompt_tokens?: unknown; completion_tokens?: unknown };\n\tconst inputTokens = typeof u.prompt_tokens === \"number\" ? u.prompt_tokens : undefined;\n\tconst outputTokens = typeof u.completion_tokens === \"number\" ? u.completion_tokens : undefined;\n\tif (inputTokens === undefined && outputTokens === undefined) return undefined;\n\treturn { inputTokens, outputTokens };\n}\n","/**\n * GitHub Copilot provider. (FR-005)\n *\n * Copilot's chat API is OpenAI-compatible, so this provider configures the shared\n * OpenAI-compatible transport with Copilot's endpoint and the caller-supplied\n * credential (a Copilot/GitHub token). The token is obtained via callback and is\n * never bundled, persisted, or logged. (FR-005a)\n *\n * In a frontend-only deployment the end user supplies their own token (it stays\n * client-side); in a backend deployment the developer may supply it, or the user\n * sends it per request over SSL/TLS and the backend must not log or persist it.\n *\n * Note: the Copilot API (`api.githubcopilot.com`) sends no CORS headers, so it\n * cannot be called directly from a browser. A browser deployment must route through\n * a backend/proxy (set `baseUrl` to it); constructing this provider in a browser\n * against the default host throws {@link RuntimeUnsupportedError}.\n *\n * @packageDocumentation\n */\n\nimport type { Provider, CredentialSource, ModelSelectionOptions } from \"./provider.js\";\nimport type { RetryOptions } from \"./retry.js\";\nimport { createOpenAICompatibleProvider } from \"./openai-compatible.js\";\nimport { detectRuntime } from \"../core/runtime.js\";\nimport { RuntimeUnsupportedError } from \"../core/errors.js\";\n\n/** Default Copilot-compatible chat completions base URL. */\nconst DEFAULT_COPILOT_BASE_URL = \"https://api.githubcopilot.com\";\n\n/**\n * Headers `api.githubcopilot.com` requires on every request. Omitting any of\n * these causes the API to reject the call with HTTP 400. They are sent by default\n * and can be overridden per option via `headers`.\n */\nconst COPILOT_DEFAULT_HEADERS: Record<string, string> = {\n\t\"Editor-Version\": \"vscode/1.95.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.20.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n\t\"Openai-Intent\": \"conversation-panel\",\n};\n\n/**\n * Options for {@link createCopilotProvider}.\n *\n * GitHub Copilot exposes several models, so configure them via `models` (with an\n * optional `defaultModel`). A single `capabilities` object is also accepted.\n */\nexport interface CopilotProviderOptions extends CredentialSource, ModelSelectionOptions {\n\t/** Override the Copilot base URL if needed. */\n\tbaseUrl?: string;\n\t/**\n\t * Extra/override request headers. Merged over the required Copilot defaults\n\t * (`Editor-Version`, `Editor-Plugin-Version`, `Copilot-Integration-Id`,\n\t * `Openai-Intent`), so you can adjust them without losing the others.\n\t */\n\theaders?: Record<string, string>;\n\t/** Retry tuning for transient failures. */\n\tretry?: RetryOptions;\n\t/** Optional custom fetch (for testing or non-standard runtimes). */\n\tfetchImpl?: typeof fetch;\n}\n\n/**\n * Create a GitHub Copilot provider.\n *\n * @example Single model\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken, // never logged or persisted\n * capabilities: { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000 },\n * });\n * ```\n *\n * @example Multiple models\n * ```ts\n * const provider = createCopilotProvider({\n * getCredential: () => myCopilotToken,\n * models: [\n * { model: \"gpt-4o\", maxInputTokens: 128000, maxOutputTokens: 16000, supportsVision: true },\n * { model: \"o3-mini\", maxInputTokens: 200000, maxOutputTokens: 100000, supportsReasoning: true },\n * ],\n * defaultModel: \"gpt-4o\",\n * });\n * // Pick a model per request: provider.generate({ messages, model: \"o3-mini\" })\n * ```\n *\n * @throws {RuntimeUnsupportedError} when constructed in a browser against the\n * default Copilot host. `api.githubcopilot.com` does not send CORS headers, so a\n * browser cannot call it directly — host a small backend/proxy and point `baseUrl`\n * at it (which lifts this guard), or run the provider server-side (Node/edge).\n */\nexport function createCopilotProvider(options: CopilotProviderOptions): Provider {\n\tconst baseUrl = options.baseUrl ?? DEFAULT_COPILOT_BASE_URL;\n\n\t// Frontend-only guard: the Copilot API has no CORS support, so a browser must\n\t// route through a backend/proxy. Setting a custom `baseUrl` (your proxy) is the\n\t// supported opt-in and lifts this guard. Edge/Node (server-side) are unaffected.\n\tconst usingDefaultHost = baseUrl === DEFAULT_COPILOT_BASE_URL;\n\tif (usingDefaultHost && detectRuntime().isBrowser) {\n\t\tthrow new RuntimeUnsupportedError(\n\t\t\t\"GitHub Copilot directly from a browser (the Copilot API sends no CORS headers)\",\n\t\t\t{\n\t\t\t\treason: \"cors\",\n\t\t\t\tremedy:\n\t\t\t\t\t\"Run a lightweight backend/proxy (e.g. a Vite dev-server proxy or a small server route) \" +\n\t\t\t\t\t\"that forwards to https://api.githubcopilot.com, then set `baseUrl` to your proxy URL. \" +\n\t\t\t\t\t\"Alternatively, run the Copilot provider server-side (Node or an edge function).\",\n\t\t\t},\n\t\t);\n\t}\n\n\tconst inner = createOpenAICompatibleProvider({\n\t\tbaseUrl,\n\t\tgetCredential: options.getCredential,\n\t\tcapabilities: options.capabilities,\n\t\tmodels: options.models,\n\t\tdefaultModel: options.defaultModel,\n\t\t// Copilot rejects calls missing its identification headers; defaults are\n\t\t// applied here and remain overridable via `options.headers`.\n\t\theaders: { ...COPILOT_DEFAULT_HEADERS, ...(options.headers ?? {}) },\n\t\tretry: options.retry,\n\t\tfetchImpl: options.fetchImpl,\n\t});\n\t// Preserve the provider contract but report the Copilot name.\n\treturn {\n\t\tname: \"copilot\",\n\t\tcapabilities: inner.capabilities,\n\t\tmodels: inner.models,\n\t\tmodel: inner.model.bind(inner),\n\t\tgenerate: inner.generate.bind(inner),\n\t\tgenerateStream: inner.generateStream.bind(inner),\n\t};\n}\n"]}