feat: Added the memory configuration properties and storage to the main app config, roles, sessions, and agents.
This commit is contained in:
@@ -352,6 +352,10 @@ impl Agent {
|
|||||||
self.config.enabled_skills.as_deref()
|
self.config.enabled_skills.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn memory(&self) -> Option<bool> {
|
||||||
|
self.config.memory
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_skills_enabled(&mut self, value: Option<bool>) {
|
pub fn set_skills_enabled(&mut self, value: Option<bool>) {
|
||||||
self.config.skills_enabled = value;
|
self.config.skills_enabled = value;
|
||||||
}
|
}
|
||||||
@@ -638,6 +642,8 @@ pub struct AgentConfig {
|
|||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub skill_instructions: Option<String>,
|
pub skill_instructions: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub memory: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub compression_threshold: Option<usize>,
|
pub compression_threshold: Option<usize>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ pub struct AppConfig {
|
|||||||
pub summarization_prompt: Option<String>,
|
pub summarization_prompt: Option<String>,
|
||||||
pub summary_context_prompt: Option<String>,
|
pub summary_context_prompt: Option<String>,
|
||||||
|
|
||||||
|
pub memory: Option<bool>,
|
||||||
|
pub memory_cap_with_tools: Option<usize>,
|
||||||
|
pub memory_cap_without_tools: Option<usize>,
|
||||||
|
|
||||||
pub rag_embedding_model: Option<String>,
|
pub rag_embedding_model: Option<String>,
|
||||||
pub rag_reranker_model: Option<String>,
|
pub rag_reranker_model: Option<String>,
|
||||||
pub rag_top_k: usize,
|
pub rag_top_k: usize,
|
||||||
@@ -132,6 +136,10 @@ impl Default for AppConfig {
|
|||||||
summarization_prompt: None,
|
summarization_prompt: None,
|
||||||
summary_context_prompt: None,
|
summary_context_prompt: None,
|
||||||
|
|
||||||
|
memory: None,
|
||||||
|
memory_cap_with_tools: None,
|
||||||
|
memory_cap_without_tools: None,
|
||||||
|
|
||||||
rag_embedding_model: None,
|
rag_embedding_model: None,
|
||||||
rag_reranker_model: None,
|
rag_reranker_model: None,
|
||||||
rag_top_k: 5,
|
rag_top_k: 5,
|
||||||
@@ -201,6 +209,10 @@ impl AppConfig {
|
|||||||
summarization_prompt: config.summarization_prompt,
|
summarization_prompt: config.summarization_prompt,
|
||||||
summary_context_prompt: config.summary_context_prompt,
|
summary_context_prompt: config.summary_context_prompt,
|
||||||
|
|
||||||
|
memory: config.memory,
|
||||||
|
memory_cap_with_tools: config.memory_cap_with_tools,
|
||||||
|
memory_cap_without_tools: config.memory_cap_without_tools,
|
||||||
|
|
||||||
rag_embedding_model: config.rag_embedding_model,
|
rag_embedding_model: config.rag_embedding_model,
|
||||||
rag_reranker_model: config.rag_reranker_model,
|
rag_reranker_model: config.rag_reranker_model,
|
||||||
rag_top_k: config.rag_top_k,
|
rag_top_k: config.rag_top_k,
|
||||||
|
|||||||
@@ -231,6 +231,10 @@ pub struct Config {
|
|||||||
pub summarization_prompt: Option<String>,
|
pub summarization_prompt: Option<String>,
|
||||||
pub summary_context_prompt: Option<String>,
|
pub summary_context_prompt: Option<String>,
|
||||||
|
|
||||||
|
pub memory: Option<bool>,
|
||||||
|
pub memory_cap_with_tools: Option<usize>,
|
||||||
|
pub memory_cap_without_tools: Option<usize>,
|
||||||
|
|
||||||
pub rag_embedding_model: Option<String>,
|
pub rag_embedding_model: Option<String>,
|
||||||
pub rag_reranker_model: Option<String>,
|
pub rag_reranker_model: Option<String>,
|
||||||
pub rag_top_k: usize,
|
pub rag_top_k: usize,
|
||||||
@@ -299,6 +303,10 @@ impl Default for Config {
|
|||||||
summarization_prompt: None,
|
summarization_prompt: None,
|
||||||
summary_context_prompt: None,
|
summary_context_prompt: None,
|
||||||
|
|
||||||
|
memory: None,
|
||||||
|
memory_cap_with_tools: None,
|
||||||
|
memory_cap_without_tools: None,
|
||||||
|
|
||||||
rag_embedding_model: None,
|
rag_embedding_model: None,
|
||||||
rag_reranker_model: None,
|
rag_reranker_model: None,
|
||||||
rag_top_k: 5,
|
rag_top_k: 5,
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ use std::io::Write;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
use super::memory::{WorkspaceMemory, MemoryStore};
|
||||||
|
|
||||||
pub struct AutoContinueConfig {
|
pub struct AutoContinueConfig {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
@@ -59,6 +60,21 @@ pub struct SkillInstructionsConfig {
|
|||||||
pub instructions: Option<String>,
|
pub instructions: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MemoryConfig {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub workspace: Option<WorkspaceMemory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryConfig {
|
||||||
|
pub fn disabled() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: false,
|
||||||
|
workspace: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Must stay in sync with the predicate that registers `skill__*` tools in `rebuild_tool_scope`
|
/// Must stay in sync with the predicate that registers `skill__*` tools in `rebuild_tool_scope`
|
||||||
/// (and in `graph::llm::run_llm_node`). Telling the model to call tools that are not exposed
|
/// (and in `graph::llm::run_llm_node`). Telling the model to call tools that are not exposed
|
||||||
/// is a footgun. `compatible_enabled` is the post-filter universe that `skill__list` would
|
/// is a footgun. `compatible_enabled` is the post-filter universe that `skill__list` would
|
||||||
@@ -705,6 +721,52 @@ impl RequestContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn memory_config(&self) -> MemoryConfig {
|
||||||
|
if let Some(agent) = &self.agent
|
||||||
|
&& graph::agent_has_graph(agent.name())
|
||||||
|
{
|
||||||
|
return MemoryConfig::disabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
let agent_pref = self.agent.as_ref().and_then(|a| a.memory());
|
||||||
|
let session_pref = self.session.as_ref().and_then(|s| s.memory());
|
||||||
|
let role_pref = self.role.as_ref().and_then(|r| r.memory());
|
||||||
|
let app_pref = self.app.config.memory;
|
||||||
|
|
||||||
|
let resolved = agent_pref
|
||||||
|
.or(session_pref)
|
||||||
|
.or(role_pref)
|
||||||
|
.or(app_pref)
|
||||||
|
.unwrap_or(true);
|
||||||
|
if !resolved {
|
||||||
|
return MemoryConfig::disabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cwd = env::current_dir().ok();
|
||||||
|
let store = cwd.as_deref().map(MemoryStore::new);
|
||||||
|
let workspace = store.as_ref().and_then(|s| s.workspace.clone());
|
||||||
|
|
||||||
|
let global_exists = paths::global_memory_index_path().exists();
|
||||||
|
let workspace_exists = workspace.is_some();
|
||||||
|
|
||||||
|
if !global_exists && !workspace_exists {
|
||||||
|
return MemoryConfig::disabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryConfig {
|
||||||
|
enabled: true,
|
||||||
|
workspace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_inject_memory(&self) -> bool {
|
||||||
|
self.memory_config().enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_register_memory_tools(&self) -> bool {
|
||||||
|
self.should_inject_memory() && self.app.config.function_calling_support
|
||||||
|
}
|
||||||
|
|
||||||
pub fn auto_continue_config(&self) -> AutoContinueConfig {
|
pub fn auto_continue_config(&self) -> AutoContinueConfig {
|
||||||
if let Some(agent) = &self.agent {
|
if let Some(agent) = &self.agent {
|
||||||
return AutoContinueConfig {
|
return AutoContinueConfig {
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ pub struct Role {
|
|||||||
inject_skill_instructions: Option<bool>,
|
inject_skill_instructions: Option<bool>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
skill_instructions: Option<String>,
|
skill_instructions: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
memory: Option<bool>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
model: Model,
|
model: Model,
|
||||||
@@ -132,6 +134,7 @@ impl Role {
|
|||||||
"skill_instructions" => {
|
"skill_instructions" => {
|
||||||
role.skill_instructions = value.as_str().map(|v| v.to_string())
|
role.skill_instructions = value.as_str().map(|v| v.to_string())
|
||||||
}
|
}
|
||||||
|
"memory" => role.memory = value.as_bool(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,6 +208,9 @@ impl Role {
|
|||||||
if let Some(skill_instructions) = &self.skill_instructions {
|
if let Some(skill_instructions) = &self.skill_instructions {
|
||||||
metadata.push(format!("skill_instructions: {skill_instructions}"));
|
metadata.push(format!("skill_instructions: {skill_instructions}"));
|
||||||
}
|
}
|
||||||
|
if let Some(memory) = self.memory {
|
||||||
|
metadata.push(format!("memory: {memory}"));
|
||||||
|
}
|
||||||
if metadata.is_empty() {
|
if metadata.is_empty() {
|
||||||
format!("{}\n", self.prompt)
|
format!("{}\n", self.prompt)
|
||||||
} else if self.prompt.is_empty() {
|
} else if self.prompt.is_empty() {
|
||||||
@@ -323,6 +329,10 @@ impl Role {
|
|||||||
self.skill_instructions.as_deref()
|
self.skill_instructions.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn memory(&self) -> Option<bool> {
|
||||||
|
self.memory
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skills_enabled(&self) -> Option<bool> {
|
pub fn skills_enabled(&self) -> Option<bool> {
|
||||||
self.skills_enabled
|
self.skills_enabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ pub struct Session {
|
|||||||
inject_skill_instructions: Option<bool>,
|
inject_skill_instructions: Option<bool>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
skill_instructions: Option<String>,
|
skill_instructions: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
memory: Option<bool>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
role_name: Option<String>,
|
role_name: Option<String>,
|
||||||
@@ -237,6 +239,9 @@ impl Session {
|
|||||||
if let Some(skill_instructions) = self.skill_instructions() {
|
if let Some(skill_instructions) = self.skill_instructions() {
|
||||||
data["skill_instructions"] = skill_instructions.into();
|
data["skill_instructions"] = skill_instructions.into();
|
||||||
}
|
}
|
||||||
|
if let Some(memory) = self.memory() {
|
||||||
|
data["memory"] = memory.into();
|
||||||
|
}
|
||||||
let (tokens, percent) = self.tokens_usage();
|
let (tokens, percent) = self.tokens_usage();
|
||||||
data["total_tokens"] = tokens.into();
|
data["total_tokens"] = tokens.into();
|
||||||
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
||||||
@@ -324,6 +329,9 @@ impl Session {
|
|||||||
if let Some(skill_instructions) = self.skill_instructions() {
|
if let Some(skill_instructions) = self.skill_instructions() {
|
||||||
items.push(("skill_instructions", skill_instructions.to_string()));
|
items.push(("skill_instructions", skill_instructions.to_string()));
|
||||||
}
|
}
|
||||||
|
if let Some(memory) = self.memory() {
|
||||||
|
items.push(("memory", memory.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
if let Some(max_input_tokens) = self.model().max_input_tokens() {
|
||||||
items.push(("max_input_tokens", max_input_tokens.to_string()));
|
items.push(("max_input_tokens", max_input_tokens.to_string()));
|
||||||
@@ -473,6 +481,10 @@ impl Session {
|
|||||||
self.skill_instructions.as_deref()
|
self.skill_instructions.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn memory(&self) -> Option<bool> {
|
||||||
|
self.memory
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_inject_todo_instructions(&mut self, value: Option<bool>) {
|
pub fn set_inject_todo_instructions(&mut self, value: Option<bool>) {
|
||||||
if self.inject_todo_instructions != value {
|
if self.inject_todo_instructions != value {
|
||||||
self.inject_todo_instructions = value;
|
self.inject_todo_instructions = value;
|
||||||
@@ -494,6 +506,13 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_memory(&mut self, value: Option<bool>) {
|
||||||
|
if self.memory != value {
|
||||||
|
self.memory = value;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_skill_instructions(&mut self, value: Option<String>) {
|
pub fn set_skill_instructions(&mut self, value: Option<String>) {
|
||||||
if self.skill_instructions != value {
|
if self.skill_instructions != value {
|
||||||
self.skill_instructions = value;
|
self.skill_instructions = value;
|
||||||
|
|||||||
Reference in New Issue
Block a user