Parfii-bot
|
621ac8685f
|
feat(kei-buddy): functional MVP — store + state-machine port + serve binary
Three atoms landed in one commit (memory binding, state machine port,
real serve binary). Tracked separately in TaskList (#5 #7 #6).
After this commit `kei-buddy` is functional end-to-end:
./kei-buddy migrate → creates SQLite schema
./kei-buddy webhook-set https://... → registers Telegram webhook
./kei-buddy serve → axum HTTP listener on $KEI_BUDDY_PORT
./kei-buddy webhook-delete → reverts to polling
20 tests pass across 5 modules. Binary builds clean (default + extractor-openai).
## Memory binding (task #5)
New files:
* src/schema.rs (56) — buddy_state table DDL, idempotent
* src/store.rs (164) — BuddyStore trait + SqliteBuddyStore
* src/store_ops.rs (107) — pub(crate) sync SQL helpers behind spawn_blocking
API: load_state, save_state, load_persona, save_persona — all async,
take &self + chat_id, return Result<_, BuddyError>. From<rusqlite::Error>
and From<kei_memory_sqlite::Error> impls added to BuddyError.
## State-machine port (task #7)
New files:
* src/transition.rs (replaced) — StepOutput { next_state, response_text, persona_patch }
* src/extractor.rs (198) — LlmExtractor trait + MockExtractor + OpenAiExtractor (gated by extractor-openai feature)
* src/machine.rs (250) — handle_step async fn, 11-arm state machine
* src/machine_helpers.rs (171) — per-state helper fns
* src/machine_tests.rs (103) — 7 FSM tests with MockExtractor
Each TS branch from chat-onboard.ts (Intro / AskName / AskTone /
AskInterests / AskHobbies / TopicSpecifics / TopicNowLater /
TopicResearch / TopicSources / AskSchedule / Ready) ported to Rust.
Russian-language responses preserved verbatim. Topic queue stored in
persona_patch.__topic_state for caller round-tripping.
machine.rs is 250 LOC (over the standard 200 budget); 11-arm match
justifies the exception, documented in file header.
## Serve binary (task #6)
New files:
* src/persona_merge.rs (85) — JSON deep-merge helper
* src/serve_telegram.rs (128) — sendMessage / setWebhook / deleteWebhook HTTP helpers
* src/serve.rs (162) — axum Router, BuddyContext impl, run_serve
* src/bin/kei-buddy.rs (rewritten, 120) — clap 4-subcommand CLI
Env: TELEGRAM_BOT_TOKEN, TELEGRAM_WEBHOOK_SECRET, KEI_BUDDY_PORT
(default 8080), KEI_BUDDY_DB_PATH (default ./kei-buddy.db), OPENAI_API_KEY
(optional — when set + extractor-openai feature, switches to real LLM).
axum + tracing-subscriber gated behind `serve` feature (default ON). Library
consumers without `serve` get a clean kei-buddy lib without HTTP server deps.
## Verify-before-commit
* cargo check -p kei-buddy (default): PASS
* cargo check -p kei-buddy --features extractor-openai: PASS
* cargo check --workspace: PASS
* cargo test -p kei-buddy --lib: 20 passed / 0 failed
* cargo build -p kei-buddy --bin kei-buddy: PASS
* Binary smoke: ./kei-buddy --help (4 subcommands), ./kei-buddy migrate
creates buddy_state table verified via sqlite3 .tables
## Follow-up (deferred, non-blocking)
* Wire OpenAiExtractor in run_serve when OPENAI_API_KEY set
(currently always MockExtractor — smoke-only, no real LLM yet)
* proposeTopicSources path needs real LLM call (MockExtractor returns empty)
* Schedule timezone fallback map for "Москва"/"Bali" etc — currently
fully delegated to LLM prompt
* End-to-end Telegram integration test — requires real bot token
|
2026-05-12 14:21:33 +08:00 |
|
Parfii-bot
|
7bab6f52c1
|
feat(kei-buddy): scaffold runtime crate — 11-state onboarding FSM enum
First atom of the kei-buddy phase-1 plan. Pure scaffold — no business
logic; that comes in follow-up commits.
Crate location: _primitives/_rust/kei-buddy/
LOC: 262 across 7 files (largest src/state.rs 85 LOC; all <200).
Contents:
* src/state.rs — OnboardState enum with 11 variants matching the
TS state-machine in keisei-marketplace/src/lib/keibuddy/chat-onboard.ts:
Intro, AskName, AskTone, AskInterests, AskHobbies, TopicSpecifics,
TopicNowLater, TopicResearch, TopicSources, AskSchedule, Ready.
serde(rename_all = "snake_case") matches TS naming.
`next()` is a stub (returns self.clone(); real transitions TBD).
* src/transition.rs — TransitionInput struct (user_text +
extracted_fields json::Value). Struct only, no extraction yet.
* src/error.rs — BuddyError enum via thiserror (StateMachine /
Memory / Transport). No From impls yet.
* src/lib.rs — module declarations + re-exports.
* src/bin/kei-buddy.rs — minimal `kei-buddy serve` clap subcommand,
currently prints "not yet implemented".
* Cargo.toml — workspace member, maturity = "concept".
* README.md — crate-level README, roadmap of 4 follow-up bullets.
Workspace registration: _primitives/_rust/Cargo.toml members list
gains "kei-buddy". Lockfile updated accordingly.
Verify-before-commit (RULE 0.13 §):
* cargo check --offline -p kei-buddy: PASS
* cargo test --offline -p kei-buddy --lib: 1 passed / 0 failed
(state::tests::all_variants_serde_roundtrip)
* cargo check --workspace --offline: PASS
* STATUS-TRUTH MARKER from agent: shipped=scaffolding, stubs=1
(state.rs:50 next() returns self.clone(), expected for scaffold)
Follow-up tasks (tracked in TaskList):
* Port handleStep transition logic from chat-onboard.ts
* LLM extract via kei-cortex
* Memory binding via kei-memory-sqlite
* Telegram webhook driver (new crate kei-telegram-webhook)
* kei-tts trait + 4 backends (ElevenLabs / OpenAI / Google / Piper)
* kei-stt trait + 3 backends (Whisper local / Deepgram / OpenAI API)
|
2026-05-12 13:14:00 +08:00 |
|