fix: resolve cascade correlation, update KNOWN_ISSUES
- MitmStore: added active_cascade_id field with set/get/clear methods - record_usage() now falls back to active_cascade_id when the heuristic cascade hint is absent (fixes usage always going to _latest) - All three API handlers set active cascade before send_message - KNOWN_ISSUES: moved 3 issues to resolved: - Request modification (already true, was stale entry) - Cascade correlation (fixed via active_cascade_id) - Progressive thinking streaming (fixed via MITM bypass)
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
All critical blockers have been resolved. Standalone LS with MITM interception
|
All critical blockers have been resolved. Standalone LS with MITM interception
|
||||||
is fully working. Reactive streaming is implemented with polling fallback.
|
is fully working. Reactive streaming is implemented with polling fallback.
|
||||||
|
All three API endpoints (Responses, Completions, Gemini) now bypass the LS
|
||||||
|
when custom tools are active, reading directly from MitmStore.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -45,43 +47,48 @@ content (see `docs/panel-stream-investigation.md`).
|
|||||||
thinking text. The panel reactive component uses a workspace-scoped ID, not
|
thinking text. The panel reactive component uses a workspace-scoped ID, not
|
||||||
cascade IDs. See `docs/panel-stream-investigation.md`.
|
cascade IDs. See `docs/panel-stream-investigation.md`.
|
||||||
|
|
||||||
---
|
### ~~Request Modification Not Implemented~~
|
||||||
|
|
||||||
## 🟡 Medium (Architecture / Future Work)
|
**Status: SOLVED (2026-02-15)**
|
||||||
|
|
||||||
### 1. Cascade Correlation Is Heuristic
|
`MitmConfig.modify_requests` is now `true` by default. Used for:
|
||||||
|
|
||||||
**File:** `src/mitm/intercept.rs` — `extract_cascade_hint()`
|
- Tool/function call injection into LS requests (Gemini `functionDeclarations`)
|
||||||
|
- Tool result injection as `functionResponse` parts
|
||||||
|
- LS bypass when custom tools are active (response captured directly from MITM)
|
||||||
|
|
||||||
The MITM proxy matches intercepted API traffic to cascade IDs heuristically.
|
### ~~Cascade Correlation Is Heuristic~~
|
||||||
Currently all intercepted usage is stored under `_latest` because the Google
|
|
||||||
SSE request body is empty (`content_length=0` — the LS sends the request body
|
|
||||||
via chunked encoding that isn't captured in the hint extractor).
|
|
||||||
|
|
||||||
**Impact:** Usage shows up in `/v1/usage` aggregate stats but isn't correlated
|
**Status: SOLVED (2026-02-15)**
|
||||||
to specific cascades. Not blocking — aggregate usage is the primary use case.
|
|
||||||
|
|
||||||
---
|
Previously, MITM usage was keyed under `_latest` because `extract_cascade_hint()`
|
||||||
|
couldn't parse the chunked-encoded Google SSE request body.
|
||||||
|
|
||||||
### 2. Request Modification Not Implemented
|
**Fix:** API handlers now call `mitm_store.set_active_cascade(cascade_id)` before
|
||||||
|
sending messages. `record_usage()` falls back to this active cascade ID when the
|
||||||
|
heuristic hint is absent, properly correlating usage to cascades.
|
||||||
|
|
||||||
**File:** `src/mitm/proxy.rs` — `modify_requests: bool`
|
### ~~Progressive Thinking Streaming~~
|
||||||
|
|
||||||
The `MitmConfig.modify_requests` flag is plumbed through but hardcoded to `false`.
|
**Status: SOLVED (2026-02-15)**
|
||||||
Reserved for future request mutation features (e.g., injecting custom system
|
|
||||||
prompts, modifying model selection).
|
The MITM proxy now captures `thinking_text` from `StreamingAccumulator` into
|
||||||
|
`MitmStore` as SSE chunks arrive. The Responses API streaming handler reads
|
||||||
|
thinking deltas from MitmStore and emits `response.reasoning_summary_text.delta`
|
||||||
|
events in real-time. This works for both Google (`thought: true` parts) and
|
||||||
|
Anthropic (`thinking_delta`) formats.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🟢 Low
|
## 🟢 Low
|
||||||
|
|
||||||
### 3. MITM Integration Tests
|
### 1. MITM Integration Tests
|
||||||
|
|
||||||
Unit tests cover protobuf decoding and intercept parsing (18 tests pass).
|
Unit tests cover protobuf decoding and intercept parsing (18 tests pass).
|
||||||
Integration tests for the full MITM pipeline (TLS interception, response
|
Integration tests for the full MITM pipeline (TLS interception, response
|
||||||
parsing, usage recording) would be valuable now that interception works.
|
parsing, usage recording) would be valuable now that interception works.
|
||||||
|
|
||||||
### 4. MITM for Main Antigravity Session
|
### 2. MITM for Main Antigravity Session
|
||||||
|
|
||||||
The current MITM only works for the standalone LS (default mode).
|
The current MITM only works for the standalone LS (default mode).
|
||||||
Intercepting the main Antigravity session's LS is harder because:
|
Intercepting the main Antigravity session's LS is harder because:
|
||||||
@@ -92,10 +99,3 @@ Intercepting the main Antigravity session's LS is harder because:
|
|||||||
`HTTPS_PROXY` unless `detect_and_use_proxy` is ENABLED via init metadata
|
`HTTPS_PROXY` unless `detect_and_use_proxy` is ENABLED via init metadata
|
||||||
|
|
||||||
**Workaround:** Use standalone mode (default) for all proxy traffic.
|
**Workaround:** Use standalone mode (default) for all proxy traffic.
|
||||||
|
|
||||||
### 5. Progressive Thinking Streaming
|
|
||||||
|
|
||||||
For extended-thinking models (Opus), thinking text may arrive progressively
|
|
||||||
across multiple reactive diffs. Currently thinking is captured atomically via
|
|
||||||
polling. Progressive streaming would require parsing reactive diff field numbers
|
|
||||||
to extract incremental thinking deltas. See `docs/panel-stream-investigation.md`.
|
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ pub(crate) async fn handle_completions(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send message
|
// Send message
|
||||||
|
state.mitm_store.set_active_cascade(&cascade_id).await;
|
||||||
match state
|
match state
|
||||||
.backend
|
.backend
|
||||||
.send_message(&cascade_id, &user_text, model.model_enum)
|
.send_message(&cascade_id, &user_text, model.model_enum)
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ pub(crate) async fn handle_gemini(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send message
|
// Send message
|
||||||
|
state.mitm_store.set_active_cascade(&cascade_id).await;
|
||||||
match state
|
match state
|
||||||
.backend
|
.backend
|
||||||
.send_message(&cascade_id, &user_text, model.model_enum)
|
.send_message(&cascade_id, &user_text, model.model_enum)
|
||||||
|
|||||||
@@ -278,6 +278,7 @@ pub(crate) async fn handle_responses(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Send message
|
// Send message
|
||||||
|
state.mitm_store.set_active_cascade(&cascade_id).await;
|
||||||
match state
|
match state
|
||||||
.backend
|
.backend
|
||||||
.send_message(&cascade_id, &user_text, model.model_enum)
|
.send_message(&cascade_id, &user_text, model.model_enum)
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ pub struct MitmStore {
|
|||||||
/// Last captured function calls (for conversation history rewriting).
|
/// Last captured function calls (for conversation history rewriting).
|
||||||
last_function_calls: Arc<RwLock<Vec<CapturedFunctionCall>>>,
|
last_function_calls: Arc<RwLock<Vec<CapturedFunctionCall>>>,
|
||||||
|
|
||||||
|
// ── Cascade correlation ──────────────────────────────────────────────
|
||||||
|
/// Active cascade ID set by the API layer before sending a message.
|
||||||
|
/// Used by the MITM proxy to correlate intercepted traffic to cascades.
|
||||||
|
active_cascade_id: Arc<RwLock<Option<String>>>,
|
||||||
|
|
||||||
// ── Direct response capture (bypasses LS) ────────────────────────────
|
// ── Direct response capture (bypasses LS) ────────────────────────────
|
||||||
/// Captured response text from MITM when custom tools are active.
|
/// Captured response text from MITM when custom tools are active.
|
||||||
/// The completions/responses handler reads this instead of polling LS steps.
|
/// The completions/responses handler reads this instead of polling LS steps.
|
||||||
@@ -135,6 +140,7 @@ impl MitmStore {
|
|||||||
pending_tool_results: Arc::new(RwLock::new(Vec::new())),
|
pending_tool_results: Arc::new(RwLock::new(Vec::new())),
|
||||||
call_id_to_name: Arc::new(RwLock::new(HashMap::new())),
|
call_id_to_name: Arc::new(RwLock::new(HashMap::new())),
|
||||||
last_function_calls: Arc::new(RwLock::new(Vec::new())),
|
last_function_calls: Arc::new(RwLock::new(Vec::new())),
|
||||||
|
active_cascade_id: Arc::new(RwLock::new(None)),
|
||||||
captured_response_text: Arc::new(RwLock::new(None)),
|
captured_response_text: Arc::new(RwLock::new(None)),
|
||||||
captured_thinking_text: Arc::new(RwLock::new(None)),
|
captured_thinking_text: Arc::new(RwLock::new(None)),
|
||||||
response_complete: Arc::new(AtomicBool::new(false)),
|
response_complete: Arc::new(AtomicBool::new(false)),
|
||||||
@@ -186,7 +192,13 @@ impl MitmStore {
|
|||||||
// Call 2: thinking summary text (thinking_output_tokens == 0, response_text has the summary)
|
// Call 2: thinking summary text (thinking_output_tokens == 0, response_text has the summary)
|
||||||
//
|
//
|
||||||
// When Call 2 arrives, we merge its response_text as thinking_text into Call 1's usage.
|
// When Call 2 arrives, we merge its response_text as thinking_text into Call 1's usage.
|
||||||
let key = cascade_id.map(|s| s.to_string()).unwrap_or_else(|| "_latest".to_string());
|
let key = if let Some(cid) = cascade_id {
|
||||||
|
cid.to_string()
|
||||||
|
} else if let Some(active) = self.active_cascade_id.read().await.as_ref() {
|
||||||
|
active.clone()
|
||||||
|
} else {
|
||||||
|
"_latest".to_string()
|
||||||
|
};
|
||||||
let mut latest = self.latest_usage.write().await;
|
let mut latest = self.latest_usage.write().await;
|
||||||
|
|
||||||
if let Some(existing) = latest.get_mut(&key) {
|
if let Some(existing) = latest.get_mut(&key) {
|
||||||
@@ -436,4 +448,22 @@ impl MitmStore {
|
|||||||
pub async fn take_thinking_text(&self) -> Option<String> {
|
pub async fn take_thinking_text(&self) -> Option<String> {
|
||||||
self.captured_thinking_text.write().await.take()
|
self.captured_thinking_text.write().await.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Cascade correlation ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Set the active cascade ID (called by API handlers before sending a message).
|
||||||
|
/// The MITM proxy will use this to correlate intercepted traffic.
|
||||||
|
pub async fn set_active_cascade(&self, cascade_id: &str) {
|
||||||
|
*self.active_cascade_id.write().await = Some(cascade_id.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the active cascade ID.
|
||||||
|
pub async fn get_active_cascade(&self) -> Option<String> {
|
||||||
|
self.active_cascade_id.read().await.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the active cascade ID (called after response is complete).
|
||||||
|
pub async fn clear_active_cascade(&self) {
|
||||||
|
*self.active_cascade_id.write().await = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user