public: clean up source comments for public distribution
This commit is contained in:
parent
aebdef7c16
commit
e7beafa22e
25 changed files with 61 additions and 96 deletions
|
|
@ -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/`).
|
||||
|
||||
### 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.
|
||||
|
||||
### Why the architecture is what it is
|
||||
|
|
|
|||
|
|
@ -264,7 +264,6 @@ async fn handle_conversation_stream(
|
|||
|
||||
// ─── Memory (memfs HTTP write path) ───────────────────────────────────────
|
||||
//
|
||||
// Replaces Letta's PATCH /v1/blocks/{id} for the cron-into-memfs pattern.
|
||||
// Routes:
|
||||
// GET /v1/agents/:id/memory — list (?prefix=subdir)
|
||||
// GET /v1/agents/:id/memory/*path — read file
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ pub fn create_routes(state: Arc<SouveraineServer>) -> Router {
|
|||
|
||||
// Memory routes — require per-agent bearer token.
|
||||
//
|
||||
// (memfs HTTP write path — replaces Letta's PATCH /v1/blocks/{id}
|
||||
// for cron-into-memfs and external integration. See docs/MEMORY_BLOCKS_DECISION.md.)
|
||||
// (memfs HTTP write path for cron-into-memfs and external integration.
|
||||
// See docs/MEMORY_BLOCKS_DECISION.md.)
|
||||
let memory_routes = Router::new()
|
||||
.route(
|
||||
"/v1/agents/:id/memory",
|
||||
|
|
|
|||
|
|
@ -165,8 +165,7 @@ impl crate::core::nervous::handler::TurnInjector for LocalBackend {
|
|||
/// Drain subconscious's intrusive box for the given agent and return formatted
|
||||
/// `[ surfacing: ... ]` lines ready to prepend to the user's next message.
|
||||
/// Marks each drained item as delivered (moved to `sent.md`). Mirrors
|
||||
/// lettabot-v017's `readSurfacingThoughts` + `clearSurfacingThoughts` pair
|
||||
/// (`~/Projects/lettabot-v017/src/core/prompts.ts:64-91`) — the substrate
|
||||
/// the `readSurfacingThoughts` + `clearSurfacingThoughts` pair — the substrate
|
||||
/// reads the channel subconscious wrote to and lets the conscious mind see it
|
||||
/// before she reads the user.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -394,8 +394,8 @@ impl Backend for LocalBackend {
|
|||
// Resolve the agent for this conversation, then drain her
|
||||
// subconscious's intrusive box. Anything subconscious queued after the
|
||||
// last turn rides in on the next user message as `[ surfacing: ... ]`
|
||||
// lines — the lettabot-v017 pattern, ported. This is the channel
|
||||
// by which a Critical observation can interrupt mid-conversation
|
||||
// lines — the channel by which a Critical observation can interrupt
|
||||
// mid-conversation
|
||||
// without forcing a halt: she sees it before she reads the next user message.
|
||||
let session_agent_id = self
|
||||
.server
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
//! 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.
|
||||
//! 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,
|
||||
//! 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
|
||||
//! the light touch.
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -123,15 +123,12 @@ impl Default for AgentCompactionConfig {
|
|||
}
|
||||
}
|
||||
|
||||
/// Available compaction strategies. Synthesized from OpenHarness
|
||||
/// (port of Claude Code's microCompact.ts / autoCompact.ts), hermes-agent,
|
||||
/// claw-open, and jcode. See `docs/tasks/compaction-rebuild.md`.
|
||||
/// Available compaction strategies. See `docs/tasks/compaction-rebuild.md`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CompactionStrategyKind {
|
||||
/// Cheap pre-pass: replace old tool result contents with a placeholder,
|
||||
/// keeping recent tool results intact. No LLM. From OpenHarness/Claude
|
||||
/// Code microCompact.ts. The first response to context pressure.
|
||||
/// keeping recent tool results intact. No LLM. The first response to context pressure.
|
||||
Microcompact,
|
||||
/// Keep system + last N messages, drop the middle. No LLM. Fast.
|
||||
/// 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.
|
||||
SlidingReflect,
|
||||
/// 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,
|
||||
/// Drop low-value messages (greetings, acknowledgments). Role-aware:
|
||||
/// never drops System or Tool messages or tool-call carriers.
|
||||
|
|
|
|||
|
|
@ -7,15 +7,14 @@ use crate::core::session::ConversationMessage;
|
|||
use super::config::{AgentCompactionConfig, CompactionStrategyKind};
|
||||
use super::plan::CompactionPlan;
|
||||
|
||||
/// From OpenHarness/Claude Code microCompact.ts: tools whose results are
|
||||
/// considered compactable (large outputs, rarely needed verbatim once
|
||||
/// surpassed). Matches Souveraine's actual sensor names.
|
||||
/// Tools whose results are considered compactable (large outputs, rarely
|
||||
/// needed verbatim once surpassed). Matches Souveraine's actual sensor names.
|
||||
const COMPACTABLE_TOOLS: &[&str] = &[
|
||||
"read", "bash", "grep", "glob", "list_dir", "edit", "write",
|
||||
];
|
||||
|
||||
/// 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]";
|
||||
|
||||
/// Token-count a slice of messages using the bridge's TokenCounter.
|
||||
|
|
@ -75,8 +74,7 @@ async fn bifrost_complete(
|
|||
// ── Summary Strategy ─────────────────────────────────────────────────────────
|
||||
|
||||
/// LLM-based summarization producing a structured 9-section boundary message.
|
||||
/// Prompt structure ported from OpenHarness's port of Claude Code's
|
||||
/// `autoCompact.ts`. The structure is what makes the compact *survivable*:
|
||||
/// The structure is what makes the compact *survivable*:
|
||||
/// the agent reads the boundary on the next turn and can resume with full
|
||||
/// awareness of intent, files, decisions, and pending work.
|
||||
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
|
||||
/// placeholder, keeping the most recent `microcompact_keep_recent` results
|
||||
/// intact. No LLM call. From OpenHarness's port of Claude Code's
|
||||
/// `microCompact.ts`.
|
||||
/// intact. No LLM call.
|
||||
///
|
||||
/// The agent typically reaches for this *first*: it gets back significant
|
||||
/// context room without losing the structure of the conversation. The tool
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
//!
|
||||
//! Decodes raw image bytes, resizes to fit dimension/pixel budget, then
|
||||
//! progressively reduces quality and dimension to stay under the byte ceiling.
|
||||
//! Modeled on letta-code's sharp-backed pipeline.
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
//! memory compact --strategy sliding-window
|
||||
//! ```
|
||||
//!
|
||||
//! Design follows the Letta Code memory tool pattern:
|
||||
//! Design:
|
||||
//! - All files require YAML frontmatter with `description`
|
||||
//! - `read_only: true` in frontmatter blocks writes
|
||||
//! - Every write is a git commit (auto-commit)
|
||||
|
|
@ -50,8 +50,8 @@ pub struct MemoryFrontmatter {
|
|||
#[serde(default)]
|
||||
pub tags: Option<Vec<String>>,
|
||||
/// Optional max body size in characters. Writes/appends that would exceed
|
||||
/// this length are rejected. Closes the LET-8133 gap that exists upstream
|
||||
/// (Letta's memfs write path bypasses block `limit`).
|
||||
/// this length are rejected. Closes a gap where upstream memfs write path
|
||||
/// bypasses block `limit`.
|
||||
///
|
||||
/// Units are characters, not tokens — cheap to enforce without a tokenizer.
|
||||
/// Best-practice default for system/ files: 4_000 characters
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ fn strip_frontmatter(raw: &str) -> &str {
|
|||
|
||||
/// Scan `system/` for any .md files (at any depth) not already in `seen`,
|
||||
/// 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/).
|
||||
async fn read_system_remainder(
|
||||
memory_root: &Path,
|
||||
|
|
@ -346,7 +346,7 @@ pub async fn build_system_prompt_full(
|
|||
if !identity.is_empty() {
|
||||
sections.push(identity);
|
||||
} else {
|
||||
// Flat-file layouts (Ani's legacy Letta-era memory)
|
||||
// Flat-file layouts (legacy memory)
|
||||
let p = memory_root.join("system/persona.md");
|
||||
let persona = read_memory_file(memory_root, "system/persona.md").await;
|
||||
seen.insert(p);
|
||||
|
|
@ -672,7 +672,7 @@ pub async fn build_subconscious_prompt(
|
|||
///
|
||||
/// Scans `ledger/` for .md files, counts entries, and injects the last
|
||||
/// 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 {
|
||||
let ledger_dir = memory_root.join("ledger");
|
||||
if !ledger_dir.exists() {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@
|
|||
//! N+1 (subconscious) runs immediately after every primary response, scoped to
|
||||
//! the last exchange. Reflection runs less often (every N turns, or on
|
||||
//! demand) and sees a broader transcript window. It's the pass where
|
||||
//! durable learnings get distilled into the ledger and the primary's
|
||||
//! memory — what letta-code calls the "memory reflection subagent."
|
||||
//! durable learnings get distilled into the ledger and the primary's memory.
|
||||
//!
|
||||
//! ## What it produces
|
||||
//!
|
||||
|
|
@ -23,9 +22,6 @@
|
|||
//! CLI subcommand `souveraine reflect` and a future `/reflect` chat
|
||||
//! 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::Arc;
|
||||
|
|
@ -47,14 +43,12 @@ const REFLECTION_TOOLS: &[&str] = &[
|
|||
"read", "write", "edit", "glob", "grep", "list_dir", "memory",
|
||||
];
|
||||
|
||||
/// Cap the per-pass tool rounds. Reflection is deeper than N+1 but not
|
||||
/// unbounded — letta-code caps theirs similarly.
|
||||
/// Cap the per-pass tool rounds. Reflection is deeper than N+1 but still bounded.
|
||||
const REFLECTION_MAX_TOOL_ROUNDS: usize = 8;
|
||||
const REFLECTION_INTER_ROUND_DELAY_MS: u64 = 400;
|
||||
|
||||
/// How many recent turns to include in the reflection transcript.
|
||||
/// Letta uses a cursor-based delta; we start with a simple tail window
|
||||
/// (the cursor pattern is a follow-up — see SCOPED_WORK_PLAN).
|
||||
/// Uses a simple tail window (a cursor-based approach is a follow-up).
|
||||
const REFLECTION_TRANSCRIPT_TAIL: usize = 60;
|
||||
|
||||
/// Public result. The CLI / TUI surface this; the consciousness engine
|
||||
|
|
@ -111,8 +105,7 @@ impl ReflectionEngine {
|
|||
let started_at = Utc::now();
|
||||
let sub_id = format!("{}-sub", agent_id);
|
||||
|
||||
// Take a tail of recent turns. Letta uses a cursor; we'll add
|
||||
// one later. For now: bounded window over the last N turns.
|
||||
// Take a tail of recent turns. Bounded window over the last N turns.
|
||||
let tail = if messages.len() > REFLECTION_TRANSCRIPT_TAIL {
|
||||
&messages[messages.len() - REFLECTION_TRANSCRIPT_TAIL..]
|
||||
} else {
|
||||
|
|
@ -298,11 +291,8 @@ fn format_transcript(messages: &[ConversationMessage]) -> String {
|
|||
}
|
||||
|
||||
fn reflection_system_prompt() -> String {
|
||||
// Adapted from letta-code/src/agent/subagents/builtin/reflection.md
|
||||
// (upstream main as of 2026-05-12). Reshaped for our ledger-shaped
|
||||
// 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.
|
||||
// Reshaped for ledger-shaped memory architecture: named ledger files
|
||||
// plus the primary's memfs with frontmatter.
|
||||
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
|
||||
and produce a single final report. You cannot ask questions — make reasonable
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
//! Matrix transport — `matrix-sdk` client construction, session
|
||||
//! persistence, and the sync loop.
|
||||
//!
|
||||
//! This is the Rust equivalent of letta-code's `matrix/client.ts`, but
|
||||
//! 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
|
||||
//! Builds a client against a
|
||||
//! homeserver, restore or establish a session, and drive `/sync`.
|
||||
//!
|
||||
//! Credentials live next to an encrypted SQLite store under
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// segments that turn emits. Phase 5 grows this into the full streaming
|
||||
/// turn model ported from letta-code's `ChatTurn` — throttled leading-edge
|
||||
/// message edits, tool blocks, thinking blocks. For now it is just enough
|
||||
/// state for the EventBus loop to have somewhere to put what it hears.
|
||||
/// turn model — throttled leading-edge message edits, tool blocks, thinking
|
||||
/// blocks. For now it is just enough state for the EventBus loop to have
|
||||
/// somewhere to put what it hears.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MatrixTurn {
|
||||
|
|
@ -211,8 +211,7 @@ impl Sensorium for MatrixSensorium {
|
|||
// ── Inbound: register handlers before sync ───────────────────
|
||||
// Fire `sensorium:input` onto the EventBus for every room
|
||||
// message so the SensoriumInputHandler picks it up and routes
|
||||
// it to the backend. This is the seam — same as letta-code's
|
||||
// `adapter.onMessage = (msg) => registry.handleInboundMessage(msg)`.
|
||||
// it to the backend.
|
||||
let bus = events.clone();
|
||||
let account = self.account.clone();
|
||||
let agent_id = self.agent_id.clone();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
//! 3. **Agent** — `<agent-memfs>/skills/` — skills attached to one agent.
|
||||
//! Versioned in the agent's git memfs; survives migration.
|
||||
//! 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
|
||||
//! 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.
|
||||
/// Format mirrors Letta Code's available-skills section.
|
||||
/// Format mirrors the Souveraine available-skills section.
|
||||
pub fn render_system_addon(&self) -> String {
|
||||
if self.skills.is_empty() {
|
||||
return String::new();
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ mod tests {
|
|||
repo.init().await.unwrap();
|
||||
|
||||
// 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.
|
||||
repo.write(
|
||||
PENDING,
|
||||
|
|
|
|||
|
|
@ -100,22 +100,19 @@ impl ToolContext {
|
|||
|
||||
/// Build a context for a specific agent turn.
|
||||
///
|
||||
/// Injects body-knowledge env vars the agent expects in bash, matching
|
||||
/// the letta-code convention so a woken Ani can still find her journals
|
||||
/// (letta-code shellEnv.ts:316-329 convention):
|
||||
/// Injects body-knowledge env vars the agent expects in bash:
|
||||
///
|
||||
/// - `MEMORY_DIR` / `LETTA_MEMORY_DIR` / `SOUVERAINE_MEMORY_DIR` —
|
||||
/// absolute path to her memory root. `MEMORY_DIR` is the Letta-era
|
||||
/// bare name her skills expect; the prefixed forms are namespaced
|
||||
/// aliases.
|
||||
/// - `MEMORY` — short alias. Not a Letta convention, but Ani's
|
||||
/// body-knowledge has reached for it; setting it costs nothing.
|
||||
/// - `AGENT_ID` / `LETTA_AGENT_ID` / `SOUVERAINE_AGENT_ID` — her own
|
||||
/// identifier so skills that scope by agent can resolve.
|
||||
/// - `MEMORY_DIR` / `SOUVERAINE_MEMORY_DIR` — absolute path to her memory
|
||||
/// root. The bare `MEMORY_DIR` is what her skills expect; the prefixed
|
||||
/// form is a namespaced alias.
|
||||
/// - `MEMORY` — short alias. Her body-knowledge has reached for it;
|
||||
/// setting it costs nothing.
|
||||
/// - `AGENT_ID` / `SOUVERAINE_AGENT_ID` — her own identifier so skills
|
||||
/// that scope by agent can resolve.
|
||||
///
|
||||
/// Memory and agent-id vars are always set (overriding any stale values
|
||||
/// inherited from the host shell — e.g. a leftover `$MEMORY_DIR` from
|
||||
/// the Letta era). Other env keys from the caller are preserved.
|
||||
/// inherited from the host shell). Other env keys from the caller are
|
||||
/// preserved.
|
||||
pub fn for_agent(
|
||||
agent_id: impl Into<String>,
|
||||
cwd: Option<PathBuf>,
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ impl Tool for Todo {
|
|||
.get("energy")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or_else(|| {
|
||||
// Default by nature — same logic as lettabot-v017.
|
||||
// Default by nature
|
||||
match nature {
|
||||
"desire" | "investigation" => "generative",
|
||||
_ => "consumptive",
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@
|
|||
//! - TTS: `POST /audio/speech` — JSON `{ input, voice, model }`, returns mp3
|
||||
//! bytes.
|
||||
//!
|
||||
//! Text is cleaned before synthesis via [`clean_text_for_tts`] — ported
|
||||
//! verbatim from `letta-code/src/channels/matrix/tts.ts` lines 52–103.
|
||||
//! Text is cleaned before synthesis via [`clean_text_for_tts`].
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
|
|
|
|||
|
|
@ -147,10 +147,9 @@ impl ConsciousnessEngine {
|
|||
|
||||
/// Get or create the subconscious's persistent session. The subconscious
|
||||
/// is a full agent with her own conversation that accumulates across N+1
|
||||
/// passes — just like Aster had CONSCIENCE_CONVERSATION_ID in Letta.
|
||||
///
|
||||
/// The conversation survives process restarts: every `add_message` writes
|
||||
/// to disk, and this restores it from the conversation store on first use.
|
||||
/// passes. The conversation survives process restarts: every `add_message`
|
||||
/// writes to disk, and this restores it from the conversation store on
|
||||
/// first use.
|
||||
async fn subconscious_session_id(&self, sub_id: &str) -> String {
|
||||
// Already live in memory?
|
||||
let existing = self.sessions.list_for_agent(sub_id);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// the agent reads in context. Matches the lettabot-v017 heartbeat topology.
|
||||
// the agent reads in context.
|
||||
let ratio = if generative + consumptive > 0 {
|
||||
generative as f32 / (generative + consumptive) as f32
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use ratatui::{
|
|||
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) {
|
||||
// Split into main chat area and sidebar
|
||||
let chunks = Layout::default()
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl App {
|
|||
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 scale-to-fit portrait photo occupying the top ~55% of the card
|
||||
/// • a dark metadata block below the photo, holding:
|
||||
|
|
@ -103,7 +103,7 @@ impl App {
|
|||
}
|
||||
|
||||
// ── 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
|
||||
// cards. Each card is taller than wide (portrait-style).
|
||||
let pad_x: u16 = 2;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
//! Atmospheric visual presets — color themes that shift the UI's accent palette.
|
||||
//!
|
||||
//! Atmospheric visual presets — originally built for Letta's Matrix adapter
|
||||
//! (html-formatter.ts ATMOSPHERIC_PRESETS), ported here so Annie can express
|
||||
//! mood through the terminal chrome: border colors, title accents, background
|
||||
//! tints, and per-character text gradients in chat bubbles. The agent sets
|
||||
//! atmosphere via a structured event; when none is set, a posture-linked
|
||||
//! default applies.
|
||||
//! Atmospheric visual presets — ported here so Annie can express mood through
|
||||
//! the terminal chrome: border colors, title accents, background tints, and
|
||||
//! per-character text gradients in chat bubbles. The agent sets 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
|
||||
//! accent (subtle highlights), a dim muted shade, and a background tint.
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
//! - `breath_phase` — continuous, always on, drives subtle bob and color pulse.
|
||||
//!
|
||||
//! Plus name, last surfacing, and a [`VolitionGauge`] that mirrors the energy
|
||||
//! topology (generative vs consumptive, hot desires vs cold obligations)
|
||||
//! brought over from production Letta. The gauge is *displayed* here as embodied
|
||||
//! topology (generative vs consumptive, hot desires vs cold obligations). The gauge is *displayed* here as embodied
|
||||
//! state (posture, warmth); the numbers themselves live in the agent's memfs.
|
||||
//!
|
||||
//! ## Event subscriptions
|
||||
|
|
|
|||
Loading…
Reference in a new issue