Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | import Anthropic from "@anthropic-ai/sdk";
import type {
AIProvider,
AIAnalysisRequest,
AIProviderResponse,
AIAnalysisResult,
} from "../types";
import { buildAnalysisPrompt } from "../prompts";
import { calculateCost } from "../costCalculator";
export class AnthropicProvider implements AIProvider {
private client: Anthropic | null = null;
private modelName: string;
constructor(apiKey?: string, modelName: string = "claude-sonnet-4-5") {
if (apiKey) {
this.client = new Anthropic({ apiKey });
}
this.modelName = modelName;
}
getName(): string {
return this.modelName;
}
getProvider(): string {
return "anthropic";
}
isAvailable(): boolean {
return this.client !== null;
}
async analyze(request: AIAnalysisRequest): Promise<AIProviderResponse> {
if (!this.client) {
throw new Error("Anthropic API key not configured");
}
const prompt = buildAnalysisPrompt(request);
const startTime = Date.now();
try {
const response = await this.client.messages.create({
model: this.modelName,
max_tokens: 1024,
messages: [
{
role: "user",
content: prompt,
},
],
tools: [
{
name: "analyze_check_in",
description: "Analyze a check-in and provide insights",
input_schema: {
type: "object",
properties: {
insight: {
type: "string",
description: "A brief, encouraging analysis of their progress (2-3 sentences)",
},
suggestion: {
type: "string",
description: "One specific, actionable recommendation (1-2 sentences)",
},
sentiment: {
type: "string",
enum: ["positive", "neutral", "negative", "mixed"],
description: "The overall tone of the check-in",
},
},
required: ["insight", "suggestion", "sentiment"],
},
},
],
tool_choice: { type: "tool", name: "analyze_check_in" },
});
const latencyMs = Date.now() - startTime;
// Extract tool use result
const toolUse = response.content.find((block) => block.type === "tool_use");
if (!toolUse || toolUse.type !== "tool_use") {
throw new Error("No tool use found in response");
}
const result = toolUse.input as AIAnalysisResult;
// Calculate cost
const promptTokens = response.usage.input_tokens;
const completionTokens = response.usage.output_tokens;
const totalTokens = promptTokens + completionTokens;
const estimatedCost = calculateCost(this.modelName, promptTokens, completionTokens);
return {
result,
metrics: {
promptTokens,
completionTokens,
totalTokens,
latencyMs,
estimatedCost,
},
modelName: this.modelName,
provider: "anthropic",
endpoint: "/v1/messages",
};
} catch (error) {
const latencyMs = Date.now() - startTime;
throw new Error(
`Anthropic API error after ${latencyMs}ms: ${error instanceof Error ? error.message : String(error)}`
);
}
}
}
|