Skip to main content

quiver_agent/
lib.rs

1//! Phase 6 — daily-task agent + learning loop.
2//!
3//! `run(cfg)` tails Claude Code session JSONL files, calls the recommender
4//! whenever a new user message arrives, writes a hint markdown for the
5//! current session, records the top-1 as a pending `agent_suggestion`, and
6//! marks suggestions accepted when the user actually invokes the suggested
7//! tool. `digest(cfg)` produces a markdown report for a sliding window.
8
9pub mod classify;
10pub mod digest;
11pub mod hint;
12pub mod recommend;
13pub mod tail;
14
15mod engine;
16
17use std::path::PathBuf;
18use std::sync::Arc;
19
20pub use classify::{ClassifiedTask, HaikuClassifier, NoopClassifier, TaskClassifier};
21pub use digest::digest;
22pub use engine::run;
23
24/// Runtime config for the agent loop.
25#[derive(Clone)]
26pub struct AgentConfig {
27    /// SQLite path. Default: `default_db_path()` (caller-provided).
28    pub db_path: PathBuf,
29    /// Root containing `<dir>/<session>.jsonl` files. Default: `~/.claude/projects`.
30    pub sessions_dir: PathBuf,
31    /// Where to write `<session>.md` hint files. Default: `~/.claude/hints`.
32    pub hints_dir: PathBuf,
33    /// How long after a suggestion a matching `tool_use` still counts as
34    /// "accepted". Default: 60 minutes.
35    pub acceptance_window_minutes: i64,
36    /// How often the engine recomputes `tool_scores` (seconds).
37    pub score_recompute_interval_secs: u64,
38    /// Number of recommendations to write into the hint file.
39    pub top_k: usize,
40    /// Optional task classifier. `None` ⇒ raw user text is sent to the
41    /// recommender verbatim (default). When set, every `UserText` event is
42    /// piped through the classifier first; non-task messages are dropped and
43    /// real tasks are rewritten into a focused query before embedding.
44    pub classifier: Option<Arc<dyn TaskClassifier>>,
45}
46
47impl AgentConfig {
48    pub fn new(db_path: PathBuf, sessions_dir: PathBuf, hints_dir: PathBuf) -> Self {
49        Self {
50            db_path,
51            sessions_dir,
52            hints_dir,
53            acceptance_window_minutes: 60,
54            score_recompute_interval_secs: 60,
55            top_k: 3,
56            classifier: None,
57        }
58    }
59
60    pub fn with_classifier(mut self, classifier: Arc<dyn TaskClassifier>) -> Self {
61        self.classifier = Some(classifier);
62        self
63    }
64}