1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! Agent Context - environment for autonomous task execution
//!
//! [`AgentContext`] bundles the stable environment that a [`TaskAgent`][super::task_agent::TaskAgent]
//! operates in: working directory, tool executor, inter-agent communication,
//! file lock coordination, and the working set of files currently in context.
//!
//! Conversation history and tool definitions are maintained *internally* by
//! the agent; they are not part of this context.
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use brainwires_core::WorkingSet;
use brainwires_tool_system::{ToolExecutor, ToolPreHook};
use crate::agent_hooks::AgentLifecycleHooks;
use crate::communication::CommunicationHub;
use crate::file_locks::FileLockManager;
/// Environment context for a task agent.
///
/// Pass this to [`TaskAgent::new`][super::task_agent::TaskAgent::new] at
/// construction time. All fields are cheaply cloneable via `Arc`.
#[non_exhaustive]
pub struct AgentContext {
/// Working directory used for resolving relative file paths.
pub working_directory: String,
/// Executes tools on behalf of the agent.
pub tool_executor: Arc<dyn ToolExecutor>,
/// Inter-agent message bus.
pub communication_hub: Arc<CommunicationHub>,
/// Coordinates exclusive/shared file access across concurrent agents.
pub file_lock_manager: Arc<FileLockManager>,
/// Tracks files currently loaded into the agent's context window.
pub working_set: Arc<RwLock<WorkingSet>>,
/// Application-specific metadata passed through to tools.
pub metadata: HashMap<String, String>,
/// Optional pre-execution hook for semantic tool validation.
///
/// When set, the hook is called before every tool execution. Returning
/// [`PreHookDecision::Reject`](crate::PreHookDecision::Reject) causes the tool call to be skipped and
/// the rejection message injected as a `ToolResult::error`.
pub pre_execute_hook: Option<Arc<dyn ToolPreHook>>,
/// Optional lifecycle hooks for granular loop control.
///
/// When set, the agent loop calls these hooks at every phase: iteration
/// boundaries, provider calls, tool execution, completion, and context
/// management. All hook methods have default no-op implementations.
///
/// See [`AgentLifecycleHooks`] for the full hook surface.
pub lifecycle_hooks: Option<Arc<dyn AgentLifecycleHooks>>,
}
impl AgentContext {
/// Create a new agent context with the given environment.
///
/// A fresh, empty [`WorkingSet`] is created automatically. Use
/// [`AgentContext::with_working_set`] to supply a pre-populated one.
pub fn new(
working_directory: impl Into<String>,
tool_executor: Arc<dyn ToolExecutor>,
communication_hub: Arc<CommunicationHub>,
file_lock_manager: Arc<FileLockManager>,
) -> Self {
Self {
working_directory: working_directory.into(),
tool_executor,
communication_hub,
file_lock_manager,
working_set: Arc::new(RwLock::new(WorkingSet::new())),
metadata: HashMap::new(),
pre_execute_hook: None,
lifecycle_hooks: None,
}
}
/// Create a context that shares an existing [`WorkingSet`].
pub fn with_working_set(
working_directory: impl Into<String>,
tool_executor: Arc<dyn ToolExecutor>,
communication_hub: Arc<CommunicationHub>,
file_lock_manager: Arc<FileLockManager>,
working_set: Arc<RwLock<WorkingSet>>,
) -> Self {
Self {
working_directory: working_directory.into(),
tool_executor,
communication_hub,
file_lock_manager,
working_set,
metadata: HashMap::new(),
pre_execute_hook: None,
lifecycle_hooks: None,
}
}
/// Add application-specific metadata.
pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
/// Set a pre-execution hook for semantic tool validation.
pub fn with_pre_execute_hook(mut self, hook: Arc<dyn ToolPreHook>) -> Self {
self.pre_execute_hook = Some(hook);
self
}
/// Set lifecycle hooks for granular loop control.
pub fn with_lifecycle_hooks(mut self, hooks: Arc<dyn AgentLifecycleHooks>) -> Self {
self.lifecycle_hooks = Some(hooks);
self
}
}