Replaces the rigid FSM after Intro/AskLanguage with a single LLM call per
turn that sees:
* persona (what's already known — slots not re-asked)
* recent 10 chat_log messages (history)
* top-5 kei-sage atoms relevant to user_text (graph-RAG, not embeddings)
* raw user_text
LLM returns JSON {slot_updates, response_text, done, focus} which drives
the next state + persona patch + reply. No embeddings, no vector store —
kei-sage's FTS5 + Obsidian-style atom graph is the retrieval layer.
New files:
* src/retrieval.rs (101 LOC) — retrieve_context(chat_log, topics,
chat_id, query, history_n, atoms_k) -> RetrievalContext
* src/conversational.rs (157 LOC) — conversational_step
(state, persona, context, text, extractor, lang) -> StepOutput
Modified:
* src/serve.rs::run_fsm — branch on state: Intro/AskLanguage still go
through legacy handle_step (jump-start); everything else routes to
conversational_step with retrieval context.
* src/lib.rs — module declarations.
Tests (5 new, 60 total passing):
* parses_well_formed_llm_response
* done_true_transitions_to_ready
* invalid_json_falls_back_gracefully
* retrieve_returns_empty_on_empty_stores
* retrieve_finds_seeded_data
Verify:
* cargo check -p kei-buddy: PASS
* cargo test -p kei-buddy --lib: 60/0 (was 55, +5)
Why graph-RAG instead of embeddings: kei-sage already in tree (atoms +
edges + BFS + PageRank + FTS5). Explicit edges (message → topic →
contact) beat opaque cosine similarity for personal-assistant memory
where relationships are typed. No sqlite-vec dep, no embedding cost.
NOT deployed yet — needs server rebuild.
59 lines
1.8 KiB
Rust
59 lines
1.8 KiB
Rust
// SPDX-License-Identifier: Apache-2.0
|
|
//! kei-buddy — KeiBuddy personal-assistant Telegram bot scaffold.
|
|
//!
|
|
//! Module layout (Constructor Pattern — one file, one responsibility):
|
|
//! * `state` — `OnboardState` enum
|
|
//! * `transition` — `StepOutput` output struct
|
|
//! * `extractor` — `LlmExtractor` trait + `MockExtractor` + `OpenAiExtractor` (feature-gated)
|
|
//! * `machine` — `handle_step` — the 11-arm onboarding FSM
|
|
//! * `error` — `BuddyError` error type
|
|
//! * `schema` — buddy-specific SQLite DDL
|
|
//! * `store` — `BuddyStore` trait + `SqliteBuddyStore` impl
|
|
|
|
pub mod chat_log;
|
|
pub(crate) mod command_exec;
|
|
pub mod commands;
|
|
pub mod contacts;
|
|
pub mod contacts_sync;
|
|
pub mod conversational;
|
|
pub mod error;
|
|
pub mod extractor;
|
|
pub mod machine;
|
|
pub(crate) mod machine_helpers;
|
|
pub(crate) mod machine_lang;
|
|
pub mod persona_merge;
|
|
pub mod retrieval;
|
|
pub mod schema;
|
|
pub mod state;
|
|
pub mod store;
|
|
pub(crate) mod store_ops;
|
|
pub mod strings;
|
|
pub mod tick;
|
|
pub mod topic_classify;
|
|
pub mod topics;
|
|
pub mod transition;
|
|
|
|
#[cfg(feature = "serve")]
|
|
pub mod serve;
|
|
#[cfg(feature = "serve")]
|
|
pub(crate) mod serve_runner;
|
|
#[cfg(feature = "serve")]
|
|
pub mod serve_telegram;
|
|
#[cfg(feature = "serve")]
|
|
pub mod voice;
|
|
|
|
pub use chat_log::ChatLog;
|
|
pub use commands::{parse_command, execute_command, Command, CommandStores};
|
|
pub use contacts_sync::{sync_from_apple, sync_from_google, SyncReport};
|
|
pub use contacts::Contacts;
|
|
pub use error::BuddyError;
|
|
pub use extractor::LlmExtractor;
|
|
pub use machine::handle_step;
|
|
pub use state::OnboardState;
|
|
pub use store::{BuddyStore, SqliteBuddyStore};
|
|
pub use strings::{Lang, Strings};
|
|
pub use tick::{run_tick, run_tick_with, TickConfig, TickReport};
|
|
pub use topics::Topics;
|
|
pub use transition::StepOutput;
|
|
#[cfg(feature = "serve")]
|
|
pub use voice::VoiceHandler;
|