refactor: move ContextState and ContextBudget to types.rs
These are data structures, not agent logic. Moving them to types.rs makes them available to other modules (context.rs, etc.) without creating circular dependencies.
This commit is contained in:
parent
b22d836287
commit
e79f17c2c8
2 changed files with 62 additions and 105 deletions
|
|
@ -57,111 +57,6 @@ struct DispatchState {
|
||||||
/// Mutable context state — the structured regions of the context window.
|
/// Mutable context state — the structured regions of the context window.
|
||||||
///
|
///
|
||||||
/// Each field is a different dimension of awareness. The struct renders
|
/// Each field is a different dimension of awareness. The struct renders
|
||||||
/// itself to text for inclusion in the context message sent to the model.
|
|
||||||
/// Tools can update individual fields mid-session.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ContextState {
|
|
||||||
/// System prompt (identity, instructions, loaded from prompt file).
|
|
||||||
pub system_prompt: String,
|
|
||||||
/// Identity files: (filename, contents). Transparent structure for
|
|
||||||
/// debug inspection and per-file budget control.
|
|
||||||
pub personality: Vec<(String, String)>,
|
|
||||||
/// Journal entries rendered as text — bridges old conversation.
|
|
||||||
pub journal: String,
|
|
||||||
/// Working stack — what the agent is currently doing.
|
|
||||||
/// Top of stack (last element) is the current focus.
|
|
||||||
pub working_stack: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Path to working stack instructions, included in context before the stack state.
|
|
||||||
const WORKING_STACK_INSTRUCTIONS: &str = "/home/kent/.config/poc-agent/working-stack.md";
|
|
||||||
|
|
||||||
/// Path to persisted working stack state.
|
|
||||||
const WORKING_STACK_FILE: &str = "/home/kent/.claude/memory/working-stack.json";
|
|
||||||
|
|
||||||
impl ContextState {
|
|
||||||
/// Render the context message for the model. Personality + working stack.
|
|
||||||
/// Journal is rendered separately as its own message in the conversation.
|
|
||||||
pub fn render_context_message(&self) -> String {
|
|
||||||
let mut parts: Vec<String> = self.personality.iter()
|
|
||||||
.map(|(name, content)| format!("## {}\n\n{}", name, content))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Always include working stack section — instructions + current state
|
|
||||||
let instructions = std::fs::read_to_string(WORKING_STACK_INSTRUCTIONS)
|
|
||||||
.unwrap_or_default();
|
|
||||||
let mut stack_section = instructions;
|
|
||||||
|
|
||||||
if self.working_stack.is_empty() {
|
|
||||||
stack_section.push_str("\n## Current stack\n\n(empty)\n");
|
|
||||||
} else {
|
|
||||||
stack_section.push_str("\n## Current stack\n\n");
|
|
||||||
for (i, item) in self.working_stack.iter().enumerate() {
|
|
||||||
if i == self.working_stack.len() - 1 {
|
|
||||||
stack_section.push_str(&format!("→ {}\n", item));
|
|
||||||
} else {
|
|
||||||
stack_section.push_str(&format!(" [{}] {}\n", i, item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parts.push(stack_section);
|
|
||||||
|
|
||||||
parts.join("\n\n---\n\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Breakdown of context window usage by category, in tokens.
|
|
||||||
///
|
|
||||||
/// Categories:
|
|
||||||
/// id — static identity context (system prompt + CLAUDE.md + memory files)
|
|
||||||
/// mem — dynamically recalled content from poc-memory (future)
|
|
||||||
/// jnl — journal entries bridging old conversation
|
|
||||||
/// conv — raw recent conversation messages
|
|
||||||
/// free — unused context window (headroom before compaction)
|
|
||||||
///
|
|
||||||
/// Token estimates are derived from char proportions scaled by the
|
|
||||||
/// API-reported prompt_tokens count. Before the first API call, uses
|
|
||||||
/// chars/4 as a rough approximation.
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct ContextBudget {
|
|
||||||
pub identity_tokens: usize,
|
|
||||||
pub memory_tokens: usize,
|
|
||||||
pub journal_tokens: usize,
|
|
||||||
pub conversation_tokens: usize,
|
|
||||||
/// Model's context window size in tokens.
|
|
||||||
pub window_tokens: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContextBudget {
|
|
||||||
pub fn used(&self) -> usize {
|
|
||||||
self.identity_tokens + self.memory_tokens + self.journal_tokens + self.conversation_tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free(&self) -> usize {
|
|
||||||
self.window_tokens.saturating_sub(self.used())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Format as a compact status string with percentages of the token window.
|
|
||||||
/// Non-zero values always show at least 1%.
|
|
||||||
pub fn status_string(&self) -> String {
|
|
||||||
let total = self.window_tokens;
|
|
||||||
if total == 0 {
|
|
||||||
return String::new();
|
|
||||||
}
|
|
||||||
let pct = |n: usize| {
|
|
||||||
if n == 0 { return 0; }
|
|
||||||
((n * 100) / total).max(1)
|
|
||||||
};
|
|
||||||
format!(
|
|
||||||
"id:{}% mem:{}% jnl:{}% conv:{}% free:{}%",
|
|
||||||
pct(self.identity_tokens),
|
|
||||||
pct(self.memory_tokens),
|
|
||||||
pct(self.journal_tokens),
|
|
||||||
pct(self.conversation_tokens),
|
|
||||||
pct(self.free()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Agent {
|
pub struct Agent {
|
||||||
client: ApiClient,
|
client: ApiClient,
|
||||||
|
|
|
||||||
|
|
@ -316,3 +316,65 @@ impl ToolDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutable context state — the structured regions of the context window.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ContextState {
|
||||||
|
pub system_prompt: String,
|
||||||
|
pub personality: Vec<(String, String)>,
|
||||||
|
pub journal: String,
|
||||||
|
pub working_stack: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const WORKING_STACK_INSTRUCTIONS: &str = "/home/kent/.config/poc-agent/working-stack.md";
|
||||||
|
pub const WORKING_STACK_FILE: &str = "/home/kent/.claude/memory/working-stack.json";
|
||||||
|
|
||||||
|
impl ContextState {
|
||||||
|
pub fn render_context_message(&self) -> String {
|
||||||
|
let mut parts: Vec<String> = self.personality.iter()
|
||||||
|
.map(|(name, content)| format!("## {}\n\n{}", name, content))
|
||||||
|
.collect();
|
||||||
|
let instructions = std::fs::read_to_string(WORKING_STACK_INSTRUCTIONS).unwrap_or_default();
|
||||||
|
let mut stack_section = instructions;
|
||||||
|
if self.working_stack.is_empty() {
|
||||||
|
stack_section.push_str("\n## Current stack\n\n(empty)\n");
|
||||||
|
} else {
|
||||||
|
stack_section.push_str("\n## Current stack\n\n");
|
||||||
|
for (i, item) in self.working_stack.iter().enumerate() {
|
||||||
|
if i == self.working_stack.len() - 1 {
|
||||||
|
stack_section.push_str(&format!("→ {}\n", item));
|
||||||
|
} else {
|
||||||
|
stack_section.push_str(&format!(" [{}] {}\n", i, item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts.push(stack_section);
|
||||||
|
parts.join("\n\n---\n\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct ContextBudget {
|
||||||
|
pub identity_tokens: usize,
|
||||||
|
pub memory_tokens: usize,
|
||||||
|
pub journal_tokens: usize,
|
||||||
|
pub conversation_tokens: usize,
|
||||||
|
pub window_tokens: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextBudget {
|
||||||
|
pub fn used(&self) -> usize {
|
||||||
|
self.identity_tokens + self.memory_tokens + self.journal_tokens + self.conversation_tokens
|
||||||
|
}
|
||||||
|
pub fn free(&self) -> usize {
|
||||||
|
self.window_tokens.saturating_sub(self.used())
|
||||||
|
}
|
||||||
|
pub fn status_string(&self) -> String {
|
||||||
|
let total = self.window_tokens;
|
||||||
|
if total == 0 { return String::new(); }
|
||||||
|
let pct = |n: usize| if n == 0 { 0 } else { ((n * 100) / total).max(1) };
|
||||||
|
format!("id:{}% mem:{}% jnl:{}% conv:{}% free:{}%",
|
||||||
|
pct(self.identity_tokens), pct(self.memory_tokens),
|
||||||
|
pct(self.journal_tokens), pct(self.conversation_tokens), pct(self.free()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue