73 lines
2.2 KiB
TypeScript
73 lines
2.2 KiB
TypeScript
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<StreamEvent> {
|
|
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<string, unknown>,
|
|
};
|
|
}
|
|
}
|
|
yield { type: "done", stopReason: toStopReason(final.stop_reason) };
|
|
},
|
|
};
|
|
}
|