llm: drop model/agent scope matching; add instance-wide compaction model picker
Nightly Build / build (push) Successful in 6m50s
Nightly Build / build (push) Successful in 6m50s
Remove the scope system end-to-end (llm_models.scope column, agent meta scope field, scope-based tier in model selection, UI checkboxes/pills): it was only a soft ranking hint, had drifted (6 UI scopes vs 3 used by agents, 'general' not even selectable) and duplicated what strength already decides. Strength stays the single AUTO-selection axis. Compaction: the summary model is now pickable from the Settings page via a new PropertyType::LlmModel config property (registry key compaction_model), instance-wide and live (no restart). Fallback chain: explicit pick -> compaction.strength from config.yml -> priority order; a deleted configured model degrades to AUTO. ContextCompactor reads the key at compact time through GlobalConfigManager.
This commit is contained in:
@@ -60,8 +60,6 @@ struct RawMeta {
|
||||
#[serde(default)]
|
||||
client: Option<String>,
|
||||
#[serde(default)]
|
||||
scope: Option<String>,
|
||||
#[serde(default)]
|
||||
strength: Option<LlmStrength>,
|
||||
/// Required: declares the agent's role. A `meta.json` without `type` fails to load.
|
||||
#[serde(rename = "type")]
|
||||
@@ -104,10 +102,6 @@ pub struct AgentMeta {
|
||||
/// If unset, the sub-agent inherits the caller's client.
|
||||
#[serde(default)]
|
||||
pub client: Option<String>,
|
||||
/// Task domain this agent operates in (e.g. "coding", "reasoning").
|
||||
/// Used by AUTO client selection to find a matching LLM.
|
||||
#[serde(default)]
|
||||
pub scope: Option<String>,
|
||||
/// Minimum LLM capability required to run this agent reliably.
|
||||
/// AUTO selection skips clients weaker than this threshold.
|
||||
#[serde(default)]
|
||||
@@ -197,13 +191,12 @@ pub fn discover() -> Result<Vec<AgentMeta>> {
|
||||
instructions: raw.instructions,
|
||||
inject_memory: raw.inject_memory,
|
||||
client: raw.client,
|
||||
scope: raw.scope,
|
||||
strength: raw.strength,
|
||||
agent_type: raw.agent_type,
|
||||
inject_skills: raw.inject_skills,
|
||||
icon: raw.icon,
|
||||
};
|
||||
trace!(agent_id = %meta.id, client = ?meta.client, scope = ?meta.scope, strength = ?meta.strength, "agent meta loaded");
|
||||
trace!(agent_id = %meta.id, client = ?meta.client, strength = ?meta.strength, "agent meta loaded");
|
||||
debug!(agent_id = %meta.id, name = %meta.name, "agent discovered");
|
||||
agents.push(meta);
|
||||
}
|
||||
@@ -230,7 +223,6 @@ pub fn load_meta(agent_id: &str) -> Result<AgentMeta> {
|
||||
instructions: raw.instructions,
|
||||
inject_memory: raw.inject_memory,
|
||||
client: raw.client,
|
||||
scope: raw.scope,
|
||||
strength: raw.strength,
|
||||
agent_type: raw.agent_type,
|
||||
inject_skills: raw.inject_skills,
|
||||
|
||||
@@ -49,12 +49,40 @@ use serde_json::json;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use core_api::{ConfigProperty, ConfigSet, PropertyType};
|
||||
|
||||
use crate::chat_event_bus::{ChatEventBus, CompactionEvent};
|
||||
use crate::chatbot::ChatOptions;
|
||||
use crate::config::CompactionConfig;
|
||||
use crate::config_store::GlobalConfigManager;
|
||||
use crate::db::{chat_history, chat_llm_tools, chat_summaries};
|
||||
use crate::llm::LlmManager;
|
||||
|
||||
/// Registry `config` key holding the name of the LLM model to use for
|
||||
/// compaction summaries. Set from the Settings page (instance-wide); empty /
|
||||
/// unset means AUTO selection by `CompactionConfig.strength` (config.yml).
|
||||
pub const COMPACTION_MODEL_KEY: &str = "compaction_model";
|
||||
|
||||
/// Settings-page section for compaction (see `i18n::config_set` for the
|
||||
/// pattern). Registered in `Runtime::config_properties`.
|
||||
pub fn config_set() -> ConfigSet {
|
||||
ConfigSet {
|
||||
name: "Compaction".into(),
|
||||
description: "How conversation history is summarised when the context grows too large.".into(),
|
||||
properties: vec![
|
||||
ConfigProperty {
|
||||
key: COMPACTION_MODEL_KEY.into(),
|
||||
name: "Compaction model".into(),
|
||||
description: "Model used to summarise compacted history, for the whole instance. \
|
||||
A cheap model is usually enough. Leave empty to auto-select \
|
||||
(by `compaction.strength` in config.yml).".into(),
|
||||
property_type: PropertyType::LlmModel,
|
||||
default_value: None,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
// ── Compaction constants (ported from Hermes context_compressor.py) ──────────
|
||||
//
|
||||
// SUMMARY_PREFIX — prepended to every stored summary when injected as context.
|
||||
@@ -158,18 +186,20 @@ Write only the summary body. Do not include any preamble or prefix.";
|
||||
// ── Public API ────────────────────────────────────────────────────────────────
|
||||
|
||||
pub struct ContextCompactor {
|
||||
config: CompactionConfig,
|
||||
llm_manager: Arc<LlmManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
config: CompactionConfig,
|
||||
llm_manager: Arc<LlmManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
config_store: Arc<GlobalConfigManager>,
|
||||
}
|
||||
|
||||
impl ContextCompactor {
|
||||
pub fn new(
|
||||
config: CompactionConfig,
|
||||
llm_manager: Arc<LlmManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
config: CompactionConfig,
|
||||
llm_manager: Arc<LlmManager>,
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
config_store: Arc<GlobalConfigManager>,
|
||||
) -> Self {
|
||||
Self { config, llm_manager, event_bus }
|
||||
Self { config, llm_manager, event_bus, config_store }
|
||||
}
|
||||
|
||||
/// Attempt to compact the conversation history for `stack_id`.
|
||||
@@ -291,9 +321,25 @@ impl ContextCompactor {
|
||||
.format_for_summary(pool, to_summarise, prior_summary.as_ref().map(|s| s.content.as_str()))
|
||||
.await?;
|
||||
|
||||
let (client_name, llm) = self.llm_manager
|
||||
.resolve(None, None, self.config.strength)
|
||||
.await?;
|
||||
// Model for the summary call: the instance-wide Settings pick
|
||||
// (`compaction_model`) wins; empty/unset falls back to AUTO selection by
|
||||
// `compaction.strength` from config.yml. A configured model that no
|
||||
// longer exists (renamed/deleted) degrades to the same AUTO path.
|
||||
let configured = self.config_store.get(COMPACTION_MODEL_KEY).await
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|s| s.trim().to_string())
|
||||
.filter(|s| !s.is_empty());
|
||||
let (client_name, llm) = match configured {
|
||||
Some(name) => match self.llm_manager.resolve(Some(&name), None).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
warn!(model = %name, error = %e, "compactor: configured compaction model unavailable, falling back to AUTO selection");
|
||||
self.llm_manager.resolve(None, self.config.strength).await?
|
||||
}
|
||||
},
|
||||
None => self.llm_manager.resolve(None, self.config.strength).await?,
|
||||
};
|
||||
|
||||
info!(
|
||||
stack_id,
|
||||
|
||||
@@ -206,7 +206,6 @@ async fn create_registry_tables(pool: &SqlitePool) -> Result<()> {
|
||||
model_id TEXT NOT NULL,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
strength TEXT,
|
||||
scope TEXT NOT NULL DEFAULT '[]',
|
||||
is_default INTEGER NOT NULL DEFAULT 0,
|
||||
priority INTEGER NOT NULL DEFAULT 100,
|
||||
extra_params TEXT,
|
||||
|
||||
@@ -93,7 +93,6 @@ struct ModelRow {
|
||||
model_id: String,
|
||||
name: String,
|
||||
strength: Option<String>,
|
||||
scope: String,
|
||||
is_default: i64,
|
||||
priority: i64,
|
||||
extra_params: Option<String>,
|
||||
@@ -106,7 +105,7 @@ struct ModelRow {
|
||||
|
||||
pub async fn load_all_models(pool: &SqlitePool) -> Result<Vec<LlmModelRecord>> {
|
||||
let rows = sqlx::query_as::<_, ModelRow>(
|
||||
"SELECT id, provider_id, model_id, name, strength, scope, is_default, priority, extra_params,
|
||||
"SELECT id, provider_id, model_id, name, strength, is_default, priority, extra_params,
|
||||
context_length, max_output_tokens, knowledge_cutoff, capabilities, reasoning
|
||||
FROM llm_models
|
||||
WHERE removed_at IS NULL
|
||||
@@ -120,7 +119,6 @@ pub async fn load_all_models(pool: &SqlitePool) -> Result<Vec<LlmModelRecord>> {
|
||||
}
|
||||
|
||||
pub async fn insert_model(pool: &SqlitePool, r: &LlmModelRecord) -> Result<i64> {
|
||||
let scope = serde_json::to_string(&r.scope)?;
|
||||
let extra_params = r.extra_params.as_ref().map(|v| v.to_string());
|
||||
let capabilities = serde_json::to_string(&r.capabilities)?;
|
||||
let reasoning = r.reasoning.as_ref().map(|v| v.to_string());
|
||||
@@ -132,14 +130,13 @@ pub async fn insert_model(pool: &SqlitePool, r: &LlmModelRecord) -> Result<i64>
|
||||
// soft-deleted row. Upsert on `name` so that existing row is revived
|
||||
// (removed_at cleared) and every field overwritten.
|
||||
let id = sqlx::query_scalar::<_, i64>(
|
||||
"INSERT INTO llm_models (provider_id, model_id, name, strength, scope, is_default, priority, extra_params,
|
||||
"INSERT INTO llm_models (provider_id, model_id, name, strength, is_default, priority, extra_params,
|
||||
context_length, max_output_tokens, knowledge_cutoff, capabilities, reasoning)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
|
||||
ON CONFLICT(name) DO UPDATE SET
|
||||
provider_id = excluded.provider_id,
|
||||
model_id = excluded.model_id,
|
||||
strength = excluded.strength,
|
||||
scope = excluded.scope,
|
||||
is_default = excluded.is_default,
|
||||
priority = excluded.priority,
|
||||
extra_params = excluded.extra_params,
|
||||
@@ -155,7 +152,6 @@ pub async fn insert_model(pool: &SqlitePool, r: &LlmModelRecord) -> Result<i64>
|
||||
.bind(&r.model_id)
|
||||
.bind(&r.name)
|
||||
.bind(r.strength.map(strength_str))
|
||||
.bind(scope)
|
||||
.bind(r.is_default as i64)
|
||||
.bind(r.priority as i64)
|
||||
.bind(extra_params)
|
||||
@@ -172,23 +168,21 @@ pub async fn insert_model(pool: &SqlitePool, r: &LlmModelRecord) -> Result<i64>
|
||||
}
|
||||
|
||||
pub async fn update_model(pool: &SqlitePool, id: i64, r: &LlmModelRecord) -> Result<()> {
|
||||
let scope = serde_json::to_string(&r.scope)?;
|
||||
let extra_params = r.extra_params.as_ref().map(|v| v.to_string());
|
||||
let capabilities = serde_json::to_string(&r.capabilities)?;
|
||||
let reasoning = r.reasoning.as_ref().map(|v| v.to_string());
|
||||
sqlx::query(
|
||||
"UPDATE llm_models
|
||||
SET provider_id=?1, model_id=?2, name=?3, strength=?4,
|
||||
scope=?5, is_default=?6, priority=?7, extra_params=?8,
|
||||
context_length=?9, max_output_tokens=?10, knowledge_cutoff=?11, capabilities=?12,
|
||||
reasoning=?13
|
||||
WHERE id=?14",
|
||||
is_default=?5, priority=?6, extra_params=?7,
|
||||
context_length=?8, max_output_tokens=?9, knowledge_cutoff=?10, capabilities=?11,
|
||||
reasoning=?12
|
||||
WHERE id=?13",
|
||||
)
|
||||
.bind(r.provider_id)
|
||||
.bind(&r.model_id)
|
||||
.bind(&r.name)
|
||||
.bind(r.strength.map(strength_str))
|
||||
.bind(scope)
|
||||
.bind(r.is_default as i64)
|
||||
.bind(r.priority as i64)
|
||||
.bind(extra_params)
|
||||
@@ -267,7 +261,6 @@ fn provider_row_to_record(r: ProviderRow) -> Result<LlmProviderRecord> {
|
||||
}
|
||||
|
||||
fn model_row_to_record(r: ModelRow) -> Result<LlmModelRecord> {
|
||||
let scope: Vec<String> = serde_json::from_str(&r.scope).unwrap_or_default();
|
||||
let extra_params = r.extra_params
|
||||
.as_deref()
|
||||
.and_then(|s| serde_json::from_str(s).ok());
|
||||
@@ -281,7 +274,6 @@ fn model_row_to_record(r: ModelRow) -> Result<LlmModelRecord> {
|
||||
model_id: r.model_id,
|
||||
name: r.name,
|
||||
strength: r.strength.as_deref().and_then(parse_strength),
|
||||
scope,
|
||||
is_default: r.is_default != 0,
|
||||
priority: r.priority as i32,
|
||||
extra_params,
|
||||
|
||||
@@ -100,12 +100,11 @@ impl LlmManager {
|
||||
pub async fn resolve(
|
||||
&self,
|
||||
client_name: Option<&str>,
|
||||
required_scope: Option<&str>,
|
||||
required_strength: Option<LlmStrength>,
|
||||
) -> Result<(String, Arc<LlmEntry>)> {
|
||||
let name = match client_name {
|
||||
None | Some(AUTO_CLIENT) => {
|
||||
let (name, entry) = self.select(required_scope, required_strength).await?;
|
||||
let (name, entry) = self.select(required_strength).await?;
|
||||
self.maybe_refresh_meta(&name).await;
|
||||
return Ok((name, entry));
|
||||
}
|
||||
@@ -368,7 +367,6 @@ impl LlmManager {
|
||||
model_id: slot.model.model_id.clone(),
|
||||
name: slot.model.name.clone(),
|
||||
strength: slot.model.strength,
|
||||
scope: slot.model.scope.clone(),
|
||||
is_default: slot.model.is_default,
|
||||
priority: slot.model.priority,
|
||||
extra_params: slot.model.extra_params.clone(),
|
||||
@@ -391,7 +389,6 @@ impl LlmManager {
|
||||
pub async fn select_excluding(
|
||||
&self,
|
||||
excluded: &[&str],
|
||||
required_scope: Option<&str>,
|
||||
required_strength: Option<LlmStrength>,
|
||||
) -> Result<(String, Arc<LlmEntry>)> {
|
||||
let state = self.state.read().await;
|
||||
@@ -401,7 +398,7 @@ impl LlmManager {
|
||||
if slots.is_empty() {
|
||||
anyhow::bail!("no alternative LLM models available");
|
||||
}
|
||||
sort_slots_for_agent(&mut slots, required_scope, required_strength);
|
||||
sort_slots_for_agent(&mut slots, required_strength);
|
||||
if let Some((name, slot)) = slots.iter().find(|(_, s)| s.health.status != ClientStatus::Down) {
|
||||
return Ok((name.to_string(), slot.entry.clone()));
|
||||
}
|
||||
@@ -414,7 +411,6 @@ impl LlmManager {
|
||||
|
||||
async fn select(
|
||||
&self,
|
||||
required_scope: Option<&str>,
|
||||
required_strength: Option<LlmStrength>,
|
||||
) -> Result<(String, Arc<LlmEntry>)> {
|
||||
let state = self.state.read().await;
|
||||
@@ -424,7 +420,7 @@ impl LlmManager {
|
||||
}
|
||||
|
||||
let mut slots: Vec<(&String, &ModelSlot)> = state.models.iter().collect();
|
||||
sort_slots_for_agent(&mut slots, required_scope, required_strength);
|
||||
sort_slots_for_agent(&mut slots, required_strength);
|
||||
|
||||
if let Some((name, slot)) = slots.iter().find(|(_, s)| s.health.status != ClientStatus::Down) {
|
||||
return Ok((name.to_string(), slot.entry.clone()));
|
||||
@@ -526,7 +522,6 @@ fn build_entry(
|
||||
model: model.model_id.clone(),
|
||||
model_db_id,
|
||||
strength: model.strength,
|
||||
scope: model.scope.clone(),
|
||||
extra_params: extra,
|
||||
context_length: model.context_length,
|
||||
prompt_cache,
|
||||
@@ -548,28 +543,24 @@ fn build_entry(
|
||||
|
||||
pub fn sort_models_for_agent(
|
||||
mut models: Vec<LlmModelInfo>,
|
||||
scope: Option<&str>,
|
||||
strength: Option<LlmStrength>,
|
||||
) -> Vec<LlmModelInfo> {
|
||||
models.sort_by_key(|m| (model_tier(m.strength, m.scope.as_slice(), scope, strength), m.priority));
|
||||
models.sort_by_key(|m| (model_tier(m.strength, strength), m.priority));
|
||||
models
|
||||
}
|
||||
|
||||
fn sort_slots_for_agent(
|
||||
slots: &mut Vec<(&String, &ModelSlot)>,
|
||||
scope: Option<&str>,
|
||||
strength: Option<LlmStrength>,
|
||||
) {
|
||||
slots.sort_by_key(|(_, s)| (
|
||||
model_tier(s.model.strength, s.model.scope.as_slice(), scope, strength),
|
||||
model_tier(s.model.strength, strength),
|
||||
s.model.priority,
|
||||
));
|
||||
}
|
||||
|
||||
fn model_tier(
|
||||
model_strength: Option<LlmStrength>,
|
||||
model_scope: &[String],
|
||||
req_scope: Option<&str>,
|
||||
req_strength: Option<LlmStrength>,
|
||||
) -> u8 {
|
||||
let strength_ok = match (req_strength, model_strength) {
|
||||
@@ -583,11 +574,9 @@ fn model_tier(
|
||||
(Some(req), Some(avail)) => avail == req,
|
||||
_ => true,
|
||||
};
|
||||
let scope_ok = req_scope.map_or(true, |sc| model_scope.iter().any(|x| x == sc));
|
||||
match (strength_ok && scope_ok, exact_match && scope_ok, strength_ok) {
|
||||
(true, true, _) => 0, // exact strength + scope ok
|
||||
(true, false, _) => 1, // over-qualified but scope ok
|
||||
(false, _, true) => 2, // strength ok, scope mismatch
|
||||
_ => 3, // doesn't meet minimum bar
|
||||
match (strength_ok, exact_match) {
|
||||
(true, true) => 0, // exact strength
|
||||
(true, false) => 1, // over-qualified
|
||||
_ => 3, // doesn't meet minimum bar
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ pub struct LlmEntry {
|
||||
pub model: String,
|
||||
pub model_db_id: i64,
|
||||
pub strength: Option<LlmStrength>,
|
||||
pub scope: Vec<String>,
|
||||
pub extra_params: Option<serde_json::Value>,
|
||||
/// Max input context window in tokens, if known.
|
||||
pub context_length: Option<i64>,
|
||||
@@ -96,7 +95,6 @@ pub struct LlmModelInfo {
|
||||
pub model_id: String,
|
||||
pub name: String,
|
||||
pub strength: Option<LlmStrength>,
|
||||
pub scope: Vec<String>,
|
||||
pub is_default: bool,
|
||||
pub priority: i32,
|
||||
pub extra_params: Option<serde_json::Value>,
|
||||
|
||||
@@ -57,7 +57,6 @@ impl ChatSessionHandler {
|
||||
let explicit_client = args["client"].as_str().or(target_meta.client.as_deref());
|
||||
let (resolved_client, _) = self.llm_manager.resolve(
|
||||
explicit_client,
|
||||
target_meta.scope.as_deref(),
|
||||
target_meta.strength,
|
||||
).await.map_err(|e| anyhow::anyhow!("dispatch_sub_agent: {e}"))?;
|
||||
|
||||
@@ -241,7 +240,7 @@ impl ChatSessionHandler {
|
||||
let meta = crate::agents::load_task_meta(&frame.agent_id)
|
||||
.map_err(|e| anyhow::anyhow!("resume: cannot load sub-agent `{}`: {e}", frame.agent_id))?;
|
||||
let (client, _) = self.llm_manager.resolve(
|
||||
meta.client.as_deref(), meta.scope.as_deref(), meta.strength,
|
||||
meta.client.as_deref(), meta.strength,
|
||||
).await?;
|
||||
self.build_sub_agent_config(root_config, &frame.agent_id, client.to_string(), frame.id, frame.depth).await
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ impl ChatSessionHandler {
|
||||
let meta = crate::agents::load_meta(&self.agent_id).ok();
|
||||
let (key, _) = self.llm_manager.resolve(
|
||||
client_name.as_deref(),
|
||||
meta.as_ref().and_then(|m| m.scope.as_deref()),
|
||||
meta.as_ref().and_then(|m| m.strength),
|
||||
).await?;
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ impl ChatSessionHandler {
|
||||
stack_id: i64,
|
||||
config: &AgentRunConfig,
|
||||
active_grants: &HashSet<String>,
|
||||
req_scope: Option<&str>,
|
||||
req_strength: Option<LlmStrength>,
|
||||
cur_name: &mut String,
|
||||
cur_llm: &mut Arc<LlmEntry>,
|
||||
@@ -155,7 +154,7 @@ impl ChatSessionHandler {
|
||||
}
|
||||
|
||||
let excluded: Vec<&str> = tried_this_round.iter().map(String::as_str).collect();
|
||||
match self.llm_manager.select_excluding(&excluded, req_scope, req_strength).await {
|
||||
match self.llm_manager.select_excluding(&excluded, req_strength).await {
|
||||
Ok((next_name, next_llm)) => {
|
||||
warn!(session_id = self.session_id, from = %cur_name, to = %next_name, "LLM fallback");
|
||||
em.model_fallback(cur_name.clone(), next_name.clone(), first_line(&e.to_string())).await;
|
||||
|
||||
@@ -65,9 +65,8 @@ impl ChatSessionHandler {
|
||||
let mut cur_llm = self.llm_manager.get(&cur_name).await
|
||||
.ok_or_else(|| anyhow::anyhow!("LLM client '{}' not found", cur_name))?;
|
||||
|
||||
// Scope/strength needed for fallback re-selection.
|
||||
// Strength needed for fallback re-selection.
|
||||
let meta = crate::agents::load_meta(&config.agent_id).ok();
|
||||
let req_scope = meta.as_ref().and_then(|m| m.scope.as_deref()).map(str::to_string);
|
||||
let req_strength = meta.as_ref().and_then(|m| m.strength);
|
||||
|
||||
// Accumulates tool calls across all rounds for the event bus.
|
||||
@@ -132,7 +131,7 @@ impl ChatSessionHandler {
|
||||
// retriable errors. `cur_name`/`cur_llm`/`messages` are updated in place.
|
||||
let turn_result = match self.call_llm_round(
|
||||
stack_id, config, &active_grants_snapshot,
|
||||
req_scope.as_deref(), req_strength,
|
||||
req_strength,
|
||||
&mut cur_name, &mut cur_llm, &mut messages, token, &em,
|
||||
).await {
|
||||
RoundLlm::Turn(t) => t,
|
||||
|
||||
@@ -331,6 +331,7 @@ impl Conversation {
|
||||
cfg.clone(),
|
||||
Arc::clone(&models.llm_manager),
|
||||
Arc::clone(&rt.event_bus),
|
||||
Arc::clone(&rt.config),
|
||||
))
|
||||
});
|
||||
if compactor.is_none() {
|
||||
|
||||
@@ -63,7 +63,11 @@ impl Runtime {
|
||||
users,
|
||||
sessions,
|
||||
config,
|
||||
config_properties: vec![crate::i18n::config_set(), crate::tic::config_set()],
|
||||
config_properties: vec![
|
||||
crate::i18n::config_set(),
|
||||
crate::tic::config_set(),
|
||||
crate::compactor::config_set(),
|
||||
],
|
||||
system_bus,
|
||||
event_bus,
|
||||
global_tx,
|
||||
|
||||
@@ -43,6 +43,7 @@ use crate::chat_hub::ChatHub;
|
||||
use crate::clarification::ClarificationManager;
|
||||
use crate::compactor::ContextCompactor;
|
||||
use crate::config::{CompactionConfig, CoreConfig, DatetimeConfig};
|
||||
use crate::config_store::GlobalConfigManager;
|
||||
use crate::container::ContainerManager;
|
||||
use crate::cron::TaskManager;
|
||||
use crate::elicitation::ElicitationManager;
|
||||
@@ -132,6 +133,7 @@ pub(super) struct UserContextFactory {
|
||||
event_bus: Arc<ChatEventBus>,
|
||||
supervisor: Arc<super::supervisor::TaskSupervisor>,
|
||||
shutdown_token: CancellationToken,
|
||||
config_store: Arc<GlobalConfigManager>,
|
||||
max_history_messages: usize,
|
||||
max_tool_rounds: usize,
|
||||
max_parallel_subagents: usize,
|
||||
@@ -166,6 +168,7 @@ impl UserContextFactory {
|
||||
event_bus: Arc::clone(&rt.event_bus),
|
||||
supervisor: Arc::clone(&rt.supervisor),
|
||||
shutdown_token: rt.shutdown_token.clone(),
|
||||
config_store: Arc::clone(&rt.config),
|
||||
max_history_messages: config.llm.max_history_messages,
|
||||
max_tool_rounds: config.llm.max_tool_rounds.unwrap_or(DEFAULT_MAX_TOOL_ROUNDS),
|
||||
max_parallel_subagents: config.llm.max_parallel_subagents.unwrap_or(DEFAULT_MAX_PARALLEL_SUBAGENTS),
|
||||
@@ -207,6 +210,7 @@ impl UserContextFactory {
|
||||
cfg.clone(),
|
||||
Arc::clone(&self.llm_manager),
|
||||
Arc::clone(&event_bus),
|
||||
Arc::clone(&self.config_store),
|
||||
))
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user