/ opencodehub / src / lib / ai / anthropic.ts
swadhinbiswas feat: add src/lib/ai/anthropic.ts · 2/18/2026
39def2b
74 lines · 2.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import type { AIAdapter, AICompletionResult, AIConfig, AIReviewPrompt } from "./types";
import { logger } from "@/lib/logger";

type AnthropicResponse = {
  content?: Array<{ type: string; text?: string }>;
  usage?: {
    input_tokens?: number;
    output_tokens?: number;
  };
};

export class AnthropicAdapter implements AIAdapter {
  async complete(prompt: AIReviewPrompt, config: AIConfig): Promise<AICompletionResult> {
    const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
    if (!apiKey) throw new Error("Anthropic API key not configured");

    const model = config.model || "claude-3-5-sonnet-latest";
    const maxTokens = config.maxTokens ?? 2048;

    logger.info({ model, provider: "anthropic" }, "Calling Anthropic");

    try {
      const response = await fetch("https://api.anthropic.com/v1/messages", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": apiKey,
          "anthropic-version": "2023-06-01",
        },
        body: JSON.stringify({
          model,
          max_tokens: maxTokens,
          temperature: config.temperature ?? 0.2,
          system: prompt.system,
          messages: [
            {
              role: "user",
              content: prompt.user,
            },
          ],
        }),
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Anthropic API Error: ${response.status} - ${errorText}`);
      }

      const data = (await response.json()) as AnthropicResponse;
      const content =
        data.content
          ?.filter((c) => c.type === "text" && c.text)
          .map((c) => c.text)
          .join("\n")
          .trim() || "{}";

      const inputTokens = data.usage?.input_tokens ?? 0;
      const outputTokens = data.usage?.output_tokens ?? 0;

      return {
        content,
        usage: {
          inputTokens,
          outputTokens,
          totalTokens: inputTokens + outputTokens,
        },
      };
    } catch (error: any) {
      logger.error({ error: error.message }, "Anthropic Error");
      throw error;
    }
  }
}