Skip to content

Commit cca22dd

Browse files
author
SqlRush
committed
Report attempted models in print results
1 parent 1459e8e commit cca22dd

4 files changed

Lines changed: 65 additions & 42 deletions

File tree

cmd/claude/main.go

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,31 +2137,32 @@ func firstNonEmpty(values ...string) string {
21372137
}
21382138

21392139
type printJSONResult struct {
2140-
Type string `json:"type"`
2141-
Subtype string `json:"subtype"`
2142-
IsError bool `json:"is_error"`
2143-
DurationMS int64 `json:"duration_ms"`
2144-
DurationAPI int64 `json:"duration_api_ms"`
2145-
NumTurns int `json:"num_turns,omitempty"`
2146-
TotalCost float64 `json:"total_cost_usd,omitempty"`
2147-
SessionID contracts.ID `json:"session_id,omitempty"`
2148-
CWD string `json:"cwd,omitempty"`
2149-
PermissionMode string `json:"permission_mode,omitempty"`
2150-
APIKeySource string `json:"api_key_source,omitempty"`
2151-
Betas []string `json:"betas,omitempty"`
2152-
FastMode bool `json:"fast_mode,omitempty"`
2153-
OutputStyle string `json:"output_style,omitempty"`
2154-
OutputStyles []string `json:"available_output_styles,omitempty"`
2155-
Result string `json:"result"`
2156-
Error string `json:"error,omitempty"`
2157-
Message *contracts.Message `json:"message,omitempty"`
2158-
StopReason string `json:"stop_reason,omitempty"`
2159-
Model string `json:"model,omitempty"`
2160-
Usage *contracts.Usage `json:"usage,omitempty"`
2161-
ToolResults []contracts.ToolResult `json:"tool_results,omitempty"`
2162-
Cleared bool `json:"cleared,omitempty"`
2163-
Compacted bool `json:"compacted,omitempty"`
2164-
Compact *session.CompactMetadata `json:"compact,omitempty"`
2140+
Type string `json:"type"`
2141+
Subtype string `json:"subtype"`
2142+
IsError bool `json:"is_error"`
2143+
DurationMS int64 `json:"duration_ms"`
2144+
DurationAPI int64 `json:"duration_api_ms"`
2145+
NumTurns int `json:"num_turns,omitempty"`
2146+
TotalCost float64 `json:"total_cost_usd,omitempty"`
2147+
SessionID contracts.ID `json:"session_id,omitempty"`
2148+
CWD string `json:"cwd,omitempty"`
2149+
PermissionMode string `json:"permission_mode,omitempty"`
2150+
APIKeySource string `json:"api_key_source,omitempty"`
2151+
Betas []string `json:"betas,omitempty"`
2152+
FastMode bool `json:"fast_mode,omitempty"`
2153+
OutputStyle string `json:"output_style,omitempty"`
2154+
OutputStyles []string `json:"available_output_styles,omitempty"`
2155+
Result string `json:"result"`
2156+
Error string `json:"error,omitempty"`
2157+
Message *contracts.Message `json:"message,omitempty"`
2158+
StopReason string `json:"stop_reason,omitempty"`
2159+
Model string `json:"model,omitempty"`
2160+
ModelsAttempted []string `json:"models_attempted,omitempty"`
2161+
Usage *contracts.Usage `json:"usage,omitempty"`
2162+
ToolResults []contracts.ToolResult `json:"tool_results,omitempty"`
2163+
Cleared bool `json:"cleared,omitempty"`
2164+
Compacted bool `json:"compacted,omitempty"`
2165+
Compact *session.CompactMetadata `json:"compact,omitempty"`
21652166
}
21662167

