anthropic-messages.recorded.test.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { describe, expect } from "bun:test"
  2. import { Effect } from "effect"
  3. import { LLM, AIError, Message, ToolCallPart } from "../../src/index.js"
  4. import { LLMClient } from "../../src/route.js"
  5. import * as Anthropic from "../../src/providers/anthropic.js"
  6. import { weatherToolName } from "../recorded-scenarios.js"
  7. import { recordedTests } from "../recorded-test.js"
  8. const model = Anthropic.configure({
  9. apiKey: process.env.ANTHROPIC_API_KEY ?? "fixture",
  10. }).model("claude-haiku-4-5-20251001")
  11. const malformedToolOrderRequest = LLM.request({
  12. id: "recorded_anthropic_malformed_tool_order",
  13. model,
  14. messages: [
  15. Message.assistant([
  16. ToolCallPart.make({ id: "call_1", name: weatherToolName, input: { city: "Paris" } }),
  17. { type: "text", text: "I will check the weather." },
  18. ]),
  19. Message.tool({ id: "call_1", name: weatherToolName, result: { temperature: "72F" } }),
  20. Message.user("Use that result to answer briefly."),
  21. ],
  22. tools: [{ name: weatherToolName, description: "Get weather", inputSchema: { type: "object", properties: {} } }],
  23. })
  24. const recorded = recordedTests({
  25. prefix: "anthropic-messages",
  26. provider: "anthropic",
  27. protocol: "anthropic-messages",
  28. requires: ["ANTHROPIC_API_KEY"],
  29. options: { redact: { allowRequestHeaders: ["anthropic-version"] } },
  30. })
  31. describe("Anthropic Messages sad-path recorded", () => {
  32. recorded.effect.with("rejects malformed assistant tool order", { tags: ["tool", "sad-path"] }, () =>
  33. Effect.gen(function* () {
  34. const error = yield* LLMClient.generate(malformedToolOrderRequest).pipe(Effect.flip)
  35. expect(error).toBeInstanceOf(AIError)
  36. expect(error.reason).toMatchObject({ _tag: "InvalidRequest" })
  37. expect(error.reason.message).toContain("`tool_use` ids were found without `tool_result` blocks")
  38. }),
  39. )
  40. })