import Anthropic from "@anthropic-ai/sdk"; import type { ChatRequest, LLMProvider, Message, StopReason, StreamEvent } from "@magiccode/core"; function toAnthropicMessages(messages: Message[]): Anthropic.MessageParam[] { return messages.map((m) => ({ role: m.role, content: m.content.map((b) => { switch (b.type) { case "text": return { type: "text" as const, text: b.text }; case "tool_use": return { type: "tool_use" as const, id: b.id, name: b.name, input: b.input }; case "tool_result": return { type: "tool_result" as const, tool_use_id: b.toolUseId, content: b.content, is_error: b.isError ?? false, }; } }), })); } function toStopReason(r: string | null): StopReason { if (r === "end_turn" || r === "tool_use" || r === "max_tokens") return r; return "other"; } /** Utilise ANTHROPIC_API_KEY depuis l'environnement. */ export function createAnthropicProvider(model: string): LLMProvider { const client = new Anthropic(); return { id: "anthropic", model, capabilities: { tools: true }, async *chat(req: ChatRequest, signal?: AbortSignal): AsyncIterable { const stream = client.messages.stream( { model, max_tokens: req.maxTokens ?? 8192, system: req.system, tools: req.tools.map((t) => ({ name: t.name, description: t.description, input_schema: t.inputSchema as Anthropic.Tool.InputSchema, })), messages: toAnthropicMessages(req.messages), }, { signal }, ); for await (const ev of stream) { if (ev.type === "content_block_delta" && ev.delta.type === "text_delta") { yield { type: "text_delta", text: ev.delta.text }; } } const final = await stream.finalMessage(); for (const block of final.content) { if (block.type === "tool_use") { yield { type: "tool_use", id: block.id, name: block.name, input: block.input as Record, }; } } yield { type: "done", stopReason: toStopReason(final.stop_reason) }; }, }; }