feat: first cut at dev brain
This commit is contained in:
@@ -382,7 +382,7 @@ fn title_context(messages: impl IntoIterator<Item = ChatTurn>) -> Vec<ChatTurn>
|
||||
|
||||
impl App {
|
||||
fn chat_system_prompt(&self, model: ModelChoice, prompt: &str, agents: Option<&str>) -> String {
|
||||
let mut prompt = crate::agent::system_prompt(model, prompt);
|
||||
let mut prompt = crate::agent::system_prompt(model, prompt, self.config.dev_brain.enabled);
|
||||
if self.config.a2ui_enabled {
|
||||
prompt.push_str("\n\n");
|
||||
prompt.push_str(crate::a2ui::SYSTEM_PROMPT);
|
||||
@@ -668,7 +668,10 @@ impl App {
|
||||
}
|
||||
|
||||
fn system_prompt_reminders(&self, model: ModelChoice) -> Vec<String> {
|
||||
let mut reminders = vec![crate::agent::system_prompt_reminder(model)];
|
||||
let mut reminders = vec![crate::agent::system_prompt_reminder(
|
||||
model,
|
||||
self.config.dev_brain.enabled,
|
||||
)];
|
||||
if self.config.a2ui_enabled {
|
||||
reminders.push(crate::a2ui::SYSTEM_PROMPT.to_owned());
|
||||
}
|
||||
@@ -1163,7 +1166,15 @@ impl App {
|
||||
.find(|project| project.project.id == project_id)
|
||||
.map(|project| PathBuf::from(&project.project.path))
|
||||
.ok_or_else(|| "The active project is unavailable.".to_owned())?;
|
||||
let tools = crate::agent::Tools::new(&root, self.config.generation.context_tokens)?;
|
||||
let mut tools = crate::agent::Tools::new(&root, self.config.generation.context_tokens)?;
|
||||
if self.config.dev_brain.enabled {
|
||||
let projects = self
|
||||
.projects
|
||||
.iter()
|
||||
.map(|project| project.project.clone())
|
||||
.collect::<Vec<_>>();
|
||||
tools.enable_dev_brain(&self.config.dev_brain, &projects)?;
|
||||
}
|
||||
self.agent_tools = Some((session_id, Arc::new(Mutex::new(tools))));
|
||||
}
|
||||
let tools = Arc::clone(&self.agent_tools.as_ref().unwrap().1);
|
||||
|
||||
@@ -10,6 +10,8 @@ pub(super) struct PreferenceDraft {
|
||||
pub(super) endpoint_port: String,
|
||||
pub(super) endpoint_enabled: bool,
|
||||
pub(super) endpoint_cors: bool,
|
||||
pub(super) dev_brain_enabled: bool,
|
||||
pub(super) dev_brain_vault_path: String,
|
||||
pub(super) context_tokens: String,
|
||||
pub(super) max_generated_tokens: String,
|
||||
pub(super) system_prompt: text_editor::Content,
|
||||
@@ -60,6 +62,8 @@ impl PreferenceDraft {
|
||||
endpoint_port: config.endpoint.port.to_string(),
|
||||
endpoint_enabled: config.endpoint.enabled,
|
||||
endpoint_cors: config.endpoint.cors,
|
||||
dev_brain_enabled: config.dev_brain.enabled,
|
||||
dev_brain_vault_path: config.dev_brain.vault_path.clone().unwrap_or_default(),
|
||||
context_tokens: generation.context_tokens.to_string(),
|
||||
max_generated_tokens: generation.max_generated_tokens.to_string(),
|
||||
system_prompt: text_editor::Content::with_text(&generation.system_prompt),
|
||||
@@ -368,6 +372,10 @@ impl App {
|
||||
enabled: self.preference_draft.endpoint_enabled,
|
||||
cors: self.preference_draft.endpoint_cors,
|
||||
},
|
||||
dev_brain: DevBrainConfig {
|
||||
enabled: self.preference_draft.dev_brain_enabled,
|
||||
vault_path: optional_text(&self.preference_draft.dev_brain_vault_path),
|
||||
},
|
||||
generation,
|
||||
runtime,
|
||||
interface: self.config.interface.clone(),
|
||||
@@ -376,6 +384,18 @@ impl App {
|
||||
self.preference_error = Some(error);
|
||||
return;
|
||||
}
|
||||
if config.dev_brain.enabled {
|
||||
let projects = self
|
||||
.projects
|
||||
.iter()
|
||||
.map(|project| project.project.clone())
|
||||
.collect::<Vec<_>>();
|
||||
if let Err(error) = crate::dev_brain::DevBrain::open(&config.dev_brain, &projects) {
|
||||
self.preference_error = Some(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let dev_brain_changed = self.config.dev_brain != config.dev_brain;
|
||||
#[cfg(target_os = "macos")]
|
||||
let endpoint_changed = self.config.endpoint != config.endpoint;
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -415,6 +435,10 @@ impl App {
|
||||
}
|
||||
self.config = config;
|
||||
#[cfg(target_os = "macos")]
|
||||
if dev_brain_changed {
|
||||
self.invalidate_dev_brain_context();
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
update_runtime_config(&self.runtime_config, &self.config);
|
||||
#[cfg(target_os = "macos")]
|
||||
if endpoint_changed {
|
||||
|
||||
@@ -152,6 +152,7 @@ impl App {
|
||||
self.project_name_input.clear();
|
||||
self.error = None;
|
||||
self.reload_projects();
|
||||
self.invalidate_dev_brain_context();
|
||||
self.refresh_git_state();
|
||||
}
|
||||
Err(error) => self.error = Some(error),
|
||||
@@ -349,6 +350,21 @@ impl App {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn invalidate_dev_brain_context(&mut self) {
|
||||
if !self.config.dev_brain.enabled {
|
||||
return;
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
self.agent_tools = None;
|
||||
for chat in self.background_chats.values_mut() {
|
||||
chat.agent_tools = None;
|
||||
chat.system_prompt_seen_at = 0;
|
||||
}
|
||||
}
|
||||
self.system_prompt_seen_at = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn read_git_state(path: &Path) -> Option<GitState> {
|
||||
|
||||
@@ -156,6 +156,33 @@ impl App {
|
||||
]
|
||||
.spacing(10),
|
||||
);
|
||||
let dev_brain_group = preference_group(
|
||||
PreferenceSection::DevBrain,
|
||||
"DEV BRAIN",
|
||||
column![
|
||||
hint(
|
||||
checkbox(self.preference_draft.dev_brain_enabled)
|
||||
.label("Enable project-backed LLM wiki")
|
||||
.on_toggle(Message::PreferenceDevBrainEnabledChanged),
|
||||
"Adds validated search, read, and batch-publication tools for a dedicated Obsidian vault. Disabled means no Dev Brain tools or prompt instructions.",
|
||||
),
|
||||
row![
|
||||
text_input(
|
||||
"/path/to/Obsidian vault",
|
||||
&self.preference_draft.dev_brain_vault_path,
|
||||
)
|
||||
.on_input(Message::PreferenceDevBrainVaultChanged)
|
||||
.padding(9)
|
||||
.width(Length::Fill),
|
||||
action_button("Choose…").on_press(Message::ChooseDevBrainVault),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(Alignment::Center),
|
||||
text("The folder must already contain .obsidian. DS4Server manages only its declared wiki pages and leaves settings, attachments, hidden files, and unrelated notes untouched.")
|
||||
.size(12),
|
||||
]
|
||||
.spacing(10),
|
||||
);
|
||||
let generation_group = preference_group(
|
||||
PreferenceSection::Generation,
|
||||
"GENERATION",
|
||||
@@ -552,6 +579,7 @@ impl App {
|
||||
let mut fields = column![
|
||||
model_group,
|
||||
endpoint_group,
|
||||
dev_brain_group,
|
||||
generation_group,
|
||||
execution_group,
|
||||
acceleration_group,
|
||||
|
||||
Reference in New Issue
Block a user