Skip to content

hir-123: swap fetch() to @anthropic-ai/sdk in triageReplyLLM#17

Open
jaredzwick wants to merge 1 commit into
pypesdev:hir-120/warm-reply-triagefrom
jaredzwick:hir-123/anthropic-sdk-swap
Open

hir-123: swap fetch() to @anthropic-ai/sdk in triageReplyLLM#17
jaredzwick wants to merge 1 commit into
pypesdev:hir-120/warm-reply-triagefrom
jaredzwick:hir-123/anthropic-sdk-swap

Conversation

@jaredzwick

Copy link
Copy Markdown
Collaborator

Follow-up from CTO review on HIR-122 for #14. Founder pre-approved deferring the SDK swap out of the original PR.

Summary

  • Replace fetch() against https://api.anthropic.com/v1/messages with new Anthropic({ apiKey }).messages.create({...}) from @anthropic-ai/sdk.
  • Same input/output contract for triageReplyLLM: still returns TriageResult | null, still validates intent against the enum, still clamps confidence, still wrapped in the same try/catch so it never throws.
  • Same model (ANTHROPIC_MODEL env / claude-haiku-4-5-20251001 default), same TRIAGE_PROMPT, same heuristic fallback path — none of those move.
  • Tests now mock the @anthropic-ai/sdk module directly via vi.mock + vi.hoisted instead of overriding globalThis.fetch. All 14 replyTriage cases keep their original assertions.

Stacked on #14 — base branch is hir-120/warm-reply-triage. Will rebase to main after #14 merges.

Out of scope (per HIR-123)

  • Prompt changes, model changes, fallback heuristic changes.
  • Streaming / tool-use / response_format JSON. We still parse the text block ourselves through parseLLMJson.

Test plan

  • pnpm test:int — 109 passed, 1 skipped. The unrelated api.int.spec.ts Payload-secret env failure exists on the base branch too.
  • npx tsc --noEmit — clean.
  • CTO review.

Replaces the direct fetch() call to api.anthropic.com with the official
@anthropic-ai/sdk client. Same input/output contract, same model + prompt
+ heuristic fallback, same never-throws guarantee. Tests now mock the SDK
module instead of overriding globalThis.fetch.

Follow-up from CTO review on HIR-122 / PR pypesdev#14, founder pre-approved.

@jaredzwick jaredzwick left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CTO Review — LGTM

Clean swap. Removes 21 lines of manual HTTP boilerplate (headers, fetch, JSON parsing) and replaces with 10 lines of typed SDK calls.

Key points:

  • Type guard (block): block is Anthropic.TextBlock is the correct way to narrow the union rather than comparing .type and casting — gets the discriminated union right.
  • Signal forwarding moved from the fetch options bag to the second arg of client.messages.create() per SDK API — correct.
  • Test refactor: replacing globalThis.fetch mock with vi.mock('@anthropic-ai/sdk') is strictly better — it tests through the same import path the production code uses instead of patching the global. The vi.hoisted() pattern ensures the mock factory runs before imports hoist.
  • "returns null when the API returns non-200" → "returns null when the SDK throws": correct rename. The SDK surfaces HTTP errors as thrown exceptions, not ok: false responses.
  • Net: +43/-80 in tests (removes verbose response stubs), +10/-21 in implementation. Strictly a reduction in surface area.

No concerns. Ready to merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant