1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! KodaAgent — shared, immutable agent resources.
//!
//! Holds everything that's constant across turns within a session:
//! tools, system prompt, project root. Shareable via `Arc`
//! for parallel sub-agents.
//!
//! Note: `KodaConfig` is NOT stored here because the REPL allows
//! switching models and providers mid-session. Config lives on the
//! caller side and is passed to `KodaSession` per-turn.
use crate::config::KodaConfig;
use crate::memory;
use crate::providers::ToolDefinition;
use crate::tools::ToolRegistry;
use anyhow::Result;
use std::path::PathBuf;
/// Shared agent resources. Immutable after construction.
///
/// Create once, share via `Arc<KodaAgent>` across sessions and sub-agents.
pub struct KodaAgent {
/// Project root directory.
pub project_root: PathBuf,
/// Tool registry with all built-in tools.
pub tools: ToolRegistry,
/// Pre-computed tool definitions for the LLM.
pub tool_defs: Vec<ToolDefinition>,
/// Assembled system prompt.
pub system_prompt: String,
}
impl KodaAgent {
/// Build a new agent from config and project root.
///
/// Initializes tools, system prompt, and tool definitions.
pub async fn new(config: &KodaConfig, project_root: PathBuf) -> Result<Self> {
let tools = ToolRegistry::new(project_root.clone(), config.max_context_tokens);
let tool_defs = tools.get_definitions(&config.allowed_tools);
let semantic_memory = memory::load(&project_root)?;
let system_prompt = crate::prompt::build_system_prompt(
&config.system_prompt,
&semantic_memory,
&config.agents_dir,
&tool_defs,
);
Ok(Self {
project_root,
tools,
tool_defs,
system_prompt,
})
}
}