@effect-uai/anthropic 0.8.0 → 0.10.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.
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"Anthropic.d.mts","names":[],"sources":["../src/Anthropic.ts"],"mappings":";;;;;;;;;;;;;KAqCY,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;;;;;;cA8NE,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"}
@@ -6,6 +6,7 @@ import { HttpClient, HttpClientRequest } from "effect/unstable/http";
6
6
  import * as AiError from "@effect-uai/core/AiError";
7
7
  import { LanguageModel, turnFromStream } from "@effect-uai/core/LanguageModel";
8
8
  import * as SSE from "@effect-uai/core/SSE";
9
+ import { descriptorsOf } from "@effect-uai/core/Tool";
9
10
  import { TurnEvent } from "@effect-uai/core/Turn";
10
11
  //#region src/Anthropic.ts
11
12
  var Anthropic_exports = /* @__PURE__ */ __exportAll({
@@ -29,11 +30,14 @@ const outputConfig = (request) => pipe(Option.fromUndefinedOr(request.structured
29
30
  schema: format.schema["~standard"].jsonSchema.input({ target: "draft-2020-12" })
30
31
  } })));
31
32
  const resolvedMaxTokens = (cfg, request) => request.maxOutputTokens ?? cfg.defaultMaxTokens ?? FALLBACK_MAX_TOKENS;
32
- const toolDescriptors = (request) => request.tools !== void 0 && request.tools.length > 0 ? Option.some(request.tools.map((t) => ({
33
- name: t.name,
34
- description: t.description,
35
- input_schema: t.inputSchema
36
- }))) : Option.none();
33
+ const toolDescriptors = (request) => {
34
+ const descriptors = descriptorsOf(request.tools);
35
+ return descriptors.length > 0 ? Option.some(descriptors.map((t) => ({
36
+ name: t.name,
37
+ description: t.description,
38
+ input_schema: t.inputSchema
39
+ }))) : Option.none();
40
+ };
37
41
  const toolChoiceWire = (request) => pipe(Option.fromUndefinedOr(request.toolChoice), Option.map((choice) => choice === "auto" ? { type: "auto" } : choice === "required" ? { type: "any" } : choice === "none" ? { type: "none" } : {
38
42
  type: "tool",
39
43
  name: choice.name
@@ -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 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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"}
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 { descriptorsOf } from \"@effect-uai/core/Tool\"\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 const descriptors = descriptorsOf(request.tools)\n return descriptors.length > 0\n ? Option.some(\n descriptors.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema,\n })),\n )\n : Option.none()\n}\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/anthropic",
3
- "version": "0.8.0",
3
+ "version": "0.10.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.8.0"
48
+ "@effect-uai/core": "0.10.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@effect-uai/core": ">=0.2.0 <1",
package/src/Anthropic.ts CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  turnFromStream,
20
20
  } from "@effect-uai/core/LanguageModel"
21
21
  import * as SSE from "@effect-uai/core/SSE"
22
+ import { descriptorsOf } from "@effect-uai/core/Tool"
22
23
  import { type Turn, TurnEvent } from "@effect-uai/core/Turn"
23
24
  import {
24
25
  type Accumulator,
@@ -132,16 +133,18 @@ const resolvedMaxTokens = (cfg: Config, request: AnthropicRequest): number =>
132
133
 
133
134
  const toolDescriptors = (
134
135
  request: AnthropicRequest,
135
- ): Option.Option<ReadonlyArray<Record<string, unknown>>> =>
136
- request.tools !== undefined && request.tools.length > 0
136
+ ): Option.Option<ReadonlyArray<Record<string, unknown>>> => {
137
+ const descriptors = descriptorsOf(request.tools)
138
+ return descriptors.length > 0
137
139
  ? Option.some(
138
- request.tools.map((t) => ({
140
+ descriptors.map((t) => ({
139
141
  name: t.name,
140
142
  description: t.description,
141
143
  input_schema: t.inputSchema,
142
144
  })),
143
145
  )
144
146
  : Option.none()
147
+ }
145
148
 
146
149
  const toolChoiceWire = (request: AnthropicRequest): Option.Option<Record<string, unknown>> =>
147
150
  pipe(