mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 23:50:17 +00:00
Break circular dependencies between agent, db, channels, and context modules by extracting shared domain types to neutral locations: - Extract routine types to src/models/routine.rs - Extract ToolFailureRecord to src/models/tool_failure.rs - Move SseEvent to src/events.rs as DomainEvent - Move HttpInterceptor to src/observability/ - Move truncate_preview to src/util.rs Add generic resilience middleware (src/resilience/): - ErrorClassifier, RetryLayer, CircuitBreakerLayer, HealthTracker Add state invalidation bus (src/state_bus.rs) Add boundary chaos tests (tests/boundary_chaos.rs) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
51 lines
1.8 KiB
Rust
51 lines
1.8 KiB
Rust
//! HTTP interception trait for trace recording and replay.
|
|
//!
|
|
//! Lives in `observability` rather than `llm::recording` so that `context::state`
|
|
//! can depend on it without pulling in the LLM module.
|
|
|
|
use async_trait::async_trait;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// The request side of an HTTP exchange.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct HttpExchangeRequest {
|
|
pub method: String,
|
|
pub url: String,
|
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
|
pub headers: Vec<(String, String)>,
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
pub body: Option<String>,
|
|
}
|
|
|
|
/// The response side of an HTTP exchange.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct HttpExchangeResponse {
|
|
pub status: u16,
|
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
|
pub headers: Vec<(String, String)>,
|
|
pub body: String,
|
|
}
|
|
|
|
/// A matched request/response pair.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct HttpExchange {
|
|
pub request: HttpExchangeRequest,
|
|
pub response: HttpExchangeResponse,
|
|
}
|
|
|
|
/// Trait for intercepting HTTP requests from tools.
|
|
///
|
|
/// During recording, the interceptor captures exchanges after the real
|
|
/// request completes. During replay, it short-circuits with a recorded response.
|
|
#[async_trait]
|
|
pub trait HttpInterceptor: Send + Sync + std::fmt::Debug {
|
|
/// Called before making an HTTP request.
|
|
///
|
|
/// Return `Some(response)` to short-circuit (replay mode).
|
|
/// Return `None` to let the real request proceed (recording mode).
|
|
async fn before_request(&self, request: &HttpExchangeRequest) -> Option<HttpExchangeResponse>;
|
|
|
|
/// Called after a real HTTP request completes (recording mode only).
|
|
async fn after_response(&self, request: &HttpExchangeRequest, response: &HttpExchangeResponse);
|
|
}
|