Skip to main content

harness_context/
lib.rs

1//! Runtime defaults and context-assembly helpers.
2//!
3//! `harness-core` defines the abstract `World`/`Clock`/`ProcessRunner`/`KvStore`
4//! traits; this crate provides the concrete implementations the framework
5//! actually runs on.
6
7pub mod file_recall;
8pub mod memory_file;
9pub mod memory_guard;
10pub mod runtime;
11
12pub use file_recall::*;
13pub use memory_file::*;
14pub use memory_guard::*;
15pub use runtime::*;
16
17use harness_core::{Action, Block, Context, Task, ToolResult, Turn, TurnRole, World};
18
19/// Convenience constructors and mutators for `Context`.
20pub trait ContextExt {
21    fn for_task(task: Task) -> Context;
22    fn push_user_text(&mut self, text: impl Into<String>);
23    fn push_assistant_text(&mut self, text: impl Into<String>);
24    fn push_tool_call(&mut self, call_id: &str, tool: &str, args: &serde_json::Value);
25    fn push_tool_result(&mut self, action: &Action, result: &ToolResult);
26}
27
28impl ContextExt for Context {
29    fn for_task(task: Task) -> Context {
30        Context::new(task)
31    }
32
33    fn push_user_text(&mut self, text: impl Into<String>) {
34        self.history.push(Turn {
35            role: TurnRole::User,
36            blocks: vec![Block::Text(text.into())],
37        });
38    }
39
40    fn push_assistant_text(&mut self, text: impl Into<String>) {
41        self.history.push(Turn {
42            role: TurnRole::Assistant,
43            blocks: vec![Block::Text(text.into())],
44        });
45    }
46
47    fn push_tool_call(&mut self, call_id: &str, tool: &str, args: &serde_json::Value) {
48        self.history.push(Turn {
49            role: TurnRole::Assistant,
50            blocks: vec![Block::ToolCall {
51                call_id: call_id.into(),
52                name: tool.into(),
53                args: args.clone(),
54            }],
55        });
56    }
57
58    fn push_tool_result(&mut self, action: &Action, result: &ToolResult) {
59        self.history.push(Turn {
60            role: TurnRole::Tool,
61            blocks: vec![Block::ToolResult {
62                call_id: action.call_id.clone(),
63                content: result.content.clone(),
64            }],
65        });
66    }
67}
68
69/// Quick way to construct a `World` rooted at the given path with the default
70/// runtime impls (tokio process runner, system clock, in-memory kv) and an
71/// empty user profile.
72///
73/// `World.profile` defaults to `UserProfile::default()` — the framework does
74/// NOT decide where profiles come from. To populate it, do:
75///
76/// ```ignore
77/// let mut world = default_world(".");
78/// world.profile = UserProfile { name: Some("…".into()), tz: Some("…".into()), ..Default::default() };
79/// ```
80///
81/// or use [`with_profile`] as a shorthand.
82pub fn default_world(repo_root: impl Into<std::path::PathBuf>) -> World {
83    use std::sync::Arc;
84    World {
85        repo: harness_core::RepoView {
86            root: repo_root.into(),
87        },
88        runner: Arc::new(TokioRunner),
89        clock: Arc::new(SystemClock),
90        kv: Arc::new(InMemoryKv::new()),
91        profile: harness_core::UserProfile::default(),
92    }
93}
94
95/// Builder shorthand: construct a default world and attach a profile in one go.
96pub fn with_profile(
97    repo_root: impl Into<std::path::PathBuf>,
98    profile: harness_core::UserProfile,
99) -> World {
100    let mut w = default_world(repo_root);
101    w.profile = profile;
102    w
103}