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(
14 context: &AliceRuntimeContext,
15 session_id: &str,
16 input: &str,
17) -> eyre::Result<AgentResponse> {
18 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 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 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 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 let session = context.backend.create_session_with_id(session_id);
66 let response = session.chat(input, request_context).await?;
67
68 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}