Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions interface/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ export interface CortexSection {
bulletin_interval_secs: number;
bulletin_max_words: number;
bulletin_max_turns: number;
auto_display_name: boolean;
}

export interface CoalesceSection {
Expand Down Expand Up @@ -570,6 +571,7 @@ export interface CortexUpdate {
bulletin_interval_secs?: number;
bulletin_max_words?: number;
bulletin_max_turns?: number;
auto_display_name?: boolean;
}

export interface CoalesceUpdate {
Expand Down
6 changes: 6 additions & 0 deletions interface/src/routes/AgentConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,12 @@ function ConfigSectionEditor({ sectionId, label, description, detail, config, on
case "cortex":
return (
<div className="grid gap-4">
<ConfigToggleField
label="Auto Display Name"
description="When enabled, cortex generates a creative display name. When disabled, the agent ID is used as display name."
value={localValues.auto_display_name as boolean}
onChange={(v) => handleChange("auto_display_name", v)}
/>
<NumberStepper
label="Tick Interval"
description="How often the cortex checks system state"
Expand Down
30 changes: 30 additions & 0 deletions src/agent/cortex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,8 +584,38 @@ struct ProfileLlmResponse {
///
/// Uses the current memory bulletin and identity files as context, then asks
/// an LLM to produce a display name, status line, and short bio.
///
/// When `auto_display_name` is disabled, the display name is set to the agent
/// ID and cortex will not overwrite it.
#[tracing::instrument(skip(deps, logger), fields(agent_id = %deps.agent_id))]
async fn generate_profile(deps: &AgentDeps, logger: &CortexLogger) {
let cortex_config = **deps.runtime_config.cortex.load();

// If auto_display_name is disabled, ensure the profile exists with
// display_name = agent_id and only update status/bio fields.
if !cortex_config.auto_display_name {
let agent_id = &deps.agent_id;
let avatar_seed = agent_id.to_string();
if let Err(error) = sqlx::query(
"INSERT INTO agent_profile (agent_id, display_name, avatar_seed, generated_at, updated_at) \
VALUES (?, ?, ?, datetime('now'), datetime('now')) \
ON CONFLICT(agent_id) DO UPDATE SET \
display_name = COALESCE(agent_profile.display_name, excluded.display_name), \
avatar_seed = excluded.avatar_seed, \
updated_at = datetime('now')",
)
.bind(agent_id.as_ref())
.bind(agent_id.as_ref())
.bind(&avatar_seed)
.execute(&deps.sqlite_pool)
.await
{
tracing::warn!(%error, "failed to ensure agent profile with agent_id as display_name");
}
tracing::info!("auto_display_name disabled, skipping cortex profile generation");
return;
}

tracing::info!("cortex generating agent profile");
let started = Instant::now();

Expand Down
6 changes: 6 additions & 0 deletions src/api/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub(super) struct CortexSection {
bulletin_interval_secs: u64,
bulletin_max_words: usize,
bulletin_max_turns: usize,
auto_display_name: bool,
}

#[derive(Serialize, Debug)]
Expand Down Expand Up @@ -148,6 +149,7 @@ pub(super) struct CortexUpdate {
bulletin_interval_secs: Option<u64>,
bulletin_max_words: Option<usize>,
bulletin_max_turns: Option<usize>,
auto_display_name: Option<bool>,
}

#[derive(Deserialize, Debug)]
Expand Down Expand Up @@ -226,6 +228,7 @@ pub(super) async fn get_agent_config(
bulletin_interval_secs: cortex.bulletin_interval_secs,
bulletin_max_words: cortex.bulletin_max_words,
bulletin_max_turns: cortex.bulletin_max_turns,
auto_display_name: cortex.auto_display_name,
},
coalesce: CoalesceSection {
enabled: coalesce.enabled,
Expand Down Expand Up @@ -522,6 +525,9 @@ fn update_cortex_table(
if let Some(v) = cortex.bulletin_max_turns {
table["bulletin_max_turns"] = toml_edit::value(v as i64);
}
if let Some(v) = cortex.auto_display_name {
table["auto_display_name"] = toml_edit::value(v);
}
Ok(())
}

Expand Down
11 changes: 11 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ pub struct CortexConfig {
pub association_updates_threshold: f32,
/// Max associations to create per pass (rate limit).
pub association_max_per_pass: usize,
/// When true, cortex auto-generates the display name. When false,
/// the display name equals the agent ID and cortex won't overwrite it.
pub auto_display_name: bool,
}

impl Default for CortexConfig {
Expand All @@ -561,6 +564,7 @@ impl Default for CortexConfig {
association_similarity_threshold: 0.85,
association_updates_threshold: 0.95,
association_max_per_pass: 100,
auto_display_name: true,
}
}
}
Expand Down Expand Up @@ -1546,6 +1550,7 @@ struct TomlCortexConfig {
association_similarity_threshold: Option<f32>,
association_updates_threshold: Option<f32>,
association_max_per_pass: Option<usize>,
auto_display_name: Option<bool>,
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -2705,6 +2710,9 @@ impl Config {
association_max_per_pass: c
.association_max_per_pass
.unwrap_or(base_defaults.cortex.association_max_per_pass),
auto_display_name: c
.auto_display_name
.unwrap_or(base_defaults.cortex.auto_display_name),
})
.unwrap_or(base_defaults.cortex),
browser: toml
Expand Down Expand Up @@ -2881,6 +2889,9 @@ impl Config {
association_max_per_pass: c
.association_max_per_pass
.unwrap_or(defaults.cortex.association_max_per_pass),
auto_display_name: c
.auto_display_name
.unwrap_or(defaults.cortex.auto_display_name),
}),
browser: a.browser.map(|b| BrowserConfig {
enabled: b.enabled.unwrap_or(defaults.browser.enabled),
Expand Down