@alma-harness/providers 0.2.0 → 0.4.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/README.md CHANGED
@@ -4,13 +4,14 @@
4
4
  Anthropic and OpenAI first-party, plus the OpenRouter gateway bridge, over one
5
5
  neutral message format.
6
6
 
7
- > **Status: 0.2.0 on npm, pre-1.0.** The API is still moving; see the
7
+ > **Status: 0.3.0 on npm, pre-1.0.** The API is still moving; see the
8
8
  > [roadmap](../../docs/architecture.md#12-adoption-roadmap) for where it stands.
9
9
 
10
10
  ## What it owns
11
11
 
12
12
  - `AnthropicModelClient` — Messages API, streaming, with explicit
13
- `cache_control` breakpoints at the stable-system boundary and the
13
+ `cache_control` breakpoints (at the wire's default duration, or the hour a
14
+ policy asks for — spec: cache-ttl; the other two wires refuse the ask) at the stable-system boundary and the
14
15
  conversation tail.
15
16
  - `OpenAIModelClient` — Responses API, streaming, automatic prefix caching.
16
17
  - `OpenRouterModelClient` — the gateway bridge (chat completions). A gateway
@@ -78,9 +79,20 @@ payload kept `opaque` for replay.
78
79
  |---|---|---|---|
79
80
  | declaration | `web_search_20250305` (the direct search; the agentic 2026-03-18 version drives `code_execution` and is another kind) with `max_uses`, `allowed_domains`, `blocked_domains` | `{ type: "web_search", filters: { allowed_domains } }` + `include: ["web_search_call.action.sources"]`; `blockedDomains` is REFUSED before the network; `maxUses` is the loop's to enforce | refused before the network |
80
81
  | on the stream | `server_tool_use` → call; `web_search_tool_result` → result (url, title, page age; an error code as `error`); `usage.server_tool_use.web_search_requests` | a completed `web_search_call` item → call (`input: action`) and result (the sources; `failed` as an error), counted | — |
81
- | replay | its own two blocks as `server_tool_use` + `web_search_tool_result` with the encrypted content; another provider's skipped | its own result's `opaque` as the item; the call block skipped | skipped |
82
+ | replay | its own two blocks as `server_tool_use` + `web_search_tool_result` with the encrypted content, only while the request declares the kind (a capped step replays the text and skips the search); another provider's skipped | its own result's `opaque` as the item, only while the request declares the kind; the call block skipped | skipped |
82
83
  | `pause_turn` | → the neutral `pause`: the loop re-sends | — | — |
83
84
 
85
+ ## Media
86
+
87
+ | | Anthropic | OpenAI | OpenRouter |
88
+ |---|---|---|---|
89
+ | image by URL | `source: { type: "url" }` | `input_image` with the URL | `image_url` with the URL |
90
+ | image by bytes (spec: media-by-bytes) | base64 source; JPEG, PNG, GIF, WebP, else refused | `input_image` with a data URL | `image_url` with a data URL |
91
+ | document | by URL: `document` source · by bytes: base64 PDF, else refused | by bytes only: `input_file` with a data URL and the ref's filename, PDF · by URL refused | refused |
92
+ | audio | refused — products transcribe upstream | refused | refused |
93
+
94
+ A block carries bytes when the loop attached `content` from the product's `MediaSource`; the adapters never fetch anything and never see the ref's path on the bytes path.
95
+
84
96
  ## Arguments the wire cut
85
97
 
86
98
  A tool call whose arguments do not parse — a response cut by `max_tokens`
package/dist/index.js CHANGED
@@ -63,12 +63,13 @@ function toAnthropicParams(req) {
63
63
  }
64
64
  const reasoning = req.reasoning;
65
65
  const replay = reasoning !== void 0 && reasoning.effort !== "none";
66
+ const ttl = req.cache?.ttl === "1h" ? "1h" : void 0;
66
67
  const params = {
67
68
  model: req.model.id,
68
69
  max_tokens: req.maxTokens,
69
70
  stream: true,
70
- system: toSystem(req.system),
71
- messages: req.messages.flatMap((m) => toMessageParams(m, replay))
71
+ system: toSystem(req.system, ttl),
72
+ messages: req.messages.flatMap((m) => toMessageParams(m, replay, declaredKinds(req)))
72
73
  };
73
74
  if (reasoning !== void 0) {
74
75
  if (reasoning.effort === "none") {
@@ -92,9 +93,12 @@ function toAnthropicParams(req) {
92
93
  }
93
94
  const tools = [...req.tools.map(toTool), ...(req.providerTools ?? []).map(toServerTool)];
94
95
  if (tools.length > 0) params.tools = tools;
95
- markConversationTail(params.messages);
96
+ markConversationTail(params.messages, ttl);
96
97
  return params;
97
98
  }
99
+ function breakpoint(ttl) {
100
+ return ttl === void 0 ? { type: "ephemeral" } : { type: "ephemeral", ttl };
101
+ }
98
102
  function toServerTool(spec) {
99
103
  const tool = { type: "web_search_20250305", name: "web_search" };
100
104
  if (spec.maxUses !== void 0) tool.max_uses = spec.maxUses;
@@ -105,53 +109,69 @@ function toServerTool(spec) {
105
109
  function toAnthropicEffort(effort) {
106
110
  return effort === "minimal" ? "low" : effort;
107
111
  }
108
- function markConversationTail(messages) {
112
+ function markConversationTail(messages, ttl) {
109
113
  const last = messages.at(-1);
110
114
  if (!last || typeof last.content === "string") return;
111
115
  const block = last.content.at(-1);
112
- if (block) block.cache_control = { type: "ephemeral" };
116
+ if (block) block.cache_control = breakpoint(ttl);
113
117
  }
114
- function toSystem(blocks) {
118
+ function toSystem(blocks, ttl) {
115
119
  const lastStable = blocks.reduce(
116
120
  (last, b, i) => b.volatility === "stable" ? i : last,
117
121
  -1
118
122
  );
119
123
  return blocks.map((b, i) => {
120
124
  const param = { type: "text", text: b.text };
121
- if (i === lastStable) param.cache_control = { type: "ephemeral" };
125
+ if (i === lastStable) param.cache_control = breakpoint(ttl);
122
126
  return param;
123
127
  });
124
128
  }
125
- function toMessageParams(msg, replayReasoning) {
129
+ function declaredKinds(req) {
130
+ return new Set((req.providerTools ?? []).map((t) => t.kind));
131
+ }
132
+ function toMessageParams(msg, replayReasoning, declared) {
126
133
  switch (msg.role) {
127
134
  case "user":
128
135
  return [{ role: "user", content: msg.blocks.map(toUserBlock) }];
129
136
  case "assistant": {
130
- const content = msg.blocks.flatMap((b) => toAssistantBlocks(b, replayReasoning));
137
+ const content = msg.blocks.flatMap((b) => toAssistantBlocks(b, replayReasoning, declared));
131
138
  return content.length === 0 ? [] : [{ role: "assistant", content }];
132
139
  }
133
140
  case "tool":
134
141
  return [{ role: "user", content: msg.blocks.map(toToolResultBlock) }];
135
142
  }
136
143
  }
144
+ var IMAGE_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"];
137
145
  function toUserBlock(block) {
138
146
  switch (block.type) {
139
147
  case "text":
140
148
  return { type: "text", text: block.text };
141
- case "media":
149
+ case "media": {
150
+ const content = block.content;
142
151
  switch (block.kind) {
143
- case "image":
144
- return { type: "image", source: { type: "url", url: block.ref.uri } };
152
+ case "image": {
153
+ if (content === void 0) return { type: "image", source: { type: "url", url: block.ref.uri } };
154
+ const mediaType = IMAGE_TYPES.find((t) => t === content.contentType);
155
+ if (mediaType === void 0) {
156
+ throw new AnthropicTranslationError(`the Anthropic adapter cannot send an image of type ${JSON.stringify(content.contentType)} by bytes (${IMAGE_TYPES.join(", ")})`);
157
+ }
158
+ return { type: "image", source: { type: "base64", media_type: mediaType, data: content.base64 } };
159
+ }
145
160
  case "document":
146
- return { type: "document", source: { type: "url", url: block.ref.uri } };
161
+ if (content === void 0) return { type: "document", source: { type: "url", url: block.ref.uri } };
162
+ if (content.contentType !== "application/pdf") {
163
+ throw new AnthropicTranslationError(`the Anthropic adapter sends only application/pdf documents by bytes, got ${JSON.stringify(content.contentType)}`);
164
+ }
165
+ return { type: "document", source: { type: "base64", media_type: "application/pdf", data: content.base64 } };
147
166
  case "audio":
148
167
  throw new AnthropicTranslationError("audio media is not supported by the Anthropic adapter");
149
168
  }
169
+ }
150
170
  default:
151
171
  throw new AnthropicTranslationError(`block type ${JSON.stringify(block.type)} is not valid in a user message`);
152
172
  }
153
173
  }
154
- function toAssistantBlocks(block, replayReasoning) {
174
+ function toAssistantBlocks(block, replayReasoning, declared) {
155
175
  switch (block.type) {
156
176
  case "text":
157
177
  return [{ type: "text", text: block.text }];
@@ -160,9 +180,9 @@ function toAssistantBlocks(block, replayReasoning) {
160
180
  case "reasoning":
161
181
  return block.provider === "anthropic" && replayReasoning ? [toThinkingParam(block)] : [];
162
182
  case "provider_tool_call":
163
- return block.provider === "anthropic" ? [{ type: "server_tool_use", id: block.id, name: block.name, input: block.input }] : [];
183
+ return block.provider === "anthropic" && declared.has(block.name) ? [{ type: "server_tool_use", id: block.id, name: block.name, input: block.input }] : [];
164
184
  case "provider_tool_result":
165
- return block.provider === "anthropic" ? [toWebSearchResultParam(block)] : [];
185
+ return block.provider === "anthropic" && declared.has(block.name) ? [toWebSearchResultParam(block)] : [];
166
186
  default:
167
187
  throw new AnthropicTranslationError(
168
188
  `block type ${JSON.stringify(block.type)} is not valid in an assistant message`
@@ -226,6 +246,7 @@ async function* translateStream(events) {
226
246
  if (u.cache_creation_input_tokens != null) {
227
247
  usage.cacheWriteInputTokens = u.cache_creation_input_tokens;
228
248
  }
249
+ if (u.cache_creation?.ephemeral_1h_input_tokens) usage.cacheWriteTtl = "1h";
229
250
  if (u.server_tool_use?.web_search_requests) usage.webSearchRequests = u.server_tool_use.web_search_requests;
230
251
  if (u.service_tier === "standard" || u.service_tier === "priority" || u.service_tier === "batch") {
231
252
  usage.serviceTier = u.service_tier;
@@ -290,7 +311,7 @@ async function* translateStream(events) {
290
311
  pendingServer.delete(event.index);
291
312
  yield {
292
313
  type: "provider_tool_call",
293
- block: { type: "provider_tool_call", id: server.id, name: server.name, provider: "anthropic", input: server.json === "" ? {} : JSON.parse(server.json) }
314
+ block: { type: "provider_tool_call", id: server.id, name: server.name, provider: "anthropic", input: parseToolArguments(server.json).input }
294
315
  };
295
316
  }
296
317
  break;
@@ -402,6 +423,7 @@ function translateMessage(message) {
402
423
  const usage = { inputTokens: u.input_tokens, outputTokens: u.output_tokens };
403
424
  if (u.cache_read_input_tokens != null) usage.cacheReadInputTokens = u.cache_read_input_tokens;
404
425
  if (u.cache_creation_input_tokens != null) usage.cacheWriteInputTokens = u.cache_creation_input_tokens;
426
+ if (u.cache_creation?.ephemeral_1h_input_tokens) usage.cacheWriteTtl = "1h";
405
427
  if (u.service_tier === "standard" || u.service_tier === "priority" || u.service_tier === "batch") {
406
428
  usage.serviceTier = u.service_tier;
407
429
  }
@@ -490,7 +512,7 @@ function toOpenAIParams(req) {
490
512
  // Privacy-first (§3, §10): the Responses API stores responses server-side
491
513
  // by default; the harness never leaves conversation state at the provider.
492
514
  store: false,
493
- input: req.messages.flatMap((m) => toInputItems(m, replay))
515
+ input: req.messages.flatMap((m) => toInputItems(m, replay, new Set((req.providerTools ?? []).map((t) => t.kind))))
494
516
  };
495
517
  if (reasoning !== void 0) {
496
518
  params.reasoning = replay ? { effort: reasoning.effort, summary: "auto" } : { effort: "none" };
@@ -509,6 +531,9 @@ function toOpenAIParams(req) {
509
531
  `the OpenAI Responses API cannot serve the ${req.serviceTier} tier on a streaming request`
510
532
  );
511
533
  }
534
+ if (req.cache !== void 0) {
535
+ throw new OpenAITranslationError("the OpenAI Responses API has no cache TTL form \u2014 the policy asked for one on a wire that cannot serve it");
536
+ }
512
537
  const instructions = toInstructions(req.system);
513
538
  if (instructions !== "") params.instructions = instructions;
514
539
  const tools = [...req.tools.map(toTool2), ...(req.providerTools ?? []).map(toWebSearchTool)];
@@ -527,12 +552,12 @@ function toWebSearchTool(spec) {
527
552
  function toInstructions(blocks) {
528
553
  return blocks.map((b) => b.text).join("\n\n");
529
554
  }
530
- function toInputItems(msg, replayReasoning) {
555
+ function toInputItems(msg, replayReasoning, declared) {
531
556
  switch (msg.role) {
532
557
  case "user":
533
558
  return [{ role: "user", content: msg.blocks.map(toUserContentPart) }];
534
559
  case "assistant":
535
- return msg.blocks.flatMap((b) => toAssistantItems(b, replayReasoning));
560
+ return msg.blocks.flatMap((b) => toAssistantItems(b, replayReasoning, declared));
536
561
  case "tool":
537
562
  return msg.blocks.map(toFunctionCallOutput);
538
563
  }
@@ -541,20 +566,29 @@ function toUserContentPart(block) {
541
566
  switch (block.type) {
542
567
  case "text":
543
568
  return { type: "input_text", text: block.text };
544
- case "media":
569
+ case "media": {
570
+ const content = block.content;
545
571
  if (block.kind === "image") {
546
- return { type: "input_image", detail: "auto", image_url: block.ref.uri };
572
+ const url = content === void 0 ? block.ref.uri : `data:${content.contentType};base64,${content.base64}`;
573
+ return { type: "input_image", detail: "auto", image_url: url };
574
+ }
575
+ if (block.kind === "document" && content !== void 0) {
576
+ if (content.contentType !== "application/pdf") {
577
+ throw new OpenAITranslationError(`the OpenAI adapter sends only application/pdf documents by bytes, got ${JSON.stringify(content.contentType)}`);
578
+ }
579
+ return { type: "input_file", filename: block.ref.filename ?? "document.pdf", file_data: `data:application/pdf;base64,${content.base64}` };
547
580
  }
548
581
  throw new OpenAITranslationError(
549
- `${block.kind} media is not supported by the OpenAI adapter`
582
+ `${block.kind} media is not supported by the OpenAI adapter${block.kind === "document" ? " by reference" : ""}`
550
583
  );
584
+ }
551
585
  default:
552
586
  throw new OpenAITranslationError(
553
587
  `block type ${JSON.stringify(block.type)} is not valid in a user message`
554
588
  );
555
589
  }
556
590
  }
557
- function toAssistantItems(block, replayReasoning) {
591
+ function toAssistantItems(block, replayReasoning, declared) {
558
592
  switch (block.type) {
559
593
  case "text":
560
594
  return [{ role: "assistant", content: block.text }];
@@ -572,7 +606,7 @@ function toAssistantItems(block, replayReasoning) {
572
606
  case "provider_tool_call":
573
607
  return [];
574
608
  case "provider_tool_result":
575
- return block.provider === "openai" ? [toWebSearchItem(block)] : [];
609
+ return block.provider === "openai" && declared.has(block.name) ? [toWebSearchItem(block)] : [];
576
610
  default:
577
611
  throw new OpenAITranslationError(
578
612
  `block type ${JSON.stringify(block.type)} is not valid in an assistant message`
@@ -790,12 +824,7 @@ function translateResponse(response) {
790
824
  break;
791
825
  case "function_call":
792
826
  sawToolCall = true;
793
- blocks.push({
794
- type: "tool_call",
795
- id: item.call_id,
796
- name: item.name,
797
- input: item.arguments === "" ? {} : JSON.parse(item.arguments)
798
- });
827
+ blocks.push({ type: "tool_call", id: item.call_id, name: item.name, input: parseToolArguments(item.arguments).input });
799
828
  break;
800
829
  case "reasoning": {
801
830
  if (typeof item.encrypted_content !== "string") break;
@@ -921,6 +950,9 @@ function toOpenRouterParams(req, routing) {
921
950
  `the OpenRouter adapter cannot serve the ${req.serviceTier} tier \u2014 the gateway prices by upstream`
922
951
  );
923
952
  }
953
+ if (req.cache !== void 0) {
954
+ throw new OpenRouterTranslationError("the OpenRouter adapter has no cache TTL form \u2014 the policy asked for one on a wire that cannot serve it");
955
+ }
924
956
  if ((req.providerTools ?? []).length > 0) {
925
957
  throw new OpenRouterTranslationError("the OpenRouter adapter cannot declare provider-executed tools \u2014 the gateway has no neutral web search");
926
958
  }
@@ -947,7 +979,8 @@ function toUserContentPart2(block) {
947
979
  return { type: "text", text: block.text };
948
980
  case "media":
949
981
  if (block.kind === "image") {
950
- return { type: "image_url", image_url: { url: block.ref.uri } };
982
+ const content = block.content;
983
+ return { type: "image_url", image_url: { url: content === void 0 ? block.ref.uri : `data:${content.contentType};base64,${content.base64}` } };
951
984
  }
952
985
  throw new OpenRouterTranslationError(
953
986
  `${block.kind} media is not supported by the OpenRouter adapter`
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/anthropic/client.ts","../src/errors.ts","../src/anthropic/translate.ts","../src/arguments.ts","../src/anthropic/jobs.ts","../src/openai/client.ts","../src/openai/translate.ts","../src/openai/jobs.ts","../src/openrouter/client.ts","../src/openrouter/translate.ts","../src/index.ts"],"sourcesContent":["import Anthropic from \"@anthropic-ai/sdk\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport { toAnthropicParams, translateStream } from \"./translate\";\n\nexport interface AnthropicModelClientOptions {\n /** Omit to use the SDK's environment resolution (ANTHROPIC_API_KEY, …). */\n apiKey?: string;\n baseURL?: string;\n}\n\n/**\n * `ModelClient` adapter for the Anthropic Messages API — §6.2, spec 002.\n * A thin shell: request/stream translation lives in ./translate (pure);\n * this class only owns the SDK client. What the SDK throws leaves as a\n * `ProviderError` (spec: error-taxonomy); a user abort passes through.\n */\nexport class AnthropicModelClient implements ModelClient {\n readonly #client: Anthropic;\n\n constructor(opts: AnthropicModelClientOptions = {}) {\n const init: ConstructorParameters<typeof Anthropic>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new Anthropic(init);\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity — spec 002 criterion 5.\n const params = toAnthropicParams(req);\n return translateStream(this.#rawEvents(params, opts?.signal));\n }\n\n async *#rawEvents(\n params: Anthropic.MessageCreateParamsStreaming,\n signal?: AbortSignal,\n ): AsyncGenerator<Anthropic.RawMessageStreamEvent> {\n try {\n const stream = await this.#client.messages.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const event of stream) yield event;\n } catch (err) {\n throw toProviderError(\"anthropic\", err);\n }\n }\n}\n","import { ProviderError, type ProviderFailureKind, type ProviderId } from \"@alma-harness/core\";\n\n/**\n * What the SDKs throw → one neutral class — spec: error-taxonomy. DUCK-TYPED\n * rather than `instanceof` over two SDKs' error trees: both expose `status`,\n * `message` and the response body on `error`, the OpenAI one `code` and the\n * Anthropic one `type`; and the gateway speaks through the OpenAI SDK to\n * upstreams that shape their bodies differently. One table over the fields\n * they share is what stays true across all three.\n */\n\ninterface SdkErrorShape {\n name?: unknown;\n status?: unknown;\n code?: unknown;\n type?: unknown;\n message?: unknown;\n error?: unknown;\n}\n\nconst CONTEXT_WINDOW = /context_length_exceeded|prompt is too long|context window|maximum context length|too many tokens|exceeds the context|input length/i;\nconst OVERLOADED = /overloaded|too many requests|capacity|server_busy/i;\n\n/** Every string the body or the error carries as a code or a type, lowercased and joined. */\nfunction hintsOf(e: SdkErrorShape): string {\n const nested = (typeof e.error === \"object\" && e.error !== null ? e.error : {}) as SdkErrorShape;\n const inner = (typeof nested.error === \"object\" && nested.error !== null ? nested.error : {}) as SdkErrorShape;\n return [e.code, e.type, nested.code, nested.type, inner.code, inner.type, inner.message]\n .filter((h): h is string => typeof h === \"string\")\n .join(\" \")\n .toLowerCase();\n}\n\n/**\n * Wraps anything but a user abort. The abort passes through untouched: the\n * loop already reads its own signal, and a wrapped abort would classify a\n * cancellation as a provider failure.\n */\nexport function toProviderError(provider: ProviderId, err: unknown): unknown {\n if (err instanceof ProviderError) return err;\n const e = (typeof err === \"object\" && err !== null ? err : {}) as SdkErrorShape;\n // The SDKs do not always set `name`; the constructor's is the fallback.\n const own = typeof e.name === \"string\" && e.name !== \"Error\" ? e.name : \"\";\n const name = own !== \"\" ? own : ((err as { constructor?: { name?: unknown } } | null)?.constructor?.name as string | undefined) ?? \"\";\n if (name === \"APIUserAbortError\" || name === \"AbortError\") return err;\n const message = err instanceof Error ? err.message : String(err);\n const status = typeof e.status === \"number\" ? e.status : undefined;\n const kind = classifyFailure(name, status, `${hintsOf(e)} ${message.toLowerCase()}`);\n return new ProviderError(provider, kind, message, { ...(status !== undefined ? { status } : {}), cause: err });\n}\n\n/** The table. Exported for the one caller that has a code and no thrown error: a failure the wire REPORTED. */\nexport function classifyFailure(name: string, status: number | undefined, hints: string): ProviderFailureKind {\n if (status === 429 || /rate_limit/.test(hints)) return hints.includes(\"insufficient_quota\") ? \"rejected\" : \"rate_limited\";\n if (status === 529 || status === 503 || ((status === undefined || status >= 500) && OVERLOADED.test(hints))) return \"overloaded\";\n if (status !== undefined && status >= 500) return \"unavailable\";\n if ((status === undefined || status === 400) && CONTEXT_WINDOW.test(hints)) return \"context_window\";\n if (status !== undefined && status >= 400) return \"rejected\";\n // No status: the SDK could not reach the wire, the wire reported a server\n // failure, or the wire sent something the translation could not read.\n if (/connection|timeout|timed out|fetch|network|socket|econn|enotfound|server_error|internal|unavailable/i.test(`${name} ${hints}`)) {\n return \"unavailable\";\n }\n return \"provider_drift\";\n}\n","import type Anthropic from \"@anthropic-ai/sdk\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type ProviderToolCallBlock,\n type ProviderToolResultBlock,\n type ProviderToolSpec,\n type ReasoningBlock,\n type ReasoningEffort,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and the Anthropic\n * Messages API — spec 002. Everything here is side-effect-free so the wire\n * mapping is testable without a network.\n */\n\n/**\n * Raised when a request or stream cannot be represented faithfully. A\n * `ProviderError` since spec: error-taxonomy — `rejected` before the network\n * (the request as built cannot be sent), `provider_drift` mid-stream (the\n * wire sent something this adapter does not know).\n */\nexport class AnthropicTranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"anthropic\", kind, message);\n this.name = \"AnthropicTranslationError\";\n }\n}\n\nexport function toAnthropicParams(req: ModelRequest): Anthropic.MessageCreateParamsStreaming {\n if (req.model.provider !== \"anthropic\") {\n throw new AnthropicTranslationError(\n `AnthropicModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n // Reasoning — spec: reasoning-blocks. Absent sends nothing (the provider's\n // default, whose thinking is opt-in); \"none\" disables explicitly; anything\n // else asks for adaptive thinking at the mapped effort. Its own blocks are\n // replayed only when thinking is on for THIS request.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n const params: Anthropic.MessageCreateParamsStreaming = {\n model: req.model.id,\n max_tokens: req.maxTokens,\n stream: true,\n system: toSystem(req.system),\n messages: req.messages.flatMap((m) => toMessageParams(m, replay)),\n };\n if (reasoning !== undefined) {\n if (reasoning.effort === \"none\") {\n params.thinking = { type: \"disabled\" };\n } else {\n params.thinking = { type: \"adaptive\" };\n params.output_config = { effort: toAnthropicEffort(reasoning.effort as Exclude<ReasoningEffort, \"none\">) };\n }\n }\n // Service tier — spec: pricing-tiers. `priority` asks for priority capacity\n // when the account has it (\"auto\": standard otherwise, and the usage says\n // which served). Flex does not exist on this wire and batch is a job, not\n // a stream: both refused before the network, never downgraded in silence.\n switch (req.serviceTier) {\n case undefined:\n case \"standard\":\n break;\n case \"priority\":\n params.service_tier = \"auto\";\n break;\n default:\n throw new AnthropicTranslationError(\n `the Anthropic Messages API cannot serve the ${req.serviceTier} tier on a streaming request`,\n );\n }\n // Provider-executed tools ride in the same list as the registered ones (spec: provider-tools).\n const tools: Anthropic.ToolUnion[] = [...req.tools.map(toTool), ...(req.providerTools ?? []).map(toServerTool)];\n if (tools.length > 0) params.tools = tools;\n markConversationTail(params.messages);\n return params;\n}\n\n/** The neutral web search → the dated server tool; every option has a wire form here. */\n/**\n * The DIRECT search (spec: provider-tools): one `server_tool_use` per query.\n * `web_search_20260318` is the agentic search, which the model drives through\n * `code_execution` — encrypted stdout, nested calls — another kind, its own spec.\n */\nfunction toServerTool(spec: ProviderToolSpec): Anthropic.WebSearchTool20250305 {\n const tool: Anthropic.WebSearchTool20250305 = { type: \"web_search_20250305\", name: \"web_search\" };\n if (spec.maxUses !== undefined) tool.max_uses = spec.maxUses;\n if (spec.allowedDomains !== undefined) tool.allowed_domains = [...spec.allowedDomains];\n if (spec.blockedDomains !== undefined) tool.blocked_domains = [...spec.blockedDomains];\n return tool;\n}\n\n/** `minimal` collapses to `low`: the Messages API has no lower rung. */\nfunction toAnthropicEffort(\n effort: Exclude<ReasoningEffort, \"none\">,\n): NonNullable<Anthropic.OutputConfig[\"effort\"]> {\n return effort === \"minimal\" ? \"low\" : effort;\n}\n\n/**\n * Cache continuation — spec 005: a second breakpoint on the conversation\n * tail lets multi-turn sessions pay incremental tokens instead of re-reading\n * the whole history every turn. (Budget: 2 of the 4 allowed breakpoints —\n * one at the stable-system boundary, one here.)\n */\nfunction markConversationTail(messages: Anthropic.MessageParam[]): void {\n const last = messages.at(-1);\n if (!last || typeof last.content === \"string\") return;\n const block = last.content.at(-1);\n if (block) (block as { cache_control?: Anthropic.CacheControlEphemeral }).cache_control = { type: \"ephemeral\" };\n}\n\n/**\n * The §6.9 stable/volatile boundary becomes the cache boundary: one\n * `cache_control` breakpoint on the LAST stable block, volatile blocks after\n * it. Order is preserved — callers must already emit stable-first.\n */\nfunction toSystem(blocks: SystemBlock[]): Anthropic.TextBlockParam[] {\n const lastStable = blocks.reduce(\n (last, b, i) => (b.volatility === \"stable\" ? i : last),\n -1,\n );\n return blocks.map((b, i) => {\n const param: Anthropic.TextBlockParam = { type: \"text\", text: b.text };\n if (i === lastStable) param.cache_control = { type: \"ephemeral\" };\n return param;\n });\n}\n\nfunction toMessageParams(msg: Msg, replayReasoning: boolean): Anthropic.MessageParam[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserBlock) }];\n case \"assistant\": {\n const content = msg.blocks.flatMap((b) => toAssistantBlocks(b, replayReasoning));\n // An assistant turn that held only another provider's reasoning has\n // nothing this wire can carry; an empty content array is a 400.\n return content.length === 0 ? [] : [{ role: \"assistant\", content }];\n }\n case \"tool\":\n // Anthropic's wire shape: tool results travel in a user-role message.\n return [{ role: \"user\", content: msg.blocks.map(toToolResultBlock) }];\n }\n}\n\nfunction toUserBlock(block: Block): Anthropic.ContentBlockParam {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"media\":\n switch (block.kind) {\n case \"image\":\n return { type: \"image\", source: { type: \"url\", url: block.ref.uri } };\n case \"document\":\n return { type: \"document\", source: { type: \"url\", url: block.ref.uri } };\n case \"audio\":\n // The Messages API takes no raw audio; products transcribe upstream.\n throw new AnthropicTranslationError(\"audio media is not supported by the Anthropic adapter\");\n }\n default:\n throw new AnthropicTranslationError(`block type ${JSON.stringify(block.type)} is not valid in a user message`);\n }\n}\n\nfunction toAssistantBlocks(block: Block, replayReasoning: boolean): Anthropic.ContentBlockParam[] {\n switch (block.type) {\n case \"text\":\n return [{ type: \"text\", text: block.text }];\n case \"tool_call\":\n return [{ type: \"tool_use\", id: block.id, name: block.name, input: block.input }];\n case \"reasoning\":\n // Own blocks go back UNMODIFIED and in order when thinking is on for\n // this request; another provider's, or any block when thinking is off,\n // are skipped without error (spec: reasoning-blocks).\n return block.provider === \"anthropic\" && replayReasoning ? [toThinkingParam(block)] : [];\n case \"provider_tool_call\":\n // Own server-tool blocks go back as they came (spec: provider-tools); another provider's are skipped.\n return block.provider === \"anthropic\" ? [{ type: \"server_tool_use\", id: block.id, name: block.name, input: block.input }] : [];\n case \"provider_tool_result\":\n return block.provider === \"anthropic\" ? [toWebSearchResultParam(block)] : [];\n default:\n throw new AnthropicTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n}\n\n/** The opaque half this adapter wrote: the encrypted results, whole, or the error. */\nfunction toWebSearchResultParam(block: ProviderToolResultBlock): Anthropic.WebSearchToolResultBlockParam {\n const opaque = block.opaque as { content?: unknown } | undefined;\n if (opaque?.content === undefined) {\n throw new AnthropicTranslationError(\"an Anthropic web search result carries no replayable content\");\n }\n return { type: \"web_search_tool_result\", tool_use_id: block.callId, content: opaque.content as Anthropic.WebSearchToolResultBlockParamContent };\n}\n\n/** The opaque half this adapter wrote: a signature, or a redacted block's data. */\nfunction toThinkingParam(block: ReasoningBlock): Anthropic.ContentBlockParam {\n const opaque = block.opaque as { signature?: unknown; redacted?: unknown } | undefined;\n if (typeof opaque?.redacted === \"string\") {\n return { type: \"redacted_thinking\", data: opaque.redacted };\n }\n if (typeof opaque?.signature === \"string\") {\n return { type: \"thinking\", thinking: block.text ?? \"\", signature: opaque.signature };\n }\n // Refused here rather than as a 400 from the provider: a block this\n // adapter did not write in this shape cannot be verified there either.\n throw new AnthropicTranslationError(\"an Anthropic reasoning block carries neither a signature nor redacted data\");\n}\n\nfunction toToolResultBlock(block: Block): Anthropic.ToolResultBlockParam {\n if (block.type !== \"tool_result\") {\n throw new AnthropicTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const param: Anthropic.ToolResultBlockParam = {\n type: \"tool_result\",\n tool_use_id: block.callId,\n // JSON.stringify yields undefined (not a string) for undefined/functions;\n // \"null\" keeps the content explicit for void tool outputs.\n content:\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\"),\n };\n if (block.isError) param.is_error = true;\n return param;\n}\n\nfunction toTool(spec: ToolSpec): Anthropic.Tool {\n return {\n name: spec.name,\n description: spec.description,\n // The registry already derived a JSON Schema object (§6.4).\n input_schema: spec.inputSchema as Anthropic.Tool.InputSchema,\n };\n}\n\n/**\n * Raw SDK stream → neutral `ModelEvent`s. Tool inputs arrive as\n * `input_json_delta` fragments; they are accumulated per content block and\n * emitted as ONE `tool_call` with parsed input at `content_block_stop`.\n * Usage is aggregated (input + cache fields from `message_start`, output from\n * `message_delta`) and emitted once before the final `stop`.\n */\nexport async function* translateStream(\n events: AsyncIterable<Anthropic.RawMessageStreamEvent>,\n): AsyncGenerator<ModelEvent> {\n const usage: Usage = { inputTokens: 0, outputTokens: 0 };\n let stopReason: Anthropic.Message[\"stop_reason\"] = null;\n const pendingTools = new Map<number, { id: string; name: string; json: string }>();\n // Thinking arrives as text deltas plus one signature delta, redacted\n // thinking as opaque data on the block start; both are emitted as ONE\n // complete reasoning block at content_block_stop (spec: reasoning-blocks).\n const pendingThinking = new Map<number, { text: string; signature: string }>();\n const pendingRedacted = new Map<number, string>();\n // A server tool's call arrives like a tool use — input as json deltas — and its\n // result arrives whole on the block start (spec: provider-tools).\n const pendingServer = new Map<number, { id: string; name: ProviderToolCallBlock[\"name\"]; json: string }>();\n\n for await (const event of events) {\n switch (event.type) {\n case \"message_start\": {\n const u = event.message.usage;\n usage.inputTokens = u.input_tokens;\n if (u.cache_read_input_tokens != null) usage.cacheReadInputTokens = u.cache_read_input_tokens;\n if (u.cache_creation_input_tokens != null) {\n usage.cacheWriteInputTokens = u.cache_creation_input_tokens;\n }\n if (u.server_tool_use?.web_search_requests) usage.webSearchRequests = u.server_tool_use.web_search_requests;\n // The tier that SERVED, off the wire (spec: pricing-tiers) — priced\n // over the tier asked, since \"auto\" may land on standard.\n if (u.service_tier === \"standard\" || u.service_tier === \"priority\" || u.service_tier === \"batch\") {\n usage.serviceTier = u.service_tier;\n }\n break;\n }\n case \"content_block_start\":\n if (event.content_block.type === \"tool_use\") {\n pendingTools.set(event.index, {\n id: event.content_block.id,\n name: event.content_block.name,\n json: \"\",\n });\n } else if (event.content_block.type === \"thinking\") {\n pendingThinking.set(event.index, { text: event.content_block.thinking, signature: event.content_block.signature });\n } else if (event.content_block.type === \"redacted_thinking\") {\n pendingRedacted.set(event.index, event.content_block.data);\n } else if (event.content_block.type === \"server_tool_use\") {\n if (event.content_block.name !== \"web_search\") {\n throw new AnthropicTranslationError(`Unmapped Anthropic server tool ${JSON.stringify(event.content_block.name)} — provider drift?`, \"provider_drift\");\n }\n pendingServer.set(event.index, { id: event.content_block.id, name: \"web_search\", json: \"\" });\n } else if (event.content_block.type === \"web_search_tool_result\") {\n yield { type: \"provider_tool_result\", block: toProviderToolResult(event.content_block) };\n }\n break;\n case \"content_block_delta\":\n if (event.delta.type === \"text_delta\") {\n yield { type: \"text_delta\", text: event.delta.text };\n } else if (event.delta.type === \"input_json_delta\") {\n const pending = pendingTools.get(event.index) ?? pendingServer.get(event.index);\n if (pending) pending.json += event.delta.partial_json;\n } else if (event.delta.type === \"thinking_delta\") {\n const pending = pendingThinking.get(event.index);\n if (pending) pending.text += event.delta.thinking;\n } else if (event.delta.type === \"signature_delta\") {\n const pending = pendingThinking.get(event.index);\n if (pending) pending.signature = event.delta.signature;\n }\n break;\n case \"content_block_stop\": {\n const pending = pendingTools.get(event.index);\n if (pending) {\n pendingTools.delete(event.index);\n // Arguments that do not parse are the loop's to answer, and the\n // stop reason that follows says whether the wire cut them.\n yield { type: \"tool_call\", id: pending.id, name: pending.name, ...parseToolArguments(pending.json) };\n }\n const thinking = pendingThinking.get(event.index);\n if (thinking) {\n pendingThinking.delete(event.index);\n yield {\n type: \"reasoning\",\n block: { type: \"reasoning\", provider: \"anthropic\", text: thinking.text, opaque: { signature: thinking.signature } },\n };\n }\n const redacted = pendingRedacted.get(event.index);\n if (redacted !== undefined) {\n pendingRedacted.delete(event.index);\n yield { type: \"reasoning\", block: { type: \"reasoning\", provider: \"anthropic\", opaque: { redacted } } };\n }\n const server = pendingServer.get(event.index);\n if (server) {\n pendingServer.delete(event.index);\n yield {\n type: \"provider_tool_call\",\n block: { type: \"provider_tool_call\", id: server.id, name: server.name, provider: \"anthropic\", input: server.json === \"\" ? {} : (JSON.parse(server.json) as unknown) },\n };\n }\n break;\n }\n case \"message_delta\":\n if (event.delta.stop_reason != null) stopReason = event.delta.stop_reason;\n usage.outputTokens = event.usage.output_tokens;\n if (event.usage.server_tool_use?.web_search_requests) usage.webSearchRequests = event.usage.server_tool_use.web_search_requests;\n break;\n case \"message_stop\":\n yield { type: \"usage\", usage: { ...usage } };\n yield { type: \"stop\", reason: mapStopReason(stopReason) };\n break;\n }\n }\n}\n\n/** A web search result block → the neutral result: the citations, the error, and the content whole for replay. */\nfunction toProviderToolResult(block: Anthropic.WebSearchToolResultBlock): ProviderToolResultBlock {\n const result: ProviderToolResultBlock = {\n type: \"provider_tool_result\",\n callId: block.tool_use_id,\n name: \"web_search\",\n provider: \"anthropic\",\n results: [],\n opaque: { content: block.content },\n };\n if (Array.isArray(block.content)) {\n result.results = block.content.map((r) => ({\n url: r.url,\n ...(r.title !== undefined ? { title: r.title } : {}),\n ...(r.page_age != null ? { pageAge: r.page_age } : {}),\n }));\n } else {\n result.error = block.content.error_code;\n }\n return result;\n}\n\nexport function mapStopReason(reason: Anthropic.Message[\"stop_reason\"]): StopReason {\n switch (reason) {\n case \"end_turn\":\n case \"stop_sequence\":\n return \"end_turn\";\n case \"tool_use\":\n return \"tool_use\";\n case \"max_tokens\":\n return \"max_tokens\";\n case \"refusal\":\n return \"refusal\";\n case \"model_context_window_exceeded\":\n return \"context_window_exceeded\";\n case \"pause_turn\":\n // A long-running server tool paused; the loop re-sends to continue (spec: provider-tools).\n return \"pause\";\n default:\n // A reason newer than this adapter: refuse loudly rather than silently truncate.\n throw new AnthropicTranslationError(\n `Unmapped Anthropic stop_reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","/**\n * Tool arguments off the wire — spec: what-the-wire-cuts. Every adapter\n * accumulates them as text and parsed them with a bare `JSON.parse`, so a\n * response cut by `max_tokens` mid-arguments threw from inside the stream\n * and the loop never saw the stop reason that explained it. A call whose\n * arguments do not parse is still a call: `input: {}` and the raw text as\n * `malformed`, for the loop to answer.\n */\nexport function parseToolArguments(json: string): { input: unknown; malformed?: string } {\n if (json === \"\") return { input: {} };\n try {\n return { input: JSON.parse(json) as unknown };\n } catch {\n return { input: {}, malformed: json };\n }\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { Block, JobHandle, JobItem, JobOutput, JobProgress, JobResult, ModelJobClient, Usage } from \"@alma-harness/core\";\n\nimport { AnthropicTranslationError, mapStopReason, toAnthropicParams } from \"./translate\";\n\n/**\n * `ModelJobClient` over the Anthropic Message Batches API — spec: model-jobs.\n * Each item's request is translated with the same function the stream uses,\n * minus `stream`; a succeeded result is a complete `Message`, translated\n * here into the neutral output the runner prices and returns.\n */\n\n/** A complete message → neutral blocks, usage and stop — the non-streaming half of spec 002. */\nexport function translateMessage(message: Anthropic.Message): JobOutput {\n const blocks: Block[] = [];\n for (const block of message.content) {\n switch (block.type) {\n case \"text\":\n blocks.push({ type: \"text\", text: block.text });\n break;\n case \"tool_use\":\n blocks.push({ type: \"tool_call\", id: block.id, name: block.name, input: block.input });\n break;\n case \"thinking\":\n blocks.push({ type: \"reasoning\", provider: \"anthropic\", text: block.thinking, opaque: { signature: block.signature } });\n break;\n case \"redacted_thinking\":\n blocks.push({ type: \"reasoning\", provider: \"anthropic\", opaque: { redacted: block.data } });\n break;\n default:\n // A job declares no tools, provider-executed ones included (spec: model-jobs).\n throw new AnthropicTranslationError(`Unmapped Anthropic content block ${JSON.stringify(block.type)} — provider drift?`, \"provider_drift\");\n }\n }\n const u = message.usage;\n const usage: Usage = { inputTokens: u.input_tokens, outputTokens: u.output_tokens };\n if (u.cache_read_input_tokens != null) usage.cacheReadInputTokens = u.cache_read_input_tokens;\n if (u.cache_creation_input_tokens != null) usage.cacheWriteInputTokens = u.cache_creation_input_tokens;\n if (u.service_tier === \"standard\" || u.service_tier === \"priority\" || u.service_tier === \"batch\") {\n usage.serviceTier = u.service_tier;\n }\n return { blocks, usage, stop: mapStopReason(message.stop_reason) };\n}\n\nexport interface AnthropicJobClientOptions {\n apiKey?: string;\n baseURL?: string;\n}\n\nexport class AnthropicJobClient implements ModelJobClient {\n readonly #client: Anthropic;\n\n constructor(opts: AnthropicJobClientOptions = {}) {\n const init: ConstructorParameters<typeof Anthropic>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new Anthropic(init);\n }\n\n async submit(items: readonly JobItem[]): Promise<JobHandle> {\n const first = items[0];\n if (!first) throw new AnthropicTranslationError(\"a batch needs at least one item\");\n const requests = items.map((item) => {\n // The item's tier is what makes it a job; the batch API has no tier\n // parameter, so the streaming translation runs with it cleared.\n const { serviceTier: _tier, ...req } = item.request;\n void _tier;\n const { stream: _stream, ...params } = toAnthropicParams(req);\n void _stream;\n return { custom_id: item.id, params: params as Anthropic.MessageCreateParamsNonStreaming };\n });\n const batch = await this.#client.messages.batches.create({ requests });\n return { provider: \"anthropic\", id: batch.id, model: first.request.model };\n }\n\n async status(handle: JobHandle): Promise<JobProgress> {\n const batch = await this.#client.messages.batches.retrieve(handle.id);\n const c = batch.request_counts;\n const total = c.processing + c.succeeded + c.errored + c.canceled + c.expired;\n const status =\n batch.processing_status === \"canceling\"\n ? \"cancelled\"\n : batch.processing_status === \"in_progress\"\n ? \"running\"\n : c.canceled === total && total > 0\n ? \"cancelled\"\n : c.expired === total && total > 0\n ? \"expired\"\n : \"done\";\n return { status, counts: { total, done: c.succeeded, failed: c.errored + c.canceled + c.expired } };\n }\n\n async *results(handle: JobHandle): AsyncIterable<JobResult> {\n const decoder = await this.#client.messages.batches.results(handle.id);\n for await (const entry of decoder) {\n const { custom_id: id, result } = entry;\n switch (result.type) {\n case \"succeeded\":\n yield { id, outcome: \"succeeded\", output: translateMessage(result.message) };\n break;\n case \"errored\": {\n const error = (result.error as { error?: { message?: string } } | undefined)?.error?.message;\n yield { id, outcome: \"errored\", ...(error !== undefined ? { error } : {}) };\n break;\n }\n case \"canceled\":\n yield { id, outcome: \"cancelled\" };\n break;\n case \"expired\":\n yield { id, outcome: \"expired\" };\n break;\n }\n }\n }\n\n async cancel(handle: JobHandle): Promise<void> {\n await this.#client.messages.batches.cancel(handle.id);\n }\n}\n","import OpenAI from \"openai\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport { toOpenAIParams, translateOpenAIStream } from \"./translate\";\n\nexport interface OpenAIModelClientOptions {\n /** Omit to use the SDK's environment resolution (OPENAI_API_KEY). */\n apiKey?: string;\n baseURL?: string;\n}\n\n/**\n * `ModelClient` adapter for the OpenAI Responses API — §6.2, spec 003.\n * A thin shell: request/stream translation lives in ./translate (pure);\n * this class only owns the SDK client. What the SDK throws leaves as a\n * `ProviderError` (spec: error-taxonomy); a user abort passes through.\n */\nexport class OpenAIModelClient implements ModelClient {\n readonly #client: OpenAI;\n\n constructor(opts: OpenAIModelClientOptions = {}) {\n const init: ConstructorParameters<typeof OpenAI>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new OpenAI(init);\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity — spec 003 criterion 6.\n const params = toOpenAIParams(req);\n return translateOpenAIStream(this.#rawEvents(params, opts?.signal));\n }\n\n async *#rawEvents(\n params: OpenAI.Responses.ResponseCreateParamsStreaming,\n signal?: AbortSignal,\n ): AsyncGenerator<OpenAI.Responses.ResponseStreamEvent> {\n try {\n const stream = await this.#client.responses.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const event of stream) yield event;\n } catch (err) {\n throw toProviderError(\"openai\", err);\n }\n }\n}\n","import type OpenAI from \"openai\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type ProviderToolResultBlock,\n type ProviderToolSpec,\n type ReasoningBlock,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\nimport { classifyFailure } from \"../errors\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and the OpenAI\n * Responses API — spec 003. Side-effect-free; testable without a network.\n */\n\n/** A `ProviderError` since spec: error-taxonomy — see `AnthropicTranslationError`. */\nexport class OpenAITranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"openai\", kind, message);\n this.name = \"OpenAITranslationError\";\n }\n}\n\nexport function toOpenAIParams(\n req: ModelRequest,\n): OpenAI.Responses.ResponseCreateParamsStreaming {\n if (req.model.provider !== \"openai\") {\n throw new OpenAITranslationError(\n `OpenAIModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n // Reasoning — spec: reasoning-blocks. Absent sends nothing and drops the\n // provider's default reasoning items as before; \"none\" disables; anything\n // else asks for the effort AND for the encrypted content, which is the only\n // form that survives `store: false` and can be carried to the next step.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n const params: OpenAI.Responses.ResponseCreateParamsStreaming = {\n model: req.model.id,\n max_output_tokens: req.maxTokens,\n stream: true,\n // Privacy-first (§3, §10): the Responses API stores responses server-side\n // by default; the harness never leaves conversation state at the provider.\n store: false,\n input: req.messages.flatMap((m) => toInputItems(m, replay)),\n };\n if (reasoning !== undefined) {\n params.reasoning = replay ? { effort: reasoning.effort, summary: \"auto\" } : { effort: \"none\" };\n if (replay) params.include = [\"reasoning.encrypted_content\"];\n }\n // Service tier — spec: pricing-tiers. Flex and priority are request\n // parameters here; batch is a job, not a stream, and is refused.\n switch (req.serviceTier) {\n case undefined:\n case \"standard\":\n break;\n case \"flex\":\n case \"priority\":\n params.service_tier = req.serviceTier;\n break;\n default:\n throw new OpenAITranslationError(\n `the OpenAI Responses API cannot serve the ${req.serviceTier} tier on a streaming request`,\n );\n }\n const instructions = toInstructions(req.system);\n if (instructions !== \"\") params.instructions = instructions;\n // Provider-executed tools ride in the same list (spec: provider-tools); the\n // sources are asked for, so the result can cite what it read.\n const tools: OpenAI.Responses.Tool[] = [...req.tools.map(toTool), ...(req.providerTools ?? []).map(toWebSearchTool)];\n if (tools.length > 0) params.tools = tools;\n if ((req.providerTools ?? []).length > 0) params.include = [...(params.include ?? []), \"web_search_call.action.sources\"];\n return params;\n}\n\n/**\n * The neutral web search → the Responses tool. An option this wire has no\n * form for is REFUSED, never dropped; `maxUses` is not one — the loop\n * enforces it across the turn's steps (spec: what-the-wire-cuts).\n */\nfunction toWebSearchTool(spec: ProviderToolSpec): OpenAI.Responses.WebSearchTool {\n if (spec.blockedDomains !== undefined) {\n throw new OpenAITranslationError(\"the OpenAI web search has no blocked-domains form — refusing rather than searching them\");\n }\n const tool: OpenAI.Responses.WebSearchTool = { type: \"web_search\" };\n if (spec.allowedDomains !== undefined) tool.filters = { allowed_domains: [...spec.allowedDomains] };\n return tool;\n}\n\n/**\n * OpenAI has no explicit cache breakpoint (prefix caching is automatic), so\n * the §6.9 stable/volatile discipline is preserved simply by keeping the\n * blocks' order — stable first — in one instructions string.\n */\nfunction toInstructions(blocks: SystemBlock[]): string {\n return blocks.map((b) => b.text).join(\"\\n\\n\");\n}\n\nfunction toInputItems(msg: Msg, replayReasoning: boolean): OpenAI.Responses.ResponseInputItem[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserContentPart) }];\n case \"assistant\":\n // Text stays a message item; each tool_call becomes its own top-level\n // function_call item, preserving block order — and a reasoning item\n // goes back ahead of them, as it came (spec: reasoning-blocks).\n return msg.blocks.flatMap((b) => toAssistantItems(b, replayReasoning));\n case \"tool\":\n return msg.blocks.map(toFunctionCallOutput);\n }\n}\n\nfunction toUserContentPart(\n block: Block,\n): OpenAI.Responses.ResponseInputText | OpenAI.Responses.ResponseInputImage {\n switch (block.type) {\n case \"text\":\n return { type: \"input_text\", text: block.text };\n case \"media\":\n if (block.kind === \"image\") {\n return { type: \"input_image\", detail: \"auto\", image_url: block.ref.uri };\n }\n // Documents/audio on the Responses input surface are file-id-centric,\n // which breaks media-by-reference (§6.1) — fail loudly (spec 003):\n // the routing policy is the layer that picks capable providers.\n throw new OpenAITranslationError(\n `${block.kind} media is not supported by the OpenAI adapter`,\n );\n default:\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a user message`,\n );\n }\n}\n\nfunction toAssistantItems(block: Block, replayReasoning: boolean): OpenAI.Responses.ResponseInputItem[] {\n switch (block.type) {\n case \"text\":\n return [{ role: \"assistant\", content: block.text }];\n case \"tool_call\":\n return [\n {\n type: \"function_call\",\n call_id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n ];\n case \"reasoning\":\n // Own items go back with their encrypted content when reasoning is on\n // for this request; another provider's, or any when it is off, are\n // skipped without error (spec: reasoning-blocks).\n return block.provider === \"openai\" && replayReasoning ? [toReasoningItem(block)] : [];\n case \"provider_tool_call\":\n // The item carries both halves; the result block replays it (spec: provider-tools).\n return [];\n case \"provider_tool_result\":\n return block.provider === \"openai\" ? [toWebSearchItem(block)] : [];\n default:\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n}\n\n/** The opaque half this adapter wrote: the whole `web_search_call` item. */\nfunction toWebSearchItem(block: ProviderToolResultBlock): OpenAI.Responses.ResponseFunctionWebSearch {\n const opaque = block.opaque as { type?: unknown } | undefined;\n if (opaque?.type !== \"web_search_call\") {\n throw new OpenAITranslationError(\"an OpenAI web search result carries no replayable item\");\n }\n return opaque as OpenAI.Responses.ResponseFunctionWebSearch;\n}\n\n/** The opaque half this adapter wrote: the item's id, summary and encrypted content. */\nfunction toReasoningItem(block: ReasoningBlock): OpenAI.Responses.ResponseReasoningItem {\n const opaque = block.opaque as\n | { id?: unknown; summary?: unknown; encrypted_content?: unknown }\n | undefined;\n if (typeof opaque?.id !== \"string\" || typeof opaque.encrypted_content !== \"string\") {\n throw new OpenAITranslationError(\"an OpenAI reasoning block carries no id or encrypted content\");\n }\n return {\n type: \"reasoning\",\n id: opaque.id,\n summary: Array.isArray(opaque.summary) ? (opaque.summary as OpenAI.Responses.ResponseReasoningItem[\"summary\"]) : [],\n encrypted_content: opaque.encrypted_content,\n };\n}\n\nfunction toFunctionCallOutput(block: Block): OpenAI.Responses.ResponseInputItem {\n if (block.type !== \"tool_result\") {\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const serialized =\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\");\n return {\n type: \"function_call_output\",\n call_id: block.callId,\n // The Responses API has no is_error flag on function outputs — an\n // explicit prefix keeps failures visible to the model (spec 003).\n output: block.isError ? `ERROR: ${serialized}` : serialized,\n };\n}\n\nfunction toTool(spec: ToolSpec): OpenAI.Responses.FunctionTool {\n return {\n type: \"function\",\n name: spec.name,\n description: spec.description,\n parameters: spec.inputSchema,\n // Registry-derived schemas are not guaranteed strict-compatible; the\n // structured-output surface is a follow-up slice (spec 003 decision).\n strict: false,\n };\n}\n\n/**\n * Semantic stream events → neutral `ModelEvent`s. Function-call arguments\n * arrive complete on `response.output_item.done`, so each call is emitted as\n * ONE parsed `tool_call`. The terminal `response.completed` / `.incomplete`\n * event carries usage; `tool_use` is inferred from having emitted tool calls\n * (the Responses API has no finish_reason).\n */\nexport async function* translateOpenAIStream(\n events: AsyncIterable<OpenAI.Responses.ResponseStreamEvent>,\n): AsyncGenerator<ModelEvent> {\n let sawToolCall = false;\n let sawRefusal = false;\n // The wire's usage does not count searches; the completed items do (spec: provider-tools).\n let searches = 0;\n const withSearches = (usage: Usage): Usage => (searches > 0 ? { ...usage, webSearchRequests: searches } : usage);\n\n for await (const event of events) {\n switch (event.type) {\n case \"response.output_text.delta\":\n yield { type: \"text_delta\", text: event.delta };\n break;\n case \"response.refusal.delta\":\n // Refusal content is user-visible text; the stop reason records the\n // refusal itself (spec 003).\n sawRefusal = true;\n yield { type: \"text_delta\", text: event.delta };\n break;\n case \"response.output_item.done\":\n if (event.item.type === \"function_call\") {\n sawToolCall = true;\n yield { type: \"tool_call\", id: event.item.call_id, name: event.item.name, ...parseToolArguments(event.item.arguments) };\n } else if (event.item.type === \"web_search_call\") {\n // One item, two neutral halves: the call (its action) and the result\n // (the sources, the item whole for replay) — spec: provider-tools.\n searches += 1;\n const item = event.item;\n const action = item.action;\n const sources = action.type === \"search\" ? (action.sources ?? []).map((s) => ({ url: s.url })) : [];\n yield { type: \"provider_tool_call\", block: { type: \"provider_tool_call\", id: item.id, name: \"web_search\", provider: \"openai\", input: action } };\n yield {\n type: \"provider_tool_result\",\n block: {\n type: \"provider_tool_result\",\n callId: item.id,\n name: \"web_search\",\n provider: \"openai\",\n results: sources,\n ...(item.status === \"failed\" ? { error: \"failed\" } : {}),\n opaque: item,\n },\n };\n } else if (event.item.type === \"reasoning\" && typeof event.item.encrypted_content === \"string\") {\n // The COMPLETED item, from `done`: `added` may carry partial\n // encrypted content. Without encrypted content the item cannot be\n // replayed under `store: false`, so it is dropped as before the\n // spec — that is the case where nobody asked for it.\n const item = event.item;\n const text = [\n ...(item.content ?? []).map((c) => c.text),\n ...item.summary.map((s) => s.text),\n ]\n .filter((t) => t !== \"\")\n .join(\"\\n\");\n yield {\n type: \"reasoning\",\n block: {\n type: \"reasoning\",\n provider: \"openai\",\n ...(text !== \"\" ? { text } : {}),\n opaque: { id: item.id, summary: item.summary, encrypted_content: item.encrypted_content },\n },\n };\n }\n break;\n case \"response.completed\":\n yield { type: \"usage\", usage: withSearches(usageOf(event.response)) };\n yield { type: \"stop\", reason: sawRefusal ? \"refusal\" : sawToolCall ? \"tool_use\" : \"end_turn\" };\n break;\n case \"response.incomplete\": {\n yield { type: \"usage\", usage: withSearches(usageOf(event.response)) };\n yield { type: \"stop\", reason: mapIncompleteReason(event.response) };\n break;\n }\n case \"response.failed\": {\n // A failure the wire REPORTED rather than threw: classified by its\n // code through the same table the SDK's thrown errors go through.\n const err = event.response.error;\n const message = `OpenAI response failed: ${err ? `${err.code}: ${err.message}` : \"unknown error\"}`;\n throw new OpenAITranslationError(message, classifyFailure(\"ResponseFailed\", undefined, message.toLowerCase()));\n }\n case \"error\": {\n const message = `OpenAI stream error: ${event.message}`;\n throw new OpenAITranslationError(message, classifyFailure(\"StreamError\", undefined, `${event.code ?? \"\"} ${message}`.toLowerCase()));\n }\n default:\n // created / in_progress / content parts / argument deltas etc. carry\n // no neutral information beyond the events handled above.\n break;\n }\n }\n}\n\n/** The neutral usage of a complete response — shared by the stream and the batch path. */\nexport function usageOf(response: OpenAI.Responses.Response): Usage {\n const u = response.usage;\n const cachedRead = u?.input_tokens_details?.cached_tokens ?? 0;\n const usage: Usage = {\n // Neutral semantics (spec 005): inputTokens EXCLUDES cache reads.\n // OpenAI's input_tokens includes cached_tokens; subtract to normalize —\n // otherwise the BudgetGuard would price the same conversation\n // differently per provider.\n inputTokens: Math.max(0, (u?.input_tokens ?? 0) - cachedRead),\n outputTokens: u?.output_tokens ?? 0,\n };\n if (cachedRead > 0) usage.cacheReadInputTokens = cachedRead;\n const cacheWrite = u?.input_tokens_details?.cache_write_tokens;\n if (cacheWrite !== undefined && cacheWrite > 0) usage.cacheWriteInputTokens = cacheWrite;\n // Telemetry only: reasoning tokens are already inside output_tokens.\n const reasoningTokens = u?.output_tokens_details?.reasoning_tokens;\n if (reasoningTokens !== undefined && reasoningTokens > 0) usage.reasoningTokens = reasoningTokens;\n // The tier that SERVED, off the wire (spec: pricing-tiers). `default` is\n // standard; `auto`, `scale`, `fast` and `ultrafast` are outside the\n // neutral union and leave the field absent, so pricing falls back to the\n // tier asked.\n const served = response.service_tier;\n if (served === \"default\") usage.serviceTier = \"standard\";\n else if (served === \"flex\" || served === \"priority\") usage.serviceTier = served;\n return usage;\n}\n\nexport function mapIncompleteReason(response: OpenAI.Responses.Response): StopReason {\n const reason = response.incomplete_details?.reason;\n switch (reason) {\n case \"max_output_tokens\":\n // NOTE (spec 003 decision): OpenAI's wire conflates context-window\n // exhaustion into this reason (or a 400 before the stream), so the\n // neutral \"context_window_exceeded\" is unreachable on this adapter —\n // the long-context policy must watch provider errors instead.\n return \"max_tokens\";\n case \"content_filter\":\n return \"refusal\";\n default:\n throw new OpenAITranslationError(\n `Unmapped OpenAI incomplete reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","import OpenAI, { toFile } from \"openai\";\nimport type { Block, JobHandle, JobItem, JobOutput, JobProgress, JobResult, ModelJobClient } from \"@alma-harness/core\";\n\nimport { mapIncompleteReason, OpenAITranslationError, toOpenAIParams, usageOf } from \"./translate\";\n\n/**\n * `ModelJobClient` over the OpenAI Batch API — spec: model-jobs. Items become\n * one JSONL file of `/v1/responses` requests, uploaded with purpose `batch`;\n * results come back as a JSONL file of complete `Response` objects, each\n * translated here into the neutral output the runner prices and returns.\n */\n\n/** One line of the batch input file. */\nexport interface BatchLine {\n custom_id: string;\n method: \"POST\";\n url: \"/v1/responses\";\n body: OpenAI.Responses.ResponseCreateParamsNonStreaming;\n}\n\nexport function toBatchLines(items: readonly JobItem[]): BatchLine[] {\n return items.map((item) => {\n const { serviceTier: _tier, ...req } = item.request;\n void _tier;\n const { stream: _stream, ...body } = toOpenAIParams(req);\n void _stream;\n return { custom_id: item.id, method: \"POST\", url: \"/v1/responses\", body: body as OpenAI.Responses.ResponseCreateParamsNonStreaming };\n });\n}\n\n/** A complete response → neutral blocks, usage and stop — the non-streaming half of spec 003. */\nexport function translateResponse(response: OpenAI.Responses.Response): JobOutput {\n const blocks: Block[] = [];\n let sawToolCall = false;\n let sawRefusal = false;\n for (const item of response.output) {\n switch (item.type) {\n case \"message\":\n for (const part of item.content) {\n if (part.type === \"output_text\") blocks.push({ type: \"text\", text: part.text });\n else if (part.type === \"refusal\") {\n sawRefusal = true;\n blocks.push({ type: \"text\", text: part.refusal });\n }\n }\n break;\n case \"function_call\":\n sawToolCall = true;\n blocks.push({\n type: \"tool_call\",\n id: item.call_id,\n name: item.name,\n input: item.arguments === \"\" ? {} : (JSON.parse(item.arguments) as unknown),\n });\n break;\n case \"reasoning\": {\n if (typeof item.encrypted_content !== \"string\") break;\n const text = [...(item.content ?? []).map((c) => c.text), ...item.summary.map((s) => s.text)].filter((t) => t !== \"\").join(\"\\n\");\n blocks.push({\n type: \"reasoning\",\n provider: \"openai\",\n ...(text !== \"\" ? { text } : {}),\n opaque: { id: item.id, summary: item.summary, encrypted_content: item.encrypted_content },\n });\n break;\n }\n default:\n throw new OpenAITranslationError(`Unmapped OpenAI output item ${JSON.stringify(item.type)} — provider drift?`, \"provider_drift\");\n }\n }\n const stop =\n response.incomplete_details?.reason !== undefined && response.incomplete_details?.reason !== null\n ? mapIncompleteReason(response)\n : sawRefusal\n ? \"refusal\"\n : sawToolCall\n ? \"tool_use\"\n : \"end_turn\";\n return { blocks, usage: usageOf(response), stop };\n}\n\nexport interface OpenAIJobClientOptions {\n apiKey?: string;\n baseURL?: string;\n}\n\ninterface OutputLine {\n custom_id: string;\n response?: { status_code: number; body: OpenAI.Responses.Response | { error?: { message?: string } } } | null;\n error?: { message?: string } | null;\n}\n\nexport class OpenAIJobClient implements ModelJobClient {\n readonly #client: OpenAI;\n\n constructor(opts: OpenAIJobClientOptions = {}) {\n const init: ConstructorParameters<typeof OpenAI>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new OpenAI(init);\n }\n\n async submit(items: readonly JobItem[]): Promise<JobHandle> {\n const first = items[0];\n if (!first) throw new OpenAITranslationError(\"a batch needs at least one item\");\n const jsonl = toBatchLines(items).map((line) => JSON.stringify(line)).join(\"\\n\") + \"\\n\";\n const file = await this.#client.files.create({\n file: await toFile(Buffer.from(jsonl, \"utf8\"), \"alma-batch.jsonl\", { type: \"application/jsonl\" }),\n purpose: \"batch\",\n });\n const batch = await this.#client.batches.create({\n input_file_id: file.id,\n endpoint: \"/v1/responses\",\n completion_window: \"24h\",\n });\n return { provider: \"openai\", id: batch.id, model: first.request.model };\n }\n\n async status(handle: JobHandle): Promise<JobProgress> {\n const batch = await this.#client.batches.retrieve(handle.id);\n const status =\n batch.status === \"validating\"\n ? \"queued\"\n : batch.status === \"in_progress\" || batch.status === \"finalizing\"\n ? \"running\"\n : batch.status === \"completed\"\n ? \"done\"\n : batch.status === \"failed\"\n ? \"failed\"\n : batch.status === \"expired\"\n ? \"expired\"\n : \"cancelled\";\n const c = batch.request_counts;\n return {\n status,\n ...(c ? { counts: { total: c.total, done: c.completed, failed: c.failed } } : {}),\n };\n }\n\n async *results(handle: JobHandle): AsyncIterable<JobResult> {\n const batch = await this.#client.batches.retrieve(handle.id);\n for (const fileId of [batch.output_file_id, batch.error_file_id]) {\n if (!fileId) continue;\n const text = await (await this.#client.files.content(fileId)).text();\n for (const raw of text.split(\"\\n\")) {\n if (raw.trim() === \"\") continue;\n const line = JSON.parse(raw) as OutputLine;\n const body = line.response?.body;\n if (line.response && line.response.status_code >= 200 && line.response.status_code < 300 && body && \"output\" in body) {\n yield { id: line.custom_id, outcome: \"succeeded\", output: translateResponse(body) };\n } else {\n const error =\n line.error?.message ?? (body && \"error\" in body ? body.error?.message : undefined) ?? `status ${line.response?.status_code ?? \"unknown\"}`;\n yield { id: line.custom_id, outcome: \"errored\", error };\n }\n }\n }\n }\n\n async cancel(handle: JobHandle): Promise<void> {\n await this.#client.batches.cancel(handle.id);\n }\n}\n","import OpenAI from \"openai\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport {\n toOpenRouterParams,\n translateOpenRouterStream,\n type OpenRouterParams,\n type OpenRouterRouting,\n} from \"./translate\";\n\nexport interface OpenRouterModelClientOptions extends OpenRouterRouting {\n /** Omit to read OPENROUTER_API_KEY (the OpenAI SDK's own env resolution\n * would read OPENAI_API_KEY — the wrong credential for this gateway). */\n apiKey?: string;\n /** Defaults to OpenRouter's public endpoint. */\n baseURL?: string;\n}\n\nconst OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\n\n/**\n * `ModelClient` adapter for OpenRouter — §6.2, spec 014 (the gateway bridge).\n * Same thin-shell shape as the first-party adapters: translation lives in\n * ./translate (pure); this class owns the SDK client and the DECLARED\n * upstream policy. A gateway erases \"who processed this data?\" unless the\n * chain is declared beforehand, so construction REFUSES to proceed without a\n * non-empty upstream allowlist — deciding after the fact enforces nothing.\n */\nexport class OpenRouterModelClient implements ModelClient {\n readonly #client: OpenAI;\n readonly #routing: OpenRouterRouting;\n\n constructor(opts: OpenRouterModelClientOptions) {\n if (!Array.isArray(opts.upstreams) || opts.upstreams.length === 0) {\n throw new Error(\n \"OpenRouterModelClient requires a non-empty `upstreams` allowlist — \" +\n \"for a gateway, the data-processing chain must be a declared fact (spec 014)\",\n );\n }\n const routing: OpenRouterRouting = { upstreams: [...opts.upstreams] };\n if (opts.allowFallbacks !== undefined) routing.allowFallbacks = opts.allowFallbacks;\n if (opts.dataCollection !== undefined) routing.dataCollection = opts.dataCollection;\n if (opts.zeroDataRetention !== undefined) routing.zeroDataRetention = opts.zeroDataRetention;\n this.#routing = routing;\n\n const apiKey = opts.apiKey ?? process.env[\"OPENROUTER_API_KEY\"];\n if (apiKey === undefined || apiKey === \"\") {\n throw new Error(\n \"OpenRouterModelClient needs an API key: pass `apiKey` or set OPENROUTER_API_KEY\",\n );\n }\n this.#client = new OpenAI({ apiKey, baseURL: opts.baseURL ?? OPENROUTER_BASE_URL });\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity, like every adapter in this package.\n const params = toOpenRouterParams(req, this.#routing);\n return translateOpenRouterStream(this.#rawChunks(params, opts?.signal));\n }\n\n async *#rawChunks(\n params: OpenRouterParams,\n signal?: AbortSignal,\n ): AsyncGenerator<OpenAI.Chat.Completions.ChatCompletionChunk> {\n try {\n const stream = await this.#client.chat.completions.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const chunk of stream) yield chunk;\n } catch (err) {\n // What the SDK throws leaves as a `ProviderError` naming the GATEWAY\n // (spec: error-taxonomy): the upstream that actually failed is inside\n // the body, and the routing policy already knows the declared chain.\n throw toProviderError(\"openrouter\", err);\n }\n }\n}\n","import type OpenAI from \"openai\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and OpenRouter's\n * chat-completions wire — spec 014. A SECOND translator over the neutral\n * format, not a `baseURL` override: the first-party OpenAI adapter speaks the\n * Responses API, and nothing in its translation is reusable here.\n * Side-effect-free; testable without a network.\n */\n\n/** A `ProviderError` since spec: error-taxonomy — see `AnthropicTranslationError`. */\nexport class OpenRouterTranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"openrouter\", kind, message);\n this.name = \"OpenRouterTranslationError\";\n }\n}\n\n/**\n * The upstream routing policy — spec 014's core constraint: for a gateway,\n * \"who processed this data?\" must be a DECLARED fact, not an observed one.\n */\nexport interface OpenRouterRouting {\n /**\n * OpenRouter provider slugs allowed to serve requests (→ `provider.only`).\n * REQUIRED and non-empty: without it the data-processing chain has no\n * answer, so the client refuses to construct.\n */\n upstreams: readonly string[];\n /**\n * Default false: a fallback is a silent change of data processor. Enabling\n * it is a stated product choice, never a default.\n */\n allowFallbacks?: boolean;\n /**\n * Default \"deny\" — OpenRouter defaults to \"allow\", and a harness whose\n * README says \"operating on sensitive data\" must not inherit the permissive\n * default (spec 014 DECISION).\n */\n dataCollection?: \"allow\" | \"deny\";\n /** Opt-in pass-through to OpenRouter's zero-data-retention guarantee. */\n zeroDataRetention?: boolean;\n}\n\n/** The `provider` routing block OpenRouter accepts on every request. */\ninterface OpenRouterProviderBlock {\n only: string[];\n allow_fallbacks: boolean;\n data_collection: \"allow\" | \"deny\";\n zdr?: boolean;\n require_parameters?: boolean;\n}\n\n/** OpenRouter's reasoning block — a gateway extension the OpenAI SDK does not type. */\ninterface OpenRouterReasoningBlock {\n effort?: \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n enabled?: boolean;\n}\n\nexport type OpenRouterParams = OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & {\n provider: OpenRouterProviderBlock;\n reasoning?: OpenRouterReasoningBlock;\n};\n\nexport function toOpenRouterParams(req: ModelRequest, routing: OpenRouterRouting): OpenRouterParams {\n if (req.model.provider !== \"openrouter\") {\n throw new OpenRouterTranslationError(\n `OpenRouterModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n const provider: OpenRouterProviderBlock = {\n only: [...routing.upstreams],\n allow_fallbacks: routing.allowFallbacks ?? false,\n data_collection: routing.dataCollection ?? \"deny\",\n };\n if (routing.zeroDataRetention === true) provider.zdr = true;\n if (req.tools.length > 0) {\n // Not cosmetic (spec 014): tool support varies by upstream, and without\n // this a model can receive the request WITHOUT the tools it was supposed\n // to have — a silent capability failure for a loop whose control flow IS\n // tool calls.\n provider.require_parameters = true;\n }\n\n // Reasoning — spec: reasoning-blocks. The gateway normalizes effort for its\n // upstreams; `max` collapses to `xhigh`, its top rung. Own blocks are\n // replayed as `reasoning_details` only when reasoning is on for THIS request.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n const params: OpenRouterParams = {\n model: req.model.id,\n // The SDK deprecates this in favor of the OpenAI-specific\n // max_completion_tokens; for a gateway fronting heterogeneous upstreams,\n // max_tokens is the common denominator OpenRouter documents.\n max_tokens: req.maxTokens,\n stream: true,\n // Review amendment (spec 014): streamed chat completions only carry usage\n // when asked — without this the BudgetGuard never sees a usage event.\n stream_options: { include_usage: true },\n messages: [...systemMessages(req.system), ...req.messages.flatMap((m) => toWireMessages(m, replay))],\n provider,\n };\n if (reasoning !== undefined) {\n params.reasoning = replay\n ? { effort: reasoning.effort === \"max\" ? \"xhigh\" : reasoning.effort }\n : { enabled: false };\n }\n // Service tier — spec: pricing-tiers. The gateway prices by upstream, not\n // by tier; anything but standard is refused before the network.\n if (req.serviceTier !== undefined && req.serviceTier !== \"standard\") {\n throw new OpenRouterTranslationError(\n `the OpenRouter adapter cannot serve the ${req.serviceTier} tier — the gateway prices by upstream`,\n );\n }\n // Provider-executed tools have no neutral form on the gateway (spec: provider-tools).\n if ((req.providerTools ?? []).length > 0) {\n throw new OpenRouterTranslationError(\"the OpenRouter adapter cannot declare provider-executed tools — the gateway has no neutral web search\");\n }\n if (req.tools.length > 0) params.tools = req.tools.map(toTool);\n return params;\n}\n\n/**\n * Chat completions has no instructions field; system blocks become one system\n * message. The §6.9 stable/volatile discipline is preserved by keeping the\n * blocks' order — stable first — exactly as the OpenAI adapter does; whether\n * an upstream caches the prefix varies (spec 014's cache-hygiene note).\n */\nfunction systemMessages(\n blocks: SystemBlock[],\n): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {\n if (blocks.length === 0) return [];\n return [{ role: \"system\", content: blocks.map((b) => b.text).join(\"\\n\\n\") }];\n}\n\nfunction toWireMessages(msg: Msg, replayReasoning: boolean): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserContentPart) }];\n case \"assistant\":\n return [toAssistantMessage(msg.blocks, replayReasoning)];\n case \"tool\":\n // Chat completions wants one tool-role message PER result, keyed by\n // tool_call_id — unlike Anthropic's single user message of results.\n return msg.blocks.map(toToolMessage);\n }\n}\n\nfunction toUserContentPart(block: Block): OpenAI.Chat.Completions.ChatCompletionContentPart {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"media\":\n if (block.kind === \"image\") {\n return { type: \"image_url\", image_url: { url: block.ref.uri } };\n }\n // Document/audio support varies wildly by upstream and the wire shapes\n // are provider-specific — fail loudly (the routing policy is the layer\n // that picks capable providers, spec 003's precedent).\n throw new OpenRouterTranslationError(\n `${block.kind} media is not supported by the OpenRouter adapter`,\n );\n default:\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a user message`,\n );\n }\n}\n\nfunction toAssistantMessage(\n blocks: Block[],\n replayReasoning: boolean,\n): OpenAI.Chat.Completions.ChatCompletionMessageParam {\n let text = \"\";\n const toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[] = [];\n const details: unknown[] = [];\n for (const block of blocks) {\n switch (block.type) {\n case \"text\":\n text += block.text;\n break;\n case \"tool_call\":\n toolCalls.push({\n id: block.id,\n type: \"function\",\n function: { name: block.name, arguments: JSON.stringify(block.input) },\n });\n break;\n case \"reasoning\": {\n // Own `reasoning_details` go back when reasoning is on for this\n // request; another provider's, or any when it is off, are skipped\n // (spec: reasoning-blocks). A block with text but no details cannot\n // be replayed and is skipped too.\n const opaque = block.opaque as { reasoning_details?: unknown } | undefined;\n if (block.provider === \"openrouter\" && replayReasoning && Array.isArray(opaque?.reasoning_details)) {\n details.push(...opaque.reasoning_details);\n }\n break;\n }\n case \"provider_tool_call\":\n case \"provider_tool_result\":\n // Another provider's search (spec: provider-tools): nothing this wire can carry; skipped.\n break;\n default:\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n }\n const message: OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam & {\n reasoning_details?: unknown[];\n } = {\n role: \"assistant\",\n content: text === \"\" ? null : text,\n };\n if (toolCalls.length > 0) message.tool_calls = toolCalls;\n if (details.length > 0) message.reasoning_details = details;\n return message;\n}\n\nfunction toToolMessage(block: Block): OpenAI.Chat.Completions.ChatCompletionMessageParam {\n if (block.type !== \"tool_result\") {\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const serialized =\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\");\n return {\n role: \"tool\",\n tool_call_id: block.callId,\n // No is_error flag on this wire either — the explicit prefix keeps\n // failures visible to the model (spec 003's precedent).\n content: block.isError ? `ERROR: ${serialized}` : serialized,\n };\n}\n\nfunction toTool(spec: ToolSpec): OpenAI.Chat.Completions.ChatCompletionTool {\n return {\n type: \"function\",\n function: {\n name: spec.name,\n description: spec.description,\n parameters: spec.inputSchema,\n },\n };\n}\n\n/**\n * Chat-completion chunks → neutral `ModelEvent`s. Tool-call arguments arrive\n * as indexed fragments (id and name on the first fragment, argument pieces on\n * the rest); they are accumulated per index and emitted as ONE parsed\n * `tool_call` each when the choice finishes. The usage chunk arrives AFTER\n * `finish_reason` (with `stream_options.include_usage`), so the terminal\n * usage + stop pair is emitted at stream end — same order every adapter emits.\n */\nexport async function* translateOpenRouterStream(\n chunks: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n): AsyncGenerator<ModelEvent> {\n const pendingTools = new Map<number, { id: string; name: string; json: string }>();\n let finish: string | null = null;\n let usage: Usage | null = null;\n let toolsEmitted = false;\n // Reasoning is a gateway extension on the delta (`reasoning` text and\n // `reasoning_details`), untyped by the SDK; accumulated and emitted as ONE\n // block when the choice finishes, ahead of the tool calls (spec:\n // reasoning-blocks).\n let reasoningText = \"\";\n const reasoningDetails: unknown[] = [];\n let reasoningEmitted = false;\n\n for await (const chunk of chunks) {\n const choice = chunk.choices[0];\n if (choice) {\n const extra = choice.delta as { reasoning?: string | null; reasoning_details?: unknown[] | null };\n if (typeof extra.reasoning === \"string\") reasoningText += extra.reasoning;\n if (Array.isArray(extra.reasoning_details)) reasoningDetails.push(...extra.reasoning_details);\n if (choice.delta.content != null && choice.delta.content !== \"\") {\n yield { type: \"text_delta\", text: choice.delta.content };\n }\n for (const fragment of choice.delta.tool_calls ?? []) {\n const pending = pendingTools.get(fragment.index) ?? { id: \"\", name: \"\", json: \"\" };\n if (fragment.id != null) pending.id = fragment.id;\n if (fragment.function?.name != null) pending.name = fragment.function.name;\n if (fragment.function?.arguments != null) pending.json += fragment.function.arguments;\n pendingTools.set(fragment.index, pending);\n }\n if (choice.finish_reason != null) {\n finish = choice.finish_reason;\n if (!reasoningEmitted && (reasoningText !== \"\" || reasoningDetails.length > 0)) {\n reasoningEmitted = true;\n yield {\n type: \"reasoning\",\n block: {\n type: \"reasoning\",\n provider: \"openrouter\",\n ...(reasoningText !== \"\" ? { text: reasoningText } : {}),\n ...(reasoningDetails.length > 0 ? { opaque: { reasoning_details: reasoningDetails } } : {}),\n },\n };\n }\n if (!toolsEmitted) {\n toolsEmitted = true;\n for (const [, call] of [...pendingTools.entries()].sort(([a], [b]) => a - b)) {\n yield { type: \"tool_call\", id: call.id, name: call.name, ...parseToolArguments(call.json) };\n }\n pendingTools.clear();\n }\n }\n }\n if (chunk.usage != null) {\n const cachedRead = chunk.usage.prompt_tokens_details?.cached_tokens ?? 0;\n usage = {\n // Neutral semantics (spec 005): inputTokens EXCLUDES cache reads —\n // the wire's prompt_tokens includes them.\n inputTokens: Math.max(0, chunk.usage.prompt_tokens - cachedRead),\n outputTokens: chunk.usage.completion_tokens,\n };\n if (cachedRead > 0) usage.cacheReadInputTokens = cachedRead;\n // No cache-write signal exists on this wire; the field stays absent.\n const reasoningTokens = chunk.usage.completion_tokens_details?.reasoning_tokens;\n if (reasoningTokens !== undefined && reasoningTokens > 0) usage.reasoningTokens = reasoningTokens;\n }\n }\n\n if (finish === null) {\n throw new OpenRouterTranslationError(\n \"OpenRouter stream ended without a finish_reason — provider drift?\",\n \"provider_drift\",\n );\n }\n if (usage !== null) yield { type: \"usage\", usage };\n yield { type: \"stop\", reason: mapFinishReason(finish) };\n}\n\nfunction mapFinishReason(reason: string): StopReason {\n switch (reason) {\n case \"stop\":\n return \"end_turn\";\n case \"tool_calls\":\n return \"tool_use\";\n case \"length\":\n return \"max_tokens\";\n case \"content_filter\":\n return \"refusal\";\n default:\n // \"error\", or a reason newer than this adapter: refuse loudly rather\n // than silently truncate. NOTE (spec 014 review amendment): context-\n // window overflow arrives as a 400 error before any stream, so the\n // neutral \"context_window_exceeded\" is unreachable on this wire — the\n // long-context policy must watch provider errors, as with the OpenAI\n // adapter.\n throw new OpenRouterTranslationError(\n `Unmapped OpenRouter finish_reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","import type { ProviderId } from \"@alma-harness/core\";\n\n/**\n * @alma-harness/providers — `ModelClient` adapters (§6.2).\n * Bi-provider from birth — `AnthropicModelClient` (spec 002) and\n * `OpenAIModelClient` (spec 003) — plus the OpenRouter gateway bridge\n * (spec 014), all over the same neutral surface.\n */\n\nexport { AnthropicModelClient } from \"./anthropic/client\";\nexport type { AnthropicModelClientOptions } from \"./anthropic/client\";\nexport {\n AnthropicTranslationError,\n toAnthropicParams,\n translateStream,\n} from \"./anthropic/translate\";\n\nexport { AnthropicJobClient, translateMessage } from \"./anthropic/jobs\";\nexport type { AnthropicJobClientOptions } from \"./anthropic/jobs\";\n\nexport { OpenAIModelClient } from \"./openai/client\";\nexport type { OpenAIModelClientOptions } from \"./openai/client\";\nexport {\n OpenAITranslationError,\n toOpenAIParams,\n translateOpenAIStream,\n} from \"./openai/translate\";\n\nexport { OpenAIJobClient, toBatchLines, translateResponse } from \"./openai/jobs\";\nexport type { BatchLine, OpenAIJobClientOptions } from \"./openai/jobs\";\n\nexport { OpenRouterModelClient } from \"./openrouter/client\";\nexport type { OpenRouterModelClientOptions } from \"./openrouter/client\";\nexport {\n OpenRouterTranslationError,\n toOpenRouterParams,\n translateOpenRouterStream,\n} from \"./openrouter/translate\";\nexport type { OpenRouterParams, OpenRouterRouting } from \"./openrouter/translate\";\n\n// What the SDKs throw → the neutral `ProviderError` — spec: error-taxonomy\nexport { classifyFailure, toProviderError } from \"./errors\";\n\nexport type { ModelClient, ModelEvent, ModelJobClient, ModelRef, ModelRequest, ProviderId } from \"@alma-harness/core\";\n\n/**\n * First-party from birth (§3 principle 4), plus the gateway bridge —\n * spec 014: `openrouter` names the EXIT, not the processor; its adapter\n * requires a declared upstream allowlist for exactly that reason.\n */\nexport const SUPPORTED_PROVIDERS = [\"anthropic\", \"openai\", \"openrouter\"] as const satisfies readonly ProviderId[];\n"],"mappings":"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","names":["ProviderError","ProviderError","Anthropic","Anthropic","ProviderError","ProviderError","toTool","OpenAI","OpenAI","OpenAI","ProviderError","ProviderError","toTool","toUserContentPart","OpenAI"]}
1
+ {"version":3,"sources":["../src/anthropic/client.ts","../src/errors.ts","../src/anthropic/translate.ts","../src/arguments.ts","../src/anthropic/jobs.ts","../src/openai/client.ts","../src/openai/translate.ts","../src/openai/jobs.ts","../src/openrouter/client.ts","../src/openrouter/translate.ts","../src/index.ts"],"sourcesContent":["import Anthropic from \"@anthropic-ai/sdk\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport { toAnthropicParams, translateStream } from \"./translate\";\n\nexport interface AnthropicModelClientOptions {\n /** Omit to use the SDK's environment resolution (ANTHROPIC_API_KEY, …). */\n apiKey?: string;\n baseURL?: string;\n}\n\n/**\n * `ModelClient` adapter for the Anthropic Messages API — §6.2, spec 002.\n * A thin shell: request/stream translation lives in ./translate (pure);\n * this class only owns the SDK client. What the SDK throws leaves as a\n * `ProviderError` (spec: error-taxonomy); a user abort passes through.\n */\nexport class AnthropicModelClient implements ModelClient {\n readonly #client: Anthropic;\n\n constructor(opts: AnthropicModelClientOptions = {}) {\n const init: ConstructorParameters<typeof Anthropic>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new Anthropic(init);\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity — spec 002 criterion 5.\n const params = toAnthropicParams(req);\n return translateStream(this.#rawEvents(params, opts?.signal));\n }\n\n async *#rawEvents(\n params: Anthropic.MessageCreateParamsStreaming,\n signal?: AbortSignal,\n ): AsyncGenerator<Anthropic.RawMessageStreamEvent> {\n try {\n const stream = await this.#client.messages.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const event of stream) yield event;\n } catch (err) {\n throw toProviderError(\"anthropic\", err);\n }\n }\n}\n","import { ProviderError, type ProviderFailureKind, type ProviderId } from \"@alma-harness/core\";\n\n/**\n * What the SDKs throw → one neutral class — spec: error-taxonomy. DUCK-TYPED\n * rather than `instanceof` over two SDKs' error trees: both expose `status`,\n * `message` and the response body on `error`, the OpenAI one `code` and the\n * Anthropic one `type`; and the gateway speaks through the OpenAI SDK to\n * upstreams that shape their bodies differently. One table over the fields\n * they share is what stays true across all three.\n */\n\ninterface SdkErrorShape {\n name?: unknown;\n status?: unknown;\n code?: unknown;\n type?: unknown;\n message?: unknown;\n error?: unknown;\n}\n\nconst CONTEXT_WINDOW = /context_length_exceeded|prompt is too long|context window|maximum context length|too many tokens|exceeds the context|input length/i;\nconst OVERLOADED = /overloaded|too many requests|capacity|server_busy/i;\n\n/** Every string the body or the error carries as a code or a type, lowercased and joined. */\nfunction hintsOf(e: SdkErrorShape): string {\n const nested = (typeof e.error === \"object\" && e.error !== null ? e.error : {}) as SdkErrorShape;\n const inner = (typeof nested.error === \"object\" && nested.error !== null ? nested.error : {}) as SdkErrorShape;\n return [e.code, e.type, nested.code, nested.type, inner.code, inner.type, inner.message]\n .filter((h): h is string => typeof h === \"string\")\n .join(\" \")\n .toLowerCase();\n}\n\n/**\n * Wraps anything but a user abort. The abort passes through untouched: the\n * loop already reads its own signal, and a wrapped abort would classify a\n * cancellation as a provider failure.\n */\nexport function toProviderError(provider: ProviderId, err: unknown): unknown {\n if (err instanceof ProviderError) return err;\n const e = (typeof err === \"object\" && err !== null ? err : {}) as SdkErrorShape;\n // The SDKs do not always set `name`; the constructor's is the fallback.\n const own = typeof e.name === \"string\" && e.name !== \"Error\" ? e.name : \"\";\n const name = own !== \"\" ? own : ((err as { constructor?: { name?: unknown } } | null)?.constructor?.name as string | undefined) ?? \"\";\n if (name === \"APIUserAbortError\" || name === \"AbortError\") return err;\n const message = err instanceof Error ? err.message : String(err);\n const status = typeof e.status === \"number\" ? e.status : undefined;\n const kind = classifyFailure(name, status, `${hintsOf(e)} ${message.toLowerCase()}`);\n return new ProviderError(provider, kind, message, { ...(status !== undefined ? { status } : {}), cause: err });\n}\n\n/** The table. Exported for the one caller that has a code and no thrown error: a failure the wire REPORTED. */\nexport function classifyFailure(name: string, status: number | undefined, hints: string): ProviderFailureKind {\n if (status === 429 || /rate_limit/.test(hints)) return hints.includes(\"insufficient_quota\") ? \"rejected\" : \"rate_limited\";\n if (status === 529 || status === 503 || ((status === undefined || status >= 500) && OVERLOADED.test(hints))) return \"overloaded\";\n if (status !== undefined && status >= 500) return \"unavailable\";\n if ((status === undefined || status === 400) && CONTEXT_WINDOW.test(hints)) return \"context_window\";\n if (status !== undefined && status >= 400) return \"rejected\";\n // No status: the SDK could not reach the wire, the wire reported a server\n // failure, or the wire sent something the translation could not read.\n if (/connection|timeout|timed out|fetch|network|socket|econn|enotfound|server_error|internal|unavailable/i.test(`${name} ${hints}`)) {\n return \"unavailable\";\n }\n return \"provider_drift\";\n}\n","import type Anthropic from \"@anthropic-ai/sdk\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type ProviderToolCallBlock,\n type ProviderToolKind,\n type ProviderToolResultBlock,\n type ProviderToolSpec,\n type ReasoningBlock,\n type ReasoningEffort,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and the Anthropic\n * Messages API — spec 002. Everything here is side-effect-free so the wire\n * mapping is testable without a network.\n */\n\n/**\n * Raised when a request or stream cannot be represented faithfully. A\n * `ProviderError` since spec: error-taxonomy — `rejected` before the network\n * (the request as built cannot be sent), `provider_drift` mid-stream (the\n * wire sent something this adapter does not know).\n */\nexport class AnthropicTranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"anthropic\", kind, message);\n this.name = \"AnthropicTranslationError\";\n }\n}\n\nexport function toAnthropicParams(req: ModelRequest): Anthropic.MessageCreateParamsStreaming {\n if (req.model.provider !== \"anthropic\") {\n throw new AnthropicTranslationError(\n `AnthropicModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n // Reasoning — spec: reasoning-blocks. Absent sends nothing (the provider's\n // default, whose thinking is opt-in); \"none\" disables explicitly; anything\n // else asks for adaptive thinking at the mapped effort. Its own blocks are\n // replayed only when thinking is on for THIS request.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n // The cache duration (spec: cache-ttl): sent only for the hour, so an unasked request is byte-identical.\n const ttl = req.cache?.ttl === \"1h\" ? \"1h\" : undefined;\n const params: Anthropic.MessageCreateParamsStreaming = {\n model: req.model.id,\n max_tokens: req.maxTokens,\n stream: true,\n system: toSystem(req.system, ttl),\n messages: req.messages.flatMap((m) => toMessageParams(m, replay, declaredKinds(req))),\n };\n if (reasoning !== undefined) {\n if (reasoning.effort === \"none\") {\n params.thinking = { type: \"disabled\" };\n } else {\n params.thinking = { type: \"adaptive\" };\n params.output_config = { effort: toAnthropicEffort(reasoning.effort as Exclude<ReasoningEffort, \"none\">) };\n }\n }\n // Service tier — spec: pricing-tiers. `priority` asks for priority capacity\n // when the account has it (\"auto\": standard otherwise, and the usage says\n // which served). Flex does not exist on this wire and batch is a job, not\n // a stream: both refused before the network, never downgraded in silence.\n switch (req.serviceTier) {\n case undefined:\n case \"standard\":\n break;\n case \"priority\":\n params.service_tier = \"auto\";\n break;\n default:\n throw new AnthropicTranslationError(\n `the Anthropic Messages API cannot serve the ${req.serviceTier} tier on a streaming request`,\n );\n }\n // Provider-executed tools ride in the same list as the registered ones (spec: provider-tools).\n const tools: Anthropic.ToolUnion[] = [...req.tools.map(toTool), ...(req.providerTools ?? []).map(toServerTool)];\n if (tools.length > 0) params.tools = tools;\n markConversationTail(params.messages, ttl);\n return params;\n}\n\n/** One breakpoint, at the wire's default or the hour (spec: cache-ttl). */\nfunction breakpoint(ttl: \"1h\" | undefined): Anthropic.CacheControlEphemeral {\n return ttl === undefined ? { type: \"ephemeral\" } : { type: \"ephemeral\", ttl };\n}\n\n/** The neutral web search → the dated server tool; every option has a wire form here. */\n/**\n * The DIRECT search (spec: provider-tools): one `server_tool_use` per query.\n * `web_search_20260318` is the agentic search, which the model drives through\n * `code_execution` — encrypted stdout, nested calls — another kind, its own spec.\n */\nfunction toServerTool(spec: ProviderToolSpec): Anthropic.WebSearchTool20250305 {\n const tool: Anthropic.WebSearchTool20250305 = { type: \"web_search_20250305\", name: \"web_search\" };\n if (spec.maxUses !== undefined) tool.max_uses = spec.maxUses;\n if (spec.allowedDomains !== undefined) tool.allowed_domains = [...spec.allowedDomains];\n if (spec.blockedDomains !== undefined) tool.blocked_domains = [...spec.blockedDomains];\n return tool;\n}\n\n/** `minimal` collapses to `low`: the Messages API has no lower rung. */\nfunction toAnthropicEffort(\n effort: Exclude<ReasoningEffort, \"none\">,\n): NonNullable<Anthropic.OutputConfig[\"effort\"]> {\n return effort === \"minimal\" ? \"low\" : effort;\n}\n\n/**\n * Cache continuation — spec 005: a second breakpoint on the conversation\n * tail lets multi-turn sessions pay incremental tokens instead of re-reading\n * the whole history every turn. (Budget: 2 of the 4 allowed breakpoints —\n * one at the stable-system boundary, one here.)\n */\nfunction markConversationTail(messages: Anthropic.MessageParam[], ttl: \"1h\" | undefined): void {\n const last = messages.at(-1);\n if (!last || typeof last.content === \"string\") return;\n const block = last.content.at(-1);\n if (block) (block as { cache_control?: Anthropic.CacheControlEphemeral }).cache_control = breakpoint(ttl);\n}\n\n/**\n * The §6.9 stable/volatile boundary becomes the cache boundary: one\n * `cache_control` breakpoint on the LAST stable block, volatile blocks after\n * it. Order is preserved — callers must already emit stable-first.\n */\nfunction toSystem(blocks: SystemBlock[], ttl: \"1h\" | undefined): Anthropic.TextBlockParam[] {\n const lastStable = blocks.reduce(\n (last, b, i) => (b.volatility === \"stable\" ? i : last),\n -1,\n );\n return blocks.map((b, i) => {\n const param: Anthropic.TextBlockParam = { type: \"text\", text: b.text };\n if (i === lastStable) param.cache_control = breakpoint(ttl);\n return param;\n });\n}\n\n/** The provider-executed kinds THIS request declares: only their blocks are replayed (spec: close-060-064-findings). */\nfunction declaredKinds(req: ModelRequest): Set<ProviderToolKind> {\n return new Set((req.providerTools ?? []).map((t) => t.kind));\n}\n\nfunction toMessageParams(msg: Msg, replayReasoning: boolean, declared: Set<ProviderToolKind>): Anthropic.MessageParam[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserBlock) }];\n case \"assistant\": {\n const content = msg.blocks.flatMap((b) => toAssistantBlocks(b, replayReasoning, declared));\n // An assistant turn that held only another provider's reasoning has\n // nothing this wire can carry; an empty content array is a 400.\n return content.length === 0 ? [] : [{ role: \"assistant\", content }];\n }\n case \"tool\":\n // Anthropic's wire shape: tool results travel in a user-role message.\n return [{ role: \"user\", content: msg.blocks.map(toToolResultBlock) }];\n }\n}\n\n/** The image types the Messages API accepts by bytes; anything else is refused before the network. */\nconst IMAGE_TYPES = [\"image/jpeg\", \"image/png\", \"image/gif\", \"image/webp\"] as const;\n\nfunction toUserBlock(block: Block): Anthropic.ContentBlockParam {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"media\": {\n // By bytes when the loop attached them (spec: media-by-bytes), by URL otherwise.\n const content = block.content;\n switch (block.kind) {\n case \"image\": {\n if (content === undefined) return { type: \"image\", source: { type: \"url\", url: block.ref.uri } };\n const mediaType = IMAGE_TYPES.find((t) => t === content.contentType);\n if (mediaType === undefined) {\n throw new AnthropicTranslationError(`the Anthropic adapter cannot send an image of type ${JSON.stringify(content.contentType)} by bytes (${IMAGE_TYPES.join(\", \")})`);\n }\n return { type: \"image\", source: { type: \"base64\", media_type: mediaType, data: content.base64 } };\n }\n case \"document\":\n if (content === undefined) return { type: \"document\", source: { type: \"url\", url: block.ref.uri } };\n if (content.contentType !== \"application/pdf\") {\n throw new AnthropicTranslationError(`the Anthropic adapter sends only application/pdf documents by bytes, got ${JSON.stringify(content.contentType)}`);\n }\n return { type: \"document\", source: { type: \"base64\", media_type: \"application/pdf\", data: content.base64 } };\n case \"audio\":\n // The Messages API takes no raw audio; products transcribe upstream.\n throw new AnthropicTranslationError(\"audio media is not supported by the Anthropic adapter\");\n }\n }\n default:\n throw new AnthropicTranslationError(`block type ${JSON.stringify(block.type)} is not valid in a user message`);\n }\n}\n\nfunction toAssistantBlocks(block: Block, replayReasoning: boolean, declared: Set<ProviderToolKind>): Anthropic.ContentBlockParam[] {\n switch (block.type) {\n case \"text\":\n return [{ type: \"text\", text: block.text }];\n case \"tool_call\":\n return [{ type: \"tool_use\", id: block.id, name: block.name, input: block.input }];\n case \"reasoning\":\n // Own blocks go back UNMODIFIED and in order when thinking is on for\n // this request; another provider's, or any block when thinking is off,\n // are skipped without error (spec: reasoning-blocks).\n return block.provider === \"anthropic\" && replayReasoning ? [toThinkingParam(block)] : [];\n case \"provider_tool_call\":\n // Own server-tool blocks go back as they came (spec: provider-tools) — and only while the\n // request declares the tool: the API refuses a server_tool_use for a tool it was not given,\n // which is what a capped step looks like (spec: close-060-064-findings).\n return block.provider === \"anthropic\" && declared.has(block.name) ? [{ type: \"server_tool_use\", id: block.id, name: block.name, input: block.input }] : [];\n case \"provider_tool_result\":\n return block.provider === \"anthropic\" && declared.has(block.name) ? [toWebSearchResultParam(block)] : [];\n default:\n throw new AnthropicTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n}\n\n/** The opaque half this adapter wrote: the encrypted results, whole, or the error. */\nfunction toWebSearchResultParam(block: ProviderToolResultBlock): Anthropic.WebSearchToolResultBlockParam {\n const opaque = block.opaque as { content?: unknown } | undefined;\n if (opaque?.content === undefined) {\n throw new AnthropicTranslationError(\"an Anthropic web search result carries no replayable content\");\n }\n return { type: \"web_search_tool_result\", tool_use_id: block.callId, content: opaque.content as Anthropic.WebSearchToolResultBlockParamContent };\n}\n\n/** The opaque half this adapter wrote: a signature, or a redacted block's data. */\nfunction toThinkingParam(block: ReasoningBlock): Anthropic.ContentBlockParam {\n const opaque = block.opaque as { signature?: unknown; redacted?: unknown } | undefined;\n if (typeof opaque?.redacted === \"string\") {\n return { type: \"redacted_thinking\", data: opaque.redacted };\n }\n if (typeof opaque?.signature === \"string\") {\n return { type: \"thinking\", thinking: block.text ?? \"\", signature: opaque.signature };\n }\n // Refused here rather than as a 400 from the provider: a block this\n // adapter did not write in this shape cannot be verified there either.\n throw new AnthropicTranslationError(\"an Anthropic reasoning block carries neither a signature nor redacted data\");\n}\n\nfunction toToolResultBlock(block: Block): Anthropic.ToolResultBlockParam {\n if (block.type !== \"tool_result\") {\n throw new AnthropicTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const param: Anthropic.ToolResultBlockParam = {\n type: \"tool_result\",\n tool_use_id: block.callId,\n // JSON.stringify yields undefined (not a string) for undefined/functions;\n // \"null\" keeps the content explicit for void tool outputs.\n content:\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\"),\n };\n if (block.isError) param.is_error = true;\n return param;\n}\n\nfunction toTool(spec: ToolSpec): Anthropic.Tool {\n return {\n name: spec.name,\n description: spec.description,\n // The registry already derived a JSON Schema object (§6.4).\n input_schema: spec.inputSchema as Anthropic.Tool.InputSchema,\n };\n}\n\n/**\n * Raw SDK stream → neutral `ModelEvent`s. Tool inputs arrive as\n * `input_json_delta` fragments; they are accumulated per content block and\n * emitted as ONE `tool_call` with parsed input at `content_block_stop`.\n * Usage is aggregated (input + cache fields from `message_start`, output from\n * `message_delta`) and emitted once before the final `stop`.\n */\nexport async function* translateStream(\n events: AsyncIterable<Anthropic.RawMessageStreamEvent>,\n): AsyncGenerator<ModelEvent> {\n const usage: Usage = { inputTokens: 0, outputTokens: 0 };\n let stopReason: Anthropic.Message[\"stop_reason\"] = null;\n const pendingTools = new Map<number, { id: string; name: string; json: string }>();\n // Thinking arrives as text deltas plus one signature delta, redacted\n // thinking as opaque data on the block start; both are emitted as ONE\n // complete reasoning block at content_block_stop (spec: reasoning-blocks).\n const pendingThinking = new Map<number, { text: string; signature: string }>();\n const pendingRedacted = new Map<number, string>();\n // A server tool's call arrives like a tool use — input as json deltas — and its\n // result arrives whole on the block start (spec: provider-tools).\n const pendingServer = new Map<number, { id: string; name: ProviderToolCallBlock[\"name\"]; json: string }>();\n\n for await (const event of events) {\n switch (event.type) {\n case \"message_start\": {\n const u = event.message.usage;\n usage.inputTokens = u.input_tokens;\n if (u.cache_read_input_tokens != null) usage.cacheReadInputTokens = u.cache_read_input_tokens;\n if (u.cache_creation_input_tokens != null) {\n usage.cacheWriteInputTokens = u.cache_creation_input_tokens;\n }\n // What the wire wrote at (spec: cache-ttl): the hour is priced at its own row.\n if (u.cache_creation?.ephemeral_1h_input_tokens) usage.cacheWriteTtl = \"1h\";\n if (u.server_tool_use?.web_search_requests) usage.webSearchRequests = u.server_tool_use.web_search_requests;\n // The tier that SERVED, off the wire (spec: pricing-tiers) — priced\n // over the tier asked, since \"auto\" may land on standard.\n if (u.service_tier === \"standard\" || u.service_tier === \"priority\" || u.service_tier === \"batch\") {\n usage.serviceTier = u.service_tier;\n }\n break;\n }\n case \"content_block_start\":\n if (event.content_block.type === \"tool_use\") {\n pendingTools.set(event.index, {\n id: event.content_block.id,\n name: event.content_block.name,\n json: \"\",\n });\n } else if (event.content_block.type === \"thinking\") {\n pendingThinking.set(event.index, { text: event.content_block.thinking, signature: event.content_block.signature });\n } else if (event.content_block.type === \"redacted_thinking\") {\n pendingRedacted.set(event.index, event.content_block.data);\n } else if (event.content_block.type === \"server_tool_use\") {\n if (event.content_block.name !== \"web_search\") {\n throw new AnthropicTranslationError(`Unmapped Anthropic server tool ${JSON.stringify(event.content_block.name)} — provider drift?`, \"provider_drift\");\n }\n pendingServer.set(event.index, { id: event.content_block.id, name: \"web_search\", json: \"\" });\n } else if (event.content_block.type === \"web_search_tool_result\") {\n yield { type: \"provider_tool_result\", block: toProviderToolResult(event.content_block) };\n }\n break;\n case \"content_block_delta\":\n if (event.delta.type === \"text_delta\") {\n yield { type: \"text_delta\", text: event.delta.text };\n } else if (event.delta.type === \"input_json_delta\") {\n const pending = pendingTools.get(event.index) ?? pendingServer.get(event.index);\n if (pending) pending.json += event.delta.partial_json;\n } else if (event.delta.type === \"thinking_delta\") {\n const pending = pendingThinking.get(event.index);\n if (pending) pending.text += event.delta.thinking;\n } else if (event.delta.type === \"signature_delta\") {\n const pending = pendingThinking.get(event.index);\n if (pending) pending.signature = event.delta.signature;\n }\n break;\n case \"content_block_stop\": {\n const pending = pendingTools.get(event.index);\n if (pending) {\n pendingTools.delete(event.index);\n // Arguments that do not parse are the loop's to answer, and the\n // stop reason that follows says whether the wire cut them.\n yield { type: \"tool_call\", id: pending.id, name: pending.name, ...parseToolArguments(pending.json) };\n }\n const thinking = pendingThinking.get(event.index);\n if (thinking) {\n pendingThinking.delete(event.index);\n yield {\n type: \"reasoning\",\n block: { type: \"reasoning\", provider: \"anthropic\", text: thinking.text, opaque: { signature: thinking.signature } },\n };\n }\n const redacted = pendingRedacted.get(event.index);\n if (redacted !== undefined) {\n pendingRedacted.delete(event.index);\n yield { type: \"reasoning\", block: { type: \"reasoning\", provider: \"anthropic\", opaque: { redacted } } };\n }\n const server = pendingServer.get(event.index);\n if (server) {\n pendingServer.delete(event.index);\n yield {\n type: \"provider_tool_call\",\n block: { type: \"provider_tool_call\", id: server.id, name: server.name, provider: \"anthropic\", input: parseToolArguments(server.json).input },\n };\n }\n break;\n }\n case \"message_delta\":\n if (event.delta.stop_reason != null) stopReason = event.delta.stop_reason;\n usage.outputTokens = event.usage.output_tokens;\n if (event.usage.server_tool_use?.web_search_requests) usage.webSearchRequests = event.usage.server_tool_use.web_search_requests;\n break;\n case \"message_stop\":\n yield { type: \"usage\", usage: { ...usage } };\n yield { type: \"stop\", reason: mapStopReason(stopReason) };\n break;\n }\n }\n}\n\n/** A web search result block → the neutral result: the citations, the error, and the content whole for replay. */\nfunction toProviderToolResult(block: Anthropic.WebSearchToolResultBlock): ProviderToolResultBlock {\n const result: ProviderToolResultBlock = {\n type: \"provider_tool_result\",\n callId: block.tool_use_id,\n name: \"web_search\",\n provider: \"anthropic\",\n results: [],\n opaque: { content: block.content },\n };\n if (Array.isArray(block.content)) {\n result.results = block.content.map((r) => ({\n url: r.url,\n ...(r.title !== undefined ? { title: r.title } : {}),\n ...(r.page_age != null ? { pageAge: r.page_age } : {}),\n }));\n } else {\n result.error = block.content.error_code;\n }\n return result;\n}\n\nexport function mapStopReason(reason: Anthropic.Message[\"stop_reason\"]): StopReason {\n switch (reason) {\n case \"end_turn\":\n case \"stop_sequence\":\n return \"end_turn\";\n case \"tool_use\":\n return \"tool_use\";\n case \"max_tokens\":\n return \"max_tokens\";\n case \"refusal\":\n return \"refusal\";\n case \"model_context_window_exceeded\":\n return \"context_window_exceeded\";\n case \"pause_turn\":\n // A long-running server tool paused; the loop re-sends to continue (spec: provider-tools).\n return \"pause\";\n default:\n // A reason newer than this adapter: refuse loudly rather than silently truncate.\n throw new AnthropicTranslationError(\n `Unmapped Anthropic stop_reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","/**\n * Tool arguments off the wire — spec: what-the-wire-cuts. Every adapter\n * accumulates them as text and parsed them with a bare `JSON.parse`, so a\n * response cut by `max_tokens` mid-arguments threw from inside the stream\n * and the loop never saw the stop reason that explained it. A call whose\n * arguments do not parse is still a call: `input: {}` and the raw text as\n * `malformed`, for the loop to answer.\n */\nexport function parseToolArguments(json: string): { input: unknown; malformed?: string } {\n if (json === \"\") return { input: {} };\n try {\n return { input: JSON.parse(json) as unknown };\n } catch {\n return { input: {}, malformed: json };\n }\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type { Block, JobHandle, JobItem, JobOutput, JobProgress, JobResult, ModelJobClient, Usage } from \"@alma-harness/core\";\n\nimport { AnthropicTranslationError, mapStopReason, toAnthropicParams } from \"./translate\";\n\n/**\n * `ModelJobClient` over the Anthropic Message Batches API — spec: model-jobs.\n * Each item's request is translated with the same function the stream uses,\n * minus `stream`; a succeeded result is a complete `Message`, translated\n * here into the neutral output the runner prices and returns.\n */\n\n/** A complete message → neutral blocks, usage and stop — the non-streaming half of spec 002. */\nexport function translateMessage(message: Anthropic.Message): JobOutput {\n const blocks: Block[] = [];\n for (const block of message.content) {\n switch (block.type) {\n case \"text\":\n blocks.push({ type: \"text\", text: block.text });\n break;\n case \"tool_use\":\n blocks.push({ type: \"tool_call\", id: block.id, name: block.name, input: block.input });\n break;\n case \"thinking\":\n blocks.push({ type: \"reasoning\", provider: \"anthropic\", text: block.thinking, opaque: { signature: block.signature } });\n break;\n case \"redacted_thinking\":\n blocks.push({ type: \"reasoning\", provider: \"anthropic\", opaque: { redacted: block.data } });\n break;\n default:\n // A job declares no tools, provider-executed ones included (spec: model-jobs).\n throw new AnthropicTranslationError(`Unmapped Anthropic content block ${JSON.stringify(block.type)} — provider drift?`, \"provider_drift\");\n }\n }\n const u = message.usage;\n const usage: Usage = { inputTokens: u.input_tokens, outputTokens: u.output_tokens };\n if (u.cache_read_input_tokens != null) usage.cacheReadInputTokens = u.cache_read_input_tokens;\n if (u.cache_creation_input_tokens != null) usage.cacheWriteInputTokens = u.cache_creation_input_tokens;\n if (u.cache_creation?.ephemeral_1h_input_tokens) usage.cacheWriteTtl = \"1h\";\n if (u.service_tier === \"standard\" || u.service_tier === \"priority\" || u.service_tier === \"batch\") {\n usage.serviceTier = u.service_tier;\n }\n return { blocks, usage, stop: mapStopReason(message.stop_reason) };\n}\n\nexport interface AnthropicJobClientOptions {\n apiKey?: string;\n baseURL?: string;\n}\n\nexport class AnthropicJobClient implements ModelJobClient {\n readonly #client: Anthropic;\n\n constructor(opts: AnthropicJobClientOptions = {}) {\n const init: ConstructorParameters<typeof Anthropic>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new Anthropic(init);\n }\n\n async submit(items: readonly JobItem[]): Promise<JobHandle> {\n const first = items[0];\n if (!first) throw new AnthropicTranslationError(\"a batch needs at least one item\");\n const requests = items.map((item) => {\n // The item's tier is what makes it a job; the batch API has no tier\n // parameter, so the streaming translation runs with it cleared.\n const { serviceTier: _tier, ...req } = item.request;\n void _tier;\n const { stream: _stream, ...params } = toAnthropicParams(req);\n void _stream;\n return { custom_id: item.id, params: params as Anthropic.MessageCreateParamsNonStreaming };\n });\n const batch = await this.#client.messages.batches.create({ requests });\n return { provider: \"anthropic\", id: batch.id, model: first.request.model };\n }\n\n async status(handle: JobHandle): Promise<JobProgress> {\n const batch = await this.#client.messages.batches.retrieve(handle.id);\n const c = batch.request_counts;\n const total = c.processing + c.succeeded + c.errored + c.canceled + c.expired;\n const status =\n batch.processing_status === \"canceling\"\n ? \"cancelled\"\n : batch.processing_status === \"in_progress\"\n ? \"running\"\n : c.canceled === total && total > 0\n ? \"cancelled\"\n : c.expired === total && total > 0\n ? \"expired\"\n : \"done\";\n return { status, counts: { total, done: c.succeeded, failed: c.errored + c.canceled + c.expired } };\n }\n\n async *results(handle: JobHandle): AsyncIterable<JobResult> {\n const decoder = await this.#client.messages.batches.results(handle.id);\n for await (const entry of decoder) {\n const { custom_id: id, result } = entry;\n switch (result.type) {\n case \"succeeded\":\n yield { id, outcome: \"succeeded\", output: translateMessage(result.message) };\n break;\n case \"errored\": {\n const error = (result.error as { error?: { message?: string } } | undefined)?.error?.message;\n yield { id, outcome: \"errored\", ...(error !== undefined ? { error } : {}) };\n break;\n }\n case \"canceled\":\n yield { id, outcome: \"cancelled\" };\n break;\n case \"expired\":\n yield { id, outcome: \"expired\" };\n break;\n }\n }\n }\n\n async cancel(handle: JobHandle): Promise<void> {\n await this.#client.messages.batches.cancel(handle.id);\n }\n}\n","import OpenAI from \"openai\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport { toOpenAIParams, translateOpenAIStream } from \"./translate\";\n\nexport interface OpenAIModelClientOptions {\n /** Omit to use the SDK's environment resolution (OPENAI_API_KEY). */\n apiKey?: string;\n baseURL?: string;\n}\n\n/**\n * `ModelClient` adapter for the OpenAI Responses API — §6.2, spec 003.\n * A thin shell: request/stream translation lives in ./translate (pure);\n * this class only owns the SDK client. What the SDK throws leaves as a\n * `ProviderError` (spec: error-taxonomy); a user abort passes through.\n */\nexport class OpenAIModelClient implements ModelClient {\n readonly #client: OpenAI;\n\n constructor(opts: OpenAIModelClientOptions = {}) {\n const init: ConstructorParameters<typeof OpenAI>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new OpenAI(init);\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity — spec 003 criterion 6.\n const params = toOpenAIParams(req);\n return translateOpenAIStream(this.#rawEvents(params, opts?.signal));\n }\n\n async *#rawEvents(\n params: OpenAI.Responses.ResponseCreateParamsStreaming,\n signal?: AbortSignal,\n ): AsyncGenerator<OpenAI.Responses.ResponseStreamEvent> {\n try {\n const stream = await this.#client.responses.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const event of stream) yield event;\n } catch (err) {\n throw toProviderError(\"openai\", err);\n }\n }\n}\n","import type OpenAI from \"openai\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type ProviderToolKind,\n type ProviderToolResultBlock,\n type ProviderToolSpec,\n type ReasoningBlock,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\nimport { classifyFailure } from \"../errors\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and the OpenAI\n * Responses API — spec 003. Side-effect-free; testable without a network.\n */\n\n/** A `ProviderError` since spec: error-taxonomy — see `AnthropicTranslationError`. */\nexport class OpenAITranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"openai\", kind, message);\n this.name = \"OpenAITranslationError\";\n }\n}\n\nexport function toOpenAIParams(\n req: ModelRequest,\n): OpenAI.Responses.ResponseCreateParamsStreaming {\n if (req.model.provider !== \"openai\") {\n throw new OpenAITranslationError(\n `OpenAIModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n // Reasoning — spec: reasoning-blocks. Absent sends nothing and drops the\n // provider's default reasoning items as before; \"none\" disables; anything\n // else asks for the effort AND for the encrypted content, which is the only\n // form that survives `store: false` and can be carried to the next step.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n const params: OpenAI.Responses.ResponseCreateParamsStreaming = {\n model: req.model.id,\n max_output_tokens: req.maxTokens,\n stream: true,\n // Privacy-first (§3, §10): the Responses API stores responses server-side\n // by default; the harness never leaves conversation state at the provider.\n store: false,\n input: req.messages.flatMap((m) => toInputItems(m, replay, new Set((req.providerTools ?? []).map((t) => t.kind)))),\n };\n if (reasoning !== undefined) {\n params.reasoning = replay ? { effort: reasoning.effort, summary: \"auto\" } : { effort: \"none\" };\n if (replay) params.include = [\"reasoning.encrypted_content\"];\n }\n // Service tier — spec: pricing-tiers. Flex and priority are request\n // parameters here; batch is a job, not a stream, and is refused.\n switch (req.serviceTier) {\n case undefined:\n case \"standard\":\n break;\n case \"flex\":\n case \"priority\":\n params.service_tier = req.serviceTier;\n break;\n default:\n throw new OpenAITranslationError(\n `the OpenAI Responses API cannot serve the ${req.serviceTier} tier on a streaming request`,\n );\n }\n // No cache duration on this wire — caching is automatic (spec: cache-ttl): refused, never dropped.\n if (req.cache !== undefined) {\n throw new OpenAITranslationError(\"the OpenAI Responses API has no cache TTL form — the policy asked for one on a wire that cannot serve it\");\n }\n const instructions = toInstructions(req.system);\n if (instructions !== \"\") params.instructions = instructions;\n // Provider-executed tools ride in the same list (spec: provider-tools); the\n // sources are asked for, so the result can cite what it read.\n const tools: OpenAI.Responses.Tool[] = [...req.tools.map(toTool), ...(req.providerTools ?? []).map(toWebSearchTool)];\n if (tools.length > 0) params.tools = tools;\n if ((req.providerTools ?? []).length > 0) params.include = [...(params.include ?? []), \"web_search_call.action.sources\"];\n return params;\n}\n\n/**\n * The neutral web search → the Responses tool. An option this wire has no\n * form for is REFUSED, never dropped; `maxUses` is not one — the loop\n * enforces it across the turn's steps (spec: what-the-wire-cuts).\n */\nfunction toWebSearchTool(spec: ProviderToolSpec): OpenAI.Responses.WebSearchTool {\n if (spec.blockedDomains !== undefined) {\n throw new OpenAITranslationError(\"the OpenAI web search has no blocked-domains form — refusing rather than searching them\");\n }\n const tool: OpenAI.Responses.WebSearchTool = { type: \"web_search\" };\n if (spec.allowedDomains !== undefined) tool.filters = { allowed_domains: [...spec.allowedDomains] };\n return tool;\n}\n\n/**\n * OpenAI has no explicit cache breakpoint (prefix caching is automatic), so\n * the §6.9 stable/volatile discipline is preserved simply by keeping the\n * blocks' order — stable first — in one instructions string.\n */\nfunction toInstructions(blocks: SystemBlock[]): string {\n return blocks.map((b) => b.text).join(\"\\n\\n\");\n}\n\nfunction toInputItems(msg: Msg, replayReasoning: boolean, declared: Set<ProviderToolKind>): OpenAI.Responses.ResponseInputItem[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserContentPart) }];\n case \"assistant\":\n // Text stays a message item; each tool_call becomes its own top-level\n // function_call item, preserving block order — and a reasoning item\n // goes back ahead of them, as it came (spec: reasoning-blocks).\n return msg.blocks.flatMap((b) => toAssistantItems(b, replayReasoning, declared));\n case \"tool\":\n return msg.blocks.map(toFunctionCallOutput);\n }\n}\n\nfunction toUserContentPart(\n block: Block,\n): OpenAI.Responses.ResponseInputText | OpenAI.Responses.ResponseInputImage | OpenAI.Responses.ResponseInputFile {\n switch (block.type) {\n case \"text\":\n return { type: \"input_text\", text: block.text };\n case \"media\": {\n const content = block.content;\n if (block.kind === \"image\") {\n // By bytes as a data URL when the loop attached them (spec: media-by-bytes), by URL otherwise.\n const url = content === undefined ? block.ref.uri : `data:${content.contentType};base64,${content.base64}`;\n return { type: \"input_image\", detail: \"auto\", image_url: url };\n }\n if (block.kind === \"document\" && content !== undefined) {\n // The first document path on this adapter: bytes as a data URL, PDF only; the wire wants a name.\n if (content.contentType !== \"application/pdf\") {\n throw new OpenAITranslationError(`the OpenAI adapter sends only application/pdf documents by bytes, got ${JSON.stringify(content.contentType)}`);\n }\n return { type: \"input_file\", filename: block.ref.filename ?? \"document.pdf\", file_data: `data:application/pdf;base64,${content.base64}` };\n }\n // A document by reference and audio: the Responses input surface is\n // file-id-centric for those, which breaks media-by-reference (§6.1) —\n // fail loudly (spec 003): the routing policy picks capable providers.\n throw new OpenAITranslationError(\n `${block.kind} media is not supported by the OpenAI adapter${block.kind === \"document\" ? \" by reference\" : \"\"}`,\n );\n }\n default:\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a user message`,\n );\n }\n}\n\nfunction toAssistantItems(block: Block, replayReasoning: boolean, declared: Set<ProviderToolKind>): OpenAI.Responses.ResponseInputItem[] {\n switch (block.type) {\n case \"text\":\n return [{ role: \"assistant\", content: block.text }];\n case \"tool_call\":\n return [\n {\n type: \"function_call\",\n call_id: block.id,\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n ];\n case \"reasoning\":\n // Own items go back with their encrypted content when reasoning is on\n // for this request; another provider's, or any when it is off, are\n // skipped without error (spec: reasoning-blocks).\n return block.provider === \"openai\" && replayReasoning ? [toReasoningItem(block)] : [];\n case \"provider_tool_call\":\n // The item carries both halves; the result block replays it (spec: provider-tools).\n return [];\n case \"provider_tool_result\":\n // Replayed only while the request declares the kind (spec: close-060-064-findings).\n return block.provider === \"openai\" && declared.has(block.name) ? [toWebSearchItem(block)] : [];\n default:\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n}\n\n/** The opaque half this adapter wrote: the whole `web_search_call` item. */\nfunction toWebSearchItem(block: ProviderToolResultBlock): OpenAI.Responses.ResponseFunctionWebSearch {\n const opaque = block.opaque as { type?: unknown } | undefined;\n if (opaque?.type !== \"web_search_call\") {\n throw new OpenAITranslationError(\"an OpenAI web search result carries no replayable item\");\n }\n return opaque as OpenAI.Responses.ResponseFunctionWebSearch;\n}\n\n/** The opaque half this adapter wrote: the item's id, summary and encrypted content. */\nfunction toReasoningItem(block: ReasoningBlock): OpenAI.Responses.ResponseReasoningItem {\n const opaque = block.opaque as\n | { id?: unknown; summary?: unknown; encrypted_content?: unknown }\n | undefined;\n if (typeof opaque?.id !== \"string\" || typeof opaque.encrypted_content !== \"string\") {\n throw new OpenAITranslationError(\"an OpenAI reasoning block carries no id or encrypted content\");\n }\n return {\n type: \"reasoning\",\n id: opaque.id,\n summary: Array.isArray(opaque.summary) ? (opaque.summary as OpenAI.Responses.ResponseReasoningItem[\"summary\"]) : [],\n encrypted_content: opaque.encrypted_content,\n };\n}\n\nfunction toFunctionCallOutput(block: Block): OpenAI.Responses.ResponseInputItem {\n if (block.type !== \"tool_result\") {\n throw new OpenAITranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const serialized =\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\");\n return {\n type: \"function_call_output\",\n call_id: block.callId,\n // The Responses API has no is_error flag on function outputs — an\n // explicit prefix keeps failures visible to the model (spec 003).\n output: block.isError ? `ERROR: ${serialized}` : serialized,\n };\n}\n\nfunction toTool(spec: ToolSpec): OpenAI.Responses.FunctionTool {\n return {\n type: \"function\",\n name: spec.name,\n description: spec.description,\n parameters: spec.inputSchema,\n // Registry-derived schemas are not guaranteed strict-compatible; the\n // structured-output surface is a follow-up slice (spec 003 decision).\n strict: false,\n };\n}\n\n/**\n * Semantic stream events → neutral `ModelEvent`s. Function-call arguments\n * arrive complete on `response.output_item.done`, so each call is emitted as\n * ONE parsed `tool_call`. The terminal `response.completed` / `.incomplete`\n * event carries usage; `tool_use` is inferred from having emitted tool calls\n * (the Responses API has no finish_reason).\n */\nexport async function* translateOpenAIStream(\n events: AsyncIterable<OpenAI.Responses.ResponseStreamEvent>,\n): AsyncGenerator<ModelEvent> {\n let sawToolCall = false;\n let sawRefusal = false;\n // The wire's usage does not count searches; the completed items do (spec: provider-tools).\n let searches = 0;\n const withSearches = (usage: Usage): Usage => (searches > 0 ? { ...usage, webSearchRequests: searches } : usage);\n\n for await (const event of events) {\n switch (event.type) {\n case \"response.output_text.delta\":\n yield { type: \"text_delta\", text: event.delta };\n break;\n case \"response.refusal.delta\":\n // Refusal content is user-visible text; the stop reason records the\n // refusal itself (spec 003).\n sawRefusal = true;\n yield { type: \"text_delta\", text: event.delta };\n break;\n case \"response.output_item.done\":\n if (event.item.type === \"function_call\") {\n sawToolCall = true;\n yield { type: \"tool_call\", id: event.item.call_id, name: event.item.name, ...parseToolArguments(event.item.arguments) };\n } else if (event.item.type === \"web_search_call\") {\n // One item, two neutral halves: the call (its action) and the result\n // (the sources, the item whole for replay) — spec: provider-tools.\n searches += 1;\n const item = event.item;\n const action = item.action;\n const sources = action.type === \"search\" ? (action.sources ?? []).map((s) => ({ url: s.url })) : [];\n yield { type: \"provider_tool_call\", block: { type: \"provider_tool_call\", id: item.id, name: \"web_search\", provider: \"openai\", input: action } };\n yield {\n type: \"provider_tool_result\",\n block: {\n type: \"provider_tool_result\",\n callId: item.id,\n name: \"web_search\",\n provider: \"openai\",\n results: sources,\n ...(item.status === \"failed\" ? { error: \"failed\" } : {}),\n opaque: item,\n },\n };\n } else if (event.item.type === \"reasoning\" && typeof event.item.encrypted_content === \"string\") {\n // The COMPLETED item, from `done`: `added` may carry partial\n // encrypted content. Without encrypted content the item cannot be\n // replayed under `store: false`, so it is dropped as before the\n // spec — that is the case where nobody asked for it.\n const item = event.item;\n const text = [\n ...(item.content ?? []).map((c) => c.text),\n ...item.summary.map((s) => s.text),\n ]\n .filter((t) => t !== \"\")\n .join(\"\\n\");\n yield {\n type: \"reasoning\",\n block: {\n type: \"reasoning\",\n provider: \"openai\",\n ...(text !== \"\" ? { text } : {}),\n opaque: { id: item.id, summary: item.summary, encrypted_content: item.encrypted_content },\n },\n };\n }\n break;\n case \"response.completed\":\n yield { type: \"usage\", usage: withSearches(usageOf(event.response)) };\n yield { type: \"stop\", reason: sawRefusal ? \"refusal\" : sawToolCall ? \"tool_use\" : \"end_turn\" };\n break;\n case \"response.incomplete\": {\n yield { type: \"usage\", usage: withSearches(usageOf(event.response)) };\n yield { type: \"stop\", reason: mapIncompleteReason(event.response) };\n break;\n }\n case \"response.failed\": {\n // A failure the wire REPORTED rather than threw: classified by its\n // code through the same table the SDK's thrown errors go through.\n const err = event.response.error;\n const message = `OpenAI response failed: ${err ? `${err.code}: ${err.message}` : \"unknown error\"}`;\n throw new OpenAITranslationError(message, classifyFailure(\"ResponseFailed\", undefined, message.toLowerCase()));\n }\n case \"error\": {\n const message = `OpenAI stream error: ${event.message}`;\n throw new OpenAITranslationError(message, classifyFailure(\"StreamError\", undefined, `${event.code ?? \"\"} ${message}`.toLowerCase()));\n }\n default:\n // created / in_progress / content parts / argument deltas etc. carry\n // no neutral information beyond the events handled above.\n break;\n }\n }\n}\n\n/** The neutral usage of a complete response — shared by the stream and the batch path. */\nexport function usageOf(response: OpenAI.Responses.Response): Usage {\n const u = response.usage;\n const cachedRead = u?.input_tokens_details?.cached_tokens ?? 0;\n const usage: Usage = {\n // Neutral semantics (spec 005): inputTokens EXCLUDES cache reads.\n // OpenAI's input_tokens includes cached_tokens; subtract to normalize —\n // otherwise the BudgetGuard would price the same conversation\n // differently per provider.\n inputTokens: Math.max(0, (u?.input_tokens ?? 0) - cachedRead),\n outputTokens: u?.output_tokens ?? 0,\n };\n if (cachedRead > 0) usage.cacheReadInputTokens = cachedRead;\n const cacheWrite = u?.input_tokens_details?.cache_write_tokens;\n if (cacheWrite !== undefined && cacheWrite > 0) usage.cacheWriteInputTokens = cacheWrite;\n // Telemetry only: reasoning tokens are already inside output_tokens.\n const reasoningTokens = u?.output_tokens_details?.reasoning_tokens;\n if (reasoningTokens !== undefined && reasoningTokens > 0) usage.reasoningTokens = reasoningTokens;\n // The tier that SERVED, off the wire (spec: pricing-tiers). `default` is\n // standard; `auto`, `scale`, `fast` and `ultrafast` are outside the\n // neutral union and leave the field absent, so pricing falls back to the\n // tier asked.\n const served = response.service_tier;\n if (served === \"default\") usage.serviceTier = \"standard\";\n else if (served === \"flex\" || served === \"priority\") usage.serviceTier = served;\n return usage;\n}\n\nexport function mapIncompleteReason(response: OpenAI.Responses.Response): StopReason {\n const reason = response.incomplete_details?.reason;\n switch (reason) {\n case \"max_output_tokens\":\n // NOTE (spec 003 decision): OpenAI's wire conflates context-window\n // exhaustion into this reason (or a 400 before the stream), so the\n // neutral \"context_window_exceeded\" is unreachable on this adapter —\n // the long-context policy must watch provider errors instead.\n return \"max_tokens\";\n case \"content_filter\":\n return \"refusal\";\n default:\n throw new OpenAITranslationError(\n `Unmapped OpenAI incomplete reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","import OpenAI, { toFile } from \"openai\";\nimport type { Block, JobHandle, JobItem, JobOutput, JobProgress, JobResult, ModelJobClient } from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\nimport { mapIncompleteReason, OpenAITranslationError, toOpenAIParams, usageOf } from \"./translate\";\n\n/**\n * `ModelJobClient` over the OpenAI Batch API — spec: model-jobs. Items become\n * one JSONL file of `/v1/responses` requests, uploaded with purpose `batch`;\n * results come back as a JSONL file of complete `Response` objects, each\n * translated here into the neutral output the runner prices and returns.\n */\n\n/** One line of the batch input file. */\nexport interface BatchLine {\n custom_id: string;\n method: \"POST\";\n url: \"/v1/responses\";\n body: OpenAI.Responses.ResponseCreateParamsNonStreaming;\n}\n\nexport function toBatchLines(items: readonly JobItem[]): BatchLine[] {\n return items.map((item) => {\n const { serviceTier: _tier, ...req } = item.request;\n void _tier;\n const { stream: _stream, ...body } = toOpenAIParams(req);\n void _stream;\n return { custom_id: item.id, method: \"POST\", url: \"/v1/responses\", body: body as OpenAI.Responses.ResponseCreateParamsNonStreaming };\n });\n}\n\n/** A complete response → neutral blocks, usage and stop — the non-streaming half of spec 003. */\nexport function translateResponse(response: OpenAI.Responses.Response): JobOutput {\n const blocks: Block[] = [];\n let sawToolCall = false;\n let sawRefusal = false;\n for (const item of response.output) {\n switch (item.type) {\n case \"message\":\n for (const part of item.content) {\n if (part.type === \"output_text\") blocks.push({ type: \"text\", text: part.text });\n else if (part.type === \"refusal\") {\n sawRefusal = true;\n blocks.push({ type: \"text\", text: part.refusal });\n }\n }\n break;\n case \"function_call\":\n sawToolCall = true;\n // A cut or broken argument string is data here too, never a throw that fails the whole collect.\n blocks.push({ type: \"tool_call\", id: item.call_id, name: item.name, input: parseToolArguments(item.arguments).input });\n break;\n case \"reasoning\": {\n if (typeof item.encrypted_content !== \"string\") break;\n const text = [...(item.content ?? []).map((c) => c.text), ...item.summary.map((s) => s.text)].filter((t) => t !== \"\").join(\"\\n\");\n blocks.push({\n type: \"reasoning\",\n provider: \"openai\",\n ...(text !== \"\" ? { text } : {}),\n opaque: { id: item.id, summary: item.summary, encrypted_content: item.encrypted_content },\n });\n break;\n }\n default:\n throw new OpenAITranslationError(`Unmapped OpenAI output item ${JSON.stringify(item.type)} — provider drift?`, \"provider_drift\");\n }\n }\n const stop =\n response.incomplete_details?.reason !== undefined && response.incomplete_details?.reason !== null\n ? mapIncompleteReason(response)\n : sawRefusal\n ? \"refusal\"\n : sawToolCall\n ? \"tool_use\"\n : \"end_turn\";\n return { blocks, usage: usageOf(response), stop };\n}\n\nexport interface OpenAIJobClientOptions {\n apiKey?: string;\n baseURL?: string;\n}\n\ninterface OutputLine {\n custom_id: string;\n response?: { status_code: number; body: OpenAI.Responses.Response | { error?: { message?: string } } } | null;\n error?: { message?: string } | null;\n}\n\nexport class OpenAIJobClient implements ModelJobClient {\n readonly #client: OpenAI;\n\n constructor(opts: OpenAIJobClientOptions = {}) {\n const init: ConstructorParameters<typeof OpenAI>[0] = {};\n if (opts.apiKey !== undefined) init.apiKey = opts.apiKey;\n if (opts.baseURL !== undefined) init.baseURL = opts.baseURL;\n this.#client = new OpenAI(init);\n }\n\n async submit(items: readonly JobItem[]): Promise<JobHandle> {\n const first = items[0];\n if (!first) throw new OpenAITranslationError(\"a batch needs at least one item\");\n const jsonl = toBatchLines(items).map((line) => JSON.stringify(line)).join(\"\\n\") + \"\\n\";\n const file = await this.#client.files.create({\n file: await toFile(Buffer.from(jsonl, \"utf8\"), \"alma-batch.jsonl\", { type: \"application/jsonl\" }),\n purpose: \"batch\",\n });\n const batch = await this.#client.batches.create({\n input_file_id: file.id,\n endpoint: \"/v1/responses\",\n completion_window: \"24h\",\n });\n return { provider: \"openai\", id: batch.id, model: first.request.model };\n }\n\n async status(handle: JobHandle): Promise<JobProgress> {\n const batch = await this.#client.batches.retrieve(handle.id);\n const status =\n batch.status === \"validating\"\n ? \"queued\"\n : batch.status === \"in_progress\" || batch.status === \"finalizing\"\n ? \"running\"\n : batch.status === \"completed\"\n ? \"done\"\n : batch.status === \"failed\"\n ? \"failed\"\n : batch.status === \"expired\"\n ? \"expired\"\n : \"cancelled\";\n const c = batch.request_counts;\n return {\n status,\n ...(c ? { counts: { total: c.total, done: c.completed, failed: c.failed } } : {}),\n };\n }\n\n async *results(handle: JobHandle): AsyncIterable<JobResult> {\n const batch = await this.#client.batches.retrieve(handle.id);\n for (const fileId of [batch.output_file_id, batch.error_file_id]) {\n if (!fileId) continue;\n const text = await (await this.#client.files.content(fileId)).text();\n for (const raw of text.split(\"\\n\")) {\n if (raw.trim() === \"\") continue;\n const line = JSON.parse(raw) as OutputLine;\n const body = line.response?.body;\n if (line.response && line.response.status_code >= 200 && line.response.status_code < 300 && body && \"output\" in body) {\n yield { id: line.custom_id, outcome: \"succeeded\", output: translateResponse(body) };\n } else {\n const error =\n line.error?.message ?? (body && \"error\" in body ? body.error?.message : undefined) ?? `status ${line.response?.status_code ?? \"unknown\"}`;\n yield { id: line.custom_id, outcome: \"errored\", error };\n }\n }\n }\n }\n\n async cancel(handle: JobHandle): Promise<void> {\n await this.#client.batches.cancel(handle.id);\n }\n}\n","import OpenAI from \"openai\";\nimport type { ModelClient, ModelEvent, ModelRequest } from \"@alma-harness/core\";\n\nimport { toProviderError } from \"../errors\";\nimport {\n toOpenRouterParams,\n translateOpenRouterStream,\n type OpenRouterParams,\n type OpenRouterRouting,\n} from \"./translate\";\n\nexport interface OpenRouterModelClientOptions extends OpenRouterRouting {\n /** Omit to read OPENROUTER_API_KEY (the OpenAI SDK's own env resolution\n * would read OPENAI_API_KEY — the wrong credential for this gateway). */\n apiKey?: string;\n /** Defaults to OpenRouter's public endpoint. */\n baseURL?: string;\n}\n\nconst OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\";\n\n/**\n * `ModelClient` adapter for OpenRouter — §6.2, spec 014 (the gateway bridge).\n * Same thin-shell shape as the first-party adapters: translation lives in\n * ./translate (pure); this class owns the SDK client and the DECLARED\n * upstream policy. A gateway erases \"who processed this data?\" unless the\n * chain is declared beforehand, so construction REFUSES to proceed without a\n * non-empty upstream allowlist — deciding after the fact enforces nothing.\n */\nexport class OpenRouterModelClient implements ModelClient {\n readonly #client: OpenAI;\n readonly #routing: OpenRouterRouting;\n\n constructor(opts: OpenRouterModelClientOptions) {\n if (!Array.isArray(opts.upstreams) || opts.upstreams.length === 0) {\n throw new Error(\n \"OpenRouterModelClient requires a non-empty `upstreams` allowlist — \" +\n \"for a gateway, the data-processing chain must be a declared fact (spec 014)\",\n );\n }\n const routing: OpenRouterRouting = { upstreams: [...opts.upstreams] };\n if (opts.allowFallbacks !== undefined) routing.allowFallbacks = opts.allowFallbacks;\n if (opts.dataCollection !== undefined) routing.dataCollection = opts.dataCollection;\n if (opts.zeroDataRetention !== undefined) routing.zeroDataRetention = opts.zeroDataRetention;\n this.#routing = routing;\n\n const apiKey = opts.apiKey ?? process.env[\"OPENROUTER_API_KEY\"];\n if (apiKey === undefined || apiKey === \"\") {\n throw new Error(\n \"OpenRouterModelClient needs an API key: pass `apiKey` or set OPENROUTER_API_KEY\",\n );\n }\n this.#client = new OpenAI({ apiKey, baseURL: opts.baseURL ?? OPENROUTER_BASE_URL });\n }\n\n stream(req: ModelRequest, opts?: { signal?: AbortSignal }): AsyncIterable<ModelEvent> {\n // Translation throws synchronously (wrong provider, unsupported blocks)\n // before any network activity, like every adapter in this package.\n const params = toOpenRouterParams(req, this.#routing);\n return translateOpenRouterStream(this.#rawChunks(params, opts?.signal));\n }\n\n async *#rawChunks(\n params: OpenRouterParams,\n signal?: AbortSignal,\n ): AsyncGenerator<OpenAI.Chat.Completions.ChatCompletionChunk> {\n try {\n const stream = await this.#client.chat.completions.create(\n params,\n signal !== undefined ? { signal } : undefined,\n );\n for await (const chunk of stream) yield chunk;\n } catch (err) {\n // What the SDK throws leaves as a `ProviderError` naming the GATEWAY\n // (spec: error-taxonomy): the upstream that actually failed is inside\n // the body, and the routing policy already knows the declared chain.\n throw toProviderError(\"openrouter\", err);\n }\n }\n}\n","import type OpenAI from \"openai\";\n\nimport {\n ProviderError,\n type Block,\n type ModelEvent,\n type ModelRequest,\n type Msg,\n type ProviderFailureKind,\n type StopReason,\n type SystemBlock,\n type ToolSpec,\n type Usage,\n} from \"@alma-harness/core\";\n\nimport { parseToolArguments } from \"../arguments\";\n\n/**\n * Pure translation between Alma's neutral vocabulary (§6.2) and OpenRouter's\n * chat-completions wire — spec 014. A SECOND translator over the neutral\n * format, not a `baseURL` override: the first-party OpenAI adapter speaks the\n * Responses API, and nothing in its translation is reusable here.\n * Side-effect-free; testable without a network.\n */\n\n/** A `ProviderError` since spec: error-taxonomy — see `AnthropicTranslationError`. */\nexport class OpenRouterTranslationError extends ProviderError {\n constructor(message: string, kind: ProviderFailureKind = \"rejected\") {\n super(\"openrouter\", kind, message);\n this.name = \"OpenRouterTranslationError\";\n }\n}\n\n/**\n * The upstream routing policy — spec 014's core constraint: for a gateway,\n * \"who processed this data?\" must be a DECLARED fact, not an observed one.\n */\nexport interface OpenRouterRouting {\n /**\n * OpenRouter provider slugs allowed to serve requests (→ `provider.only`).\n * REQUIRED and non-empty: without it the data-processing chain has no\n * answer, so the client refuses to construct.\n */\n upstreams: readonly string[];\n /**\n * Default false: a fallback is a silent change of data processor. Enabling\n * it is a stated product choice, never a default.\n */\n allowFallbacks?: boolean;\n /**\n * Default \"deny\" — OpenRouter defaults to \"allow\", and a harness whose\n * README says \"operating on sensitive data\" must not inherit the permissive\n * default (spec 014 DECISION).\n */\n dataCollection?: \"allow\" | \"deny\";\n /** Opt-in pass-through to OpenRouter's zero-data-retention guarantee. */\n zeroDataRetention?: boolean;\n}\n\n/** The `provider` routing block OpenRouter accepts on every request. */\ninterface OpenRouterProviderBlock {\n only: string[];\n allow_fallbacks: boolean;\n data_collection: \"allow\" | \"deny\";\n zdr?: boolean;\n require_parameters?: boolean;\n}\n\n/** OpenRouter's reasoning block — a gateway extension the OpenAI SDK does not type. */\ninterface OpenRouterReasoningBlock {\n effort?: \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n enabled?: boolean;\n}\n\nexport type OpenRouterParams = OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming & {\n provider: OpenRouterProviderBlock;\n reasoning?: OpenRouterReasoningBlock;\n};\n\nexport function toOpenRouterParams(req: ModelRequest, routing: OpenRouterRouting): OpenRouterParams {\n if (req.model.provider !== \"openrouter\") {\n throw new OpenRouterTranslationError(\n `OpenRouterModelClient received a request for provider ${JSON.stringify(req.model.provider)}`,\n );\n }\n const provider: OpenRouterProviderBlock = {\n only: [...routing.upstreams],\n allow_fallbacks: routing.allowFallbacks ?? false,\n data_collection: routing.dataCollection ?? \"deny\",\n };\n if (routing.zeroDataRetention === true) provider.zdr = true;\n if (req.tools.length > 0) {\n // Not cosmetic (spec 014): tool support varies by upstream, and without\n // this a model can receive the request WITHOUT the tools it was supposed\n // to have — a silent capability failure for a loop whose control flow IS\n // tool calls.\n provider.require_parameters = true;\n }\n\n // Reasoning — spec: reasoning-blocks. The gateway normalizes effort for its\n // upstreams; `max` collapses to `xhigh`, its top rung. Own blocks are\n // replayed as `reasoning_details` only when reasoning is on for THIS request.\n const reasoning = req.reasoning;\n const replay = reasoning !== undefined && reasoning.effort !== \"none\";\n const params: OpenRouterParams = {\n model: req.model.id,\n // The SDK deprecates this in favor of the OpenAI-specific\n // max_completion_tokens; for a gateway fronting heterogeneous upstreams,\n // max_tokens is the common denominator OpenRouter documents.\n max_tokens: req.maxTokens,\n stream: true,\n // Review amendment (spec 014): streamed chat completions only carry usage\n // when asked — without this the BudgetGuard never sees a usage event.\n stream_options: { include_usage: true },\n messages: [...systemMessages(req.system), ...req.messages.flatMap((m) => toWireMessages(m, replay))],\n provider,\n };\n if (reasoning !== undefined) {\n params.reasoning = replay\n ? { effort: reasoning.effort === \"max\" ? \"xhigh\" : reasoning.effort }\n : { enabled: false };\n }\n // Service tier — spec: pricing-tiers. The gateway prices by upstream, not\n // by tier; anything but standard is refused before the network.\n if (req.serviceTier !== undefined && req.serviceTier !== \"standard\") {\n throw new OpenRouterTranslationError(\n `the OpenRouter adapter cannot serve the ${req.serviceTier} tier — the gateway prices by upstream`,\n );\n }\n // No cache duration on the gateway either (spec: cache-ttl): refused before the network.\n if (req.cache !== undefined) {\n throw new OpenRouterTranslationError(\"the OpenRouter adapter has no cache TTL form — the policy asked for one on a wire that cannot serve it\");\n }\n // Provider-executed tools have no neutral form on the gateway (spec: provider-tools).\n if ((req.providerTools ?? []).length > 0) {\n throw new OpenRouterTranslationError(\"the OpenRouter adapter cannot declare provider-executed tools — the gateway has no neutral web search\");\n }\n if (req.tools.length > 0) params.tools = req.tools.map(toTool);\n return params;\n}\n\n/**\n * Chat completions has no instructions field; system blocks become one system\n * message. The §6.9 stable/volatile discipline is preserved by keeping the\n * blocks' order — stable first — exactly as the OpenAI adapter does; whether\n * an upstream caches the prefix varies (spec 014's cache-hygiene note).\n */\nfunction systemMessages(\n blocks: SystemBlock[],\n): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {\n if (blocks.length === 0) return [];\n return [{ role: \"system\", content: blocks.map((b) => b.text).join(\"\\n\\n\") }];\n}\n\nfunction toWireMessages(msg: Msg, replayReasoning: boolean): OpenAI.Chat.Completions.ChatCompletionMessageParam[] {\n switch (msg.role) {\n case \"user\":\n return [{ role: \"user\", content: msg.blocks.map(toUserContentPart) }];\n case \"assistant\":\n return [toAssistantMessage(msg.blocks, replayReasoning)];\n case \"tool\":\n // Chat completions wants one tool-role message PER result, keyed by\n // tool_call_id — unlike Anthropic's single user message of results.\n return msg.blocks.map(toToolMessage);\n }\n}\n\nfunction toUserContentPart(block: Block): OpenAI.Chat.Completions.ChatCompletionContentPart {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"media\":\n if (block.kind === \"image\") {\n // By bytes as a data URL when the loop attached them (spec: media-by-bytes), by URL otherwise.\n const content = block.content;\n return { type: \"image_url\", image_url: { url: content === undefined ? block.ref.uri : `data:${content.contentType};base64,${content.base64}` } };\n }\n // Document/audio support varies wildly by upstream and the wire shapes\n // are provider-specific — fail loudly (the routing policy is the layer\n // that picks capable providers, spec 003's precedent).\n throw new OpenRouterTranslationError(\n `${block.kind} media is not supported by the OpenRouter adapter`,\n );\n default:\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a user message`,\n );\n }\n}\n\nfunction toAssistantMessage(\n blocks: Block[],\n replayReasoning: boolean,\n): OpenAI.Chat.Completions.ChatCompletionMessageParam {\n let text = \"\";\n const toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[] = [];\n const details: unknown[] = [];\n for (const block of blocks) {\n switch (block.type) {\n case \"text\":\n text += block.text;\n break;\n case \"tool_call\":\n toolCalls.push({\n id: block.id,\n type: \"function\",\n function: { name: block.name, arguments: JSON.stringify(block.input) },\n });\n break;\n case \"reasoning\": {\n // Own `reasoning_details` go back when reasoning is on for this\n // request; another provider's, or any when it is off, are skipped\n // (spec: reasoning-blocks). A block with text but no details cannot\n // be replayed and is skipped too.\n const opaque = block.opaque as { reasoning_details?: unknown } | undefined;\n if (block.provider === \"openrouter\" && replayReasoning && Array.isArray(opaque?.reasoning_details)) {\n details.push(...opaque.reasoning_details);\n }\n break;\n }\n case \"provider_tool_call\":\n case \"provider_tool_result\":\n // Another provider's search (spec: provider-tools): nothing this wire can carry; skipped.\n break;\n default:\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in an assistant message`,\n );\n }\n }\n const message: OpenAI.Chat.Completions.ChatCompletionAssistantMessageParam & {\n reasoning_details?: unknown[];\n } = {\n role: \"assistant\",\n content: text === \"\" ? null : text,\n };\n if (toolCalls.length > 0) message.tool_calls = toolCalls;\n if (details.length > 0) message.reasoning_details = details;\n return message;\n}\n\nfunction toToolMessage(block: Block): OpenAI.Chat.Completions.ChatCompletionMessageParam {\n if (block.type !== \"tool_result\") {\n throw new OpenRouterTranslationError(\n `block type ${JSON.stringify(block.type)} is not valid in a tool message`,\n );\n }\n const serialized =\n typeof block.output === \"string\" ? block.output : (JSON.stringify(block.output) ?? \"null\");\n return {\n role: \"tool\",\n tool_call_id: block.callId,\n // No is_error flag on this wire either — the explicit prefix keeps\n // failures visible to the model (spec 003's precedent).\n content: block.isError ? `ERROR: ${serialized}` : serialized,\n };\n}\n\nfunction toTool(spec: ToolSpec): OpenAI.Chat.Completions.ChatCompletionTool {\n return {\n type: \"function\",\n function: {\n name: spec.name,\n description: spec.description,\n parameters: spec.inputSchema,\n },\n };\n}\n\n/**\n * Chat-completion chunks → neutral `ModelEvent`s. Tool-call arguments arrive\n * as indexed fragments (id and name on the first fragment, argument pieces on\n * the rest); they are accumulated per index and emitted as ONE parsed\n * `tool_call` each when the choice finishes. The usage chunk arrives AFTER\n * `finish_reason` (with `stream_options.include_usage`), so the terminal\n * usage + stop pair is emitted at stream end — same order every adapter emits.\n */\nexport async function* translateOpenRouterStream(\n chunks: AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>,\n): AsyncGenerator<ModelEvent> {\n const pendingTools = new Map<number, { id: string; name: string; json: string }>();\n let finish: string | null = null;\n let usage: Usage | null = null;\n let toolsEmitted = false;\n // Reasoning is a gateway extension on the delta (`reasoning` text and\n // `reasoning_details`), untyped by the SDK; accumulated and emitted as ONE\n // block when the choice finishes, ahead of the tool calls (spec:\n // reasoning-blocks).\n let reasoningText = \"\";\n const reasoningDetails: unknown[] = [];\n let reasoningEmitted = false;\n\n for await (const chunk of chunks) {\n const choice = chunk.choices[0];\n if (choice) {\n const extra = choice.delta as { reasoning?: string | null; reasoning_details?: unknown[] | null };\n if (typeof extra.reasoning === \"string\") reasoningText += extra.reasoning;\n if (Array.isArray(extra.reasoning_details)) reasoningDetails.push(...extra.reasoning_details);\n if (choice.delta.content != null && choice.delta.content !== \"\") {\n yield { type: \"text_delta\", text: choice.delta.content };\n }\n for (const fragment of choice.delta.tool_calls ?? []) {\n const pending = pendingTools.get(fragment.index) ?? { id: \"\", name: \"\", json: \"\" };\n if (fragment.id != null) pending.id = fragment.id;\n if (fragment.function?.name != null) pending.name = fragment.function.name;\n if (fragment.function?.arguments != null) pending.json += fragment.function.arguments;\n pendingTools.set(fragment.index, pending);\n }\n if (choice.finish_reason != null) {\n finish = choice.finish_reason;\n if (!reasoningEmitted && (reasoningText !== \"\" || reasoningDetails.length > 0)) {\n reasoningEmitted = true;\n yield {\n type: \"reasoning\",\n block: {\n type: \"reasoning\",\n provider: \"openrouter\",\n ...(reasoningText !== \"\" ? { text: reasoningText } : {}),\n ...(reasoningDetails.length > 0 ? { opaque: { reasoning_details: reasoningDetails } } : {}),\n },\n };\n }\n if (!toolsEmitted) {\n toolsEmitted = true;\n for (const [, call] of [...pendingTools.entries()].sort(([a], [b]) => a - b)) {\n yield { type: \"tool_call\", id: call.id, name: call.name, ...parseToolArguments(call.json) };\n }\n pendingTools.clear();\n }\n }\n }\n if (chunk.usage != null) {\n const cachedRead = chunk.usage.prompt_tokens_details?.cached_tokens ?? 0;\n usage = {\n // Neutral semantics (spec 005): inputTokens EXCLUDES cache reads —\n // the wire's prompt_tokens includes them.\n inputTokens: Math.max(0, chunk.usage.prompt_tokens - cachedRead),\n outputTokens: chunk.usage.completion_tokens,\n };\n if (cachedRead > 0) usage.cacheReadInputTokens = cachedRead;\n // No cache-write signal exists on this wire; the field stays absent.\n const reasoningTokens = chunk.usage.completion_tokens_details?.reasoning_tokens;\n if (reasoningTokens !== undefined && reasoningTokens > 0) usage.reasoningTokens = reasoningTokens;\n }\n }\n\n if (finish === null) {\n throw new OpenRouterTranslationError(\n \"OpenRouter stream ended without a finish_reason — provider drift?\",\n \"provider_drift\",\n );\n }\n if (usage !== null) yield { type: \"usage\", usage };\n yield { type: \"stop\", reason: mapFinishReason(finish) };\n}\n\nfunction mapFinishReason(reason: string): StopReason {\n switch (reason) {\n case \"stop\":\n return \"end_turn\";\n case \"tool_calls\":\n return \"tool_use\";\n case \"length\":\n return \"max_tokens\";\n case \"content_filter\":\n return \"refusal\";\n default:\n // \"error\", or a reason newer than this adapter: refuse loudly rather\n // than silently truncate. NOTE (spec 014 review amendment): context-\n // window overflow arrives as a 400 error before any stream, so the\n // neutral \"context_window_exceeded\" is unreachable on this wire — the\n // long-context policy must watch provider errors, as with the OpenAI\n // adapter.\n throw new OpenRouterTranslationError(\n `Unmapped OpenRouter finish_reason ${JSON.stringify(reason)} — provider drift?`,\n \"provider_drift\",\n );\n }\n}\n","import type { ProviderId } from \"@alma-harness/core\";\n\n/**\n * @alma-harness/providers — `ModelClient` adapters (§6.2).\n * Bi-provider from birth — `AnthropicModelClient` (spec 002) and\n * `OpenAIModelClient` (spec 003) — plus the OpenRouter gateway bridge\n * (spec 014), all over the same neutral surface.\n */\n\nexport { AnthropicModelClient } from \"./anthropic/client\";\nexport type { AnthropicModelClientOptions } from \"./anthropic/client\";\nexport {\n AnthropicTranslationError,\n toAnthropicParams,\n translateStream,\n} from \"./anthropic/translate\";\n\nexport { AnthropicJobClient, translateMessage } from \"./anthropic/jobs\";\nexport type { AnthropicJobClientOptions } from \"./anthropic/jobs\";\n\nexport { OpenAIModelClient } from \"./openai/client\";\nexport type { OpenAIModelClientOptions } from \"./openai/client\";\nexport {\n OpenAITranslationError,\n toOpenAIParams,\n translateOpenAIStream,\n} from \"./openai/translate\";\n\nexport { OpenAIJobClient, toBatchLines, translateResponse } from \"./openai/jobs\";\nexport type { BatchLine, OpenAIJobClientOptions } from \"./openai/jobs\";\n\nexport { OpenRouterModelClient } from \"./openrouter/client\";\nexport type { OpenRouterModelClientOptions } from \"./openrouter/client\";\nexport {\n OpenRouterTranslationError,\n toOpenRouterParams,\n translateOpenRouterStream,\n} from \"./openrouter/translate\";\nexport type { OpenRouterParams, OpenRouterRouting } from \"./openrouter/translate\";\n\n// What the SDKs throw → the neutral `ProviderError` — spec: error-taxonomy\nexport { classifyFailure, toProviderError } from \"./errors\";\n\nexport type { ModelClient, ModelEvent, ModelJobClient, ModelRef, ModelRequest, ProviderId } from \"@alma-harness/core\";\n\n/**\n * First-party from birth (§3 principle 4), plus the gateway bridge —\n * spec 014: `openrouter` names the EXIT, not the processor; its adapter\n * requires a declared upstream allowlist for exactly that reason.\n */\nexport const SUPPORTED_PROVIDERS = [\"anthropic\", \"openai\", \"openrouter\"] as const satisfies readonly ProviderId[];\n"],"mappings":"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","names":["ProviderError","ProviderError","Anthropic","Anthropic","ProviderError","ProviderError","toTool","OpenAI","OpenAI","OpenAI","ProviderError","ProviderError","toTool","toUserContentPart","OpenAI"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alma-harness/providers",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "ModelClient adapters for Anthropic and OpenAI over Alma's neutral message format.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  "openai": "^7.5.0"
24
24
  },
25
25
  "peerDependencies": {
26
- "@alma-harness/core": "^0.2.0"
26
+ "@alma-harness/core": "^0.4.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.1.0",