mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-10 03:30:59 +00:00
parent
3db33e7609
commit
80c53a9111
5 changed files with 700 additions and 37 deletions
413
run.json
413
run.json
File diff suppressed because one or more lines are too long
114
stages/006-simplify_opus@1/diff.patch
Normal file
114
stages/006-simplify_opus@1/diff.patch
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
diff --git a/lib/crates/fabro-agent/src/context_window.rs b/lib/crates/fabro-agent/src/context_window.rs
|
||||
index 6d6923dae..ae2cdd343 100644
|
||||
--- a/lib/crates/fabro-agent/src/context_window.rs
|
||||
+++ b/lib/crates/fabro-agent/src/context_window.rs
|
||||
@@ -5,7 +5,7 @@ use fabro_llm::token_count::{
|
||||
estimate_message_tokens, estimate_request_control_tokens, estimate_text_tokens,
|
||||
estimate_tool_definition_tokens, is_local_estimator_warning,
|
||||
};
|
||||
-use fabro_llm::types::{Request, Role, Warning as LlmWarning};
|
||||
+use fabro_llm::types::{Request, Role, TokenCounts, Warning as LlmWarning};
|
||||
use fabro_types::{
|
||||
StageContextWindowBreakdownItem, StageContextWindowCategory, StageContextWindowCountMethod,
|
||||
StageContextWindowProjection, StageContextWindowStaleness, StageContextWindowWarning,
|
||||
@@ -115,8 +115,31 @@ const fn total_is_provider_authoritative(method: StageContextWindowCountMethod)
|
||||
)
|
||||
}
|
||||
|
||||
+/// Build a projection from a previously-computed local snapshot and the
|
||||
+/// token usage returned by the LLM response. If the response carried no
|
||||
+/// usable input tokens, fall back to the local estimate unchanged.
|
||||
#[must_use]
|
||||
-pub(crate) fn warnings_from_llm(warnings: &[LlmWarning]) -> Vec<StageContextWindowWarning> {
|
||||
+pub(crate) fn context_window_from_response_usage(
|
||||
+ local_snapshot: &StageContextWindowProjection,
|
||||
+ usage: &TokenCounts,
|
||||
+) -> StageContextWindowProjection {
|
||||
+ let input_tokens = usage
|
||||
+ .input_tokens
|
||||
+ .saturating_add(usage.cache_read_tokens)
|
||||
+ .saturating_add(usage.cache_write_tokens);
|
||||
+ if input_tokens <= 0 {
|
||||
+ return local_snapshot.clone();
|
||||
+ }
|
||||
+ scaled_snapshot(
|
||||
+ local_snapshot,
|
||||
+ u64::try_from(input_tokens).unwrap_or(u64::MAX),
|
||||
+ StageContextWindowCountMethod::ResponseUsageScaledBreakdown,
|
||||
+ local_snapshot.warnings.clone(),
|
||||
+ )
|
||||
+}
|
||||
+
|
||||
+#[must_use]
|
||||
+fn warnings_from_llm(warnings: &[LlmWarning]) -> Vec<StageContextWindowWarning> {
|
||||
warnings
|
||||
.iter()
|
||||
.map(|warning| StageContextWindowWarning {
|
||||
diff --git a/lib/crates/fabro-agent/src/session.rs b/lib/crates/fabro-agent/src/session.rs
|
||||
index e7fd25566..9b49059dd 100644
|
||||
--- a/lib/crates/fabro-agent/src/session.rs
|
||||
+++ b/lib/crates/fabro-agent/src/session.rs
|
||||
@@ -9,15 +9,15 @@ use fabro_llm::generate::StreamAccumulator;
|
||||
use fabro_llm::provider::StreamEventStream;
|
||||
use fabro_llm::types::{
|
||||
ContentPart, Message as LlmMessage, ReasoningEffort, Request, RetryPolicy, StreamEvent,
|
||||
- TokenCounts, ToolChoice,
|
||||
+ ToolChoice,
|
||||
};
|
||||
use fabro_llm::{Error as LlmError, retry};
|
||||
use fabro_mcp::config::{McpServerSettings, McpTransport};
|
||||
use fabro_mcp::connection_manager::McpConnectionManager;
|
||||
use fabro_model::{AgentProfileKind, Catalog, ModelRef, Speed};
|
||||
use fabro_types::{
|
||||
- PermissionLevel, Principal, SessionMessage, SessionRecord, StageContextWindowCountMethod,
|
||||
- StageContextWindowProjection, SteeringMessage,
|
||||
+ PermissionLevel, Principal, SessionMessage, SessionRecord, StageContextWindowProjection,
|
||||
+ SteeringMessage,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use tokio::sync::{Mutex as AsyncMutex, Notify, broadcast};
|
||||
@@ -28,7 +28,9 @@ use tracing::{debug, info, warn};
|
||||
use crate::agent_profile::AgentProfile;
|
||||
use crate::compaction::{check_context_usage, compact_context};
|
||||
use crate::config::SessionOptions;
|
||||
-use crate::context_window::{ContextWindowInput, build_local_snapshot, scaled_snapshot};
|
||||
+use crate::context_window::{
|
||||
+ ContextWindowInput, build_local_snapshot, context_window_from_response_usage,
|
||||
+};
|
||||
use crate::error::{Error, InterruptReason};
|
||||
use crate::event::Emitter;
|
||||
use crate::file_tracker::FileTracker;
|
||||
@@ -1898,25 +1900,6 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
-fn context_window_from_response_usage(
|
||||
- local_snapshot: &StageContextWindowProjection,
|
||||
- usage: &TokenCounts,
|
||||
-) -> StageContextWindowProjection {
|
||||
- let input_tokens = usage
|
||||
- .input_tokens
|
||||
- .saturating_add(usage.cache_read_tokens)
|
||||
- .saturating_add(usage.cache_write_tokens);
|
||||
- if input_tokens <= 0 {
|
||||
- return local_snapshot.clone();
|
||||
- }
|
||||
- scaled_snapshot(
|
||||
- local_snapshot,
|
||||
- u64::try_from(input_tokens).unwrap_or(u64::MAX),
|
||||
- StageContextWindowCountMethod::ResponseUsageScaledBreakdown,
|
||||
- local_snapshot.warnings.clone(),
|
||||
- )
|
||||
-}
|
||||
-
|
||||
const fn is_auth_error(err: &LlmError) -> bool {
|
||||
matches!(
|
||||
err.provider_kind(),
|
||||
@@ -1954,6 +1937,7 @@ mod tests {
|
||||
ContentPart, ReasoningEffort, Request, Response, Role, StreamEvent, TokenCounts, ToolCall,
|
||||
ToolDefinition,
|
||||
};
|
||||
+ use fabro_types::StageContextWindowCountMethod;
|
||||
use futures::stream;
|
||||
use tokio::time::{sleep, timeout};
|
||||
|
||||
6
stages/006-simplify_opus@1/status.json
Normal file
6
stages/006-simplify_opus@1/status.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"outcome": "succeeded",
|
||||
"notes": "Stage completed: simplify_opus",
|
||||
"failure_reason": null,
|
||||
"timestamp": "2026-05-24T18:12:11.657608Z"
|
||||
}
|
||||
199
stages/007-simplify_gpt@1/prompt.md
Normal file
199
stages/007-simplify_gpt@1/prompt.md
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
Goal: # Fold Context Window Into Agent Messages Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Remove the chatty `agent.context_window.snapshot` event and persist context-window data through existing `agent.message` events.
|
||||
|
||||
**Architecture:** Compute the context-window breakdown locally while the agent still has the exact request, attach the final content-free projection to the next `agent.message`, and let the run projection reducer store that latest projection for `GET /runs/{id}/stages/{stageId}/context-window`. Do not call provider token-count APIs during normal execution.
|
||||
|
||||
**Tech Stack:** Rust, Serde, Fabro agent/session events, Fabro workflow event conversion, Fabro store projections, OpenAPI/progenitor, generated TypeScript client, React/SWR.
|
||||
|
||||
---
|
||||
|
||||
## Scope And Decisions
|
||||
|
||||
- Remove `agent.context_window.snapshot` completely from new code. This is a greenfield/no-prod app, so do not preserve backward-compatible deserialization or frontend handling for old snapshot events.
|
||||
- Keep `StageContextWindowProjection`, `StageContextWindow`, `StageProjection.context_window`, and the existing context-window GET endpoint.
|
||||
- Add optional `context_window` data to `agent.message` properties.
|
||||
- Normal execution uses only local estimates and token usage returned by normal LLM responses.
|
||||
- Do not call `Client::count_input_tokens` from `fabro-agent::Session`.
|
||||
- The GET endpoint remains projection-backed for this pass. It must not require an in-memory session and must not trigger provider token-count API calls.
|
||||
- Failed-before-response turns do not persist context-window data.
|
||||
- Live pre-response context-window updates are not required. The UI updates after `agent.message`.
|
||||
|
||||
## File Map
|
||||
|
||||
- Modify `lib/crates/fabro-types/src/run_event/agent.rs`
|
||||
- Add `context_window: Option<StageContextWindowProjection>` to `AgentMessageProps`.
|
||||
- Remove `AgentContextWindowSnapshotProps`.
|
||||
- Modify `lib/crates/fabro-types/src/run_event/mod.rs`
|
||||
- Remove the `AgentContextWindowSnapshot` event variant, name mapping, known-event entry, and serde tests.
|
||||
- Update `agent.message` serde tests to cover optional context-window data.
|
||||
- Modify `lib/crates/fabro-agent/src/types.rs`
|
||||
- Remove `AgentEvent::ContextWindowSnapshot`.
|
||||
- Add `context_window: Option<StageContextWindowProjection>` to `AgentEvent::AssistantMessage`.
|
||||
- Modify `lib/crates/fabro-agent/src/session.rs`
|
||||
- Remove async provider-count task and response-usage snapshot event emission.
|
||||
- Keep local context-window snapshot construction at request-build time.
|
||||
- Attach the scaled or local projection to `AssistantMessage`.
|
||||
- Keep `lib/crates/fabro-agent/src/context_window.rs`
|
||||
- Reuse `build_local_snapshot` and `scaled_snapshot`.
|
||||
- Remove only tests or helpers that exist solely for provider-count snapshot emission.
|
||||
- Modify `lib/crates/fabro-workflow/src/event/convert.rs`
|
||||
- Remove conversion for `AgentEvent::ContextWindowSnapshot`.
|
||||
- Copy `context_window` from `AgentEvent::AssistantMessage` into `AgentMessageProps`.
|
||||
- Modify `lib/crates/fabro-workflow/src/event/names.rs`
|
||||
- Remove the snapshot event name.
|
||||
- Modify `lib/crates/fabro-store/src/run_state.rs`
|
||||
- Remove reducer support for `EventBody::AgentContextWindowSnapshot`.
|
||||
- When reducing `EventBody::AgentMessage`, copy `props.context_window` into `stage.context_window` when present and stamp `event_seq`.
|
||||
- Modify `lib/crates/fabro-server/src/server/tests.rs`
|
||||
- Seed context-window endpoint tests with `agent.message` events that include context-window data.
|
||||
- Modify `docs/public/api-reference/fabro-api.yaml`
|
||||
- Add optional `context_window` to `AgentMessageProps`.
|
||||
- Remove the snapshot event schema/variant.
|
||||
- Regenerate/update `lib/packages/fabro-api-client/src`.
|
||||
- Modify `apps/fabro-web/app/lib/run-events.ts` and tests
|
||||
- Remove special handling for `agent.context_window.snapshot`.
|
||||
- Rely on existing `agent.message` invalidation for stage events and context-window data.
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
### Task 1: Move The Event Contract Onto `agent.message`
|
||||
|
||||
- [ ] Add optional `context_window` to Rust `AgentMessageProps`.
|
||||
- [ ] Remove `AgentContextWindowSnapshotProps` and the `agent.context_window.snapshot` `EventBody` variant.
|
||||
- [ ] Update run-event serde tests so `agent.message` round-trips with and without `context_window`.
|
||||
- [ ] Remove tests whose only assertion is that `agent.context_window.snapshot` is known or serializes.
|
||||
|
||||
### Task 2: Stop Emitting Snapshot Events
|
||||
|
||||
- [ ] Remove `AgentEvent::ContextWindowSnapshot` and its trace/debug handling.
|
||||
- [ ] Change `AgentEvent::AssistantMessage` to carry `context_window: Option<StageContextWindowProjection>`.
|
||||
- [ ] In `Session::run_single_input`, keep the local context-window snapshot returned from request construction.
|
||||
- [ ] Delete the spawned `count_input_tokens(... PreferProvider)` task and its fingerprint suppression state.
|
||||
- [ ] After the normal LLM response arrives, compute:
|
||||
- `ResponseUsageScaledBreakdown` when response input/cache usage is positive.
|
||||
- `LocalEstimate` when response usage has no usable input tokens.
|
||||
- [ ] Attach that projection to the emitted `AssistantMessage`.
|
||||
|
||||
### Task 3: Update Workflow Conversion And Store Projection
|
||||
|
||||
- [ ] Remove snapshot event name/conversion branches.
|
||||
- [ ] Include `context_window` when converting `AgentEvent::AssistantMessage` to `EventBody::AgentMessage`.
|
||||
- [ ] In the store reducer, update `stage.context_window` from `AgentMessageProps.context_window`.
|
||||
- [ ] Stamp the copied projection with the `agent.message` event sequence.
|
||||
- [ ] Replace store tests for snapshot replacement with message-carried context-window tests.
|
||||
|
||||
### Task 4: Keep The GET Endpoint Projection-Backed
|
||||
|
||||
- [ ] Keep the endpoint route and response type unchanged.
|
||||
- [ ] Keep existing `not_agent_stage`, `not_observed`, and terminal `stored` behavior.
|
||||
- [ ] Update endpoint tests to seed context-window data via `agent.message`.
|
||||
- [ ] Do not add endpoint-time provider token-count calls.
|
||||
|
||||
### Task 5: Remove Frontend And API Trace
|
||||
|
||||
- [ ] Remove frontend constants/tests for `agent.context_window.snapshot`.
|
||||
- [ ] Ensure `agent.message` still invalidates `stageContextWindow` through existing stage activity handling.
|
||||
- [ ] Update OpenAPI and regenerated TypeScript client so no snapshot event model remains.
|
||||
- [ ] Run a final search for `agent.context_window.snapshot`, `AgentContextWindowSnapshot`, and `ContextWindowSnapshot`; only historical docs or this plan may remain.
|
||||
|
||||
## Test Plan
|
||||
|
||||
- Run `cargo build -p fabro-api` after OpenAPI/Rust type changes.
|
||||
- Run targeted Rust tests:
|
||||
- `cargo nextest run -p fabro-agent`
|
||||
- `cargo nextest run -p fabro-workflow`
|
||||
- `cargo nextest run -p fabro-store`
|
||||
- `cargo nextest run -p fabro-server get_run_stage_context_window`
|
||||
- `cargo nextest run -p fabro-types agent_message`
|
||||
- Regenerate TypeScript client with `cd lib/packages/fabro-api-client && bun run generate`.
|
||||
- Run web checks:
|
||||
- `cd apps/fabro-web && bun test`
|
||||
- `cd apps/fabro-web && bun run typecheck`
|
||||
- `cd lib/packages/fabro-api-client && bun run typecheck`
|
||||
- Run final targeted searches:
|
||||
- `rg -n "agent\\.context_window\\.snapshot|AgentContextWindowSnapshot|ContextWindowSnapshot" lib/crates apps/fabro-web lib/packages docs/public/api-reference/fabro-api.yaml`
|
||||
- Expected: no implementation/API/frontend matches.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- Normal agent runs do not emit `agent.context_window.snapshot`.
|
||||
- Normal agent runs do not call provider token-count endpoints for context-window reporting.
|
||||
- `agent.message` includes context-window data when the agent produced a response.
|
||||
- `GET /runs/{id}/stages/{stageId}/context-window` still returns the latest context-window projection.
|
||||
- The event log contains no standalone context-window snapshot events.
|
||||
- Public API/client/types no longer expose `agent.context_window.snapshot`.
|
||||
|
||||
|
||||
## Completed stages
|
||||
- **toolchain**: succeeded
|
||||
- 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`
|
||||
- Output:
|
||||
```
|
||||
cargo 1.95.0 (f2d3ce0bd 2026-03-21)
|
||||
```
|
||||
- **preflight_compile**: succeeded
|
||||
- Script: `cargo check -q --workspace 2>&1`
|
||||
- Output: (empty)
|
||||
- **preflight_lint**: succeeded
|
||||
- Script: `cargo +nightly-2026-04-14 clippy -q --workspace --all-targets -- -D warnings 2>&1`
|
||||
- Output: (empty)
|
||||
- **implement**: succeeded
|
||||
- Model: gpt-5.5, 6.5m tokens in / 33.3k out
|
||||
- **simplify_opus**: succeeded
|
||||
- Model: claude-opus-4-7, 67.8k tokens in / 15.7k out
|
||||
- Files: /home/daytona/workspace/fabro/lib/crates/fabro-agent/src/context_window.rs, /home/daytona/workspace/fabro/lib/crates/fabro-agent/src/session.rs
|
||||
|
||||
|
||||
# Simplify: Code Review and Cleanup
|
||||
|
||||
Review changes vs. origin for reuse, quality, and efficiency. Fix any issues found.
|
||||
|
||||
## Phase 1: Identify Changes
|
||||
|
||||
Run git diff (or git diff HEAD if there are staged changes) to see what changed. If there are no git changes, review the most recently modified files that the user mentioned or that you edited earlier in this conversation.
|
||||
|
||||
## Phase 2: Launch Three Review Agents in Parallel
|
||||
|
||||
Use the Agent tool to launch all three agents concurrently in a single message. Pass each agent the full diff so it has the complete context.
|
||||
|
||||
### Agent 1: Code Reuse Review
|
||||
|
||||
For each change:
|
||||
|
||||
1. Search for existing utilities and helpers that could replace newly written code. Use Grep to find similar patterns elsewhere in the codebase — common locations are utility directories, shared modules, and files adjacent to the changed ones.
|
||||
2. Flag any new function that duplicates existing functionality. Suggest the existing function to use instead.
|
||||
3. Flag any inline logic that could use an existing utility — hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns are common candidates.
|
||||
|
||||
Note: This is a greenfield app, so focus on maximizing simplicity and don't worry about changing things to achieve it.
|
||||
|
||||
### Agent 2: Code Quality Review
|
||||
|
||||
Review the same changes for hacky patterns:
|
||||
|
||||
1. Redundant state: state that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls
|
||||
2. Parameter sprawl: adding new parameters to a function instead of generalizing or restructuring existing ones
|
||||
3. Copy-paste with slight variation: near-duplicate code blocks that should be unified with a shared abstraction
|
||||
4. Leaky abstractions: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries
|
||||
5. Stringly-typed code: using raw strings where constants, enums (string unions), or branded types already exist in the codebase
|
||||
|
||||
Note: This is a greenfield app, so be aggressive in optimizing quality.
|
||||
|
||||
### Agent 3: Efficiency Review
|
||||
|
||||
Review the same changes for efficiency:
|
||||
|
||||
1. Unnecessary work: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns
|
||||
2. Missed concurrency: independent operations run sequentially when they could run in parallel
|
||||
3. Hot-path bloat: new blocking work added to startup or per-request/per-render hot paths
|
||||
4. Unnecessary existence checks: pre-checking file/resource existence before operating (TOCTOU anti-pattern) — operate directly and handle the error
|
||||
5. Memory: unbounded data structures, missing cleanup, event listener leaks
|
||||
6. Overly broad operations: reading entire files when only a portion is needed, loading all items when filtering for one
|
||||
|
||||
## Phase 3: Fix Issues
|
||||
|
||||
Wait for all three agents to complete. Aggregate their findings and fix each issue directly. If a finding is a false positive or not worth addressing, note it and move on — do not argue with the finding, just skip it.
|
||||
|
||||
When done, briefly summarize what was fixed (or confirm the code was already clean).
|
||||
5
stages/007-simplify_gpt@1/provider_used.json
Normal file
5
stages/007-simplify_gpt@1/provider_used.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mode": "agent",
|
||||
"provider": "openai",
|
||||
"model": "gpt-5.5"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue