✨ Identity onboarding + Verbatim dialogue memory
- Added [identity] config section (agent_name, agent_role, user_name, user_role, setup_complete) to GyandootConfig and AgentConfig - Agent loop now injects identity into system prompt on startup - Agent loop injects past verbatim dialogue memory into system prompt - Added dialogue_append() / dialogue_read() to MemPalace - Word-by-word, line-by-line verbatim record in dialogue.md - No compression, no truncation — every message preserved - Agent loop writes to BOTH daily transcript AND verbatim dialogue on every turn - All config paths pass identity through (flat converter, subagents)
This commit is contained in:
@@ -388,7 +388,55 @@ impl MemPalace {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ── Getters ─────────────────────────────────────────────────────────
|
||||
// ── Dialogue / verbatim memory ─────────────────────────────────────
|
||||
|
||||
/// Append a single message to the verbatim dialogue log.
|
||||
///
|
||||
/// This is a line-by-line, word-by-word record of every message,
|
||||
/// stored in `dialogue.md` within the wing directory. Each entry
|
||||
/// is timestamped and tagged with role — no compression, no truncation.
|
||||
pub async fn dialogue_append(&self, role: &str, content: &str) -> PalaceResult<()> {
|
||||
let path = self.base_dir.join("dialogue.md");
|
||||
let timestamp = Utc::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
||||
|
||||
use std::io::Write;
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&path)?;
|
||||
|
||||
// Write a header line for this exchange
|
||||
let header = format!("\n## [{timestamp}] **{role}**\n");
|
||||
file.write_all(header.as_bytes())?;
|
||||
|
||||
// Write every single line of content verbatim
|
||||
for line in content.lines() {
|
||||
writeln!(file, "{}", line)?;
|
||||
}
|
||||
file.flush()?;
|
||||
|
||||
debug!(
|
||||
"Dialogue appended {role} message ({len}B) to dialogue.md",
|
||||
len = content.len()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read the full dialogue log, up to max_chars (for context injection).
|
||||
pub async fn dialogue_read(&self, max_chars: usize) -> PalaceResult<String> {
|
||||
let path = self.base_dir.join("dialogue.md");
|
||||
if !path.exists() {
|
||||
return Ok(String::new());
|
||||
}
|
||||
let content = std::fs::read_to_string(&path)?;
|
||||
if content.len() <= max_chars {
|
||||
Ok(content)
|
||||
} else {
|
||||
// Take the last max_chars chars (recent history)
|
||||
let start = content.len().saturating_sub(max_chars);
|
||||
Ok(content[start..].to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the in-memory transcript store.
|
||||
pub fn transcript_store(&self) -> &TranscriptStore {
|
||||
|
||||
Reference in New Issue
Block a user