@effect-uai/anthropic 0.5.1 → 0.6.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.
@@ -5,7 +5,7 @@ import { Context, Effect, Layer, Redacted, Stream } from "effect";
5
5
  import { HttpClient } from "effect/unstable/http";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
7
  import { CommonRequest, LanguageModel } from "@effect-uai/core/LanguageModel";
8
- import { TurnEvent } from "@effect-uai/core/Turn";
8
+ import { Turn, TurnEvent } from "@effect-uai/core/Turn";
9
9
 
10
10
  //#region src/Anthropic.d.ts
11
11
  declare namespace Anthropic_d_exports {
@@ -46,6 +46,14 @@ type AnthropicService = {
46
46
  * `streamNative |> toCanonical`.
47
47
  */
48
48
  readonly streamTurn: (request: AnthropicRequest) => Stream.Stream<TurnEvent, AiError.AiError>;
49
+ /**
50
+ * Drain a single turn and return the assembled `Turn`. Derived from
51
+ * `streamTurn` — Anthropic's non-streaming `/messages` endpoint
52
+ * differs from the streamed one in subtle ways (no incremental
53
+ * thinking deltas), so we route everything through streaming for
54
+ * consistency.
55
+ */
56
+ readonly turn: (request: AnthropicRequest) => Effect.Effect<Turn, AiError.AiError>;
49
57
  /**
50
58
  * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.
51
59
  * Stateful (threads an `Accumulator` for tool-call lookup and
@@ -1 +1 @@
1
- {"version":3,"file":"Anthropic.d.mts","names":[],"sources":["../src/Anthropic.ts"],"mappings":";;;;;;;;;;;;;KAmCY,gBAAA,GAAmB,IAAA,CAAK,aAAA;;;;;WAKzB,KAAA,EAAO,cAAA;;;;;WAKP,IAAA;WAEA,aAAA,GAAgB,aAAA;EAZC;;;;;EAAA,SAkBjB,QAAA,GAAW,cAAA;EAAA;;;EAAA,SAIX,IAAA;AAAA;AAAA,KAGC,gBAAA;EApBM;;;;;EAAA,SA0BP,YAAA,GACP,OAAA,EAAS,gBAAA,KACN,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,OAAA,CAAQ,OAAA;EAXjC;;;AAGX;EAHW,SAgBA,UAAA,GAAa,OAAA,EAAS,gBAAA,KAAqB,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA;EAb3D;;;;;EAAA,SAmBjB,WAAA,SACP,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,CAAA,MAChC,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,CAAA,EAAG,CAAA;AAAA;AAAA,cAClC,cAAA;;;;;;;cAQY,SAAA,SAAkB,cAAA;AAAA,KAInB,MAAA;EAAA,SACD,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SACjB,OAAA;EA9BA;;;;;EAAA,SAoCA,gBAAA;AAAA;;;;;;cA4NE,WAAA,SACX,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,CAAA,MAClC,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,CAAA,EAAG,CAAA;;;;cAmBlB,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAS,MAAA,CAAO,MAAA,CAAO,gBAAA,SAAyB,UAAA,CAAW,UAAA;;;;;;;;cAkBxE,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,SAAA,GAAY,aAAA,SAAsB,UAAA,CAAW,UAAA"}
1
+ {"version":3,"file":"Anthropic.d.mts","names":[],"sources":["../src/Anthropic.ts"],"mappings":";;;;;;;;;;;;;KAoCY,gBAAA,GAAmB,IAAA,CAAK,aAAA;;;;;WAKzB,KAAA,EAAO,cAAA;;;;;WAKP,IAAA;WAEA,aAAA,GAAgB,aAAA;EAZC;;;;;EAAA,SAkBjB,QAAA,GAAW,cAAA;EAAA;;;EAAA,SAIX,IAAA;AAAA;AAAA,KAGC,gBAAA;EApBM;;;;;EAAA,SA0BP,YAAA,GACP,OAAA,EAAS,gBAAA,KACN,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,OAAA,CAAQ,OAAA;EAXjC;;;AAGX;EAHW,SAgBA,UAAA,GAAa,OAAA,EAAS,gBAAA,KAAqB,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,OAAA;EAb3D;;;;;;;EAAA,SAqBjB,IAAA,GAAO,OAAA,EAAS,gBAAA,KAAqB,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,OAAA,CAAQ,OAAA;EARtB;;;;;EAAA,SAc3C,WAAA,SACP,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,CAAA,MAChC,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,CAAA,EAAG,CAAA;AAAA;AAAA,cAClC,cAAA;;;;;;;cAQY,SAAA,SAAkB,cAAA;AAAA,KAInB,MAAA;EAAA,SACD,MAAA,EAAQ,QAAA,CAAS,QAAA;EAAA,SACjB,OAAA;EApCG;;;;;EAAA,SA0CH,gBAAA;AAAA;;;;;;cA4NE,WAAA,SACX,CAAA,EAAG,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,CAAA,MAClC,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,CAAA,EAAG,CAAA;;;;cAmBlB,IAAA,GAAQ,GAAA,EAAK,MAAA,KAAS,MAAA,CAAO,MAAA,CAAO,gBAAA,SAAyB,UAAA,CAAW,UAAA;;;;;;;;cAqBxE,KAAA,GACX,GAAA,EAAK,MAAA,KACJ,KAAA,CAAM,KAAA,CAAM,SAAA,GAAY,aAAA,SAAsB,UAAA,CAAW,UAAA"}
@@ -4,7 +4,7 @@ import { KnownProviderEvent, applyEvent } from "./streamEvents.mjs";
4
4
  import { Context, Effect, Layer, Match, Option, Redacted, Result, Schema, Stream, pipe } from "effect";
5
5
  import { HttpClient, HttpClientRequest } from "effect/unstable/http";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
- import { LanguageModel } from "@effect-uai/core/LanguageModel";
7
+ import { LanguageModel, turnFromStream } from "@effect-uai/core/LanguageModel";
8
8
  import * as SSE from "@effect-uai/core/SSE";
9
9
  import { TurnEvent } from "@effect-uai/core/Turn";
10
10
  //#region src/Anthropic.ts
@@ -188,9 +188,11 @@ const toCanonical = (s) => s.pipe(Stream.mapAccum(() => emptyAccumulator, (acc,
188
188
  */
189
189
  const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => {
190
190
  const streamNative = (request) => buildNativeStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client));
191
+ const streamTurn = (request) => toCanonical(streamNative(request));
191
192
  return {
192
193
  streamNative,
193
- streamTurn: (request) => toCanonical(streamNative(request)),
194
+ streamTurn,
195
+ turn: turnFromStream(streamTurn),
194
196
  toCanonical
195
197
  };
196
198
  });
