fix(runtime): DeepSeekAgent records the failure Claude Code states, like ClaudeAgent - #1225
Conversation
|
Priority note for maintainers: this is not a stability fix, so merging it can wait. Like #1224, this PR makes failures easier to diagnose; it doesn't change whether runs fail. It records the cause Claude Code states next to
The branch is up to date with #1224 and |
|
Thanks @mrthankyou. This is a clean port of #1224's hook to We'll merge this right after #1224. What we checked:
Merge mechanics. #1224 is squash-merged first. We then move this branch's own commits onto main; the resulting tree is identical to the tested head. The squash message is the PR description, because the first commit's line "Not exercised against the real DeepSeek endpoint" is out of date. What we'll do in a follow-up PR:
One thing we're deliberately not changing: following #1224's rule that the stated text is never classified, DeepSeek's 401/402 wording still isn't classified. A bad key or an empty balance still retries until the identical-failure stall, but the cause now shows in |
…ike ClaudeAgent DeepSeekAgent runs Claude Code against DeepSeek's Anthropic-compatible endpoint through its own ClaudeCodeAgent subclass, so it has the same #1084 gap: a failed result without an `error` field is reported only as "Claude run failed" and the `result` text is dropped. It now uses the same output-interpreter hook as the Claude adapter, sharing that adapter's `claudeResultText` and `attachStatedFailure` helpers, and carries the text as `details.agentStatedFailure` beside the unchanged message. The workflow normalizer and run synchronization from the Claude change already surface it. Not exercised against the real DeepSeek endpoint: covered by a Bun adapter test with a fake `claude` CLI only. Refs #1084 Co-Authored-By: Claude Opus 5.5 <[email protected]>
9b5f556 to
4e6c3af
Compare
A related gap to #1084, found by reading the code; nobody has reported it. #1084 itself is about
ClaudeAgentonly. Stacked on #1224: this PR's base isfix/1084-claude-stated-failure. Merge #1224 first; this diff then contains only the DeepSeek change.Problem
DeepSeekAgentruns Claude Code against DeepSeek's Anthropic-compatible endpoint through its ownClaudeCodeAgentsubclass (DeepSeekClaudeCodeAgent). So it has the same gap #1224 fixes forClaudeAgent: a failed result without anerrorfield is reported only asClaude run failed, and Claude Code'sresulttext, which states the cause (e.g. an auth error from the DeepSeek route), is dropped.Change
agents/deepseek.tsxgets the same output-interpreter hook andgenerate()override asclaude.tsx. The stated text is attached asdetails.agentStatedFailure; the message and code are unchanged, so nothing Smithers classifies changes.agents/claude.tsxexports its two helpers (claudeResultText,attachStatedFailure) and theGENERIC_CLAUDE_FAILUREconstant, so DeepSeek reuses them instead of copying them.openrouter.tsximporting./codexis the precedent for a cross-adapter import.deepseek.tsxdeclaresoutput-interpretation, linked to Concurrent agents race on OAuth token refresh; three immediate retries all re-race and kill the run with an opaque "Claude run failed" #1084.The workflow normalizer and run synchronization from #1224 already carry the field through to
last_errorand the attempt ledger, so nothing else changes.Verification
Real endpoint, invalid key (local): the generated
DeepSeekClaudeCodeAgentfrom this branch, run with Claude Code 2.1.285 andultrafuzzApiKeyset to an invalid value, calledgenerate()once againsthttps://api.deepseek.com/anthropic. DeepSeek rejected the key, so no tokens were spent. Result:AGENT_CLI_ERROR, messageClaude run failed See https://smithers.sh/reference/errors. That's unchanged, and there's no401in the message, so Smithers' auth regex does not fire.details.agentStatedFailure:Failed to authenticate. API Error: 401 Authentication Fails, Your api key: ****robe is invalid (request_id: …)This confirms that Claude Code reports a DeepSeek route failure only in
result, which the fake-CLI test had assumed.New Bun adapter test: it loads the generated DeepSeek adapter and runs it against a fake
claudeCLI that prints anis_errorresult and exits 1. The thrown message staysClaude run failed…with codeAGENT_CLI_ERROR,details.agentStatedFailurecarries a 401-worded statement, and a result without text attaches nothing.Existing tests pass: the DeepSeek and Claude adapter contracts (7/7), the adapter-boundary gate and the
inittemplate test.Clean checks: lint, strict lint, Prettier and
knip.Not done: a successful DeepSeek-backed campaign (no key), and the full
runtime.test.tslocally.🤖 Generated with Claude Code
The PR appears safe to merge based on the available changes.
Summary
The PR preserves Claude Code’s stated failure text for DeepSeek attempts without changing the error message Smithers classifies.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR A[Claude Code result] --> B[DeepSeek output interpreter] B --> C[Generic error for Smithers classification] B --> D[Stated failure in error details] D --> E[Attempt ledger and last_error]Reviews (5) · Last reviewed commit: "fix(runtime): DeepSeekAgent records the ..."