mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
feat(engine): wire reflection pipeline + trace analysis into thread lifecycle
After every thread completes, ThreadManager now automatically runs:
1. Retrospective trace analysis (non-LLM, always):
- Detects 8 issue categories (tool errors, code errors, missing
outputs, excessive steps, hallucination risk, etc.)
- Logs issues at warn level when found
2. Trace file recording (when ENGINE_V2_TRACE=1):
- Writes full JSON trace to engine_trace_{timestamp}.json
3. LLM reflection (when enable_reflection=true):
- Calls reflection pipeline to produce Summary, Lesson, Issue docs
- Saves docs to store for future context retrieval
- Enabled by default in the bridge router
All three run inside the spawned tokio task after exec.run() completes,
before saving the final thread state. No external wiring needed.
Removed duplicate trace recording from the router — it's now handled
by ThreadManager automatically.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
@@ -156,11 +156,51 @@ impl ThreadManager {
|
||||
|
||||
// Spawn background task
|
||||
let store_for_task = Arc::clone(&self.store);
|
||||
let llm_for_reflection = Arc::clone(&self.llm);
|
||||
let handle = tokio::spawn(async move {
|
||||
let mut exec = exec_loop;
|
||||
let result = exec.run().await;
|
||||
debug!(thread_id = %thread_id, "thread execution finished");
|
||||
// Save final thread state to store (for trace recording)
|
||||
|
||||
// Run retrospective trace analysis (non-LLM, always runs)
|
||||
let trace = crate::executor::trace::build_trace(&exec.thread);
|
||||
if !trace.issues.is_empty() {
|
||||
crate::executor::trace::log_trace_summary(&trace);
|
||||
}
|
||||
|
||||
// Write trace file if enabled
|
||||
if crate::executor::trace::is_trace_enabled() {
|
||||
crate::executor::trace::write_trace(&trace);
|
||||
}
|
||||
|
||||
// Run LLM reflection if enabled and thread completed
|
||||
if exec.thread.config.enable_reflection
|
||||
&& (exec.thread.state == crate::types::thread::ThreadState::Completed
|
||||
|| exec.thread.state == crate::types::thread::ThreadState::Done)
|
||||
{
|
||||
debug!(thread_id = %thread_id, "running reflection pipeline");
|
||||
match crate::reflection::reflect(&exec.thread, &llm_for_reflection).await {
|
||||
Ok(reflection) => {
|
||||
debug!(
|
||||
thread_id = %thread_id,
|
||||
docs = reflection.docs.len(),
|
||||
tokens = reflection.tokens_used.total(),
|
||||
"reflection complete"
|
||||
);
|
||||
for doc in &reflection.docs {
|
||||
let _ = store_for_task.save_memory_doc(doc).await;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::warn!(
|
||||
thread_id = %thread_id,
|
||||
"reflection failed: {e}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save final thread state to store
|
||||
let _ = store_for_task.save_thread(&exec.thread).await;
|
||||
result
|
||||
});
|
||||
|
||||
@@ -168,7 +168,10 @@ pub async fn handle_with_engine(
|
||||
content,
|
||||
state.default_project_id,
|
||||
&message.user_id,
|
||||
ThreadConfig::default(),
|
||||
ThreadConfig {
|
||||
enable_reflection: true,
|
||||
..ThreadConfig::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -222,14 +225,9 @@ pub async fn handle_with_engine(
|
||||
.record_thread_outcome(conv_id, thread_id, &outcome)
|
||||
.await;
|
||||
|
||||
// Trace recording + retrospective analysis
|
||||
if ironclaw_engine::executor::trace::is_trace_enabled()
|
||||
&& let Ok(Some(thread)) = state.store.load_thread(thread_id).await
|
||||
{
|
||||
let trace = ironclaw_engine::executor::trace::build_trace(&thread);
|
||||
ironclaw_engine::executor::trace::log_trace_summary(&trace);
|
||||
ironclaw_engine::executor::trace::write_trace(&trace);
|
||||
}
|
||||
// Note: trace recording, retrospective analysis, and LLM reflection
|
||||
// all run automatically inside ThreadManager after the thread completes.
|
||||
// See crates/ironclaw_engine/src/runtime/manager.rs.
|
||||
|
||||
// Convert outcome to response
|
||||
match outcome {
|
||||
|
||||
Reference in New Issue
Block a user