diff --git a/checkpoint.json b/checkpoint.json index be118698e..5179eee32 100644 --- a/checkpoint.json +++ b/checkpoint.json @@ -1,6 +1,6 @@ { - "timestamp": "2026-03-20T22:28:59.742896Z", - "current_node": "verify", + "timestamp": "2026-03-20T22:29:05.269650Z", + "current_node": "fmt", "completed_nodes": [ "start", "toolchain", @@ -9,7 +9,8 @@ "implement", "simplify_opus", "simplify_gpt", - "verify" + "verify", + "fmt" ], "node_retries": { "preflight_compile": 1, @@ -18,6 +19,7 @@ "toolchain": 1, "verify": 1, "preflight_lint": 1, + "fmt": 1, "implement": 1, "start": 1 }, @@ -27,18 +29,19 @@ "internal.fidelity": "compact", "thread.simplify_gpt.current_node": "verify", "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` to `Request` (after `reasoning_effort`, line ~454)\n- Add `speed: Option` 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` 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` 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` 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` 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", - "command.output": "────────────\n Nextest run ID 996a8d3a-c50f-47e9-a42c-4460e60f1bfe with nextest profile: default\n Starting 3279 tests across 41 binaries (177 tests skipped)\n────────────\n Summary [ 23.531s] 3279 tests run: 3279 passed, 177 skipped\n", + "command.output": "", "internal.retry_count.simplify_gpt": 1, + "internal.retry_count.fmt": 1, "internal.retry_count.simplify_opus": 1, "internal.retry_count.start": 1, "thread.preflight_compile.current_node": "preflight_lint", "internal.retry_count.preflight_compile": 1, - "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` to `Request` (after `reasoning_effort`, line ~454)\n- Add `speed: Option` 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` 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` 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` 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` 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\n## Completed stages\n- **toolchain**: success\n - Script: `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`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **preflight_lint**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **implement**: success\n - Model: claude-opus-4-6, 169.9k tokens in / 37.5k out\n - Files: /home/daytona/workspace/lib/crates/fabro-agent/src/compaction.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/config.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/session.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/tools.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/types.rs, /home/daytona/workspace/lib/crates/fabro-api/src/server.rs, /home/daytona/workspace/lib/crates/fabro-cli/src/doctor.rs, /home/daytona/workspace/lib/crates/fabro-graphviz/src/graph/types.rs, /home/daytona/workspace/lib/crates/fabro-hooks/src/executor.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/client.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/generate.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/anthropic.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/fabro_server.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/gemini.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/openai.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/openai_compatible.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/types.rs, /home/daytona/workspace/lib/crates/fabro-llm/tests/integration.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/backend/api.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/backend/cli.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/cost.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/event.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/outcome.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/preamble.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/stylesheet.rs, /home/daytona/workspace/lib/crates/fabro-workflows/tests/integration.rs\n- **simplify_opus**: success\n - Model: claude-opus-4-6, 38.3k tokens in / 8.3k out\n- **simplify_gpt**: fail\n\n## Context\n- failure_class: deterministic\n- failure_signature: simplify_gpt|deterministic|api_deterministic|openai|invalid_request\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` to `Request` (after `reasoning_effort`, line ~454)\n- Add `speed: Option` 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` 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` 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` 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` 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\n## Completed stages\n- **toolchain**: success\n - Script: `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`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **preflight_lint**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **implement**: success\n - Model: claude-opus-4-6, 169.9k tokens in / 37.5k out\n - Files: /home/daytona/workspace/lib/crates/fabro-agent/src/compaction.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/config.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/session.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/tools.rs, /home/daytona/workspace/lib/crates/fabro-agent/src/types.rs, /home/daytona/workspace/lib/crates/fabro-api/src/server.rs, /home/daytona/workspace/lib/crates/fabro-cli/src/doctor.rs, /home/daytona/workspace/lib/crates/fabro-graphviz/src/graph/types.rs, /home/daytona/workspace/lib/crates/fabro-hooks/src/executor.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/client.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/generate.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/anthropic.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/fabro_server.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/gemini.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/openai.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/providers/openai_compatible.rs, /home/daytona/workspace/lib/crates/fabro-llm/src/types.rs, /home/daytona/workspace/lib/crates/fabro-llm/tests/integration.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/backend/api.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/backend/cli.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/cost.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/event.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/outcome.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/preamble.rs, /home/daytona/workspace/lib/crates/fabro-workflows/src/stylesheet.rs, /home/daytona/workspace/lib/crates/fabro-workflows/tests/integration.rs\n- **simplify_opus**: success\n - Model: claude-opus-4-6, 38.3k tokens in / 8.3k out\n- **simplify_gpt**: fail\n- **verify**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1 && cargo nextest run --cargo-quiet --workspace --status-level fail 2>&1`\n - Stdout:\n ```\n ────────────\n Nextest run ID 996a8d3a-c50f-47e9-a42c-4460e60f1bfe with nextest profile: default\n Starting 3279 tests across 41 binaries (177 tests skipped)\n ────────────\n Summary [ 23.531s] 3279 tests run: 3279 passed, 177 skipped\n ```\n - Stderr: (empty)\n", "thread.toolchain.current_node": "preflight_compile", "outcome": "success", "internal.retry_count.toolchain": 1, "thread.preflight_lint.current_node": "implement", - "current_node": "verify", + "current_node": "fmt", "internal.node_visit_count": 1, "thread.simplify_opus.current_node": "simplify_gpt", "thread.start.current_node": "toolchain", @@ -52,12 +55,22 @@ "failure_class": "", "last_stage": "simplify_opus", "response.implement": "All verification passes. Let me summarize all the changes made:\n\n## Summary of Changes\n\n### 1. Foundation: `lib/crates/fabro-llm/src/types.rs`\n- Added `speed: Option` to `Request` struct (after `reasoning_effort`)\n- Added `speed: Option` to `Usage` struct (with `serde(default, skip_serializing_if)`, before `raw`)\n- Added `speed: self.speed` to `Usage::Add` impl (left-hand side wins)\n- Updated all test struct literals to include `speed: None`\n\n### 2. Graph layer: `lib/crates/fabro-graphviz/src/graph/types.rs`\n- Added `speed()` method to `Node` returning `Option<&str>` (no default, unlike `reasoning_effort` which defaults to \"high\")\n- Added `assert_eq!(node.speed(), None)` to `node_defaults` test\n\n### 3. Stylesheet: `lib/crates/fabro-workflows/src/stylesheet.rs`\n- Added `\"speed\"` to `STYLESHEET_PROPERTIES` array\n- Added `apply_speed_property` test\n\n### 4. Agent config: `lib/crates/fabro-agent/src/config.rs`\n- Added `pub speed: Option` to `SessionConfig`\n- Added `speed: None` to `Default` impl\n\n### 5. Session wiring: `lib/crates/fabro-agent/src/session.rs`\n- Added `speed: self.config.speed.clone()` to Request construction\n- Added `set_speed()` method\n\n### 6. Anthropic provider: `lib/crates/fabro-llm/src/providers/anthropic.rs`\n- **6a.** Added `speed: Option` to `ApiRequest` struct\n- **6b.** Added `FAST_MODE_BETA_HEADER` constant (`\"fast-mode-2026-02-01\"`)\n- **6c.** Extended `build_beta_header()` with `include_fast_mode_header: bool` parameter\n- **6d.** In `build_api_request()`: set `speed` on ApiRequest, compute `is_fast`, pass to `build_beta_header()`\n- **6e.** Added `speed: Option` to `ApiUsage` struct\n- **6f.** Map `api_resp.usage.speed` → `Usage.speed` in both non-streaming and streaming paths\n- Added 3 new tests: `build_api_request_sets_speed`, `build_api_request_injects_fast_mode_beta_header`, `beta_header_includes_both_cache_and_fast_mode`\n\n### 7. Usage tracking: `lib/crates/fabro-workflows/src/outcome.rs`\n- Added `speed: Option` to `StageUsage` (with `serde(default, skip_serializing_if)`)\n- Updated `From<&StageUsage> for Usage` to include `speed`\n\n### 8. Cost multiplier: `lib/crates/fabro-workflows/src/cost.rs`\n- Applied 6x multiplier when `speed == \"fast\"`\n- Added `compute_stage_cost_fast_mode_6x_multiplier` test\n\n### 9. Backend wiring: `lib/crates/fabro-workflows/src/backend/api.rs`\n- SessionConfig construction: added `speed: node.speed().map(String::from)`\n- Prompt-mode Request construction: added `speed: node.speed().map(String::from)`\n- Both StageUsage constructions: added `speed: response.usage.speed.clone()` / `total_usage.speed.clone()`\n\n### 10. Other files updated with `speed: None` in struct literals:\n- `fabro-agent/src/compaction.rs`, `fabro-agent/src/tools.rs`, `fabro-agent/src/types.rs`\n- `fabro-hooks/src/executor.rs`\n- `fabro-api/src/server.rs`\n- `fabro-cli/src/doctor.rs`\n- `fabro-llm/src/generate.rs` (also added `speed` to `GenerateParams`)\n- `fabro-llm/src/client.rs`, `fabro-llm/src/providers/fabro_server.rs`, `fabro-llm/src/providers/gemini.rs`, `fabro-llm/src/providers/openai.rs`, `fabro-llm/src/providers/openai_compatible.rs`\n- `fabro-workflows/src/backend/cli.rs`, `fabro-workflows/src/event.rs`, `fabro-workflows/src/preamble.rs`\n- `fabro-llm/tests/integration.rs`, `fabro-workflows/tests/integration.rs`", - "internal.thread_id": "simplify_gpt", + "thread.verify.current_node": "fmt", + "internal.thread_id": "verify", "graph.rankdir": "LR", "internal.retry_count.implement": 1 }, "logs": [], "node_outcomes": { + "fmt": { + "status": "success", + "context_updates": { + "command.output": "", + "command.stderr": "" + }, + "notes": "Script completed: cargo fmt --all 2>&1", + "duration_ms": 1435 + }, "preflight_lint": { "status": "success", "context_updates": { @@ -174,7 +187,7 @@ "duration_ms": 479380 } }, - "next_node_id": "fmt", + "next_node_id": "exit", "loop_failure_signatures": { "simplify_gpt|deterministic|api_deterministic|openai|invalid_request": 1 }, @@ -184,6 +197,7 @@ "implement": 1, "start": 1, "verify": 1, + "fmt": 1, "toolchain": 1, "preflight_lint": 1, "simplify_opus": 1 diff --git a/nodes/fmt/script_invocation.json b/nodes/fmt/script_invocation.json new file mode 100644 index 000000000..237863974 --- /dev/null +++ b/nodes/fmt/script_invocation.json @@ -0,0 +1,5 @@ +{ + "command": "cargo fmt --all 2>&1", + "language": "shell", + "timeout_ms": null +} \ No newline at end of file diff --git a/nodes/fmt/script_timing.json b/nodes/fmt/script_timing.json new file mode 100644 index 000000000..92c1d0e28 --- /dev/null +++ b/nodes/fmt/script_timing.json @@ -0,0 +1,5 @@ +{ + "duration_ms": 1432, + "exit_code": 0, + "timed_out": false +} \ No newline at end of file diff --git a/nodes/fmt/status.json b/nodes/fmt/status.json new file mode 100644 index 000000000..7f876267b --- /dev/null +++ b/nodes/fmt/status.json @@ -0,0 +1,6 @@ +{ + "status": "success", + "notes": "Script completed: cargo fmt --all 2>&1", + "failure_reason": null, + "timestamp": "2026-03-20T22:29:05.268921+00:00" +} \ No newline at end of file