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/`).
|
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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
//!
|
//!
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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 52–103.
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue