From 9734f2dc417ce76a2213475cdade9f094a39e311 Mon Sep 17 00:00:00 2001 From: Fabro Date: Fri, 20 Mar 2026 17:30:57 -0400 Subject: [PATCH] checkpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚒️ Generated with [Fabro](https://fabro.sh) --- checkpoint.json | 52 ++++++++++++++++++++++++++ nodes/start/status.json | 6 +++ nodes/toolchain/script_invocation.json | 5 +++ nodes/toolchain/script_timing.json | 5 +++ nodes/toolchain/status.json | 6 +++ 5 files changed, 74 insertions(+) create mode 100644 checkpoint.json create mode 100644 nodes/start/status.json create mode 100644 nodes/toolchain/script_invocation.json create mode 100644 nodes/toolchain/script_timing.json create mode 100644 nodes/toolchain/status.json diff --git a/checkpoint.json b/checkpoint.json new file mode 100644 index 000000000..a50ebda53 --- /dev/null +++ b/checkpoint.json @@ -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` 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", + "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` 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", + "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 + } +} \ No newline at end of file diff --git a/nodes/start/status.json b/nodes/start/status.json new file mode 100644 index 000000000..9a765f8f0 --- /dev/null +++ b/nodes/start/status.json @@ -0,0 +1,6 @@ +{ + "status": "success", + "notes": null, + "failure_reason": null, + "timestamp": "2026-03-20T21:30:57.634914+00:00" +} \ No newline at end of file diff --git a/nodes/toolchain/script_invocation.json b/nodes/toolchain/script_invocation.json new file mode 100644 index 000000000..d68c414c4 --- /dev/null +++ b/nodes/toolchain/script_invocation.json @@ -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 +} \ No newline at end of file diff --git a/nodes/toolchain/script_timing.json b/nodes/toolchain/script_timing.json new file mode 100644 index 000000000..20a7816c9 --- /dev/null +++ b/nodes/toolchain/script_timing.json @@ -0,0 +1,5 @@ +{ + "duration_ms": 209, + "exit_code": 0, + "timed_out": false +} \ No newline at end of file diff --git a/nodes/toolchain/status.json b/nodes/toolchain/status.json new file mode 100644 index 000000000..94f7d69a4 --- /dev/null +++ b/nodes/toolchain/status.json @@ -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" +} \ No newline at end of file