checkpoint

⚒️ Generated with [Fabro](https://fabro.sh)
This commit is contained in:
Fabro 2026-05-23 17:44:15 -04:00
parent 86ef1dd6e2
commit 2756a039ca
4 changed files with 634 additions and 97 deletions

463
run.json

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,257 @@
diff --git a/apps/fabro-web/app/lib/query-keys.test.ts b/apps/fabro-web/app/lib/query-keys.test.ts
index 4ac4f438e..914f3b11f 100644
--- a/apps/fabro-web/app/lib/query-keys.test.ts
+++ b/apps/fabro-web/app/lib/query-keys.test.ts
@@ -69,13 +69,14 @@ describe("queryKeys", () => {
queryKeys.runs.graph("run-1", "TB"),
queryKeys.runs.detail("run-1"),
queryKeys.runs.stageEvents("run-1", "stage-1"),
+ queryKeys.runs.stageContextWindow("run-1", "stage-1"),
]);
expect(queryKeysForRunEvent("run-1", "run.title.updated")).toEqual([
queryKeys.runs.detail("run-1"),
]);
});
- test("agent activity events invalidate the per-stage events key", () => {
+ test("agent activity events invalidate per-stage resources", () => {
for (const event of [
"stage.prompt",
"agent.message",
@@ -86,6 +87,7 @@ describe("queryKeys", () => {
]) {
expect(queryKeysForRunEvent("run-1", event, "stage-1")).toEqual([
queryKeys.runs.stageEvents("run-1", "stage-1"),
+ queryKeys.runs.stageContextWindow("run-1", "stage-1"),
]);
}
});
diff --git a/apps/fabro-web/app/lib/run-events.test.tsx b/apps/fabro-web/app/lib/run-events.test.tsx
index 141826e41..0a33cc3d5 100644
--- a/apps/fabro-web/app/lib/run-events.test.tsx
+++ b/apps/fabro-web/app/lib/run-events.test.tsx
@@ -52,7 +52,7 @@ describe("queryKeysForRunEvent", () => {
]);
});
- test("stage.retrying invalidates stages, billing, events, graph, detail, and stage events", () => {
+ test("stage.retrying invalidates stage-scoped and run-scoped resources", () => {
expect(queryKeysForRunEvent("run-1", "stage.retrying", "verify@2")).toEqual([
queryKeys.runs.stages("run-1"),
queryKeys.runs.billing("run-1"),
@@ -61,29 +61,34 @@ describe("queryKeysForRunEvent", () => {
queryKeys.runs.graph("run-1", "TB"),
queryKeys.runs.detail("run-1"),
queryKeys.runs.stageEvents("run-1", "verify@2"),
+ queryKeys.runs.stageContextWindow("run-1", "verify@2"),
]);
});
- test("stage-scoped steering events invalidate run events and stage events", () => {
+ test("stage-scoped steering events invalidate run events and stage-scoped resources", () => {
expect(queryKeysForRunEvent("run-1", "agent.session.activated", "agent@1")).toEqual([
queryKeys.runs.events("run-1", 1000),
queryKeys.runs.stageEvents("run-1", "agent@1"),
+ queryKeys.runs.stageContextWindow("run-1", "agent@1"),
]);
});
- test("stage-scoped interrupt injection invalidates run events and stage events", () => {
+ test("stage-scoped interrupt injection invalidates run events and stage-scoped resources", () => {
expect(queryKeysForRunEvent("run-1", "agent.interrupt.injected", "nap@1")).toEqual([
queryKeys.runs.events("run-1", 1000),
queryKeys.runs.stageEvents("run-1", "nap@1"),
+ queryKeys.runs.stageContextWindow("run-1", "nap@1"),
]);
});
- test("pair messages invalidate the stage events query", () => {
+ test("pair messages invalidate stage-scoped resources", () => {
expect(queryKeysForRunEvent("run-1", "agent.pair.user_message", "nap@1")).toEqual([
queryKeys.runs.stageEvents("run-1", "nap@1"),
+ queryKeys.runs.stageContextWindow("run-1", "nap@1"),
]);
expect(queryKeysForRunEvent("run-1", "agent.pair.system_message", "nap@1")).toEqual([
queryKeys.runs.stageEvents("run-1", "nap@1"),
+ queryKeys.runs.stageContextWindow("run-1", "nap@1"),
]);
});
diff --git a/apps/fabro-web/app/lib/run-events.ts b/apps/fabro-web/app/lib/run-events.ts
index 70bacc7d7..c88c76341 100644
--- a/apps/fabro-web/app/lib/run-events.ts
+++ b/apps/fabro-web/app/lib/run-events.ts
@@ -155,6 +155,7 @@ export function queryKeysForRunEvent(
];
if (stageId) {
keys.push(queryKeys.runs.stageEvents(runId, stageId));
+ keys.push(queryKeys.runs.stageContextWindow(runId, stageId));
}
return keys;
}
@@ -163,6 +164,7 @@ export function queryKeysForRunEvent(
const keys: Key[] = [queryKeys.runs.events(runId, 1000)];
if (stageId) {
keys.push(queryKeys.runs.stageEvents(runId, stageId));
+ keys.push(queryKeys.runs.stageContextWindow(runId, stageId));
}
return keys;
}
@@ -177,7 +179,12 @@ export function queryKeysForRunEvent(
}
if (STAGE_ACTIVITY_EVENTS.has(event)) {
- return stageId ? [queryKeys.runs.stageEvents(runId, stageId)] : [];
+ return stageId
+ ? [
+ queryKeys.runs.stageEvents(runId, stageId),
+ queryKeys.runs.stageContextWindow(runId, stageId),
+ ]
+ : [];
}
if (TODO_EVENTS.has(event)) {
diff --git a/lib/crates/fabro-agent/src/session.rs b/lib/crates/fabro-agent/src/session.rs
index 5ad7824a7..4f7cd9ccf 100644
--- a/lib/crates/fabro-agent/src/session.rs
+++ b/lib/crates/fabro-agent/src/session.rs
@@ -17,7 +17,9 @@ 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::{Principal, SessionMessage, SessionRecord, SteeringMessage};
+use fabro_types::{
+ Principal, SessionMessage, SessionRecord, StageContextWindowProjection, SteeringMessage,
+};
use futures::StreamExt;
use tokio::sync::{Mutex as AsyncMutex, Notify, broadcast};
use tokio::time;
@@ -306,6 +308,11 @@ struct BuiltRequest {
tools: Vec<ToolDefinitionWithSource>,
}
+struct EmittedContextWindowSnapshot {
+ local_snapshot: StageContextWindowProjection,
+ fingerprint: Option<u64>,
+}
+
pub struct Session {
id: String,
/// Root agent session ID for this session's agent tree. A root session
@@ -333,6 +340,7 @@ pub struct Session {
system_prompt: String,
activated_skill_context_observed: bool,
context_window_counted_fingerprints: HashSet<u64>,
+ context_window_response_usage_fingerprints: Arc<Mutex<HashSet<u64>>>,
file_tracker: FileTracker,
tool_env_provider: Option<Arc<dyn ToolEnvProvider>>,
subagent_manager: Option<Arc<AsyncMutex<SubAgentManager>>>,
@@ -372,6 +380,7 @@ impl Session {
system_prompt: String::new(),
activated_skill_context_observed: false,
context_window_counted_fingerprints: HashSet::new(),
+ context_window_response_usage_fingerprints: Arc::new(Mutex::new(HashSet::new())),
file_tracker: FileTracker::default(),
tool_env_provider: None,
subagent_manager,
@@ -1591,9 +1600,7 @@ impl Session {
.cloned()
.collect();
let usage = response.usage.clone();
- if let Some(local_snapshot) = context_window_snapshot.as_ref() {
- self.emit_response_usage_context_window_snapshot(local_snapshot, &usage);
- }
+ self.emit_response_usage_context_window_snapshot(&context_window_snapshot, &usage);
self.history.push(Message::Assistant {
content: text.clone(),
@@ -1727,7 +1734,7 @@ impl Session {
fn emit_context_window_snapshots(
&mut self,
built_request: &BuiltRequest,
- ) -> Option<fabro_types::StageContextWindowProjection> {
+ ) -> EmittedContextWindowSnapshot {
let provider = self.provider_profile.provider_id().to_string();
let model = self.provider_profile.model().to_string();
let local_snapshot = build_local_snapshot(ContextWindowSnapshotInput {
@@ -1746,9 +1753,17 @@ impl Session {
AgentEvent::ContextWindowSnapshot(local_snapshot.clone()),
);
- let fingerprint = request_fingerprint(&built_request.request)?;
+ let Some(fingerprint) = request_fingerprint(&built_request.request) else {
+ return EmittedContextWindowSnapshot {
+ local_snapshot,
+ fingerprint: None,
+ };
+ };
if !self.context_window_counted_fingerprints.insert(fingerprint) {
- return Some(local_snapshot);
+ return EmittedContextWindowSnapshot {
+ local_snapshot,
+ fingerprint: Some(fingerprint),
+ };
}
let client = self.llm_client.clone();
@@ -1757,6 +1772,8 @@ impl Session {
let emitter = self.event_emitter.clone();
let local_for_count = local_snapshot.clone();
let close_token = self.close_token.clone();
+ let response_usage_fingerprints =
+ Arc::clone(&self.context_window_response_usage_fingerprints);
tokio::spawn(async move {
let count_result = tokio::select! {
biased;
@@ -1766,6 +1783,13 @@ impl Session {
if close_token.is_cancelled() {
return;
}
+ if response_usage_fingerprints
+ .lock()
+ .expect("context window response-usage fingerprint lock poisoned")
+ .contains(&fingerprint)
+ {
+ return;
+ }
let snapshot = match count_result {
Ok(count) if count.method == InputTokenCountMethod::ProviderApi => {
let input_tokens = u64::try_from(count.input_tokens.max(0)).unwrap_or(u64::MAX);
@@ -1801,12 +1825,15 @@ impl Session {
emitter.emit(session_id, AgentEvent::ContextWindowSnapshot(snapshot));
});
- Some(local_snapshot)
+ EmittedContextWindowSnapshot {
+ local_snapshot,
+ fingerprint: Some(fingerprint),
+ }
}
fn emit_response_usage_context_window_snapshot(
&self,
- local_snapshot: &fabro_types::StageContextWindowProjection,
+ context_window_snapshot: &EmittedContextWindowSnapshot,
usage: &TokenCounts,
) {
let input_tokens = usage
@@ -1816,11 +1843,17 @@ impl Session {
if input_tokens <= 0 {
return;
}
+ if let Some(fingerprint) = context_window_snapshot.fingerprint {
+ self.context_window_response_usage_fingerprints
+ .lock()
+ .expect("context window response-usage fingerprint lock poisoned")
+ .insert(fingerprint);
+ }
let snapshot = scaled_snapshot(
- local_snapshot,
+ &context_window_snapshot.local_snapshot,
u64::try_from(input_tokens).unwrap_or(u64::MAX),
fabro_types::StageContextWindowCountMethod::ResponseUsageScaledBreakdown,
- local_snapshot.warnings.clone(),
+ context_window_snapshot.local_snapshot.warnings.clone(),
);
self.event_emitter
.emit(self.id.clone(), AgentEvent::ContextWindowSnapshot(snapshot));

View file

@ -0,0 +1,6 @@
{
"outcome": "succeeded",
"notes": "Stage completed: simplify_gpt",
"failure_reason": null,
"timestamp": "2026-05-23T21:35:11.507680Z"
}

View file

@ -0,0 +1,5 @@
{
"script": "git fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\\bActorRef\\b|\\bActorKind\\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\\s*==\\s*\"disabled\"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1",
"command": "exec 2>&1\ngit fetch origin main 2>&1 && git merge --no-edit --no-stat origin/main 2>&1 && cargo +nightly-2026-04-14 fmt --all 2>&1 && cargo dev docs refresh 2>&1 && cargo +nightly-2026-04-14 fmt --check --all 2>&1 && ! rg -n 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\\bActorRef\\b|\\bActorKind\\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\\s*==\\s*\"disabled\"' lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml 2>&1 && cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D warnings 2>&1 && cargo nextest run --workspace --status-level slow --profile ci 2>&1 && cargo dev docs check 2>&1 && bun install --frozen-lockfile 2>&1 && (cd apps/fabro-web && bun run typecheck) 2>&1 && (cd apps/fabro-web && bun run test) 2>&1 && (cd lib/packages/fabro-api-client && bun run typecheck) 2>&1 && cargo dev build -- -p fabro-cli --release 2>&1",
"language": "shell"
}