@@ -203,7 +205,10 @@ const make = (cfg) => Effect.map(HttpClient.HttpClient.asEffect(), (client) => {
203
205
  */
204
206
  const layer = (cfg) => {
205
207
  const typed = Layer.effect(Anthropic, make(cfg));
206
- const generic = Layer.effect(LanguageModel, Effect.map(make(cfg), (s) => ({ streamTurn: (request) => s.streamTurn(request) })));
208
+ const generic = Layer.effect(LanguageModel, Effect.map(make(cfg), (s) => ({
209
+ streamTurn: (request) => s.streamTurn(request),
210
+ turn: (request) => s.turn(request)
211
+ })));
207
212
  return Layer.merge(typed, generic);
208
213
  };
209
214
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"Anthropic.mjs","names":[],"sources":["../src/Anthropic.ts"],"sourcesContent":["import {\n Context,\n Effect,\n Layer,\n Match,\n Option,\n Redacted,\n Result,\n Schema,\n Stream,\n pipe,\n} from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport {\n type CommonRequest,\n LanguageModel,\n type LanguageModelService,\n} from \"@effect-uai/core/LanguageModel\"\nimport * as SSE from \"@effect-uai/core/SSE\"\nimport { TurnEvent } from \"@effect-uai/core/Turn\"\nimport {\n type Accumulator,\n type ThinkingConfig,\n accumulatorToTurn,\n buildRequestBody,\n emptyAccumulator,\n} from \"./codec.js\"\nimport type { AnthropicModel } from \"./models.js\"\nimport { KnownProviderEvent, ProviderEvent, applyEvent } from \"./streamEvents.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type AnthropicRequest = Omit<CommonRequest, \"model\"> & {\n /**\n * Narrows `CommonRequest.model` (`string`) to the typed `AnthropicModel`\n * literal union for autocomplete.\n */\n readonly model: AnthropicModel\n /**\n * Top-K nucleus sampling parameter. Anthropic-specific; not exposed on the\n * common surface.\n */\n readonly topK?: number\n /** Stop sequences that abort generation when matched. */\n readonly stopSequences?: ReadonlyArray<string>\n /**\n * Extended thinking configuration. `0` budget is equivalent to disabled.\n * Only the `claude-sonnet-4-x`, `claude-haiku-4-x`, and pre-Opus-4.7\n * model lines support extended thinking.\n */\n readonly thinking?: ThinkingConfig\n /**\n * `metadata.user_id` on the wire. End-user tracking identifier.\n */\n readonly user?: string\n}\n\nexport type AnthropicService = {\n /**\n * Stream the provider's native event vocabulary (post-SSE-decode).\n * Use this when you need full vendor fidelity (e.g. `signature_delta` for\n * encrypted reasoning state). For provider-portable code, use `streamTurn`.\n */\n readonly streamNative: (\n request: AnthropicRequest,\n ) => Stream.Stream<ProviderEvent, AiError.AiError>\n /**\n * Stream canonical `TurnEvent`s. Implemented as\n * `streamNative |> toCanonical`.\n */\n readonly streamTurn: (request: AnthropicRequest) => Stream.Stream<TurnEvent, AiError.AiError>\n /**\n * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.\n * Stateful (threads an `Accumulator` for tool-call lookup and\n * accumulator-to-Turn assembly).\n */\n readonly toCanonical: <E, R>(\n s: Stream.Stream<ProviderEvent, E, R>,\n ) => Stream.Stream<TurnEvent, E, R>\n}\n\n/**\n * Provider-typed service tag. Yield this when you want Anthropic-specific\n * options (`topK`, `stopSequences`, `thinking`); yield the generic\n * `LanguageModel` tag for provider-portable code. Both are registered by\n * `layer`.\n */\nexport class Anthropic extends Context.Service<Anthropic, AnthropicService>()(\n \"@betalyra/effect-uai/providers/anthropic/Anthropic\",\n) {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n /**\n * Default `max_tokens` for requests that don't override via\n * `request.maxOutputTokens`. Anthropic requires this field; we default to\n * 4096 if neither is set.\n */\n readonly defaultMaxTokens?: number\n}\n\nconst ANTHROPIC_VERSION = \"2023-06-01\"\nconst STRUCTURED_OUTPUTS_BETA = \"structured-outputs-2025-11-13\"\nconst FALLBACK_MAX_TOKENS = 4096\n\nconst outputConfig = (request: AnthropicRequest): Option.Option<Record<string, unknown>> =>\n pipe(\n Option.fromUndefinedOr(request.structured),\n Option.map((format) => ({\n format: {\n type: \"json_schema\",\n schema: format.schema[\"~standard\"].jsonSchema.input({ target: \"draft-2020-12\" }),\n },\n })),\n )\n\nconst resolvedMaxTokens = (cfg: Config, request: AnthropicRequest): number =>\n request.maxOutputTokens ?? cfg.defaultMaxTokens ?? FALLBACK_MAX_TOKENS\n\nconst toolDescriptors = (\n request: AnthropicRequest,\n): Option.Option<ReadonlyArray<Record<string, unknown>>> =>\n request.tools !== undefined && request.tools.length > 0\n ? Option.some(\n request.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n })),\n )\n : Option.none()\n\nconst toolChoiceWire = (request: AnthropicRequest): Option.Option<Record<string, unknown>> =>\n pipe(\n Option.fromUndefinedOr(request.toolChoice),\n Option.map((choice) =>\n choice === \"auto\"\n ? { type: \"auto\" }\n : choice === \"required\"\n ? { type: \"any\" }\n : choice === \"none\"\n ? { type: \"none\" }\n : { type: \"tool\", name: choice.name },\n ),\n )\n\n// ---------------------------------------------------------------------------\n// SSE event → ProviderEvent\n// ---------------------------------------------------------------------------\n\nconst decodeKnown = Schema.decodeUnknownEffect(KnownProviderEvent)\nconst parseJsonUnknown = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\nconst makeUnknown = (raw: unknown): ProviderEvent => ({ type: \"_unknown\", raw })\n\n/**\n * Parse one SSE event's `data` payload into a typed `ProviderEvent`. Never\n * fails: JSON-parse and schema-decode failures both produce a synthesized\n * `_unknown` event so consumers of `streamNative` never silently miss a\n * wire event we didn't model. When the payload IS valid JSON but doesn't\n * match the known-event schema, `_unknown.raw` carries the parsed value;\n * when JSON parsing fails outright, it carries the raw string.\n */\nconst sseEventToProviderEvent = (ev: SSE.Event): Effect.Effect<ProviderEvent> =>\n parseJsonUnknown(ev.data).pipe(\n Effect.flatMap((parsed) =>\n decodeKnown(parsed).pipe(Effect.orElseSucceed(() => makeUnknown(parsed))),\n ),\n Effect.orElseSucceed(() => makeUnknown(ev.data)),\n )\n\n// ---------------------------------------------------------------------------\n// Per-event derivation of TurnEvents. Drives off the new accumulator and the\n// raw event, since some deltas (`tool_call_args_delta`) need the call_id\n// which lives on the accumulator's per-index block.\n// ---------------------------------------------------------------------------\n\nconst deltasFromEvent = (next: Accumulator, event: ProviderEvent): ReadonlyArray<TurnEvent> =>\n Match.value(event).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n content_block_start: (e) =>\n e.content_block.type === \"tool_use\"\n ? [\n TurnEvent.ToolCallStart({\n call_id: e.content_block.id,\n name: e.content_block.name,\n }),\n ]\n : [],\n content_block_delta: (e) =>\n Match.value(e.delta).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n text_delta: (d) => [TurnEvent.TextDelta({ text: d.text })],\n thinking_delta: (d) => [TurnEvent.ReasoningDelta({ text: d.thinking, kind: \"trace\" })],\n input_json_delta: (d) => {\n const block = next.blocks[e.index]\n if (block === undefined) return []\n const callId = Option.getOrElse(block.id, () => \"\")\n return callId.length === 0\n ? []\n : [TurnEvent.ToolCallArgsDelta({ call_id: callId, delta: d.partial_json })]\n },\n // Encrypted reasoning state - flows through `streamNative` but has\n // no canonical representation.\n signature_delta: () => [],\n }),\n ),\n message_start: (e) =>\n e.message.usage === undefined ? [] : [TurnEvent.UsageUpdate({ usage: next.usage })],\n message_delta: (e) =>\n e.usage === undefined ? [] : [TurnEvent.UsageUpdate({ usage: next.usage })],\n message_stop: () => [TurnEvent.TurnComplete({ turn: accumulatorToTurn(next) })],\n content_block_stop: () => [],\n ping: () => [],\n error: () => [],\n _unknown: () => [],\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Service implementation\n// ---------------------------------------------------------------------------\n\nconst httpStatusError = (status: number, body: string): AiError.AiError => {\n const provider = \"anthropic\"\n const raw = body\n if (status === 429) return new AiError.RateLimited({ provider, raw })\n if (status === 408 || status === 504) return new AiError.Timeout({ provider, raw })\n if (status === 401) return new AiError.AuthFailed({ provider, subtype: \"auth\", raw })\n if (status === 403) return new AiError.AuthFailed({ provider, subtype: \"permission\", raw })\n if (status === 402) return new AiError.AuthFailed({ provider, subtype: \"billing\", raw })\n if (status === 413) return new AiError.ContextLengthExceeded({ provider, raw })\n if (status === 529) return new AiError.Unavailable({ provider, status, raw })\n if (status >= 500) return new AiError.Unavailable({ provider, status, raw })\n return new AiError.InvalidRequest({ provider, raw })\n}\n\nconst buildNativeStream = (cfg: Config) => {\n const baseUrl = cfg.baseUrl ?? \"https://api.anthropic.com\"\n const url = `${baseUrl}/v1/messages`\n return (\n request: AnthropicRequest,\n ): Stream.Stream<ProviderEvent, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const structured = outputConfig(request)\n const bodyResult = buildRequestBody({\n model: request.model,\n history: request.history,\n maxTokens: resolvedMaxTokens(cfg, request),\n temperature: Option.fromUndefinedOr(request.temperature),\n topP: Option.fromUndefinedOr(request.topP),\n topK: Option.fromUndefinedOr(request.topK),\n stopSequences: Option.fromUndefinedOr(request.stopSequences),\n thinking: Option.fromUndefinedOr(request.thinking),\n tools: toolDescriptors(request),\n toolChoice: toolChoiceWire(request),\n userId: Option.fromUndefinedOr(request.user),\n outputConfig: structured,\n })\n\n const body = yield* Result.match(bodyResult, {\n onFailure: (cause) =>\n Effect.fail(\n new AiError.InvalidRequest({\n provider: \"anthropic\",\n param: \"input.function_call.arguments\",\n raw: cause,\n }),\n ),\n onSuccess: (b) => Effect.succeed(b),\n })\n\n const client = yield* HttpClient.HttpClient\n const baseRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"x-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.setHeader(\"anthropic-version\", ANTHROPIC_VERSION),\n HttpClientRequest.bodyJsonUnsafe(body),\n HttpClientRequest.accept(\"text/event-stream\"),\n )\n const httpRequest = Option.isSome(structured)\n ? baseRequest.pipe(HttpClientRequest.setHeader(\"anthropic-beta\", STRUCTURED_OUTPUTS_BETA))\n : baseRequest\n const response = yield* client\n .execute(httpRequest)\n .pipe(\n Effect.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"anthropic\", raw: cause }),\n ),\n )\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n\n return response.stream.pipe(\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"anthropic\", raw: cause }),\n ),\n SSE.fromBytes,\n Stream.mapEffect(sseEventToProviderEvent),\n Stream.flatMap((event) =>\n event.type === \"error\"\n ? Stream.fail(new AiError.Unavailable({ provider: \"anthropic\", raw: event }))\n : Stream.succeed(event),\n ),\n )\n }),\n )\n}\n\n/**\n * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.\n * Threads a fresh `Accumulator` per stream so tool-call lookup and\n * `accumulatorToTurn` assembly work correctly across the run.\n */\nexport const toCanonical = <E, R>(\n s: Stream.Stream<ProviderEvent, E, R>,\n): Stream.Stream<TurnEvent, E, R> =>\n s.pipe(\n Stream.mapAccum(\n () => emptyAccumulator,\n (acc, event) => {\n const next = applyEvent(acc, event)\n const deltas = deltasFromEvent(next, event)\n return [next, deltas] as const\n },\n ),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\n/**\n * Build an `AnthropicService` value. For Layer-based setup, prefer `layer`.\n */\nexport const make = (cfg: Config): Effect.Effect<AnthropicService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => {\n const streamNative: AnthropicService[\"streamNative\"] = (request) =>\n buildNativeStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client))\n return {\n streamNative,\n streamTurn: (request) => toCanonical(streamNative(request)),\n toCanonical,\n }\n })\n\n/**\n * Layer that registers both the provider-specific `Anthropic` tag and the\n * generic `LanguageModel` tag, sharing one underlying implementation.\n *\n * The generic tag accepts `CommonRequest`; the typed tag accepts the full\n * `AnthropicRequest` surface.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<Anthropic | LanguageModel, never, HttpClient.HttpClient> => {\n const typed = Layer.effect(Anthropic, make(cfg))\n const generic = Layer.effect(\n LanguageModel,\n Effect.map(\n make(cfg),\n (s): LanguageModelService => ({\n streamTurn: (request) => s.streamTurn(request as AnthropicRequest),\n }),\n ),\n )\n return Layer.merge(typed, generic)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Anthropic.mjs","names":[],"sources":["../src/Anthropic.ts"],"sourcesContent":["import {\n Context,\n Effect,\n Layer,\n Match,\n Option,\n Redacted,\n Result,\n Schema,\n Stream,\n pipe,\n} from \"effect\"\nimport { HttpClient, HttpClientRequest } from \"effect/unstable/http\"\nimport * as AiError from \"@effect-uai/core/AiError\"\nimport {\n type CommonRequest,\n LanguageModel,\n type LanguageModelService,\n turnFromStream,\n} from \"@effect-uai/core/LanguageModel\"\nimport * as SSE from \"@effect-uai/core/SSE\"\nimport { type Turn, TurnEvent } from \"@effect-uai/core/Turn\"\nimport {\n type Accumulator,\n type ThinkingConfig,\n accumulatorToTurn,\n buildRequestBody,\n emptyAccumulator,\n} from \"./codec.js\"\nimport type { AnthropicModel } from \"./models.js\"\nimport { KnownProviderEvent, ProviderEvent, applyEvent } from \"./streamEvents.js\"\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type AnthropicRequest = Omit<CommonRequest, \"model\"> & {\n /**\n * Narrows `CommonRequest.model` (`string`) to the typed `AnthropicModel`\n * literal union for autocomplete.\n */\n readonly model: AnthropicModel\n /**\n * Top-K nucleus sampling parameter. Anthropic-specific; not exposed on the\n * common surface.\n */\n readonly topK?: number\n /** Stop sequences that abort generation when matched. */\n readonly stopSequences?: ReadonlyArray<string>\n /**\n * Extended thinking configuration. `0` budget is equivalent to disabled.\n * Only the `claude-sonnet-4-x`, `claude-haiku-4-x`, and pre-Opus-4.7\n * model lines support extended thinking.\n */\n readonly thinking?: ThinkingConfig\n /**\n * `metadata.user_id` on the wire. End-user tracking identifier.\n */\n readonly user?: string\n}\n\nexport type AnthropicService = {\n /**\n * Stream the provider's native event vocabulary (post-SSE-decode).\n * Use this when you need full vendor fidelity (e.g. `signature_delta` for\n * encrypted reasoning state). For provider-portable code, use `streamTurn`.\n */\n readonly streamNative: (\n request: AnthropicRequest,\n ) => Stream.Stream<ProviderEvent, AiError.AiError>\n /**\n * Stream canonical `TurnEvent`s. Implemented as\n * `streamNative |> toCanonical`.\n */\n readonly streamTurn: (request: AnthropicRequest) => Stream.Stream<TurnEvent, AiError.AiError>\n /**\n * Drain a single turn and return the assembled `Turn`. Derived from\n * `streamTurn` — Anthropic's non-streaming `/messages` endpoint\n * differs from the streamed one in subtle ways (no incremental\n * thinking deltas), so we route everything through streaming for\n * consistency.\n */\n readonly turn: (request: AnthropicRequest) => Effect.Effect<Turn, AiError.AiError>\n /**\n * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.\n * Stateful (threads an `Accumulator` for tool-call lookup and\n * accumulator-to-Turn assembly).\n */\n readonly toCanonical: <E, R>(\n s: Stream.Stream<ProviderEvent, E, R>,\n ) => Stream.Stream<TurnEvent, E, R>\n}\n\n/**\n * Provider-typed service tag. Yield this when you want Anthropic-specific\n * options (`topK`, `stopSequences`, `thinking`); yield the generic\n * `LanguageModel` tag for provider-portable code. Both are registered by\n * `layer`.\n */\nexport class Anthropic extends Context.Service<Anthropic, AnthropicService>()(\n \"@betalyra/effect-uai/providers/anthropic/Anthropic\",\n) {}\n\nexport type Config = {\n readonly apiKey: Redacted.Redacted\n readonly baseUrl?: string\n /**\n * Default `max_tokens` for requests that don't override via\n * `request.maxOutputTokens`. Anthropic requires this field; we default to\n * 4096 if neither is set.\n */\n readonly defaultMaxTokens?: number\n}\n\nconst ANTHROPIC_VERSION = \"2023-06-01\"\nconst STRUCTURED_OUTPUTS_BETA = \"structured-outputs-2025-11-13\"\nconst FALLBACK_MAX_TOKENS = 4096\n\nconst outputConfig = (request: AnthropicRequest): Option.Option<Record<string, unknown>> =>\n pipe(\n Option.fromUndefinedOr(request.structured),\n Option.map((format) => ({\n format: {\n type: \"json_schema\",\n schema: format.schema[\"~standard\"].jsonSchema.input({ target: \"draft-2020-12\" }),\n },\n })),\n )\n\nconst resolvedMaxTokens = (cfg: Config, request: AnthropicRequest): number =>\n request.maxOutputTokens ?? cfg.defaultMaxTokens ?? FALLBACK_MAX_TOKENS\n\nconst toolDescriptors = (\n request: AnthropicRequest,\n): Option.Option<ReadonlyArray<Record<string, unknown>>> =>\n request.tools !== undefined && request.tools.length > 0\n ? Option.some(\n request.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n })),\n )\n : Option.none()\n\nconst toolChoiceWire = (request: AnthropicRequest): Option.Option<Record<string, unknown>> =>\n pipe(\n Option.fromUndefinedOr(request.toolChoice),\n Option.map((choice) =>\n choice === \"auto\"\n ? { type: \"auto\" }\n : choice === \"required\"\n ? { type: \"any\" }\n : choice === \"none\"\n ? { type: \"none\" }\n : { type: \"tool\", name: choice.name },\n ),\n )\n\n// ---------------------------------------------------------------------------\n// SSE event → ProviderEvent\n// ---------------------------------------------------------------------------\n\nconst decodeKnown = Schema.decodeUnknownEffect(KnownProviderEvent)\nconst parseJsonUnknown = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Unknown))\n\nconst makeUnknown = (raw: unknown): ProviderEvent => ({ type: \"_unknown\", raw })\n\n/**\n * Parse one SSE event's `data` payload into a typed `ProviderEvent`. Never\n * fails: JSON-parse and schema-decode failures both produce a synthesized\n * `_unknown` event so consumers of `streamNative` never silently miss a\n * wire event we didn't model. When the payload IS valid JSON but doesn't\n * match the known-event schema, `_unknown.raw` carries the parsed value;\n * when JSON parsing fails outright, it carries the raw string.\n */\nconst sseEventToProviderEvent = (ev: SSE.Event): Effect.Effect<ProviderEvent> =>\n parseJsonUnknown(ev.data).pipe(\n Effect.flatMap((parsed) =>\n decodeKnown(parsed).pipe(Effect.orElseSucceed(() => makeUnknown(parsed))),\n ),\n Effect.orElseSucceed(() => makeUnknown(ev.data)),\n )\n\n// ---------------------------------------------------------------------------\n// Per-event derivation of TurnEvents. Drives off the new accumulator and the\n// raw event, since some deltas (`tool_call_args_delta`) need the call_id\n// which lives on the accumulator's per-index block.\n// ---------------------------------------------------------------------------\n\nconst deltasFromEvent = (next: Accumulator, event: ProviderEvent): ReadonlyArray<TurnEvent> =>\n Match.value(event).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n content_block_start: (e) =>\n e.content_block.type === \"tool_use\"\n ? [\n TurnEvent.ToolCallStart({\n call_id: e.content_block.id,\n name: e.content_block.name,\n }),\n ]\n : [],\n content_block_delta: (e) =>\n Match.value(e.delta).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n text_delta: (d) => [TurnEvent.TextDelta({ text: d.text })],\n thinking_delta: (d) => [TurnEvent.ReasoningDelta({ text: d.thinking, kind: \"trace\" })],\n input_json_delta: (d) => {\n const block = next.blocks[e.index]\n if (block === undefined) return []\n const callId = Option.getOrElse(block.id, () => \"\")\n return callId.length === 0\n ? []\n : [TurnEvent.ToolCallArgsDelta({ call_id: callId, delta: d.partial_json })]\n },\n // Encrypted reasoning state - flows through `streamNative` but has\n // no canonical representation.\n signature_delta: () => [],\n }),\n ),\n message_start: (e) =>\n e.message.usage === undefined ? [] : [TurnEvent.UsageUpdate({ usage: next.usage })],\n message_delta: (e) =>\n e.usage === undefined ? [] : [TurnEvent.UsageUpdate({ usage: next.usage })],\n message_stop: () => [TurnEvent.TurnComplete({ turn: accumulatorToTurn(next) })],\n content_block_stop: () => [],\n ping: () => [],\n error: () => [],\n _unknown: () => [],\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Service implementation\n// ---------------------------------------------------------------------------\n\nconst httpStatusError = (status: number, body: string): AiError.AiError => {\n const provider = \"anthropic\"\n const raw = body\n if (status === 429) return new AiError.RateLimited({ provider, raw })\n if (status === 408 || status === 504) return new AiError.Timeout({ provider, raw })\n if (status === 401) return new AiError.AuthFailed({ provider, subtype: \"auth\", raw })\n if (status === 403) return new AiError.AuthFailed({ provider, subtype: \"permission\", raw })\n if (status === 402) return new AiError.AuthFailed({ provider, subtype: \"billing\", raw })\n if (status === 413) return new AiError.ContextLengthExceeded({ provider, raw })\n if (status === 529) return new AiError.Unavailable({ provider, status, raw })\n if (status >= 500) return new AiError.Unavailable({ provider, status, raw })\n return new AiError.InvalidRequest({ provider, raw })\n}\n\nconst buildNativeStream = (cfg: Config) => {\n const baseUrl = cfg.baseUrl ?? \"https://api.anthropic.com\"\n const url = `${baseUrl}/v1/messages`\n return (\n request: AnthropicRequest,\n ): Stream.Stream<ProviderEvent, AiError.AiError, HttpClient.HttpClient> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const structured = outputConfig(request)\n const bodyResult = buildRequestBody({\n model: request.model,\n history: request.history,\n maxTokens: resolvedMaxTokens(cfg, request),\n temperature: Option.fromUndefinedOr(request.temperature),\n topP: Option.fromUndefinedOr(request.topP),\n topK: Option.fromUndefinedOr(request.topK),\n stopSequences: Option.fromUndefinedOr(request.stopSequences),\n thinking: Option.fromUndefinedOr(request.thinking),\n tools: toolDescriptors(request),\n toolChoice: toolChoiceWire(request),\n userId: Option.fromUndefinedOr(request.user),\n outputConfig: structured,\n })\n\n const body = yield* Result.match(bodyResult, {\n onFailure: (cause) =>\n Effect.fail(\n new AiError.InvalidRequest({\n provider: \"anthropic\",\n param: \"input.function_call.arguments\",\n raw: cause,\n }),\n ),\n onSuccess: (b) => Effect.succeed(b),\n })\n\n const client = yield* HttpClient.HttpClient\n const baseRequest = HttpClientRequest.post(url).pipe(\n HttpClientRequest.setHeader(\"x-api-key\", Redacted.value(cfg.apiKey)),\n HttpClientRequest.setHeader(\"anthropic-version\", ANTHROPIC_VERSION),\n HttpClientRequest.bodyJsonUnsafe(body),\n HttpClientRequest.accept(\"text/event-stream\"),\n )\n const httpRequest = Option.isSome(structured)\n ? baseRequest.pipe(HttpClientRequest.setHeader(\"anthropic-beta\", STRUCTURED_OUTPUTS_BETA))\n : baseRequest\n const response = yield* client\n .execute(httpRequest)\n .pipe(\n Effect.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"anthropic\", raw: cause }),\n ),\n )\n if (response.status >= 400) {\n const text = yield* response.text.pipe(Effect.orElseSucceed(() => \"\"))\n return Stream.fail(httpStatusError(response.status, text))\n }\n\n return response.stream.pipe(\n Stream.mapError(\n (cause): AiError.AiError =>\n new AiError.Unavailable({ provider: \"anthropic\", raw: cause }),\n ),\n SSE.fromBytes,\n Stream.mapEffect(sseEventToProviderEvent),\n Stream.flatMap((event) =>\n event.type === \"error\"\n ? Stream.fail(new AiError.Unavailable({ provider: \"anthropic\", raw: event }))\n : Stream.succeed(event),\n ),\n )\n }),\n )\n}\n\n/**\n * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.\n * Threads a fresh `Accumulator` per stream so tool-call lookup and\n * `accumulatorToTurn` assembly work correctly across the run.\n */\nexport const toCanonical = <E, R>(\n s: Stream.Stream<ProviderEvent, E, R>,\n): Stream.Stream<TurnEvent, E, R> =>\n s.pipe(\n Stream.mapAccum(\n () => emptyAccumulator,\n (acc, event) => {\n const next = applyEvent(acc, event)\n const deltas = deltasFromEvent(next, event)\n return [next, deltas] as const\n },\n ),\n )\n\n// ---------------------------------------------------------------------------\n// Constructors\n// ---------------------------------------------------------------------------\n\n/**\n * Build an `AnthropicService` value. For Layer-based setup, prefer `layer`.\n */\nexport const make = (cfg: Config): Effect.Effect<AnthropicService, never, HttpClient.HttpClient> =>\n Effect.map(HttpClient.HttpClient.asEffect(), (client) => {\n const streamNative: AnthropicService[\"streamNative\"] = (request) =>\n buildNativeStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client))\n const streamTurn: AnthropicService[\"streamTurn\"] = (request) =>\n toCanonical(streamNative(request))\n return {\n streamNative,\n streamTurn,\n turn: turnFromStream(streamTurn),\n toCanonical,\n }\n })\n\n/**\n * Layer that registers both the provider-specific `Anthropic` tag and the\n * generic `LanguageModel` tag, sharing one underlying implementation.\n *\n * The generic tag accepts `CommonRequest`; the typed tag accepts the full\n * `AnthropicRequest` surface.\n */\nexport const layer = (\n cfg: Config,\n): Layer.Layer<Anthropic | LanguageModel, never, HttpClient.HttpClient> => {\n const typed = Layer.effect(Anthropic, make(cfg))\n const generic = Layer.effect(\n LanguageModel,\n Effect.map(\n make(cfg),\n (s): LanguageModelService => ({\n streamTurn: (request) => s.streamTurn(request as AnthropicRequest),\n turn: (request) => s.turn(request as AnthropicRequest),\n }),\n ),\n )\n return Layer.merge(typed, generic)\n}\n"],"mappings":"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"}
package/dist/codec.d.mts CHANGED
@@ -101,7 +101,7 @@ type RequestBody = {
101
101
  };
102
102
  declare const buildRequestBody: (params: {
103
103
  readonly model: string;
104
- readonly history: ReadonlyArray<Items.Item>;
104
+ readonly history: ReadonlyArray<Items.HistoryItem>;
105
105
  readonly maxTokens: number;
106
106
  readonly temperature: Option.Option<number>;
107
107
  readonly topP: Option.Option<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":"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"}
1
+ {"version":3,"file":"codec.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"codec.mjs","names":["Arr"],"sources":["../src/codec.ts"],"sourcesContent":["import { Array as Arr, Encoding, Match, Option, Order, Result, Schema, pipe } from \"effect\"\nimport * as Items from \"@effect-uai/core/Items\"\nimport { JsonParseError } from \"@effect-uai/core/JSONL\"\nimport type { Turn } from \"@effect-uai/core/Turn\"\n\n// ---------------------------------------------------------------------------\n// Wire schemas - subset of Anthropic Messages API we consume.\n// Reference: https://platform.claude.com/docs/en/api/messages\n// ---------------------------------------------------------------------------\n\nconst WireTextBlock = Schema.Struct({\n type: Schema.Literal(\"text\"),\n text: Schema.String,\n})\n\nconst WireToolUseBlock = Schema.Struct({\n type: Schema.Literal(\"tool_use\"),\n id: Schema.String,\n name: Schema.String,\n input: Schema.Unknown,\n})\n\nconst WireThinkingBlock = Schema.Struct({\n type: Schema.Literal(\"thinking\"),\n thinking: Schema.String,\n signature: Schema.optional(Schema.String),\n})\n\nconst WireRedactedThinkingBlock = Schema.Struct({\n type: Schema.Literal(\"redacted_thinking\"),\n data: Schema.String,\n})\n\nexport const WireContentBlock = Schema.Union([\n WireTextBlock,\n WireToolUseBlock,\n WireThinkingBlock,\n WireRedactedThinkingBlock,\n])\nexport type WireContentBlock = typeof WireContentBlock.Type\n\nconst WireUsage = Schema.Struct({\n input_tokens: Schema.optional(Schema.Number),\n output_tokens: Schema.optional(Schema.Number),\n cache_creation_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),\n cache_read_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),\n})\nexport type WireUsage = typeof WireUsage.Type\n\n// ---------------------------------------------------------------------------\n// History → request body\n// ---------------------------------------------------------------------------\n\ntype RequestTextContent = {\n readonly type: \"text\"\n readonly text: string\n}\n\ntype RequestToolResultContent = {\n readonly type: \"tool_result\"\n readonly tool_use_id: string\n readonly content: string\n}\n\ntype RequestToolUseContent = {\n readonly type: \"tool_use\"\n readonly id: string\n readonly name: string\n readonly input: unknown\n}\n\ntype RequestThinkingContent = {\n readonly type: \"thinking\"\n readonly thinking: string\n readonly signature?: string\n}\n\ntype RequestRedactedThinkingContent = {\n readonly type: \"redacted_thinking\"\n readonly data: string\n}\n\ntype RequestImageContent = {\n readonly type: \"image\"\n readonly source:\n | { readonly type: \"url\"; readonly url: string }\n | { readonly type: \"base64\"; readonly media_type: string; readonly data: string }\n}\n\ntype RequestUserContentBlock = RequestTextContent | RequestToolResultContent | RequestImageContent\n\ntype RequestAssistantContentBlock =\n | RequestTextContent\n | RequestToolUseContent\n | RequestThinkingContent\n | RequestRedactedThinkingContent\n\ntype RequestUserMessage = {\n readonly role: \"user\"\n readonly content: ReadonlyArray<RequestUserContentBlock>\n}\n\ntype RequestAssistantMessage = {\n readonly role: \"assistant\"\n readonly content: ReadonlyArray<RequestAssistantContentBlock>\n}\n\ntype RequestMessage = RequestUserMessage | RequestAssistantMessage\n\nconst blockText = Match.type<Items.ContentBlock>().pipe(\n Match.discriminatorsExhaustive(\"type\")({\n input_text: (b) => b.text,\n input_image: () => \"\",\n output_text: (b) => b.text,\n refusal: (b) => b.text,\n }),\n)\n\nconst messageText = (message: Items.Message): string => message.content.map(blockText).join(\"\")\n\nconst imageSourceToWire = Match.type<Items.InputImage[\"source\"]>().pipe(\n Match.tag(\"url\", (s): RequestImageContent[\"source\"] => ({ type: \"url\", url: s.url })),\n Match.tag(\"base64\", (s): RequestImageContent[\"source\"] => ({\n type: \"base64\",\n media_type: s.mimeType,\n data: s.base64,\n })),\n Match.tag(\"bytes\", (s): RequestImageContent[\"source\"] => ({\n type: \"base64\",\n media_type: s.mimeType,\n data: Encoding.encodeBase64(s.bytes),\n })),\n Match.exhaustive,\n)\n\nconst userContentBlock = (\n block: Items.ContentBlock,\n): Result.Result<RequestUserContentBlock, void> =>\n Match.value(block).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n input_text: (b) =>\n b.text.length === 0\n ? Result.failVoid\n : Result.succeed({ type: \"text\" as const, text: b.text }),\n input_image: (b) =>\n Result.succeed({ type: \"image\" as const, source: imageSourceToWire(b.source) }),\n // Assistant content; never appears on a user message in practice. Skip.\n output_text: () => Result.failVoid,\n refusal: () => Result.failVoid,\n }),\n )\n\nconst parseJson = (s: string): Result.Result<unknown, JsonParseError> =>\n Result.try({\n try: () => JSON.parse(s) as unknown,\n catch: (cause) => new JsonParseError({ line: s, cause }),\n })\n\ntype RoleBucket = \"user\" | \"assistant\" | \"system\"\n\nconst roleBucket = (item: Items.Item): RoleBucket =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m) => m.role,\n function_call: () => \"assistant\" as const,\n function_call_output: () => \"user\" as const,\n reasoning: () => \"assistant\" as const,\n }),\n )\n\nconst itemToUserBlocks = (item: Items.Item): ReadonlyArray<RequestUserContentBlock> =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m): ReadonlyArray<RequestUserContentBlock> =>\n m.role === \"user\" ? pipe(m.content, Arr.filterMap(userContentBlock)) : [],\n function_call: (): ReadonlyArray<RequestUserContentBlock> => [],\n function_call_output: (o): ReadonlyArray<RequestUserContentBlock> => [\n { type: \"tool_result\", tool_use_id: o.call_id, content: o.output },\n ],\n reasoning: (): ReadonlyArray<RequestUserContentBlock> => [],\n }),\n )\n\nconst itemToAssistantBlocks = (\n item: Items.Item,\n): Result.Result<ReadonlyArray<RequestAssistantContentBlock>, JsonParseError> =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m): Result.Result<ReadonlyArray<RequestAssistantContentBlock>, JsonParseError> => {\n const text = messageText(m)\n return Result.succeed(\n m.role === \"assistant\" && text.length > 0 ? [{ type: \"text\", text }] : [],\n )\n },\n function_call: (f) =>\n pipe(\n parseJson(f.arguments),\n Result.map(\n (input): ReadonlyArray<RequestAssistantContentBlock> => [\n { type: \"tool_use\", id: f.call_id, name: f.name, input },\n ],\n ),\n ),\n function_call_output: (): Result.Result<\n ReadonlyArray<RequestAssistantContentBlock>,\n JsonParseError\n > => Result.succeed([]),\n reasoning: (r) => {\n const blocks: ReadonlyArray<RequestAssistantContentBlock> =\n r.summary !== undefined\n ? [\n {\n type: \"thinking\",\n thinking: r.summary,\n ...(r.signature !== undefined && { signature: r.signature }),\n },\n ]\n : r.signature !== undefined\n ? [{ type: \"redacted_thinking\", data: r.signature }]\n : []\n return Result.succeed(blocks)\n },\n }),\n )\n\ntype GroupAcc = {\n readonly messages: ReadonlyArray<RequestMessage>\n readonly currentRole: Option.Option<\"user\" | \"assistant\">\n readonly userBuf: ReadonlyArray<RequestUserContentBlock>\n readonly assistantBuf: ReadonlyArray<RequestAssistantContentBlock>\n}\n\nconst flushAcc = (acc: GroupAcc): ReadonlyArray<RequestMessage> =>\n Option.match(acc.currentRole, {\n onNone: () => acc.messages,\n onSome: (role) =>\n role === \"user\" && acc.userBuf.length > 0\n ? [...acc.messages, { role: \"user\", content: acc.userBuf }]\n : role === \"assistant\" && acc.assistantBuf.length > 0\n ? [...acc.messages, { role: \"assistant\", content: acc.assistantBuf }]\n : acc.messages,\n })\n\nconst appendUser = (acc: GroupAcc, blocks: ReadonlyArray<RequestUserContentBlock>): GroupAcc =>\n blocks.length === 0\n ? acc\n : Option.isSome(acc.currentRole) && acc.currentRole.value === \"user\"\n ? { ...acc, userBuf: [...acc.userBuf, ...blocks] }\n : {\n messages: flushAcc(acc),\n currentRole: Option.some(\"user\"),\n userBuf: blocks,\n assistantBuf: [],\n }\n\nconst appendAssistant = (\n acc: GroupAcc,\n blocks: ReadonlyArray<RequestAssistantContentBlock>,\n): GroupAcc =>\n blocks.length === 0\n ? acc\n : Option.isSome(acc.currentRole) && acc.currentRole.value === \"assistant\"\n ? { ...acc, assistantBuf: [...acc.assistantBuf, ...blocks] }\n : {\n messages: flushAcc(acc),\n currentRole: Option.some(\"assistant\"),\n userBuf: [],\n assistantBuf: blocks,\n }\n\nconst groupStep = (acc: GroupAcc, item: Items.Item): Result.Result<GroupAcc, JsonParseError> => {\n const bucket = roleBucket(item)\n if (bucket === \"system\") return Result.succeed(acc)\n if (bucket === \"user\") {\n return Result.succeed(appendUser(acc, itemToUserBlocks(item)))\n }\n return pipe(\n itemToAssistantBlocks(item),\n Result.map((blocks) => appendAssistant(acc, blocks)),\n )\n}\n\n/**\n * Group consecutive same-role items into Anthropic-shaped messages.\n * Anthropic requires strict user/assistant alternation; consecutive items\n * from the same role are folded into one message's `content`. Fails if any\n * `function_call.arguments` is not valid JSON, since Anthropic's wire shape\n * requires an object input.\n */\nconst groupedMessages = (\n history: ReadonlyArray<Items.Item>,\n): Result.Result<ReadonlyArray<RequestMessage>, JsonParseError> => {\n const initial: Result.Result<GroupAcc, JsonParseError> = Result.succeed({\n messages: [],\n currentRole: Option.none(),\n userBuf: [],\n assistantBuf: [],\n })\n return pipe(\n Arr.reduce(history, initial, (acc, item) => Result.flatMap(acc, (a) => groupStep(a, item))),\n Result.map(flushAcc),\n )\n}\n\nconst isSystemMessage = (item: Items.Item): item is Items.Message =>\n item.type === \"message\" && item.role === \"system\"\n\nconst systemFromHistory = (history: ReadonlyArray<Items.Item>): Option.Option<string> => {\n const texts = pipe(\n history,\n Arr.filterMap((item) =>\n isSystemMessage(item) ? Result.succeed(messageText(item)) : Result.failVoid,\n ),\n Arr.filter((s) => s.length > 0),\n )\n return texts.length === 0 ? Option.none() : Option.some(texts.join(\"\\n\"))\n}\n\nexport type ThinkingConfig = {\n readonly type: \"enabled\"\n readonly budget_tokens: number\n}\n\nexport type RequestBody = {\n readonly model: string\n readonly messages: ReadonlyArray<RequestMessage>\n readonly max_tokens: number\n readonly system?: string\n readonly temperature?: number\n readonly top_p?: number\n readonly top_k?: number\n readonly stop_sequences?: ReadonlyArray<string>\n readonly thinking?: ThinkingConfig\n readonly tools?: ReadonlyArray<Record<string, unknown>>\n readonly tool_choice?: Record<string, unknown>\n readonly metadata?: { readonly user_id: string }\n readonly output_config?: Record<string, unknown>\n readonly stream: true\n}\n\nexport const buildRequestBody = (params: {\n readonly model: string\n readonly history: ReadonlyArray<Items.Item>\n readonly maxTokens: number\n readonly temperature: Option.Option<number>\n readonly topP: Option.Option<number>\n readonly topK: Option.Option<number>\n readonly stopSequences: Option.Option<ReadonlyArray<string>>\n readonly thinking: Option.Option<ThinkingConfig>\n readonly tools: Option.Option<ReadonlyArray<Record<string, unknown>>>\n readonly toolChoice: Option.Option<Record<string, unknown>>\n readonly userId: Option.Option<string>\n readonly outputConfig: Option.Option<Record<string, unknown>>\n}): Result.Result<RequestBody, JsonParseError> =>\n pipe(\n groupedMessages(params.history),\n Result.map(\n (messages): RequestBody => ({\n model: params.model,\n messages,\n max_tokens: params.maxTokens,\n ...Option.match(systemFromHistory(params.history), {\n onNone: () => ({}),\n onSome: (system) => ({ system }),\n }),\n ...Option.match(params.temperature, {\n onNone: () => ({}),\n onSome: (temperature) => ({ temperature }),\n }),\n ...Option.match(params.topP, {\n onNone: () => ({}),\n onSome: (top_p) => ({ top_p }),\n }),\n ...Option.match(params.topK, {\n onNone: () => ({}),\n onSome: (top_k) => ({ top_k }),\n }),\n ...Option.match(params.stopSequences, {\n onNone: () => ({}),\n onSome: (stop_sequences) => ({ stop_sequences }),\n }),\n ...Option.match(params.thinking, {\n onNone: () => ({}),\n onSome: (thinking) => ({ thinking }),\n }),\n ...Option.match(params.tools, {\n onNone: () => ({}),\n onSome: (tools) => ({ tools }),\n }),\n ...Option.match(params.toolChoice, {\n onNone: () => ({}),\n onSome: (tool_choice) => ({ tool_choice }),\n }),\n ...Option.match(params.userId, {\n onNone: () => ({}),\n onSome: (user_id) => ({ metadata: { user_id } }),\n }),\n ...Option.match(params.outputConfig, {\n onNone: () => ({}),\n onSome: (output_config) => ({ output_config }),\n }),\n stream: true,\n }),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// Stream-level state - assemble content blocks index-by-index, then emit\n// our `Items.Item[]` when `message_stop` lands.\n// ---------------------------------------------------------------------------\n\ntype BlockBuffer = {\n readonly type: WireContentBlock[\"type\"]\n readonly text: string\n readonly inputJson: string\n readonly thinking: string\n readonly signature: string\n readonly id: Option.Option<string>\n readonly name: Option.Option<string>\n readonly redactedData: Option.Option<string>\n}\n\nconst emptyBlock = (type: WireContentBlock[\"type\"]): BlockBuffer => ({\n type,\n text: \"\",\n inputJson: \"\",\n thinking: \"\",\n signature: \"\",\n id: Option.none(),\n name: Option.none(),\n redactedData: Option.none(),\n})\n\nexport type Accumulator = {\n readonly blocks: Readonly<Record<number, BlockBuffer>>\n readonly stopReason: Option.Option<string>\n readonly usage: Items.Usage\n}\n\nexport const emptyAccumulator: Accumulator = {\n blocks: {},\n stopReason: Option.none(),\n usage: {},\n}\n\nconst replaceBlock = (acc: Accumulator, index: number, block: BlockBuffer): Accumulator => ({\n ...acc,\n blocks: { ...acc.blocks, [index]: block },\n})\n\nconst updateBlock = (\n acc: Accumulator,\n index: number,\n patch: (block: BlockBuffer) => BlockBuffer,\n): Accumulator => replaceBlock(acc, index, patch(acc.blocks[index] ?? emptyBlock(\"text\")))\n\nexport const startBlock = (acc: Accumulator, index: number, block: WireContentBlock): Accumulator =>\n Match.value(block).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n text: () => replaceBlock(acc, index, emptyBlock(\"text\")),\n tool_use: (b) =>\n replaceBlock(acc, index, {\n ...emptyBlock(\"tool_use\"),\n id: Option.some(b.id),\n name: Option.some(b.name),\n inputJson: typeof b.input === \"string\" ? b.input : \"\",\n }),\n thinking: () => replaceBlock(acc, index, emptyBlock(\"thinking\")),\n redacted_thinking: (b) =>\n replaceBlock(acc, index, {\n ...emptyBlock(\"redacted_thinking\"),\n redactedData: Option.some(b.data),\n }),\n }),\n )\n\nexport const appendTextDelta = (acc: Accumulator, index: number, text: string): Accumulator =>\n updateBlock(acc, index, (b) => ({ ...b, text: b.text + text }))\n\nexport const appendInputJsonDelta = (\n acc: Accumulator,\n index: number,\n partial: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, inputJson: b.inputJson + partial }))\n\nexport const appendThinkingDelta = (\n acc: Accumulator,\n index: number,\n thinking: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, thinking: b.thinking + thinking }))\n\nexport const appendSignatureDelta = (\n acc: Accumulator,\n index: number,\n signature: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, signature: b.signature + signature }))\n\nexport const setStopReason = (acc: Accumulator, reason: string): Accumulator => ({\n ...acc,\n stopReason: Option.some(reason),\n})\n\nconst cachedFromWire = (wire: WireUsage): Option.Option<number> =>\n Option.fromNullishOr(wire.cache_read_input_tokens)\n\nexport const mergeUsage = (acc: Accumulator, wire: WireUsage): Accumulator => {\n const cached = cachedFromWire(wire)\n const usage: Items.Usage = {\n ...acc.usage,\n ...(wire.input_tokens !== undefined && { input_tokens: wire.input_tokens }),\n ...(wire.output_tokens !== undefined && { output_tokens: wire.output_tokens }),\n ...(wire.input_tokens !== undefined &&\n wire.output_tokens !== undefined && {\n total_tokens: wire.input_tokens + wire.output_tokens,\n }),\n ...Option.match(cached, {\n onNone: () => ({}),\n onSome: (cached_tokens) => ({ input_tokens_details: { cached_tokens } }),\n }),\n }\n return { ...acc, usage }\n}\n\nconst stopReasonFromAnthropic = (reason: Option.Option<string>): Turn[\"stop_reason\"] =>\n Option.match(reason, {\n onNone: () => \"stop\" as const,\n onSome: (r) =>\n Match.value(r).pipe(\n Match.when(\"tool_use\", () => \"tool_calls\" as const),\n Match.when(\"max_tokens\", () => \"max_tokens\" as const),\n Match.orElse(() => \"stop\" as const),\n ),\n })\n\nconst blocksByIndex = (acc: Accumulator): ReadonlyArray<BlockBuffer> =>\n pipe(\n Object.keys(acc.blocks),\n Arr.map((k) => Number(k)),\n Arr.sort(Order.Number),\n Arr.map((i) => acc.blocks[i]!),\n )\n\nconst blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>\n Match.value(block.type).pipe(\n Match.when(\n \"text\",\n (): ReadonlyArray<Items.Item> =>\n block.text.length === 0\n ? []\n : [\n {\n type: \"message\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: block.text }],\n },\n ],\n ),\n Match.when(\n \"tool_use\",\n (): ReadonlyArray<Items.Item> => [\n {\n type: \"function_call\",\n call_id: Option.getOrElse(block.id, () => \"\"),\n name: Option.getOrElse(block.name, () => \"\"),\n arguments: block.inputJson,\n },\n ],\n ),\n Match.when(\n \"thinking\",\n (): ReadonlyArray<Items.Item> => [\n {\n type: \"reasoning\",\n ...(block.thinking.length > 0 && { summary: block.thinking }),\n ...(block.signature.length > 0 && { signature: block.signature }),\n },\n ],\n ),\n Match.when(\n \"redacted_thinking\",\n (): ReadonlyArray<Items.Item> => [\n {\n type: \"reasoning\",\n ...Option.match(block.redactedData, {\n onNone: () => ({}),\n onSome: (signature) => ({ signature }),\n }),\n },\n ],\n ),\n Match.exhaustive,\n )\n\ntype MergeAcc = {\n readonly out: ReadonlyArray<Items.Item>\n}\n\nconst mergeStep = (acc: MergeAcc, item: Items.Item): MergeAcc => {\n const last = Arr.last(acc.out)\n if (\n Option.isSome(last) &&\n last.value.type === \"message\" &&\n last.value.role === \"assistant\" &&\n item.type === \"message\" &&\n item.role === \"assistant\"\n ) {\n const merged: Items.Message = {\n ...last.value,\n content: [...last.value.content, ...item.content],\n }\n return { out: [...acc.out.slice(0, -1), merged] }\n }\n return { out: [...acc.out, item] }\n}\n\nconst mergeAdjacentAssistantText = (items: ReadonlyArray<Items.Item>): ReadonlyArray<Items.Item> =>\n Arr.reduce(items, { out: [] } as MergeAcc, mergeStep).out\n\nexport const accumulatorToTurn = (acc: Accumulator): Turn => ({\n items: pipe(blocksByIndex(acc), Arr.flatMap(blockToItems), mergeAdjacentAssistantText),\n usage: acc.usage,\n stop_reason: stopReasonFromAnthropic(acc.stopReason),\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"codec.mjs","names":["Arr"],"sources":["../src/codec.ts"],"sourcesContent":["import { Array as Arr, Encoding, Match, Option, Order, Result, Schema, pipe } from \"effect\"\nimport * as Items from \"@effect-uai/core/Items\"\nimport { JsonParseError } from \"@effect-uai/core/JSONL\"\nimport type { Turn } from \"@effect-uai/core/Turn\"\n\n// ---------------------------------------------------------------------------\n// Wire schemas - subset of Anthropic Messages API we consume.\n// Reference: https://platform.claude.com/docs/en/api/messages\n// ---------------------------------------------------------------------------\n\nconst WireTextBlock = Schema.Struct({\n type: Schema.Literal(\"text\"),\n text: Schema.String,\n})\n\nconst WireToolUseBlock = Schema.Struct({\n type: Schema.Literal(\"tool_use\"),\n id: Schema.String,\n name: Schema.String,\n input: Schema.Unknown,\n})\n\nconst WireThinkingBlock = Schema.Struct({\n type: Schema.Literal(\"thinking\"),\n thinking: Schema.String,\n signature: Schema.optional(Schema.String),\n})\n\nconst WireRedactedThinkingBlock = Schema.Struct({\n type: Schema.Literal(\"redacted_thinking\"),\n data: Schema.String,\n})\n\nexport const WireContentBlock = Schema.Union([\n WireTextBlock,\n WireToolUseBlock,\n WireThinkingBlock,\n WireRedactedThinkingBlock,\n])\nexport type WireContentBlock = typeof WireContentBlock.Type\n\nconst WireUsage = Schema.Struct({\n input_tokens: Schema.optional(Schema.Number),\n output_tokens: Schema.optional(Schema.Number),\n cache_creation_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),\n cache_read_input_tokens: Schema.optional(Schema.NullOr(Schema.Number)),\n})\nexport type WireUsage = typeof WireUsage.Type\n\n// ---------------------------------------------------------------------------\n// History → request body\n// ---------------------------------------------------------------------------\n\ntype RequestTextContent = {\n readonly type: \"text\"\n readonly text: string\n}\n\ntype RequestToolResultContent = {\n readonly type: \"tool_result\"\n readonly tool_use_id: string\n readonly content: string\n}\n\ntype RequestToolUseContent = {\n readonly type: \"tool_use\"\n readonly id: string\n readonly name: string\n readonly input: unknown\n}\n\ntype RequestThinkingContent = {\n readonly type: \"thinking\"\n readonly thinking: string\n readonly signature?: string\n}\n\ntype RequestRedactedThinkingContent = {\n readonly type: \"redacted_thinking\"\n readonly data: string\n}\n\ntype RequestImageContent = {\n readonly type: \"image\"\n readonly source:\n | { readonly type: \"url\"; readonly url: string }\n | { readonly type: \"base64\"; readonly media_type: string; readonly data: string }\n}\n\ntype RequestUserContentBlock = RequestTextContent | RequestToolResultContent | RequestImageContent\n\ntype RequestAssistantContentBlock =\n | RequestTextContent\n | RequestToolUseContent\n | RequestThinkingContent\n | RequestRedactedThinkingContent\n\ntype RequestUserMessage = {\n readonly role: \"user\"\n readonly content: ReadonlyArray<RequestUserContentBlock>\n}\n\ntype RequestAssistantMessage = {\n readonly role: \"assistant\"\n readonly content: ReadonlyArray<RequestAssistantContentBlock>\n}\n\ntype RequestMessage = RequestUserMessage | RequestAssistantMessage\n\nconst blockText = Match.type<Items.ContentBlock>().pipe(\n Match.discriminatorsExhaustive(\"type\")({\n input_text: (b) => b.text,\n input_image: () => \"\",\n output_text: (b) => b.text,\n refusal: (b) => b.text,\n }),\n)\n\nconst messageText = (message: Items.Message): string => message.content.map(blockText).join(\"\")\n\nconst imageSourceToWire = Match.type<Items.InputImage[\"source\"]>().pipe(\n Match.tag(\"url\", (s): RequestImageContent[\"source\"] => ({ type: \"url\", url: s.url })),\n Match.tag(\"base64\", (s): RequestImageContent[\"source\"] => ({\n type: \"base64\",\n media_type: s.mimeType,\n data: s.base64,\n })),\n Match.tag(\"bytes\", (s): RequestImageContent[\"source\"] => ({\n type: \"base64\",\n media_type: s.mimeType,\n data: Encoding.encodeBase64(s.bytes),\n })),\n Match.exhaustive,\n)\n\nconst userContentBlock = (\n block: Items.ContentBlock,\n): Result.Result<RequestUserContentBlock, void> =>\n Match.value(block).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n input_text: (b) =>\n b.text.length === 0\n ? Result.failVoid\n : Result.succeed({ type: \"text\" as const, text: b.text }),\n input_image: (b) =>\n Result.succeed({ type: \"image\" as const, source: imageSourceToWire(b.source) }),\n // Assistant content; never appears on a user message in practice. Skip.\n output_text: () => Result.failVoid,\n refusal: () => Result.failVoid,\n }),\n )\n\nconst parseJson = (s: string): Result.Result<unknown, JsonParseError> =>\n Result.try({\n try: () => JSON.parse(s) as unknown,\n catch: (cause) => new JsonParseError({ line: s, cause }),\n })\n\ntype RoleBucket = \"user\" | \"assistant\" | \"system\"\n\nconst roleBucket = (item: Items.HistoryItem): RoleBucket =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m) => m.role,\n function_call: () => \"assistant\" as const,\n function_call_output: () => \"user\" as const,\n reasoning: () => \"assistant\" as const,\n }),\n )\n\nconst itemToUserBlocks = (item: Items.HistoryItem): ReadonlyArray<RequestUserContentBlock> =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m): ReadonlyArray<RequestUserContentBlock> =>\n m.role === \"user\" ? pipe(m.content, Arr.filterMap(userContentBlock)) : [],\n function_call: (): ReadonlyArray<RequestUserContentBlock> => [],\n function_call_output: (o): ReadonlyArray<RequestUserContentBlock> => [\n { type: \"tool_result\", tool_use_id: o.call_id, content: o.output },\n ],\n reasoning: (): ReadonlyArray<RequestUserContentBlock> => [],\n }),\n )\n\nconst itemToAssistantBlocks = (\n item: Items.HistoryItem,\n): Result.Result<ReadonlyArray<RequestAssistantContentBlock>, JsonParseError> =>\n Match.value(item).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n message: (m): Result.Result<ReadonlyArray<RequestAssistantContentBlock>, JsonParseError> => {\n const text = messageText(m)\n return Result.succeed(\n m.role === \"assistant\" && text.length > 0 ? [{ type: \"text\", text }] : [],\n )\n },\n function_call: (f) =>\n pipe(\n parseJson(f.arguments),\n Result.map(\n (input): ReadonlyArray<RequestAssistantContentBlock> => [\n { type: \"tool_use\", id: f.call_id, name: f.name, input },\n ],\n ),\n ),\n function_call_output: (): Result.Result<\n ReadonlyArray<RequestAssistantContentBlock>,\n JsonParseError\n > => Result.succeed([]),\n reasoning: (r) => {\n const blocks: ReadonlyArray<RequestAssistantContentBlock> =\n r.summary !== undefined\n ? [\n {\n type: \"thinking\",\n thinking: r.summary,\n ...(r.signature !== undefined && { signature: r.signature }),\n },\n ]\n : r.signature !== undefined\n ? [{ type: \"redacted_thinking\", data: r.signature }]\n : []\n return Result.succeed(blocks)\n },\n }),\n )\n\ntype GroupAcc = {\n readonly messages: ReadonlyArray<RequestMessage>\n readonly currentRole: Option.Option<\"user\" | \"assistant\">\n readonly userBuf: ReadonlyArray<RequestUserContentBlock>\n readonly assistantBuf: ReadonlyArray<RequestAssistantContentBlock>\n}\n\nconst flushAcc = (acc: GroupAcc): ReadonlyArray<RequestMessage> =>\n Option.match(acc.currentRole, {\n onNone: () => acc.messages,\n onSome: (role) =>\n role === \"user\" && acc.userBuf.length > 0\n ? [...acc.messages, { role: \"user\", content: acc.userBuf }]\n : role === \"assistant\" && acc.assistantBuf.length > 0\n ? [...acc.messages, { role: \"assistant\", content: acc.assistantBuf }]\n : acc.messages,\n })\n\nconst appendUser = (acc: GroupAcc, blocks: ReadonlyArray<RequestUserContentBlock>): GroupAcc =>\n blocks.length === 0\n ? acc\n : Option.isSome(acc.currentRole) && acc.currentRole.value === \"user\"\n ? { ...acc, userBuf: [...acc.userBuf, ...blocks] }\n : {\n messages: flushAcc(acc),\n currentRole: Option.some(\"user\"),\n userBuf: blocks,\n assistantBuf: [],\n }\n\nconst appendAssistant = (\n acc: GroupAcc,\n blocks: ReadonlyArray<RequestAssistantContentBlock>,\n): GroupAcc =>\n blocks.length === 0\n ? acc\n : Option.isSome(acc.currentRole) && acc.currentRole.value === \"assistant\"\n ? { ...acc, assistantBuf: [...acc.assistantBuf, ...blocks] }\n : {\n messages: flushAcc(acc),\n currentRole: Option.some(\"assistant\"),\n userBuf: [],\n assistantBuf: blocks,\n }\n\nconst groupStep = (\n acc: GroupAcc,\n item: Items.HistoryItem,\n): Result.Result<GroupAcc, JsonParseError> => {\n const bucket = roleBucket(item)\n if (bucket === \"system\") return Result.succeed(acc)\n if (bucket === \"user\") {\n return Result.succeed(appendUser(acc, itemToUserBlocks(item)))\n }\n return pipe(\n itemToAssistantBlocks(item),\n Result.map((blocks) => appendAssistant(acc, blocks)),\n )\n}\n\n/**\n * Group consecutive same-role items into Anthropic-shaped messages.\n * Anthropic requires strict user/assistant alternation; consecutive items\n * from the same role are folded into one message's `content`. Fails if any\n * `function_call.arguments` is not valid JSON, since Anthropic's wire shape\n * requires an object input.\n */\nconst groupedMessages = (\n history: ReadonlyArray<Items.HistoryItem>,\n): Result.Result<ReadonlyArray<RequestMessage>, JsonParseError> => {\n const initial: Result.Result<GroupAcc, JsonParseError> = Result.succeed({\n messages: [],\n currentRole: Option.none(),\n userBuf: [],\n assistantBuf: [],\n })\n return pipe(\n Arr.reduce(history, initial, (acc, item) => Result.flatMap(acc, (a) => groupStep(a, item))),\n Result.map(flushAcc),\n )\n}\n\nconst isSystemMessage = (item: Items.HistoryItem): item is Items.Message =>\n item.type === \"message\" && item.role === \"system\"\n\nconst systemFromHistory = (history: ReadonlyArray<Items.HistoryItem>): Option.Option<string> => {\n const texts = pipe(\n history,\n Arr.filterMap((item) =>\n isSystemMessage(item) ? Result.succeed(messageText(item)) : Result.failVoid,\n ),\n Arr.filter((s) => s.length > 0),\n )\n return texts.length === 0 ? Option.none() : Option.some(texts.join(\"\\n\"))\n}\n\nexport type ThinkingConfig = {\n readonly type: \"enabled\"\n readonly budget_tokens: number\n}\n\nexport type RequestBody = {\n readonly model: string\n readonly messages: ReadonlyArray<RequestMessage>\n readonly max_tokens: number\n readonly system?: string\n readonly temperature?: number\n readonly top_p?: number\n readonly top_k?: number\n readonly stop_sequences?: ReadonlyArray<string>\n readonly thinking?: ThinkingConfig\n readonly tools?: ReadonlyArray<Record<string, unknown>>\n readonly tool_choice?: Record<string, unknown>\n readonly metadata?: { readonly user_id: string }\n readonly output_config?: Record<string, unknown>\n readonly stream: true\n}\n\nexport const buildRequestBody = (params: {\n readonly model: string\n readonly history: ReadonlyArray<Items.HistoryItem>\n readonly maxTokens: number\n readonly temperature: Option.Option<number>\n readonly topP: Option.Option<number>\n readonly topK: Option.Option<number>\n readonly stopSequences: Option.Option<ReadonlyArray<string>>\n readonly thinking: Option.Option<ThinkingConfig>\n readonly tools: Option.Option<ReadonlyArray<Record<string, unknown>>>\n readonly toolChoice: Option.Option<Record<string, unknown>>\n readonly userId: Option.Option<string>\n readonly outputConfig: Option.Option<Record<string, unknown>>\n}): Result.Result<RequestBody, JsonParseError> =>\n pipe(\n groupedMessages(params.history),\n Result.map(\n (messages): RequestBody => ({\n model: params.model,\n messages,\n max_tokens: params.maxTokens,\n ...Option.match(systemFromHistory(params.history), {\n onNone: () => ({}),\n onSome: (system) => ({ system }),\n }),\n ...Option.match(params.temperature, {\n onNone: () => ({}),\n onSome: (temperature) => ({ temperature }),\n }),\n ...Option.match(params.topP, {\n onNone: () => ({}),\n onSome: (top_p) => ({ top_p }),\n }),\n ...Option.match(params.topK, {\n onNone: () => ({}),\n onSome: (top_k) => ({ top_k }),\n }),\n ...Option.match(params.stopSequences, {\n onNone: () => ({}),\n onSome: (stop_sequences) => ({ stop_sequences }),\n }),\n ...Option.match(params.thinking, {\n onNone: () => ({}),\n onSome: (thinking) => ({ thinking }),\n }),\n ...Option.match(params.tools, {\n onNone: () => ({}),\n onSome: (tools) => ({ tools }),\n }),\n ...Option.match(params.toolChoice, {\n onNone: () => ({}),\n onSome: (tool_choice) => ({ tool_choice }),\n }),\n ...Option.match(params.userId, {\n onNone: () => ({}),\n onSome: (user_id) => ({ metadata: { user_id } }),\n }),\n ...Option.match(params.outputConfig, {\n onNone: () => ({}),\n onSome: (output_config) => ({ output_config }),\n }),\n stream: true,\n }),\n ),\n )\n\n// ---------------------------------------------------------------------------\n// Stream-level state - assemble content blocks index-by-index, then emit\n// our `Items.HistoryItem[]` when `message_stop` lands.\n// ---------------------------------------------------------------------------\n\ntype BlockBuffer = {\n readonly type: WireContentBlock[\"type\"]\n readonly text: string\n readonly inputJson: string\n readonly thinking: string\n readonly signature: string\n readonly id: Option.Option<string>\n readonly name: Option.Option<string>\n readonly redactedData: Option.Option<string>\n}\n\nconst emptyBlock = (type: WireContentBlock[\"type\"]): BlockBuffer => ({\n type,\n text: \"\",\n inputJson: \"\",\n thinking: \"\",\n signature: \"\",\n id: Option.none(),\n name: Option.none(),\n redactedData: Option.none(),\n})\n\nexport type Accumulator = {\n readonly blocks: Readonly<Record<number, BlockBuffer>>\n readonly stopReason: Option.Option<string>\n readonly usage: Items.Usage\n}\n\nexport const emptyAccumulator: Accumulator = {\n blocks: {},\n stopReason: Option.none(),\n usage: {},\n}\n\nconst replaceBlock = (acc: Accumulator, index: number, block: BlockBuffer): Accumulator => ({\n ...acc,\n blocks: { ...acc.blocks, [index]: block },\n})\n\nconst updateBlock = (\n acc: Accumulator,\n index: number,\n patch: (block: BlockBuffer) => BlockBuffer,\n): Accumulator => replaceBlock(acc, index, patch(acc.blocks[index] ?? emptyBlock(\"text\")))\n\nexport const startBlock = (acc: Accumulator, index: number, block: WireContentBlock): Accumulator =>\n Match.value(block).pipe(\n Match.discriminatorsExhaustive(\"type\")({\n text: () => replaceBlock(acc, index, emptyBlock(\"text\")),\n tool_use: (b) =>\n replaceBlock(acc, index, {\n ...emptyBlock(\"tool_use\"),\n id: Option.some(b.id),\n name: Option.some(b.name),\n inputJson: typeof b.input === \"string\" ? b.input : \"\",\n }),\n thinking: () => replaceBlock(acc, index, emptyBlock(\"thinking\")),\n redacted_thinking: (b) =>\n replaceBlock(acc, index, {\n ...emptyBlock(\"redacted_thinking\"),\n redactedData: Option.some(b.data),\n }),\n }),\n )\n\nexport const appendTextDelta = (acc: Accumulator, index: number, text: string): Accumulator =>\n updateBlock(acc, index, (b) => ({ ...b, text: b.text + text }))\n\nexport const appendInputJsonDelta = (\n acc: Accumulator,\n index: number,\n partial: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, inputJson: b.inputJson + partial }))\n\nexport const appendThinkingDelta = (\n acc: Accumulator,\n index: number,\n thinking: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, thinking: b.thinking + thinking }))\n\nexport const appendSignatureDelta = (\n acc: Accumulator,\n index: number,\n signature: string,\n): Accumulator => updateBlock(acc, index, (b) => ({ ...b, signature: b.signature + signature }))\n\nexport const setStopReason = (acc: Accumulator, reason: string): Accumulator => ({\n ...acc,\n stopReason: Option.some(reason),\n})\n\nconst cachedFromWire = (wire: WireUsage): Option.Option<number> =>\n Option.fromNullishOr(wire.cache_read_input_tokens)\n\nexport const mergeUsage = (acc: Accumulator, wire: WireUsage): Accumulator => {\n const cached = cachedFromWire(wire)\n const usage: Items.Usage = {\n ...acc.usage,\n ...(wire.input_tokens !== undefined && { input_tokens: wire.input_tokens }),\n ...(wire.output_tokens !== undefined && { output_tokens: wire.output_tokens }),\n ...(wire.input_tokens !== undefined &&\n wire.output_tokens !== undefined && {\n total_tokens: wire.input_tokens + wire.output_tokens,\n }),\n ...Option.match(cached, {\n onNone: () => ({}),\n onSome: (cached_tokens) => ({ input_tokens_details: { cached_tokens } }),\n }),\n }\n return { ...acc, usage }\n}\n\nconst stopReasonFromAnthropic = (reason: Option.Option<string>): Turn[\"stop_reason\"] =>\n Option.match(reason, {\n onNone: () => \"stop\" as const,\n onSome: (r) =>\n Match.value(r).pipe(\n Match.when(\"tool_use\", () => \"tool_calls\" as const),\n Match.when(\"max_tokens\", () => \"max_tokens\" as const),\n Match.orElse(() => \"stop\" as const),\n ),\n })\n\nconst blocksByIndex = (acc: Accumulator): ReadonlyArray<BlockBuffer> =>\n pipe(\n Object.keys(acc.blocks),\n Arr.map((k) => Number(k)),\n Arr.sort(Order.Number),\n Arr.map((i) => acc.blocks[i]!),\n )\n\nconst blockToItems = (block: BlockBuffer): ReadonlyArray<Items.HistoryItem> =>\n Match.value(block.type).pipe(\n Match.when(\n \"text\",\n (): ReadonlyArray<Items.HistoryItem> =>\n block.text.length === 0\n ? []\n : [\n {\n type: \"message\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text: block.text }],\n },\n ],\n ),\n Match.when(\n \"tool_use\",\n (): ReadonlyArray<Items.HistoryItem> => [\n {\n type: \"function_call\",\n call_id: Option.getOrElse(block.id, () => \"\"),\n name: Option.getOrElse(block.name, () => \"\"),\n arguments: block.inputJson,\n },\n ],\n ),\n Match.when(\n \"thinking\",\n (): ReadonlyArray<Items.HistoryItem> => [\n {\n type: \"reasoning\",\n ...(block.thinking.length > 0 && { summary: block.thinking }),\n ...(block.signature.length > 0 && { signature: block.signature }),\n },\n ],\n ),\n Match.when(\n \"redacted_thinking\",\n (): ReadonlyArray<Items.HistoryItem> => [\n {\n type: \"reasoning\",\n ...Option.match(block.redactedData, {\n onNone: () => ({}),\n onSome: (signature) => ({ signature }),\n }),\n },\n ],\n ),\n Match.exhaustive,\n )\n\ntype MergeAcc = {\n readonly out: ReadonlyArray<Items.HistoryItem>\n}\n\nconst mergeStep = (acc: MergeAcc, item: Items.HistoryItem): MergeAcc => {\n const last = Arr.last(acc.out)\n if (\n Option.isSome(last) &&\n last.value.type === \"message\" &&\n last.value.role === \"assistant\" &&\n item.type === \"message\" &&\n item.role === \"assistant\"\n ) {\n const merged: Items.Message = {\n ...last.value,\n content: [...last.value.content, ...item.content],\n }\n return { out: [...acc.out.slice(0, -1), merged] }\n }\n return { out: [...acc.out, item] }\n}\n\nconst mergeAdjacentAssistantText = (\n items: ReadonlyArray<Items.HistoryItem>,\n): ReadonlyArray<Items.HistoryItem> => Arr.reduce(items, { out: [] } as MergeAcc, mergeStep).out\n\nexport const accumulatorToTurn = (acc: Accumulator): Turn => ({\n items: pipe(blocksByIndex(acc), Arr.flatMap(blockToItems), mergeAdjacentAssistantText),\n usage: acc.usage,\n stop_reason: stopReasonFromAnthropic(acc.stopReason),\n})\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/anthropic",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Anthropic Messages API provider for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "ai",
@@ -45,7 +45,7 @@
45
45
  "devDependencies": {
46
46
  "effect": "4.0.0-beta.57",
47
47
  "typescript": "^6.0.3",
48
- "@effect-uai/core": "0.5.1"
48
+ "@effect-uai/core": "0.6.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@effect-uai/core": ">=0.2.0 <1",
package/src/Anthropic.ts CHANGED
@@ -16,9 +16,10 @@ import {
16
16
  type CommonRequest,
17
17
  LanguageModel,
18
18
  type LanguageModelService,
19
+ turnFromStream,
19
20
  } from "@effect-uai/core/LanguageModel"
20
21
  import * as SSE from "@effect-uai/core/SSE"
21
- import { TurnEvent } from "@effect-uai/core/Turn"
22
+ import { type Turn, TurnEvent } from "@effect-uai/core/Turn"
22
23
  import {
23
24
  type Accumulator,
24
25
  type ThinkingConfig,
@@ -72,6 +73,14 @@ export type AnthropicService = {
72
73
  * `streamNative |> toCanonical`.
73
74
  */
74
75
  readonly streamTurn: (request: AnthropicRequest) => Stream.Stream<TurnEvent, AiError.AiError>
76
+ /**
77
+ * Drain a single turn and return the assembled `Turn`. Derived from
78
+ * `streamTurn` — Anthropic's non-streaming `/messages` endpoint
79
+ * differs from the streamed one in subtle ways (no incremental
80
+ * thinking deltas), so we route everything through streaming for
81
+ * consistency.
82
+ */
83
+ readonly turn: (request: AnthropicRequest) => Effect.Effect<Turn, AiError.AiError>
75
84
  /**
76
85
  * Project a stream of native `ProviderEvent`s into canonical `TurnEvent`s.
77
86
  * Stateful (threads an `Accumulator` for tool-call lookup and
@@ -345,9 +354,12 @@ export const make = (cfg: Config): Effect.Effect<AnthropicService, never, HttpCl
345
354
  Effect.map(HttpClient.HttpClient.asEffect(), (client) => {
346
355
  const streamNative: AnthropicService["streamNative"] = (request) =>
347
356
  buildNativeStream(cfg)(request).pipe(Stream.provideService(HttpClient.HttpClient, client))
357
+ const streamTurn: AnthropicService["streamTurn"] = (request) =>
358
+ toCanonical(streamNative(request))
348
359
  return {
349
360
  streamNative,
350
- streamTurn: (request) => toCanonical(streamNative(request)),
361
+ streamTurn,
362
+ turn: turnFromStream(streamTurn),
351
363
  toCanonical,
352
364
  }
353
365
  })
@@ -369,6 +381,7 @@ export const layer = (
369
381
  make(cfg),
370
382
  (s): LanguageModelService => ({
371
383
  streamTurn: (request) => s.streamTurn(request as AnthropicRequest),
384
+ turn: (request) => s.turn(request as AnthropicRequest),
372
385
  }),
373
386
  ),
374
387
  )
package/src/codec.ts CHANGED
@@ -158,7 +158,7 @@ const parseJson = (s: string): Result.Result<unknown, JsonParseError> =>
158
158
 
159
159
  type RoleBucket = "user" | "assistant" | "system"
160
160
 
161
- const roleBucket = (item: Items.Item): RoleBucket =>
161
+ const roleBucket = (item: Items.HistoryItem): RoleBucket =>
162
162
  Match.value(item).pipe(
163
163
  Match.discriminatorsExhaustive("type")({
164
164
  message: (m) => m.role,
@@ -168,7 +168,7 @@ const roleBucket = (item: Items.Item): RoleBucket =>
168
168
  }),
169
169
  )
170
170
 
171
- const itemToUserBlocks = (item: Items.Item): ReadonlyArray<RequestUserContentBlock> =>
171
+ const itemToUserBlocks = (item: Items.HistoryItem): ReadonlyArray<RequestUserContentBlock> =>
172
172
  Match.value(item).pipe(
173
173
  Match.discriminatorsExhaustive("type")({
174
174
  message: (m): ReadonlyArray<RequestUserContentBlock> =>
@@ -182,7 +182,7 @@ const itemToUserBlocks = (item: Items.Item): ReadonlyArray<RequestUserContentBlo
182
182
  )
183
183
 
184
184
  const itemToAssistantBlocks = (
185
- item: Items.Item,
185
+ item: Items.HistoryItem,
186
186
  ): Result.Result<ReadonlyArray<RequestAssistantContentBlock>, JsonParseError> =>
187
187
  Match.value(item).pipe(
188
188
  Match.discriminatorsExhaustive("type")({
@@ -268,7 +268,10 @@ const appendAssistant = (
268
268
  assistantBuf: blocks,
269
269
  }
270
270
 
271
- const groupStep = (acc: GroupAcc, item: Items.Item): Result.Result<GroupAcc, JsonParseError> => {
271
+ const groupStep = (
272
+ acc: GroupAcc,
273
+ item: Items.HistoryItem,
274
+ ): Result.Result<GroupAcc, JsonParseError> => {
272
275
  const bucket = roleBucket(item)
273
276
  if (bucket === "system") return Result.succeed(acc)
274
277
  if (bucket === "user") {
@@ -288,7 +291,7 @@ const groupStep = (acc: GroupAcc, item: Items.Item): Result.Result<GroupAcc, Jso
288
291
  * requires an object input.
289
292
  */
290
293
  const groupedMessages = (
291
- history: ReadonlyArray<Items.Item>,
294
+ history: ReadonlyArray<Items.HistoryItem>,
292
295
  ): Result.Result<ReadonlyArray<RequestMessage>, JsonParseError> => {
293
296
  const initial: Result.Result<GroupAcc, JsonParseError> = Result.succeed({
294
297
  messages: [],
@@ -302,10 +305,10 @@ const groupedMessages = (
302
305
  )
303
306
  }
304
307
 
305
- const isSystemMessage = (item: Items.Item): item is Items.Message =>
308
+ const isSystemMessage = (item: Items.HistoryItem): item is Items.Message =>
306
309
  item.type === "message" && item.role === "system"
307
310
 
308
- const systemFromHistory = (history: ReadonlyArray<Items.Item>): Option.Option<string> => {
311
+ const systemFromHistory = (history: ReadonlyArray<Items.HistoryItem>): Option.Option<string> => {
309
312
  const texts = pipe(
310
313
  history,
311
314
  Arr.filterMap((item) =>
@@ -340,7 +343,7 @@ export type RequestBody = {
340
343
 
341
344
  export const buildRequestBody = (params: {
342
345
  readonly model: string
343
- readonly history: ReadonlyArray<Items.Item>
346
+ readonly history: ReadonlyArray<Items.HistoryItem>
344
347
  readonly maxTokens: number
345
348
  readonly temperature: Option.Option<number>
346
349
  readonly topP: Option.Option<number>
@@ -406,7 +409,7 @@ export const buildRequestBody = (params: {
406
409
 
407
410
  // ---------------------------------------------------------------------------
408
411
  // Stream-level state - assemble content blocks index-by-index, then emit
409
- // our `Items.Item[]` when `message_stop` lands.
412
+ // our `Items.HistoryItem[]` when `message_stop` lands.
410
413
  // ---------------------------------------------------------------------------
411
414
 
412
415
  type BlockBuffer = {
@@ -540,11 +543,11 @@ const blocksByIndex = (acc: Accumulator): ReadonlyArray<BlockBuffer> =>
540
543
  Arr.map((i) => acc.blocks[i]!),
541
544
  )
542
545
 
543
- const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>
546
+ const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.HistoryItem> =>
544
547
  Match.value(block.type).pipe(
545
548
  Match.when(
546
549
  "text",
547
- (): ReadonlyArray<Items.Item> =>
550
+ (): ReadonlyArray<Items.HistoryItem> =>
548
551
  block.text.length === 0
549
552
  ? []
550
553
  : [
@@ -557,7 +560,7 @@ const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>
557
560
  ),
558
561
  Match.when(
559
562
  "tool_use",
560
- (): ReadonlyArray<Items.Item> => [
563
+ (): ReadonlyArray<Items.HistoryItem> => [
561
564
  {
562
565
  type: "function_call",
563
566
  call_id: Option.getOrElse(block.id, () => ""),
@@ -568,7 +571,7 @@ const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>
568
571
  ),
569
572
  Match.when(
570
573
  "thinking",
571
- (): ReadonlyArray<Items.Item> => [
574
+ (): ReadonlyArray<Items.HistoryItem> => [
572
575
  {
573
576
  type: "reasoning",
574
577
  ...(block.thinking.length > 0 && { summary: block.thinking }),
@@ -578,7 +581,7 @@ const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>
578
581
  ),
579
582
  Match.when(
580
583
  "redacted_thinking",
581
- (): ReadonlyArray<Items.Item> => [
584
+ (): ReadonlyArray<Items.HistoryItem> => [
582
585
  {
583
586
  type: "reasoning",
584
587
  ...Option.match(block.redactedData, {
@@ -592,10 +595,10 @@ const blockToItems = (block: BlockBuffer): ReadonlyArray<Items.Item> =>
592
595
  )
593
596
 
594
597
  type MergeAcc = {
595
- readonly out: ReadonlyArray<Items.Item>
598
+ readonly out: ReadonlyArray<Items.HistoryItem>
596
599
  }
597
600
 
598
- const mergeStep = (acc: MergeAcc, item: Items.Item): MergeAcc => {
601
+ const mergeStep = (acc: MergeAcc, item: Items.HistoryItem): MergeAcc => {
599
602
  const last = Arr.last(acc.out)
600
603
  if (
601
604
  Option.isSome(last) &&
@@ -613,8 +616,9 @@ const mergeStep = (acc: MergeAcc, item: Items.Item): MergeAcc => {
613
616
  return { out: [...acc.out, item] }
614
617
  }
615
618
 
616
- const mergeAdjacentAssistantText = (items: ReadonlyArray<Items.Item>): ReadonlyArray<Items.Item> =>
617
- Arr.reduce(items, { out: [] } as MergeAcc, mergeStep).out
619
+ const mergeAdjacentAssistantText = (
620
+ items: ReadonlyArray<Items.HistoryItem>,
621
+ ): ReadonlyArray<Items.HistoryItem> => Arr.reduce(items, { out: [] } as MergeAcc, mergeStep).out
618
622
 
619
623
  export const accumulatorToTurn = (acc: Accumulator): Turn => ({
620
624
  items: pipe(blocksByIndex(acc), Arr.flatMap(blockToItems), mergeAdjacentAssistantText),