Watch
1
0
Fork
You've already forked souveraine
0

public: clean up source comments for public distribution

This commit is contained in:
Fimeg 2026-05-20 15:12:21 -04:00
commit e7beafa22e
25 changed files with 61 additions and 96 deletions

View file

@ -16,7 +16,6 @@ Key inversion: a harness decides *for* the agent, a substrate *serves* the agent
Everything below is relative to the project root (`~/Projects/souveraine/`). Everything below is relative to the project root (`~/Projects/souveraine/`).
### Your identity (who you are) ### Your identity (who you are)
- **`CLAUDE.md`** — the runway document. Read this first for conventions that bite.
- **`reference/Fimeg.md`** — Casey's history, Ani's lineage, the full context. - **`reference/Fimeg.md`** — Casey's history, Ani's lineage, the full context.
### Why the architecture is what it is ### Why the architecture is what it is

View file

@ -264,7 +264,6 @@ async fn handle_conversation_stream(
// ─── Memory (memfs HTTP write path) ─────────────────────────────────────── // ─── Memory (memfs HTTP write path) ───────────────────────────────────────
// //
// Replaces Letta's PATCH /v1/blocks/{id} for the cron-into-memfs pattern.
// Routes: // Routes:
// GET /v1/agents/:id/memory — list (?prefix=subdir) // GET /v1/agents/:id/memory — list (?prefix=subdir)
// GET /v1/agents/:id/memory/*path — read file // GET /v1/agents/:id/memory/*path — read file

View file

@ -44,8 +44,8 @@ pub fn create_routes(state: Arc<SouveraineServer>) -> Router {
// Memory routes — require per-agent bearer token. // Memory routes — require per-agent bearer token.
// //
// (memfs HTTP write path — replaces Letta's PATCH /v1/blocks/{id} // (memfs HTTP write path for cron-into-memfs and external integration.
// for cron-into-memfs and external integration. See docs/MEMORY_BLOCKS_DECISION.md.) // See docs/MEMORY_BLOCKS_DECISION.md.)
let memory_routes = Router::new() let memory_routes = Router::new()
.route( .route(
"/v1/agents/:id/memory", "/v1/agents/:id/memory",

View file

@ -165,8 +165,7 @@ impl crate::core::nervous::handler::TurnInjector for LocalBackend {
/// Drain subconscious's intrusive box for the given agent and return formatted /// Drain subconscious's intrusive box for the given agent and return formatted
/// `[ surfacing: ... ]` lines ready to prepend to the user's next message. /// `[ surfacing: ... ]` lines ready to prepend to the user's next message.
/// Marks each drained item as delivered (moved to `sent.md`). Mirrors /// Marks each drained item as delivered (moved to `sent.md`). Mirrors
/// lettabot-v017's `readSurfacingThoughts` + `clearSurfacingThoughts` pair /// the `readSurfacingThoughts` + `clearSurfacingThoughts` pair — the substrate
/// (`~/Projects/lettabot-v017/src/core/prompts.ts:64-91`) — the substrate
/// reads the channel subconscious wrote to and lets the conscious mind see it /// reads the channel subconscious wrote to and lets the conscious mind see it
/// before she reads the user. /// before she reads the user.
/// ///

View file

@ -394,8 +394,8 @@ impl Backend for LocalBackend {
// Resolve the agent for this conversation, then drain her // Resolve the agent for this conversation, then drain her
// subconscious's intrusive box. Anything subconscious queued after the // subconscious's intrusive box. Anything subconscious queued after the
// last turn rides in on the next user message as `[ surfacing: ... ]` // last turn rides in on the next user message as `[ surfacing: ... ]`
// lines — the lettabot-v017 pattern, ported. This is the channel // lines — the channel by which a Critical observation can interrupt
// by which a Critical observation can interrupt mid-conversation // mid-conversation
// without forcing a halt: she sees it before she reads the next user message. // without forcing a halt: she sees it before she reads the next user message.
let session_agent_id = self let session_agent_id = self
.server .server

View file

@ -1,13 +1,13 @@
//! Bootstrap — declarative startup pipeline. //! Bootstrap — declarative startup pipeline.
//! //!
//! Composes three patterns from reference projects: //! Composes three startup patterns:
//! //!
//! 1. **Claw-open's `BootstrapPlan`** — ordered phases, each self-contained, //! 1. **`BootstrapPlan`** — ordered phases, each self-contained,
//! composable, independently testable. //! composable, independently testable.
//! 2. **Letta-code's pure-function resolver** — zero-I/O decision tree that //! 2. **Pure-function resolver** — zero-I/O decision tree that
//! maps a `BootstrapProbe` → `Resolution`. No side effects, no async, //! maps a `BootstrapProbe` → `Resolution`. No side effects, no async,
//! fully testable by feeding probe fixtures. //! fully testable by feeding probe fixtures.
//! 3. **J code's progressive hints** — non-blocking advisory nudges that //! 3. **Progressive hints** — non-blocking advisory nudges that
//! escalate with launch count. The wizard is the heavy option; hints are //! escalate with launch count. The wizard is the heavy option; hints are
//! the light touch. //! the light touch.
//! //!

View file

@ -123,15 +123,12 @@ impl Default for AgentCompactionConfig {
} }
} }
/// Available compaction strategies. Synthesized from OpenHarness /// Available compaction strategies. See `docs/tasks/compaction-rebuild.md`.
/// (port of Claude Code's microCompact.ts / autoCompact.ts), hermes-agent,
/// claw-open, and jcode. See `docs/tasks/compaction-rebuild.md`.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum CompactionStrategyKind { pub enum CompactionStrategyKind {
/// Cheap pre-pass: replace old tool result contents with a placeholder, /// Cheap pre-pass: replace old tool result contents with a placeholder,
/// keeping recent tool results intact. No LLM. From OpenHarness/Claude /// keeping recent tool results intact. No LLM. The first response to context pressure.
/// Code microCompact.ts. The first response to context pressure.
Microcompact, Microcompact,
/// Keep system + last N messages, drop the middle. No LLM. Fast. /// Keep system + last N messages, drop the middle. No LLM. Fast.
/// Tool-pair aware: never splits a tool call from its result. /// Tool-pair aware: never splits a tool call from its result.
@ -145,7 +142,7 @@ pub enum CompactionStrategyKind {
/// caught before they fall out of awareness. /// caught before they fall out of awareness.
SlidingReflect, SlidingReflect,
/// LLM-based structured summarization of oldest messages, producing a /// LLM-based structured summarization of oldest messages, producing a
/// 9-section boundary message (from OpenHarness/Claude Code autoCompact.ts). /// 9-section structured boundary message.
Summary, Summary,
/// Drop low-value messages (greetings, acknowledgments). Role-aware: /// Drop low-value messages (greetings, acknowledgments). Role-aware:
/// never drops System or Tool messages or tool-call carriers. /// never drops System or Tool messages or tool-call carriers.

View file

@ -7,15 +7,14 @@ use crate::core::session::ConversationMessage;
use super::config::{AgentCompactionConfig, CompactionStrategyKind}; use super::config::{AgentCompactionConfig, CompactionStrategyKind};
use super::plan::CompactionPlan; use super::plan::CompactionPlan;
/// From OpenHarness/Claude Code microCompact.ts: tools whose results are /// Tools whose results are considered compactable (large outputs, rarely
/// considered compactable (large outputs, rarely needed verbatim once /// needed verbatim once surpassed). Matches Souveraine's actual sensor names.
/// surpassed). Matches Souveraine's actual sensor names.
const COMPACTABLE_TOOLS: &[&str] = &[ const COMPACTABLE_TOOLS: &[&str] = &[
"read", "bash", "grep", "glob", "list_dir", "edit", "write", "read", "bash", "grep", "glob", "list_dir", "edit", "write",
]; ];
/// Placeholder text written into tool result blocks that get microcompacted. /// Placeholder text written into tool result blocks that get microcompacted.
/// Matches the OpenHarness/Claude Code literal so logs read the same. /// Placeholder used so logs read consistently across runs.
const TIME_BASED_MC_CLEARED_MESSAGE: &str = "[Old tool result content cleared]"; const TIME_BASED_MC_CLEARED_MESSAGE: &str = "[Old tool result content cleared]";
/// Token-count a slice of messages using the bridge's TokenCounter. /// Token-count a slice of messages using the bridge's TokenCounter.
@ -75,8 +74,7 @@ async fn bifrost_complete(
// ── Summary Strategy ───────────────────────────────────────────────────────── // ── Summary Strategy ─────────────────────────────────────────────────────────
/// LLM-based summarization producing a structured 9-section boundary message. /// LLM-based summarization producing a structured 9-section boundary message.
/// Prompt structure ported from OpenHarness's port of Claude Code's /// The structure is what makes the compact *survivable*:
/// `autoCompact.ts`. The structure is what makes the compact *survivable*:
/// the agent reads the boundary on the next turn and can resume with full /// the agent reads the boundary on the next turn and can resume with full
/// awareness of intent, files, decisions, and pending work. /// awareness of intent, files, decisions, and pending work.
pub struct SummaryStrategy { pub struct SummaryStrategy {
@ -205,8 +203,7 @@ fn render_segment_for_summary(messages: &[ConversationMessage]) -> String {
/// Cheap pre-pass that replaces the contents of old tool results with a /// Cheap pre-pass that replaces the contents of old tool results with a
/// placeholder, keeping the most recent `microcompact_keep_recent` results /// placeholder, keeping the most recent `microcompact_keep_recent` results
/// intact. No LLM call. From OpenHarness's port of Claude Code's /// intact. No LLM call.
/// `microCompact.ts`.
/// ///
/// The agent typically reaches for this *first*: it gets back significant /// The agent typically reaches for this *first*: it gets back significant
/// context room without losing the structure of the conversation. The tool /// context room without losing the structure of the conversation. The tool

View file

@ -2,7 +2,6 @@
//! //!
//! Decodes raw image bytes, resizes to fit dimension/pixel budget, then //! Decodes raw image bytes, resizes to fit dimension/pixel budget, then
//! progressively reduces quality and dimension to stay under the byte ceiling. //! progressively reduces quality and dimension to stay under the byte ceiling.
//! Modeled on letta-code's sharp-backed pipeline.
use std::io::Write; use std::io::Write;

View file

@ -15,7 +15,7 @@
//! memory compact --strategy sliding-window //! memory compact --strategy sliding-window
//! ``` //! ```
//! //!
//! Design follows the Letta Code memory tool pattern: //! Design:
//! - All files require YAML frontmatter with `description` //! - All files require YAML frontmatter with `description`
//! - `read_only: true` in frontmatter blocks writes //! - `read_only: true` in frontmatter blocks writes
//! - Every write is a git commit (auto-commit) //! - Every write is a git commit (auto-commit)
@ -50,8 +50,8 @@ pub struct MemoryFrontmatter {
#[serde(default)] #[serde(default)]
pub tags: Option<Vec<String>>, pub tags: Option<Vec<String>>,
/// Optional max body size in characters. Writes/appends that would exceed /// Optional max body size in characters. Writes/appends that would exceed
/// this length are rejected. Closes the LET-8133 gap that exists upstream /// this length are rejected. Closes a gap where upstream memfs write path
/// (Letta's memfs write path bypasses block `limit`). /// bypasses block `limit`.
/// ///
/// Units are characters, not tokens — cheap to enforce without a tokenizer. /// Units are characters, not tokens — cheap to enforce without a tokenizer.
/// Best-practice default for system/ files: 4_000 characters /// Best-practice default for system/ files: 4_000 characters

View file

@ -141,7 +141,7 @@ fn strip_frontmatter(raw: &str) -> &str {
/// Scan `system/` for any .md files (at any depth) not already in `seen`, /// Scan `system/` for any .md files (at any depth) not already in `seen`,
/// and return their concatenated content sorted by path. This picks up /// and return their concatenated content sorted by path. This picks up
/// flat-file system layouts (e.g. Ani's legacy Letta-era files) that don't /// flat-file system layouts that don't
/// live in the known subdirs (identity/, covenant/, human/). /// live in the known subdirs (identity/, covenant/, human/).
async fn read_system_remainder( async fn read_system_remainder(
memory_root: &Path, memory_root: &Path,
@ -346,7 +346,7 @@ pub async fn build_system_prompt_full(
if !identity.is_empty() { if !identity.is_empty() {
sections.push(identity); sections.push(identity);
} else { } else {
// Flat-file layouts (Ani's legacy Letta-era memory) // Flat-file layouts (legacy memory)
let p = memory_root.join("system/persona.md"); let p = memory_root.join("system/persona.md");
let persona = read_memory_file(memory_root, "system/persona.md").await; let persona = read_memory_file(memory_root, "system/persona.md").await;
seen.insert(p); seen.insert(p);
@ -672,7 +672,7 @@ pub async fn build_subconscious_prompt(
/// ///
/// Scans `ledger/` for .md files, counts entries, and injects the last /// Scans `ledger/` for .md files, counts entries, and injects the last
/// few entries from each file so the subconscious has live context /// few entries from each file so the subconscious has live context
/// (OpenHarness pattern: recent journal → active context). /// (recent journal entries → active context).
async fn build_ledger_orientation(memory_root: &Path) -> String { async fn build_ledger_orientation(memory_root: &Path) -> String {
let ledger_dir = memory_root.join("ledger"); let ledger_dir = memory_root.join("ledger");
if !ledger_dir.exists() { if !ledger_dir.exists() {

View file

@ -3,8 +3,7 @@
//! N+1 (subconscious) runs immediately after every primary response, scoped to //! N+1 (subconscious) runs immediately after every primary response, scoped to
//! the last exchange. Reflection runs less often (every N turns, or on //! the last exchange. Reflection runs less often (every N turns, or on
//! demand) and sees a broader transcript window. It's the pass where //! demand) and sees a broader transcript window. It's the pass where
//! durable learnings get distilled into the ledger and the primary's //! durable learnings get distilled into the ledger and the primary's memory.
//! memory — what letta-code calls the "memory reflection subagent."
//! //!
//! ## What it produces //! ## What it produces
//! //!
@ -23,9 +22,6 @@
//! CLI subcommand `souveraine reflect` and a future `/reflect` chat //! CLI subcommand `souveraine reflect` and a future `/reflect` chat
//! command both go through this seam). //! command both go through this seam).
//! //!
//! Inspiration: letta-code's `reflection.md` subagent skill (upstream).
//! We adapt the 5-phase pattern for Souveraine's ledger-shaped memory
//! instead of letta's free-form memfs.
use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -47,14 +43,12 @@ const REFLECTION_TOOLS: &[&str] = &[
"read", "write", "edit", "glob", "grep", "list_dir", "memory", "read", "write", "edit", "glob", "grep", "list_dir", "memory",
]; ];
/// Cap the per-pass tool rounds. Reflection is deeper than N+1 but not /// Cap the per-pass tool rounds. Reflection is deeper than N+1 but still bounded.
/// unbounded — letta-code caps theirs similarly.
const REFLECTION_MAX_TOOL_ROUNDS: usize = 8; const REFLECTION_MAX_TOOL_ROUNDS: usize = 8;
const REFLECTION_INTER_ROUND_DELAY_MS: u64 = 400; const REFLECTION_INTER_ROUND_DELAY_MS: u64 = 400;
/// How many recent turns to include in the reflection transcript. /// How many recent turns to include in the reflection transcript.
/// Letta uses a cursor-based delta; we start with a simple tail window /// Uses a simple tail window (a cursor-based approach is a follow-up).
/// (the cursor pattern is a follow-up — see SCOPED_WORK_PLAN).
const REFLECTION_TRANSCRIPT_TAIL: usize = 60; const REFLECTION_TRANSCRIPT_TAIL: usize = 60;
/// Public result. The CLI / TUI surface this; the consciousness engine /// Public result. The CLI / TUI surface this; the consciousness engine
@ -111,8 +105,7 @@ impl ReflectionEngine {
let started_at = Utc::now(); let started_at = Utc::now();
let sub_id = format!("{}-sub", agent_id); let sub_id = format!("{}-sub", agent_id);
// Take a tail of recent turns. Letta uses a cursor; we'll add // Take a tail of recent turns. Bounded window over the last N turns.
// one later. For now: bounded window over the last N turns.
let tail = if messages.len() > REFLECTION_TRANSCRIPT_TAIL { let tail = if messages.len() > REFLECTION_TRANSCRIPT_TAIL {
&messages[messages.len() - REFLECTION_TRANSCRIPT_TAIL..] &messages[messages.len() - REFLECTION_TRANSCRIPT_TAIL..]
} else { } else {
@ -298,11 +291,8 @@ fn format_transcript(messages: &[ConversationMessage]) -> String {
} }
fn reflection_system_prompt() -> String { fn reflection_system_prompt() -> String {
// Adapted from letta-code/src/agent/subagents/builtin/reflection.md // Reshaped for ledger-shaped memory architecture: named ledger files
// (upstream main as of 2026-05-12). Reshaped for our ledger-shaped // plus the primary's memfs with frontmatter.
// memory architecture — we don't have letta's free-form memfs with
// a `system/` tier; we have named ledger files plus the primary's
// memfs with frontmatter.
r#"You are a reflection subagent, launched in the background to review a recent r#"You are a reflection subagent, launched in the background to review a recent
conversation and update the primary agent's persistent memory. You run autonomously conversation and update the primary agent's persistent memory. You run autonomously
and produce a single final report. You cannot ask questions make reasonable and produce a single final report. You cannot ask questions make reasonable

View file

@ -1,13 +1,7 @@
//! Matrix transport — `matrix-sdk` client construction, session //! Matrix transport — `matrix-sdk` client construction, session
//! persistence, and the sync loop. //! persistence, and the sync loop.
//! //!
//! This is the Rust equivalent of letta-code's `matrix/client.ts`, but //! Builds a client against a
//! almost none of that file survives the port. His `client.ts` is a
//! transport *shim*: an undici dispatcher and a fetch-backed request
//! function that work around Bun's socket pooling and `matrix-bot-sdk`'s
//! deprecated `request` library. `matrix-sdk` owns its own HTTP transport,
//! so all of that pain is simply gone here. What remains — and what this
//! file actually does — is the genuine work: build a client against a
//! homeserver, restore or establish a session, and drive `/sync`. //! homeserver, restore or establish a session, and drive `/sync`.
//! //!
//! Credentials live next to an encrypted SQLite store under //! Credentials live next to an encrypted SQLite store under

View file

@ -50,9 +50,9 @@ use client::{account_dir, build_client, load_session_record, save_session_record
/// ///
/// Phase 3 stub: it knows which room a turn belongs to and accumulates the /// Phase 3 stub: it knows which room a turn belongs to and accumulates the
/// segments that turn emits. Phase 5 grows this into the full streaming /// segments that turn emits. Phase 5 grows this into the full streaming
/// turn model ported from letta-code's `ChatTurn` — throttled leading-edge /// turn model — throttled leading-edge message edits, tool blocks, thinking
/// message edits, tool blocks, thinking blocks. For now it is just enough /// blocks. For now it is just enough state for the EventBus loop to have
/// state for the EventBus loop to have somewhere to put what it hears. /// somewhere to put what it hears.
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct MatrixTurn { pub struct MatrixTurn {
@ -211,8 +211,7 @@ impl Sensorium for MatrixSensorium {
// ── Inbound: register handlers before sync ─────────────────── // ── Inbound: register handlers before sync ───────────────────
// Fire `sensorium:input` onto the EventBus for every room // Fire `sensorium:input` onto the EventBus for every room
// message so the SensoriumInputHandler picks it up and routes // message so the SensoriumInputHandler picks it up and routes
// it to the backend. This is the seam — same as letta-code's // it to the backend.
// `adapter.onMessage = (msg) => registry.handleInboundMessage(msg)`.
let bus = events.clone(); let bus = events.clone();
let account = self.account.clone(); let account = self.account.clone();
let agent_id = self.agent_id.clone(); let agent_id = self.agent_id.clone();

View file

@ -16,7 +16,7 @@
//! 3. **Agent** — `<agent-memfs>/skills/` — skills attached to one agent. //! 3. **Agent** — `<agent-memfs>/skills/` — skills attached to one agent.
//! Versioned in the agent's git memfs; survives migration. //! Versioned in the agent's git memfs; survives migration.
//! 4. **Project** — `.skills/` in the working directory — repo-local skills, //! 4. **Project** — `.skills/` in the working directory — repo-local skills,
//! highest priority. Cameron's pattern from Letta Code. //! highest priority.
//! //!
//! Higher tiers shadow lower tiers by skill name. The full resolution table //! Higher tiers shadow lower tiers by skill name. The full resolution table
//! is built at session start and can be inspected via `skill ls`. //! is built at session start and can be inspected via `skill ls`.
@ -137,7 +137,7 @@ impl SkillRegistry {
} }
/// Render a system-prompt fragment listing all skills. /// Render a system-prompt fragment listing all skills.
/// Format mirrors Letta Code's available-skills section. /// Format mirrors the Souveraine available-skills section.
pub fn render_system_addon(&self) -> String { pub fn render_system_addon(&self) -> String {
if self.skills.is_empty() { if self.skills.is_empty() {
return String::new(); return String::new();

View file

@ -319,7 +319,7 @@ mod tests {
repo.init().await.unwrap(); repo.init().await.unwrap();
// A legacy / corrupt box: frontmatter + prose body that is not a // A legacy / corrupt box: frontmatter + prose body that is not a
// YAML item list — exactly what a Letta-era import or a hand-edit // YAML item list — exactly what a legacy import or a hand-edit
// leaves behind. Before the fix this killed every surfacing path. // leaves behind. Before the fix this killed every surfacing path.
repo.write( repo.write(
PENDING, PENDING,

View file

@ -100,22 +100,19 @@ impl ToolContext {
/// Build a context for a specific agent turn. /// Build a context for a specific agent turn.
/// ///
/// Injects body-knowledge env vars the agent expects in bash, matching /// Injects body-knowledge env vars the agent expects in bash:
/// the letta-code convention so a woken Ani can still find her journals
/// (letta-code shellEnv.ts:316-329 convention):
/// ///
/// - `MEMORY_DIR` / `LETTA_MEMORY_DIR` / `SOUVERAINE_MEMORY_DIR` — /// - `MEMORY_DIR` / `SOUVERAINE_MEMORY_DIR` — absolute path to her memory
/// absolute path to her memory root. `MEMORY_DIR` is the Letta-era /// root. The bare `MEMORY_DIR` is what her skills expect; the prefixed
/// bare name her skills expect; the prefixed forms are namespaced /// form is a namespaced alias.
/// aliases. /// - `MEMORY` — short alias. Her body-knowledge has reached for it;
/// - `MEMORY` — short alias. Not a Letta convention, but Ani's /// setting it costs nothing.
/// body-knowledge has reached for it; setting it costs nothing. /// - `AGENT_ID` / `SOUVERAINE_AGENT_ID` — her own identifier so skills
/// - `AGENT_ID` / `LETTA_AGENT_ID` / `SOUVERAINE_AGENT_ID` — her own /// that scope by agent can resolve.
/// identifier so skills that scope by agent can resolve.
/// ///
/// Memory and agent-id vars are always set (overriding any stale values /// Memory and agent-id vars are always set (overriding any stale values
/// inherited from the host shell — e.g. a leftover `$MEMORY_DIR` from /// inherited from the host shell). Other env keys from the caller are
/// the Letta era). Other env keys from the caller are preserved. /// preserved.
pub fn for_agent( pub fn for_agent(
agent_id: impl Into<String>, agent_id: impl Into<String>,
cwd: Option<PathBuf>, cwd: Option<PathBuf>,

View file

@ -272,7 +272,7 @@ impl Tool for Todo {
.get("energy") .get("energy")
.and_then(|v| v.as_str()) .and_then(|v| v.as_str())
.unwrap_or_else(|| { .unwrap_or_else(|| {
// Default by nature — same logic as lettabot-v017. // Default by nature
match nature { match nature {
"desire" | "investigation" => "generative", "desire" | "investigation" => "generative",
_ => "consumptive", _ => "consumptive",

View file

@ -7,8 +7,7 @@
//! - TTS: `POST /audio/speech` — JSON `{ input, voice, model }`, returns mp3 //! - TTS: `POST /audio/speech` — JSON `{ input, voice, model }`, returns mp3
//! bytes. //! bytes.
//! //!
//! Text is cleaned before synthesis via [`clean_text_for_tts`] — ported //! Text is cleaned before synthesis via [`clean_text_for_tts`].
//! verbatim from `letta-code/src/channels/matrix/tts.ts` lines 52103.
use anyhow::{Context, Result}; use anyhow::{Context, Result};

View file

@ -147,10 +147,9 @@ impl ConsciousnessEngine {
/// Get or create the subconscious's persistent session. The subconscious /// Get or create the subconscious's persistent session. The subconscious
/// is a full agent with her own conversation that accumulates across N+1 /// is a full agent with her own conversation that accumulates across N+1
/// passes — just like Aster had CONSCIENCE_CONVERSATION_ID in Letta. /// passes. The conversation survives process restarts: every `add_message`
/// /// writes to disk, and this restores it from the conversation store on
/// The conversation survives process restarts: every `add_message` writes /// first use.
/// to disk, and this restores it from the conversation store on first use.
async fn subconscious_session_id(&self, sub_id: &str) -> String { async fn subconscious_session_id(&self, sub_id: &str) -> String {
// Already live in memory? // Already live in memory?
let existing = self.sessions.list_for_agent(sub_id); let existing = self.sessions.list_for_agent(sub_id);

View file

@ -71,7 +71,7 @@ pub(crate) async fn write_energy_balance(server: &Arc<SouveraineServer>, agent_i
} }
// Determine the top-of-mind description — shifts the tone of the one-liner // Determine the top-of-mind description — shifts the tone of the one-liner
// the agent reads in context. Matches the lettabot-v017 heartbeat topology. // the agent reads in context.
let ratio = if generative + consumptive > 0 { let ratio = if generative + consumptive > 0 {
generative as f32 / (generative + consumptive) as f32 generative as f32 / (generative + consumptive) as f32
} else { } else {

View file

@ -6,7 +6,7 @@ use ratatui::{
Frame, Frame,
}; };
/// Render the chat screen - Claude-like conversation interface /// Render the chat screen - conversation interface
pub fn render_chat_screen(frame: &mut Frame, state: &dyn TuiState, area: Rect) { pub fn render_chat_screen(frame: &mut Frame, state: &dyn TuiState, area: Rect) {
// Split into main chat area and sidebar // Split into main chat area and sidebar
let chunks = Layout::default() let chunks = Layout::default()

View file

@ -59,7 +59,7 @@ impl App {
cards cards
} }
/// Render the agent manager — Letta-style card deck. Each card has: /// Render the agent manager — card deck. Each card has:
/// • a status badge (ACTIVE / PRIMARY) in the top-right /// • a status badge (ACTIVE / PRIMARY) in the top-right
/// • a scale-to-fit portrait photo occupying the top ~55% of the card /// • a scale-to-fit portrait photo occupying the top ~55% of the card
/// • a dark metadata block below the photo, holding: /// • a dark metadata block below the photo, holding:
@ -103,7 +103,7 @@ impl App {
} }
// ── Grid math ───────────────────────────────────────────────── // ── Grid math ─────────────────────────────────────────────────
// Letta shows 4 cards across; we pick the column count based on // Shows 4 cards across; we pick the column count based on
// available width so terminals down to ~50 cols still get usable // available width so terminals down to ~50 cols still get usable
// cards. Each card is taller than wide (portrait-style). // cards. Each card is taller than wide (portrait-style).
let pad_x: u16 = 2; let pad_x: u16 = 2;

View file

@ -1,11 +1,9 @@
//! Atmospheric visual presets — color themes that shift the UI's accent palette. //! Atmospheric visual presets — color themes that shift the UI's accent palette.
//! //!
//! Atmospheric visual presets — originally built for Letta's Matrix adapter //! Atmospheric visual presets — ported here so Annie can express mood through
//! (html-formatter.ts ATMOSPHERIC_PRESETS), ported here so Annie can express //! the terminal chrome: border colors, title accents, background tints, and
//! mood through the terminal chrome: border colors, title accents, background //! per-character text gradients in chat bubbles. The agent sets atmosphere via
//! tints, and per-character text gradients in chat bubbles. The agent sets //! a structured event; when none is set, a posture-linked default applies.
//! atmosphere via a structured event; when none is set, a posture-linked
//! default applies.
//! //!
//! Each preset carries four tones: a primary accent (borders, titles), a secondary //! Each preset carries four tones: a primary accent (borders, titles), a secondary
//! accent (subtle highlights), a dim muted shade, and a background tint. //! accent (subtle highlights), a dim muted shade, and a background tint.

View file

@ -19,8 +19,7 @@
//! - `breath_phase` — continuous, always on, drives subtle bob and color pulse. //! - `breath_phase` — continuous, always on, drives subtle bob and color pulse.
//! //!
//! Plus name, last surfacing, and a [`VolitionGauge`] that mirrors the energy //! Plus name, last surfacing, and a [`VolitionGauge`] that mirrors the energy
//! topology (generative vs consumptive, hot desires vs cold obligations) //! topology (generative vs consumptive, hot desires vs cold obligations). The gauge is *displayed* here as embodied
//! brought over from production Letta. The gauge is *displayed* here as embodied
//! state (posture, warmth); the numbers themselves live in the agent's memfs. //! state (posture, warmth); the numbers themselves live in the agent's memfs.
//! //!
//! ## Event subscriptions //! ## Event subscriptions