Skip to main content

alice_runtime/
memory_context.rs

1//! Turn execution helpers with memory recall/writeback and skill injection.
2
3use bob_core::types::{RequestContext, RequestToolPolicy};
4use bob_runtime::AgentResponse;
5
6use crate::context::AliceRuntimeContext;
7
8/// Execute one turn with memory-aware + skill-augmented prompt context.
9///
10/// # Errors
11///
12/// Returns an error if the agent runtime fails to execute the turn.
13pub async fn run_turn_with_memory(
14    context: &AliceRuntimeContext,
15    session_id: &str,
16    input: &str,
17) -> eyre::Result<AgentResponse> {
18    // 1. Memory recall
19    let recalled = match context.memory_service.recall_for_turn(session_id, input) {
20        Ok(hits) => hits,
21        Err(error) => {
22            tracing::warn!("memory recall failed: {error}");
23            Vec::new()
24        }
25    };
26    let memory_prompt =
27        alice_core::memory::service::MemoryService::render_recall_context(&recalled);
28
29    // 2. Skill injection
30    let skills_bundle = context.skill_composer.as_ref().map(|composer| {
31        crate::skill_wiring::inject_skills_context(composer, input, context.skill_token_budget)
32    });
33
34    // 3. Compose system prompt: memory + skills
35    let mut system_parts = Vec::new();
36    if let Some(ref mem) = memory_prompt {
37        system_parts.push(mem.as_str());
38    }
39    if let Some(ref bundle) = skills_bundle &&
40        !bundle.prompt.is_empty()
41    {
42        system_parts.push(&bundle.prompt);
43    }
44    let system_prompt =
45        if system_parts.is_empty() { None } else { Some(system_parts.join("\n\n")) };
46
47    // 4. Build request context with skills metadata
48    let (selected_skills, tool_policy) = if let Some(ref bundle) = skills_bundle {
49        let policy = if bundle.selected_allowed_tools.is_empty() {
50            RequestToolPolicy::default()
51        } else {
52            RequestToolPolicy {
53                allow_tools: Some(bundle.selected_allowed_tools.clone()),
54                ..RequestToolPolicy::default()
55            }
56        };
57        (bundle.selected_skill_names.clone(), policy)
58    } else {
59        (Vec::new(), RequestToolPolicy::default())
60    };
61
62    let request_context = RequestContext { system_prompt, selected_skills, tool_policy };
63
64    // 5. Execute turn via agent backend
65    let session = context.backend.create_session_with_id(session_id);
66    let response = session.chat(input, request_context).await?;
67
68    // 6. Persist memory
69    if let Err(error) = context.memory_service.persist_turn(session_id, input, &response.content) {
70        tracing::warn!("memory persistence failed: {error}");
71    }
72
73    Ok(response)
74}