alice_runtime/
memory_context.rs1use bob_core::types::{RequestContext, RequestToolPolicy};
4use bob_runtime::AgentResponse;
5
6use crate::context::AliceRuntimeContext;
7
8pub async fn run_turn_with_memory(
18 context: &AliceRuntimeContext,
19 session_id: &str,
20 input: &str,
21) -> eyre::Result<AgentResponse> {
22 let recalled = match context.memory_service().recall_for_turn(session_id, input) {
24 Ok(hits) => hits,
25 Err(error) => {
26 tracing::warn!("memory recall failed: {error}");
27 Vec::new()
28 }
29 };
30 let memory_prompt =
31 alice_core::memory::service::MemoryService::render_recall_context(&recalled);
32
33 let skills_bundle = context.skill_composer().map(|composer| {
35 crate::skill_wiring::inject_skills_context(composer, input, context.skill_token_budget())
36 });
37
38 let mut system_parts = Vec::new();
40 if let Some(ref mem) = memory_prompt {
41 system_parts.push(mem.as_str());
42 }
43 if let Some(ref bundle) = skills_bundle &&
44 !bundle.prompt.is_empty()
45 {
46 system_parts.push(&bundle.prompt);
47 }
48 let system_prompt =
49 if system_parts.is_empty() { None } else { Some(system_parts.join("\n\n")) };
50
51 let (selected_skills, tool_policy) = if let Some(ref bundle) = skills_bundle {
53 let policy = if bundle.selected_allowed_tools.is_empty() {
54 RequestToolPolicy::default()
55 } else {
56 RequestToolPolicy {
57 allow_tools: Some(bundle.selected_allowed_tools.clone()),
58 ..RequestToolPolicy::default()
59 }
60 };
61 (bundle.selected_skill_names.clone(), policy)
62 } else {
63 (Vec::new(), RequestToolPolicy::default())
64 };
65
66 let request_context = RequestContext { system_prompt, selected_skills, tool_policy };
67
68 let session = context.backend().create_session_with_id(session_id);
70 let response = session.chat(input, request_context).await?;
71
72 if let Err(error) = context.memory_service().persist_turn(session_id, input, &response.content)
74 {
75 tracing::warn!("memory persistence failed: {error}");
76 }
77
78 Ok(response)
79}