checkpoint

⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
Fabro 2026-03-20 17:30:57 -04:00
parent f026885e56
commit 9734f2dc41
5 changed files with 74 additions and 0 deletions

52
checkpoint.json Normal file
View file

@ -0,0 +1,52 @@
{
"timestamp": "2026-03-20T21:30:57.855582Z",
"current_node": "toolchain",
"completed_nodes": [
"start",
"toolchain"
],
"node_retries": {
"start": 1,
"toolchain": 1
},
"context_values": {
"internal.thread_id": "start",
"current_node": "toolchain",
"graph.goal": "# Plan: Support Anthropic fast mode (`speed: fast`) — Issue #120\n\n## Context\n\nAnthropic's API supports [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) (beta) for Claude Opus 4.6 — up to 2.5x faster output at 6x pricing ($30/$150 per MTok vs $5/$25 standard). The API requires:\n- `\"speed\": \"fast\"` top-level field in request body\n- `anthropic-beta: fast-mode-2026-02-01` header\n- Response includes `usage.speed` confirming actual speed used\n\nThis follows the same pattern as `reasoning_effort`, which is already implemented end-to-end.\n\n## Implementation\n\n### 1. Foundation: `lib/crates/fabro-llm/src/types.rs`\n\n- Add `speed: Option<String>` to `Request` (after `reasoning_effort`, line ~454)\n- Add `speed: Option<String>` to `Usage` (before `raw`, line ~372)\n- In `Usage::Add` impl (line ~389): propagate `speed` from `self` (left-hand side wins, since all requests in a session use the same speed)\n\n### 2. Graph layer: `lib/crates/fabro-graphviz/src/graph/types.rs`\n\nAdd after `reasoning_effort()` (~line 211):\n```rust\n#[must_use]\npub fn speed(&self) -> Option<&str> {\n self.str_attr(\"speed\")\n}\n```\nReturns `Option` (no default) — unlike `reasoning_effort` which defaults to \"high\", speed defaults to None (standard) since fast mode is 6x cost.\n\n### 3. Stylesheet: `lib/crates/fabro-workflows/src/stylesheet.rs`\n\nAdd `\"speed\"` to `STYLESHEET_PROPERTIES` array (line 5):\n```rust\nconst STYLESHEET_PROPERTIES: &[&str] = &[\"model\", \"provider\", \"reasoning_effort\", \"speed\", \"backend\"];\n```\n\n### 4. Agent config: `lib/crates/fabro-agent/src/config.rs`\n\n- Add `pub speed: Option<String>` field to `SessionConfig` (line ~66)\n- Add `speed: None` to `Default` impl (line ~135)\n\n### 5. Session wiring: `lib/crates/fabro-agent/src/session.rs`\n\n- Add `speed: self.config.speed.clone()` to Request construction (~line 908)\n- Add `set_speed()` method analogous to `set_reasoning_effort()` (~line 458)\n\n### 6. Anthropic provider: `lib/crates/fabro-llm/src/providers/anthropic.rs`\n\n**6a. `ApiRequest` struct** (~line 87): Add `speed: Option<String>` field\n\n**6b. Beta header constant** (~line 510):\n```rust\nconst FAST_MODE_BETA_HEADER: &str = \"fast-mode-2026-02-01\";\n```\n\n**6c. `build_beta_header()`** (~line 582): Add `include_fast_mode_header: bool` parameter. Inject fast-mode header (same pattern as cache header).\n\n**6d. `build_api_request()`** (~line 1082):\n- Set `speed: request.speed.clone()` on `ApiRequest`\n- Compute `let is_fast = request.speed.as_deref() == Some(\"fast\")`\n- Pass `is_fast` to `build_beta_header()`\n\n**6e. `ApiUsage`** (~line 160): Add `speed: Option<String>` field\n\n**6f. Response parsing**: Map `api_resp.usage.speed` → `Usage.speed` in both:\n- Non-streaming path (~line 1192)\n- Streaming `message_start` handler (~line 690)\n\n### 7. Usage tracking: `lib/crates/fabro-workflows/src/outcome.rs`\n\n- Add `speed: Option<String>` to `StageUsage` (with `serde(default, skip_serializing_if)`)\n- Update `From<&StageUsage> for Usage` to include `speed`\n\n### 8. Cost multiplier: `lib/crates/fabro-workflows/src/cost.rs`\n\nApply 6x multiplier when `speed == \"fast\"`:\n```rust\nlet multiplier = if usage.speed.as_deref() == Some(\"fast\") { 6.0 } else { 1.0 };\n// Apply multiplier to final cost\n```\n\n### 9. Backend wiring: `lib/crates/fabro-workflows/src/backend/api.rs`\n\n- SessionConfig construction (~line 195): add `speed: node.speed().map(String::from)`\n- Prompt-mode Request construction (~line 285): add `speed: node.speed().map(String::from)`\n- Both StageUsage constructions (~lines 389, 589): add `speed: response.usage.speed.clone()` / `total_usage.speed.clone()`\n\n### 10. Tests\n\n- `anthropic.rs`: `build_api_request_sets_speed`, `build_api_request_injects_fast_mode_beta_header`, `beta_header_includes_both_cache_and_fast_mode`\n- `cost.rs`: `compute_stage_cost_fast_mode_6x_multiplier`\n- `stylesheet.rs`: `apply_speed_property`\n- `session.rs`: `set_speed_mid_session`\n- Update all existing struct literals (`Request`, `Usage`, `SessionConfig`, `StageUsage`, `ApiRequest`, `ApiUsage`) in tests to include `speed: None`\n\n## Implementation order\n\n1. `types.rs` (Request + Usage) — everything depends on this\n2. `graph/types.rs` + `stylesheet.rs` — graph layer\n3. `config.rs` + `session.rs` — agent layer\n4. `anthropic.rs` — provider (ApiRequest, beta header, response parsing)\n5. `outcome.rs` + `cost.rs` — usage tracking\n6. `backend/api.rs` — final wiring\n7. Tests throughout\n\n## Verification\n\n```\ncargo build --workspace\ncargo test --workspace\ncargo fmt --check --all\ncargo clippy --workspace -- -D warnings\n```\n",
"internal.node_visit_count": 1,
"thread.start.current_node": "toolchain",
"command.output": "cargo 1.94.0 (85eff7c80 2026-01-15)\n",
"failure_signature": "",
"internal.retry_count.start": 1,
"command.stderr": "",
"graph.model_stylesheet": "\n * { backend: api; model: claude-opus-4-6;}\n ",
"current.preamble": "Goal: # Plan: Support Anthropic fast mode (`speed: fast`) — Issue #120\n\n## Context\n\nAnthropic's API supports [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) (beta) for Claude Opus 4.6 — up to 2.5x faster output at 6x pricing ($30/$150 per MTok vs $5/$25 standard). The API requires:\n- `\"speed\": \"fast\"` top-level field in request body\n- `anthropic-beta: fast-mode-2026-02-01` header\n- Response includes `usage.speed` confirming actual speed used\n\nThis follows the same pattern as `reasoning_effort`, which is already implemented end-to-end.\n\n## Implementation\n\n### 1. Foundation: `lib/crates/fabro-llm/src/types.rs`\n\n- Add `speed: Option<String>` to `Request` (after `reasoning_effort`, line ~454)\n- Add `speed: Option<String>` to `Usage` (before `raw`, line ~372)\n- In `Usage::Add` impl (line ~389): propagate `speed` from `self` (left-hand side wins, since all requests in a session use the same speed)\n\n### 2. Graph layer: `lib/crates/fabro-graphviz/src/graph/types.rs`\n\nAdd after `reasoning_effort()` (~line 211):\n```rust\n#[must_use]\npub fn speed(&self) -> Option<&str> {\n self.str_attr(\"speed\")\n}\n```\nReturns `Option` (no default) — unlike `reasoning_effort` which defaults to \"high\", speed defaults to None (standard) since fast mode is 6x cost.\n\n### 3. Stylesheet: `lib/crates/fabro-workflows/src/stylesheet.rs`\n\nAdd `\"speed\"` to `STYLESHEET_PROPERTIES` array (line 5):\n```rust\nconst STYLESHEET_PROPERTIES: &[&str] = &[\"model\", \"provider\", \"reasoning_effort\", \"speed\", \"backend\"];\n```\n\n### 4. Agent config: `lib/crates/fabro-agent/src/config.rs`\n\n- Add `pub speed: Option<String>` field to `SessionConfig` (line ~66)\n- Add `speed: None` to `Default` impl (line ~135)\n\n### 5. Session wiring: `lib/crates/fabro-agent/src/session.rs`\n\n- Add `speed: self.config.speed.clone()` to Request construction (~line 908)\n- Add `set_speed()` method analogous to `set_reasoning_effort()` (~line 458)\n\n### 6. Anthropic provider: `lib/crates/fabro-llm/src/providers/anthropic.rs`\n\n**6a. `ApiRequest` struct** (~line 87): Add `speed: Option<String>` field\n\n**6b. Beta header constant** (~line 510):\n```rust\nconst FAST_MODE_BETA_HEADER: &str = \"fast-mode-2026-02-01\";\n```\n\n**6c. `build_beta_header()`** (~line 582): Add `include_fast_mode_header: bool` parameter. Inject fast-mode header (same pattern as cache header).\n\n**6d. `build_api_request()`** (~line 1082):\n- Set `speed: request.speed.clone()` on `ApiRequest`\n- Compute `let is_fast = request.speed.as_deref() == Some(\"fast\")`\n- Pass `is_fast` to `build_beta_header()`\n\n**6e. `ApiUsage`** (~line 160): Add `speed: Option<String>` field\n\n**6f. Response parsing**: Map `api_resp.usage.speed` → `Usage.speed` in both:\n- Non-streaming path (~line 1192)\n- Streaming `message_start` handler (~line 690)\n\n### 7. Usage tracking: `lib/crates/fabro-workflows/src/outcome.rs`\n\n- Add `speed: Option<String>` to `StageUsage` (with `serde(default, skip_serializing_if)`)\n- Update `From<&StageUsage> for Usage` to include `speed`\n\n### 8. Cost multiplier: `lib/crates/fabro-workflows/src/cost.rs`\n\nApply 6x multiplier when `speed == \"fast\"`:\n```rust\nlet multiplier = if usage.speed.as_deref() == Some(\"fast\") { 6.0 } else { 1.0 };\n// Apply multiplier to final cost\n```\n\n### 9. Backend wiring: `lib/crates/fabro-workflows/src/backend/api.rs`\n\n- SessionConfig construction (~line 195): add `speed: node.speed().map(String::from)`\n- Prompt-mode Request construction (~line 285): add `speed: node.speed().map(String::from)`\n- Both StageUsage constructions (~lines 389, 589): add `speed: response.usage.speed.clone()` / `total_usage.speed.clone()`\n\n### 10. Tests\n\n- `anthropic.rs`: `build_api_request_sets_speed`, `build_api_request_injects_fast_mode_beta_header`, `beta_header_includes_both_cache_and_fast_mode`\n- `cost.rs`: `compute_stage_cost_fast_mode_6x_multiplier`\n- `stylesheet.rs`: `apply_speed_property`\n- `session.rs`: `set_speed_mid_session`\n- Update all existing struct literals (`Request`, `Usage`, `SessionConfig`, `StageUsage`, `ApiRequest`, `ApiUsage`) in tests to include `speed: None`\n\n## Implementation order\n\n1. `types.rs` (Request + Usage) — everything depends on this\n2. `graph/types.rs` + `stylesheet.rs` — graph layer\n3. `config.rs` + `session.rs` — agent layer\n4. `anthropic.rs` — provider (ApiRequest, beta header, response parsing)\n5. `outcome.rs` + `cost.rs` — usage tracking\n6. `backend/api.rs` — final wiring\n7. Tests throughout\n\n## Verification\n\n```\ncargo build --workspace\ncargo test --workspace\ncargo fmt --check --all\ncargo clippy --workspace -- -D warnings\n```\n\n",
"failure_class": "",
"outcome": "success",
"internal.retry_count.toolchain": 1,
"graph.rankdir": "LR",
"internal.run_id": "01KM6JGQQDB57HD9DCDRGN4FSW",
"internal.fidelity": "compact"
},
"logs": [],
"node_outcomes": {
"start": {
"status": "success",
"duration_ms": 0
},
"toolchain": {
"status": "success",
"context_updates": {
"command.stderr": "",
"command.output": "cargo 1.94.0 (85eff7c80 2026-01-15)\n"
},
"notes": "Script completed: command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1",
"duration_ms": 218
}
},
"next_node_id": "preflight_compile",
"node_visits": {
"start": 1,
"toolchain": 1
}
}

6
nodes/start/status.json Normal file
View file

@ -0,0 +1,6 @@
{
"status": "success",
"notes": null,
"failure_reason": null,
"timestamp": "2026-03-20T21:30:57.634914+00:00"
}

View file

@ -0,0 +1,5 @@
{
"command": "command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1",
"language": "shell",
"timeout_ms": null
}

View file

@ -0,0 +1,5 @@
{
"duration_ms": 209,
"exit_code": 0,
"timed_out": false
}

View file

@ -0,0 +1,6 @@
{
"status": "success",
"notes": "Script completed: command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1",
"failure_reason": null,
"timestamp": "2026-03-20T21:30:57.854709+00:00"
}