feat(agent): inject user/bot identity and recent chat context into agent and TUI sessions
This commit is contained in:
26
src/agent.rs
26
src/agent.rs
@@ -73,13 +73,13 @@ impl Agent {
|
||||
let (child, mut stdin, stdout) = claude::spawn_claude(Some(cwd))?;
|
||||
let pid = child.id();
|
||||
|
||||
// Inject self-awareness + git context
|
||||
// Inject self-awareness + user/bot context
|
||||
let user_ctx = load_user_context();
|
||||
let identity = format!(
|
||||
"[system]\n\
|
||||
You are agent '{name}' running inside aishell.\n\
|
||||
aishell is a multi-agent development tool. You are one of potentially several agents working in parallel.\n\
|
||||
If you find issues or have follow-up work, you can propose: @agent-name task -c dir\n\
|
||||
Your feedback about aishell itself is also valuable.\n"
|
||||
{user_ctx}\
|
||||
If you find issues or have follow-up work, propose: @agent-name task -c dir\n"
|
||||
);
|
||||
let git_ctx = git_context(cwd)
|
||||
.map(|ctx| format!("\n[git context]\n{ctx}"))
|
||||
@@ -290,6 +290,24 @@ impl Drop for Agent {
|
||||
}
|
||||
}
|
||||
|
||||
/// Load user/bot identity from shared config.
|
||||
fn load_user_context() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
let path = if cfg!(target_os = "macos") {
|
||||
format!("{home}/Library/Application Support/ai.syui.log/config.json")
|
||||
} else {
|
||||
format!("{home}/.config/ai.syui.log/config.json")
|
||||
};
|
||||
let config: serde_json::Value = std::fs::read_to_string(&path).ok()
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let user = config["handle"].as_str().unwrap_or("");
|
||||
let bot = config["bot"]["handle"].as_str().unwrap_or("");
|
||||
if user.is_empty() { return String::new(); }
|
||||
format!("user: {user}, ai: {bot}\n")
|
||||
}
|
||||
|
||||
/// Load last 3 session summaries for agent context.
|
||||
fn recent_session_summary() -> String {
|
||||
let dir = if cfg!(target_os = "macos") {
|
||||
|
||||
75
src/tui.rs
75
src/tui.rs
@@ -92,13 +92,14 @@ impl App {
|
||||
should_quit: false,
|
||||
};
|
||||
|
||||
// Send protocol + project context
|
||||
// Send protocol + identity + project context
|
||||
if let Some(ref mut claude) = app.claude {
|
||||
let cwd = std::env::current_dir()
|
||||
.map(|p| p.display().to_string())
|
||||
.unwrap_or_else(|_| ".".to_string());
|
||||
let ctx = crate::agent::git_context(&cwd).unwrap_or_default();
|
||||
let msg = format!("{AI_IDENTITY}\n\n[project context]\n{ctx}");
|
||||
let git_ctx = crate::agent::git_context(&cwd).unwrap_or_default();
|
||||
let identity_ctx = load_identity_context();
|
||||
let msg = format!("{AI_IDENTITY}\n\n{identity_ctx}[project]\n{git_ctx}");
|
||||
claude.send(&msg);
|
||||
}
|
||||
|
||||
@@ -661,6 +662,74 @@ fn parse_agent_commands(text: &str) -> Vec<(String, String, String)> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Load identity context from atproto config + recent chat.
|
||||
fn load_identity_context() -> String {
|
||||
let home = std::env::var("HOME").unwrap_or_default();
|
||||
let config_path = if cfg!(target_os = "macos") {
|
||||
format!("{home}/Library/Application Support/ai.syui.log/config.json")
|
||||
} else {
|
||||
format!("{home}/.config/ai.syui.log/config.json")
|
||||
};
|
||||
|
||||
let config: serde_json::Value = match std::fs::read_to_string(&config_path) {
|
||||
Ok(s) => serde_json::from_str(&s).unwrap_or_default(),
|
||||
Err(_) => return String::new(),
|
||||
};
|
||||
|
||||
let mut ctx = String::new();
|
||||
|
||||
// User & bot identity
|
||||
let user_handle = config["handle"].as_str().unwrap_or("?");
|
||||
let bot_handle = config["bot"]["handle"].as_str().unwrap_or("?");
|
||||
let bot_did = config["bot"]["did"].as_str().unwrap_or("?");
|
||||
let network = config["network"].as_str().unwrap_or("?");
|
||||
|
||||
ctx.push_str(&format!(
|
||||
"[identity]\nuser: {user_handle}\nyou: {bot_handle} ({bot_did})\nnetwork: {network}\n\n"
|
||||
));
|
||||
|
||||
// Recent chat (last 2 entries for context)
|
||||
let bot_path = config["bot"]["path"].as_str().unwrap_or("");
|
||||
let expanded = expand_tilde(bot_path);
|
||||
let chat_dir = format!(
|
||||
"{}/{}/ai.syui.log.chat",
|
||||
if expanded.is_empty() { format!("{home}/.config/ai.syui.log/at") } else { expanded.clone() },
|
||||
config["bot"]["did"].as_str().unwrap_or("did")
|
||||
);
|
||||
|
||||
// Also check user's chat dir
|
||||
let user_did = config["did"].as_str().unwrap_or("");
|
||||
let user_chat_dir = format!("{}/{}/ai.syui.log.chat",
|
||||
if expanded.is_empty() { format!("{home}/.config/ai.syui.log/at") } else { expanded },
|
||||
user_did
|
||||
);
|
||||
|
||||
for dir in [&chat_dir, &user_chat_dir] {
|
||||
if let Ok(mut entries) = std::fs::read_dir(dir) {
|
||||
let mut files: Vec<_> = entries
|
||||
.flatten()
|
||||
.filter(|e| e.path().extension().is_some_and(|x| x == "json"))
|
||||
.collect();
|
||||
files.sort_by_key(|e| std::cmp::Reverse(e.file_name()));
|
||||
|
||||
for f in files.iter().take(1) {
|
||||
if let Ok(content) = std::fs::read_to_string(f.path()) {
|
||||
if let Ok(record) = serde_json::from_str::<serde_json::Value>(&content) {
|
||||
let text = record["value"]["content"]["text"].as_str().unwrap_or("");
|
||||
if !text.is_empty() {
|
||||
let short: String = text.chars().take(200).collect();
|
||||
ctx.push_str(&format!("[recent chat]\n{short}\n\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break; // Use first available dir
|
||||
}
|
||||
}
|
||||
|
||||
ctx
|
||||
}
|
||||
|
||||
fn expand_tilde(path: &str) -> String {
|
||||
if let Some(rest) = path.strip_prefix('~') {
|
||||
if let Ok(home) = std::env::var("HOME") {
|
||||
|
||||
Reference in New Issue
Block a user