Files
curriculum-project-hub/docs/adr/0017-agent-session-is-provider-bound.md
T
hongjr03 082562ca08 docs(adr): ADR-0017 重写——从 provider-agnostic 改为 Claude Code SDK
放弃 provider-agnostic,用 @anthropic-ai/claude-agent-sdk。代价:不能走
OpenRouter(GLM 等),需 Anthropic API key。收益:compaction、工具审批、
partial message 流式、Claude-to-IM 原生兼容。迁移路径:如果将来需要
provider-agnostic,用 streamText + SSE 转换层(~100 行)替回 query()。
2026-07-08 01:40:28 +08:00

2.5 KiB

ADR 0017: Agent Runtime — Claude Code SDK

Status

Accepted — supersedes the original ADR-0017 (provider-agnostic session).

Context

The original ADR-0017 mandated a provider-agnostic agent layer: any OpenAI-compatible model via OpenRouter, custom agent loop built on Vercel AI SDK's streamText. The motivation was to avoid vendor lock-in.

In practice, the hand-rolled agent loop lacked capabilities that a production agent needs: context compaction (long conversations), tool approval flows, partial-message streaming, and a battle-tested multi-turn loop. Building these ourselves meant re-implementing what the Claude Code SDK already provides.

The Feishu integration also proved costly to hand-roll — card schema quirks, patch limitations, file support — each API quirk cost a round-trip. The Claude-to-IM library (2.7K stars) has already solved these, but its LLMProvider interface expects Claude Code SDK's SSE event format. Using it with a generic provider would require a conversion layer.

Decision

Adopt @anthropic-ai/claude-agent-sdk as the agent runtime. The SDK's query() function owns the agent loop (tool dispatch, compaction, streaming). Built-in tools (Read, Write, Bash, Glob, Grep) cover the entire tool surface — no custom tools needed. cph check / cph build run via Bash.

This means:

  • The agent layer is Anthropic-specific, not provider-agnostic. Claude Code SDK speaks the Anthropic Messages API and cannot be pointed at OpenRouter (which is OpenAI-compatible).
  • An Anthropic API key (or OAuth via Claude Pro/Max) is required.
  • Model selection is within the Anthropic model family (Sonnet, Haiku, Opus), not across vendors.

Consequences

  • We lose the ability to route to GLM or other non-Anthropic models via OpenRouter. This is the accepted cost of getting a mature agent loop.
  • The Vercel AI SDK dependency is dropped.
  • Custom tools (read_file, write_file, cph_check, cph_build) are replaced by the SDK's built-in Read/Write/Bash/Glob/Grep.
  • The SSE event format matches Claude-to-IM's expected protocol natively — adopting Claude-to-IM for Feishu integration is a direct fit, no conversion.
  • Per-run model selection still works (role→model mapping), but models are Anthropic aliases, not OpenRouter routing IDs.
  • If provider-agnosticism becomes a hard requirement again, the migration path is: replace query() with a Vercel AI SDK streamText call + an SSE format converter (~100 lines). The rest of the architecture (trigger, lock, permission, Feishu client) is provider-agnostic already.