21672168
type printStreamEvent struct {
@@ -2622,22 +2623,23 @@ func writePrintJSONResult(stdout io.Writer, runner conversation.Runner, result c
26222623
model = strings.TrimSpace(runner.Model)
26232624
}
26242625
envelope := printJSONResult{
2625-
Type: "result",
2626-
Subtype: "success",
2627-
IsError: false,
2628-
DurationMS: durationMillis(duration),
2629-
DurationAPI: durationMillis(result.APIDuration),
2630-
NumTurns: resultNumTurns(result),
2631-
TotalCost: usageCostUSD(usage),
2632-
SessionID: sessionID,
2633-
Result: text,
2634-
Message: messagePtr,
2635-
StopReason: result.StopReason,
2636-
Model: model,
2637-
Usage: usage,
2638-
ToolResults: result.ToolResults,
2639-
Cleared: result.Cleared,
2640-
Compacted: result.Compacted,
2626+
Type: "result",
2627+
Subtype: "success",
2628+
IsError: false,
2629+
DurationMS: durationMillis(duration),
2630+
DurationAPI: durationMillis(result.APIDuration),
2631+
NumTurns: resultNumTurns(result),
2632+
TotalCost: usageCostUSD(usage),
2633+
SessionID: sessionID,
2634+
Result: text,
2635+
Message: messagePtr,
2636+
StopReason: result.StopReason,
2637+
Model: model,
2638+
ModelsAttempted: append([]string(nil), result.ModelsAttempt...),
2639+
Usage: usage,
2640+
ToolResults: result.ToolResults,
2641+
Cleared: result.Cleared,
2642+
Compacted: result.Compacted,
26412643
}
26422644
applyPrintJSONRuntime(&envelope, runner)
26432645
if result.Compact != nil {

cmd/claude/main_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,6 +2273,25 @@ func TestResultNumTurnsCountsAssistantMessages(t *testing.T) {
22732273
}
22742274
}
22752275

2276+
func TestWritePrintJSONResultIncludesModelsAttempted(t *testing.T) {
2277+
result := conversation.Result{
2278+
Assistant: messages.AssistantText("fallback ok", "haiku", nil),
2279+
ModelsAttempt: []string{"sonnet", "haiku"},
2280+
}
2281+
var stdout bytes.Buffer
2282+
if err := writePrintJSONResult(&stdout, conversation.Runner{Model: "sonnet"}, result, "fallback ok", 10); err != nil {
2283+
t.Fatal(err)
2284+
}
2285+
var payload map[string]any
2286+
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
2287+
t.Fatalf("invalid json stdout %q: %v", stdout.String(), err)
2288+
}
2289+
attempts, ok := payload["models_attempted"].([]any)
2290+
if !ok || len(attempts) != 2 || attempts[0] != "sonnet" || attempts[1] != "haiku" {
2291+
t.Fatalf("models_attempted = %#v", payload["models_attempted"])
2292+
}
2293+
}
2294+
22762295
func TestWritePrintJSONResultIncludesCompactMetadata(t *testing.T) {
22772296
plan := compactpkg.BuildPlan(
22782297
[]contracts.Message{messages.UserText("old")},

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,8 @@ M7 补充:terminal input parser 和 configurable keybinding name parser 现在
15381538

15391539
本轮补充:模型 fallback retry 事件现在携带可消费 breadcrumb:conversation event、telemetry 和 `--output-format stream-json` 都会暴露 attempt/max_attempts、failed_model、next_model 和 fallback 标记,便于 SDK/headless 调用方展示模型切换原因和下一跳。
15401540

1541+
本轮补充:CLI JSON/NDJSON final result envelope 现在暴露 `models_attempted`,保留本轮请求实际尝试过的模型顺序;配合 retry breadcrumb,headless/SDK 调用方可以在最终结果里审计 fallback 路径。
1542+
15411543
本轮补充:CLI headless runner 在 Anthropic client 初始化阶段失败时会保留已构造的 runner 元数据,因此缺凭证等 late setup error 的 JSON/NDJSON structured error result 也能输出 `cwd``session_id` 和 settings-derived runtime context。
15421544

15431545
当前状态:已新增 `internal/mcp` 配置地基,覆盖 transport 归一化、stdio/url server signature、CCR proxy URL 解包、plugin MCP server 去重、allowed/denied MCP policy 的基础判定和过滤、MCP server config 环境变量展开、server scope/merge 基础、`.mcp.json` schema 解析/校验基础、项目目录链 `.mcp.json` 加载/合并、settings `mcpServers` scope 解析和 user/project/local 手工配置合并过滤、settings/.mcp.json/policy 到多 server toolset 的高层装配入口基础、conversation runner 对 configured MCP toolsets 的自动合并/执行基础、settings 文件到 runner `MCPConfig` 的 loader 接线入口及默认 MCP OAuth provider 注入、CLI bootstrap 到 runner MCP config skeleton 接线基础、MCP tool result 归一化/错误标记/result meta/content aliases/content-item aliases/大输出落盘基础、`mcp__server__tool` 名称归一化/解析 helper、MCP remote tool discovery/call 到 Go tool registry 的基础适配、MCP tool input/output schema 解析和传播、MCP tools/resources/prompts list pagination 和 cursor alias、MCP resource read content aliases 和 subscribe 调用/工具入口、MCP prompt get message aliases、MCP resource list/read/subscribe helper tool 基础、MCP prompt list/get helper tool 基础、resource/prompt helper 输入 trim 校验、MCP utility/prompt/resource client 输入 trim/校验、MCP JSON-RPC protocol client initialize/initialized lifecycle、ping 和 session-expired 判定/reset/reinitialize/retry 基础、client roots/list capability、roots/list_changed notification、cancelled/progress notification 和 CWD root 注入基础、stdio newline JSON-RPC transport/process launch 和 context cancellation 基础、HTTP JSON-RPC transport 基础、HTTP event-stream response parsing、byte limit 和 inbound request response POST 基础、`mcp-session-id` header 复用和 DELETE close 基础、传统 SSE endpoint discovery byte limit + POST + async response stream 和 stream inbound request response POST 基础、WebSocket JSON-RPC transport 和 context cancellation 基础、stdio/HTTP/SSE/WS JSON-RPC notification 捕获/handler 和 notification event 归一化/结构化 handler adapter surface 基础、stdio/WS inbound server request handler 与 elicitation/create 默认 cancel/自定义 handler、elicitation request/response alias surface 和结构化 handler adapter 基础、static authToken/OAuth beta transport header 基础、HTTP/SSE/WS dynamic auth header provider 基础、通用 OAuth refresh-token provider 基础、OAuth credential file store 和 refresh 持久化基础、MCP OAuth server file-backed access-token provider 注入基础、MCP HTTP/SSE/WS 401 reactive authorization refresh 基础、stdio/HTTP/SSE/WS protocol client 到 server toolset 的装配基础、多 server toolset 聚合和统一 close 基础、MCP tool annotations read-only/destructive hint 解析,以及 `cmd/claude-mcp` stdio 内置工具 server 初版(initialize、initialized lifecycle guard、ping、tools/list annotations 和 outputSchema、tools/call、resources/prompts 空列表与 not-found 响应、resources/subscribe 兼容 not-found 响应、JSON-RPC id 保留、batch request、invalid request 错误、client cancellation notification 基础、read-only 默认权限、`--allow-mutating-tools`)。完整 CLI/TUI 交互主循环与 runner 执行接线、完整 SSE/WS lifecycle hardening、HTTP streaming lifecycle hardening、stdio lifecycle hardening、完整 OAuth 授权/secure storage、完整 channel notification/elicitation surface 和完整内置 MCP server parity 仍未完成。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Anthropic API 和 conversation:
8585
- OAuth support now includes production OAuth config, scope parsing, Claude.ai scope detection, auth URL construction, PKCE verifier/challenge, state generation, and expiry checks.
8686
- Session/history support now includes CC-compatible prompt history references, pasted text/image placeholder parsing, paste-cache hashing and retrieval, `history.jsonl` append/load, current-session-first up-arrow ordering, ctrl+r-style deduped timestamped history, `CLAUDE_CODE_SKIP_PROMPT_HISTORY`, remote session event pagination helpers, lenient transcript loading, legacy progress parent-bridge recovery, compact-boundary pruning, snip removal/relink replay, metadata entry collection, leaf UUID calculation, conversation-chain reconstruction, orphaned parallel tool-result recovery, content-replacement record loading/reconstruction, tombstone metadata delete/relink replay, and tombstone-style transcript message removal with a size guard.
8787
- Anthropic API layer now covers streaming accumulation, usage update/accumulation semantics, non-streaming max token cap, thinking-budget adjustment, retry/backoff with `Retry-After` and `x-should-retry`, context-overflow `max_tokens` retry adjustment, beta-header dedupe, custom request headers, basic prompt cache breakpoint/cache-reference/cache-edits placement, prompt dump JSONL capture for init/new user messages/non-streaming responses/stream chunks, and CC-compatible USD cost calculation for known Claude models including cache read/write, web search requests, and Opus 4.6 fast-tier pricing.
88-
- Tool runtime now includes concurrency partitioning, ordered concurrent execution, interrupt behavior/defaults, max result size metadata, oversized result persistence, pre/post/permission-denied/permission-request hook dispatch, settings and local-plugin command-backed/HTTP hook execution for synchronous tool and conversation lifecycle hooks, hook-driven input updates/blocking/permission-request allow-deny, prompt/compact context injection, executor hook phase progress events, lifecycle progress events, retry/fallback model breadcrumbs, headless stream-json progress events, snake_case token warning NDJSON payloads, lightweight compact NDJSON metadata, and pre-call cancellation checks.
88+
- Tool runtime now includes concurrency partitioning, ordered concurrent execution, interrupt behavior/defaults, max result size metadata, oversized result persistence, pre/post/permission-denied/permission-request hook dispatch, settings and local-plugin command-backed/HTTP hook execution for synchronous tool and conversation lifecycle hooks, hook-driven input updates/blocking/permission-request allow-deny, prompt/compact context injection, executor hook phase progress events, lifecycle progress events, retry/fallback model breadcrumbs, final-result model attempt lists, headless stream-json progress events, snake_case token warning NDJSON payloads, lightweight compact NDJSON metadata, and pre-call cancellation checks.
8989
- Conversation runner can now use streaming clients, aggregate stream events into assistant messages, run tool calls through the orchestrator, preserve transcript append behavior, and apply CC-style per-message aggregate tool-result budget replacement before API requests with persisted replacement records for resume.
9090

9191
## Still Missing For 100% Compatibility

0 commit comments

Comments
 (0)