40 lines
4.3 KiB
Markdown
40 lines
4.3 KiB
Markdown
# 报错 `missing_credentials` 调用链及业务逻辑分析
|
||
|
||
当运行 `cargo run --package rusty-claude-cli --bin claw` 时,如果没有配置相应的环境变量,会报 `[error-kind: missing_credentials]` 错误。以下是完整的调用链及业务逻辑分析:
|
||
|
||
## 1. 调用链 (Call Chain)
|
||
|
||
1. **`rusty-claude-cli/src/main.rs:202`**: `main()` 函数作为入口,调用 `run()`。
|
||
2. **`rusty-claude-cli/src/main.rs:335`**: `run()` 函数解析命令行参数。如果匹配到需要与模型交互的动作(如 `Prompt` 或 `Repl`),则调用 `LiveCli::new(...)` 实例化客户端。
|
||
|
||
3. **`rusty-claude-cli/src/main.rs:4134`**: `LiveCli::new()` 内部调用 `build_runtime(...)` 构建会话运行时。
|
||
4. **`rusty-claude-cli/src/main.rs:7252`**: `build_runtime()` 调用 `build_runtime_with_plugin_state(...)`。
|
||
5. **`rusty-claude-cli/src/main.rs:7280`**: `build_runtime_with_plugin_state()` 中实例化 `AnthropicRuntimeClient::new(...)` 以创建 API 提供商客户端。
|
||
6. **`rusty-claude-cli/src/main.rs:7433`**: `AnthropicRuntimeClient::new()` 会在匹配到 `ProviderKind::Anthropic`(默认)时,调用 `resolve_cli_auth_source()`。
|
||
7. **`rusty-claude-cli/src/main.rs:7504`**: `resolve_cli_auth_source()` 调用内部函数 `resolve_cli_auth_source_for_cwd()`。
|
||
8. **`rusty-claude-cli/src/main.rs:7508`**: `resolve_cli_auth_source_for_cwd()` 跨 crate 调用 `api::resolve_startup_auth_source(|| Ok(None))`。
|
||
9. **`api/src/providers/anthropic.rs:656`**: `resolve_startup_auth_source()` 尝试从环境变量或 `.env` 文件中读取 `ANTHROPIC_API_KEY` 和 `ANTHROPIC_AUTH_TOKEN`。
|
||
10. **`api/src/providers/mod.rs:394`**: 如果上述两个环境变量均不存在,调用 `anthropic_missing_credentials()` 并返回 `Err`。
|
||
11. **错误向上冒泡**: `Err` 通过 `?` 操作符层层冒泡,最终被 `main()` 函数捕获。
|
||
12. **`rusty-claude-cli/src/main.rs:202`**: `main()` 函数捕获错误后,调用 `classify_error_kind(&message)` 将错误归类为 `"missing_credentials"`,然后将格式化后的错误 `[error-kind: missing_credentials]` 打印到终端并退出。
|
||
|
||
## 2. 业务逻辑 (Business Logic)
|
||
|
||
**前置校验(Fail-Fast)**
|
||
Claw 命令行工具的设计采用了“快速失败(Fail-Fast)”的策略。在进入 REPL(交互式命令行)或处理 Prompt 之前,它必须确保有权访问大模型 API(默认是 Anthropic)。因此,在构建核心的 `ConversationRuntime` 和 API Client 阶段,它会主动(eagerly)去检测鉴权凭证是否存在。
|
||
|
||
这样做的好处是避免了用户可能输入了一大段 Prompt 或者开启了会话后,在实际发起 HTTP 请求时才报错,提供了更好的用户体验。
|
||
|
||
**鉴权方式的优先级**
|
||
在 `resolve_startup_auth_source` 的逻辑中:
|
||
- 优先检查 `ANTHROPIC_API_KEY`。如果存在,还会进一步检查是否有 `ANTHROPIC_AUTH_TOKEN`,如果有则组成 `ApiKeyAndBearer`,否则仅使用 `ApiKey`。
|
||
- 如果没有 `API_KEY`,则检查是否有 `ANTHROPIC_AUTH_TOKEN`,如果有则使用 `BearerToken` 方式。
|
||
- 如果二者都读取不到(无论从系统环境变量还是当前目录的 `.env` 文件),则直接抛出凭证缺失错误。
|
||
|
||
## 3. 其他修改/绕过方式的可能思路
|
||
|
||
如果你不想直接在系统中配置环境变量,基于上述代码逻辑,有以下几种替代方案:
|
||
1. **使用 `.env` 文件**:底层 `read_env_non_empty` 函数会 fallback 到 `super::dotenv_value(key)`,这意味着你可以在项目运行目录(如 `rust/crates/rusty-claude-cli` 或 Workspace 根目录)创建一个 `.env` 文件,在里面写上 `ANTHROPIC_API_KEY=xxx`,程序也能读取到。
|
||
2. **切换 Provider / Model**:`AnthropicRuntimeClient::new()` 内部通过 `detect_provider_kind(&resolved_model)` 进行路由。如果在启动时传入 `--model openai/gpt-4` 或者通过 `.claw.json` 配置了其他模型(如 OpenAI、xAI 等),程序会进入其他的 Client 初始化分支,从而绕过针对 Anthropic 环境变量的强校验(当然,它会转而去校验相应提供商的环境变量,如 `OPENAI_API_KEY`)。
|
||
3. **Mock Server 测试模式**:在测试用例中,代码会读取 `ANTHROPIC_BASE_URL` 指向本地 Mock 服务器。如果你在做纯离线开发,也许可以考虑走测试桩(Mock)的逻辑,但这通常只在单元测试(如 `tests/compact_output.rs`)中适用。
|