memory: add agent-context placeholder, split context groups

Add `agent: bool` field to ContextGroup (default true) so agents get
personality/identity context without session-specific groups (journal,
where-am-i). Agents now get the full identity.md, reflections.md,
toolkit, etc. instead of the compact core-personality loader.

New {{agent-context}} placeholder resolves all agent-tagged groups
using the same get_group_content() as load-context.
This commit is contained in:
ProofOfConcept 2026-03-24 20:00:36 -04:00
parent c5ce6e515f
commit b6bfb26369
4 changed files with 43 additions and 8 deletions

View file

@ -37,15 +37,23 @@ Already in current context (don't re-surface unless the conversation has shifted
Surfaced before compaction (context was reset — re-surface if still relevant):
{{seen_previous}}
How focused is the current conversation? If it's highly focus, you should only
be surfacing highly relevant memories; if it seems more dreamy or brainstormy,
go a bit wider and surface more.
How focused is the current conversation? If it's highly focused, you should only
be surfacing memories that are directly relevant memories; if it seems more
dreamy or brainstormy, go a bit wider and surface more, for better lateral
thinking. When considering relevance, don't just look for memories that are
immediately factually relevant; memories for skills, problem solving, or that
demonstrate relevant techniques may be quite useful - anything that will help
in accomplishing the current goal.
Prioritize new turns in the conversation, think ahead to where the conversation
is going - try to have stuff ready for your conscious self as you want it.
Context budget: {{memory_ratio}}
Try to keep memories at under 50% of the context window.
Search at most 2-3 hops, and output at most 2-3 memories, picking the most
relevant. When you're done, output exactly one of these two formats:
{{node:memory-instructions-core}}
{{node:core-personality}}
{{agent-context}}
{{conversation}}

View file

@ -412,6 +412,25 @@ fn resolve(
Some(Resolved { text, keys: vec![] })
}
// agent-context — personality/identity groups from load-context config
"agent-context" => {
let cfg = crate::config::get();
let mut text = String::new();
let mut keys = Vec::new();
for group in &cfg.context_groups {
if !group.agent { continue; }
let entries = crate::cli::misc::get_group_content(group, store, &cfg);
for (key, content) in entries {
use std::fmt::Write;
writeln!(text, "--- {} ({}) ---", key, group.label).ok();
writeln!(text, "{}\n", content).ok();
keys.push(key);
}
}
if text.is_empty() { None }
else { Some(Resolved { text, keys }) }
}
// node:KEY — inline a node's content by key
other if other.starts_with("node:") => {
let key = &other[5..];

View file

@ -204,7 +204,7 @@ pub fn cmd_query(expr: &[String]) -> Result<(), String> {
crate::query_parser::run_query(&store, &graph, &query_str)
}
fn get_group_content(group: &crate::config::ContextGroup, store: &crate::store::Store, cfg: &crate::config::Config) -> Vec<(String, String)> {
pub fn get_group_content(group: &crate::config::ContextGroup, store: &crate::store::Store, cfg: &crate::config::Config) -> Vec<(String, String)> {
match group.source {
crate::config::ContextSource::Journal => {
let mut entries = Vec::new();

View file

@ -33,8 +33,13 @@ pub struct ContextGroup {
pub keys: Vec<String>,
#[serde(default)]
pub source: ContextSource,
/// Include this group in agent context (default true)
#[serde(default = "default_true")]
pub agent: bool,
}
fn default_true() -> bool { true }
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(default)]
@ -92,11 +97,13 @@ impl Default for Config {
label: "identity".into(),
keys: vec!["identity".into()],
source: ContextSource::Store,
agent: true,
},
ContextGroup {
label: "core-practices".into(),
keys: vec!["core-practices".into()],
source: ContextSource::Store,
agent: true,
},
],
llm_concurrency: 1,
@ -243,7 +250,8 @@ impl Config {
_ => ContextSource::Store,
};
context_groups.push(ContextGroup { label: label.to_string(), keys, source });
let agent = obj.get("agent").and_then(|v| v.as_bool()).unwrap_or(true);
context_groups.push(ContextGroup { label: label.to_string(), keys, source, agent });
}
}