MTP-0.2.0 migration
This commit is contained in:
parent
ad42c0e51f
commit
f1c7317fab
14 changed files with 1309 additions and 281 deletions
|
|
@ -1,2 +1,2 @@
|
||||||
[env]
|
[env]
|
||||||
MTP_TYPE_MAPS = { value = "type-maps.yaml", relative = true }
|
MTP_TYPE_MAPS = { value = "../type-maps.yaml", relative = true }
|
||||||
|
|
|
||||||
658
Cargo.lock
generated
658
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,9 +10,12 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
mtp = { git = "https://git@git.methanium.net/methanium/mtp.git", features = [] }
|
mtp = { git = "https://git@git.methanium.net/methanium/mtp.git", features = [
|
||||||
|
"crypto",
|
||||||
|
] }
|
||||||
tokio = "1"
|
tokio = "1"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
|
url = "2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::task::SessionBudget;
|
||||||
|
|
||||||
/* ExploreAgent is intentionally limited to read-only tools so it can be
|
/* ExploreAgent is intentionally limited to read-only tools so it can be
|
||||||
dispatched without approval for safe, unrestricted codebase exploration. */
|
dispatched without approval for safe, unrestricted codebase exploration. */
|
||||||
|
|
@ -37,6 +38,35 @@ impl AgentType {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_session_budget(&self) -> SessionBudget {
|
||||||
|
match self {
|
||||||
|
AgentType::BuildAgent => SessionBudget {
|
||||||
|
max_tool_calls: 50,
|
||||||
|
max_tokens: 100_000,
|
||||||
|
},
|
||||||
|
AgentType::Planner => SessionBudget {
|
||||||
|
max_tool_calls: 30,
|
||||||
|
max_tokens: 50_000,
|
||||||
|
},
|
||||||
|
AgentType::ExploreAgent => SessionBudget {
|
||||||
|
max_tool_calls: 10,
|
||||||
|
max_tokens: 5_000,
|
||||||
|
},
|
||||||
|
AgentType::DocAgent => SessionBudget {
|
||||||
|
max_tool_calls: 20,
|
||||||
|
max_tokens: 20_000,
|
||||||
|
},
|
||||||
|
AgentType::TestJudge => SessionBudget {
|
||||||
|
max_tool_calls: 10,
|
||||||
|
max_tokens: 10_000,
|
||||||
|
},
|
||||||
|
AgentType::ChatAgent => SessionBudget {
|
||||||
|
max_tool_calls: 5,
|
||||||
|
max_tokens: 5_000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
|
@ -46,6 +76,24 @@ pub enum ApprovalMode {
|
||||||
PerTool,
|
PerTool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Controls what happens when a tool call requires approval and the user defers it.
|
||||||
|
/// Orthogonal to `ApprovalMode` (which controls *how* approvals are collected).
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ApprovalTurnMode {
|
||||||
|
/// Block the agent turn; resume by injecting the approval result into the same turn.
|
||||||
|
Wait,
|
||||||
|
/// Return a placeholder result to the agent immediately ("Approval pending");
|
||||||
|
/// the actual approval result is injected in a subsequent turn.
|
||||||
|
Defer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ApprovalTurnMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
ApprovalTurnMode::Wait
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PlannedAction {
|
pub struct PlannedAction {
|
||||||
pub tool_name: String,
|
pub tool_name: String,
|
||||||
|
|
@ -70,6 +118,10 @@ pub struct AgentPolicy {
|
||||||
pub max_tokens: u32,
|
pub max_tokens: u32,
|
||||||
pub allowed_tools: Vec<String>,
|
pub allowed_tools: Vec<String>,
|
||||||
pub forbidden_mutations: Vec<String>,
|
pub forbidden_mutations: Vec<String>,
|
||||||
|
/// Controls what happens when a tool call is deferred by the user.
|
||||||
|
/// `Wait` pauses the turn; `Defer` returns a placeholder immediately.
|
||||||
|
#[serde(default)]
|
||||||
|
pub turn_mode: ApprovalTurnMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentPolicy {
|
impl AgentPolicy {
|
||||||
|
|
@ -84,6 +136,7 @@ impl AgentPolicy {
|
||||||
max_tokens: 4096,
|
max_tokens: 4096,
|
||||||
allowed_tools: vec!["read_file".into(), "write_file".into(), "edit_file".into()],
|
allowed_tools: vec!["read_file".into(), "write_file".into(), "edit_file".into()],
|
||||||
forbidden_mutations: vec!["Cargo.toml".into(), "package.json".into()],
|
forbidden_mutations: vec!["Cargo.toml".into(), "package.json".into()],
|
||||||
|
turn_mode: ApprovalTurnMode::Defer,
|
||||||
},
|
},
|
||||||
AgentType::TestJudge => Self {
|
AgentType::TestJudge => Self {
|
||||||
agent_type: agent_type.clone(),
|
agent_type: agent_type.clone(),
|
||||||
|
|
@ -94,6 +147,7 @@ impl AgentPolicy {
|
||||||
max_tokens: 4096,
|
max_tokens: 4096,
|
||||||
allowed_tools: vec![],
|
allowed_tools: vec![],
|
||||||
forbidden_mutations: vec![],
|
forbidden_mutations: vec![],
|
||||||
|
turn_mode: ApprovalTurnMode::Defer,
|
||||||
},
|
},
|
||||||
AgentType::BuildAgent => Self {
|
AgentType::BuildAgent => Self {
|
||||||
agent_type: agent_type.clone(),
|
agent_type: agent_type.clone(),
|
||||||
|
|
@ -104,6 +158,7 @@ impl AgentPolicy {
|
||||||
max_tokens: 131072,
|
max_tokens: 131072,
|
||||||
allowed_tools: vec![],
|
allowed_tools: vec![],
|
||||||
forbidden_mutations: vec!["Cargo.toml".into(), "package.json".into()],
|
forbidden_mutations: vec!["Cargo.toml".into(), "package.json".into()],
|
||||||
|
turn_mode: ApprovalTurnMode::Wait,
|
||||||
},
|
},
|
||||||
AgentType::Planner => Self {
|
AgentType::Planner => Self {
|
||||||
agent_type: agent_type.clone(),
|
agent_type: agent_type.clone(),
|
||||||
|
|
@ -114,6 +169,7 @@ impl AgentPolicy {
|
||||||
max_tokens: 131072,
|
max_tokens: 131072,
|
||||||
allowed_tools: vec![],
|
allowed_tools: vec![],
|
||||||
forbidden_mutations: vec![],
|
forbidden_mutations: vec![],
|
||||||
|
turn_mode: ApprovalTurnMode::Defer,
|
||||||
},
|
},
|
||||||
AgentType::ChatAgent => Self {
|
AgentType::ChatAgent => Self {
|
||||||
agent_type: agent_type.clone(),
|
agent_type: agent_type.clone(),
|
||||||
|
|
@ -124,6 +180,7 @@ impl AgentPolicy {
|
||||||
max_tokens: 4096,
|
max_tokens: 4096,
|
||||||
allowed_tools: vec![],
|
allowed_tools: vec![],
|
||||||
forbidden_mutations: vec![],
|
forbidden_mutations: vec![],
|
||||||
|
turn_mode: ApprovalTurnMode::Defer,
|
||||||
},
|
},
|
||||||
/* ExploreAgent: auto-approved, read-only tools only, short timeout.
|
/* ExploreAgent: auto-approved, read-only tools only, short timeout.
|
||||||
Forbidden mutations set to wildcard to block all writes. */
|
Forbidden mutations set to wildcard to block all writes. */
|
||||||
|
|
@ -143,6 +200,7 @@ impl AgentPolicy {
|
||||||
"web_fetch".into(),
|
"web_fetch".into(),
|
||||||
],
|
],
|
||||||
forbidden_mutations: vec!["*".into()],
|
forbidden_mutations: vec!["*".into()],
|
||||||
|
turn_mode: ApprovalTurnMode::Defer,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,53 +21,144 @@ pub struct AiConversation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct StreamEvent {
|
#[serde(tag = "type")]
|
||||||
#[serde(rename = "type")]
|
pub enum StreamEvent {
|
||||||
pub event_type: String,
|
#[serde(rename = "content")]
|
||||||
pub content: Option<String>,
|
Content { content: String },
|
||||||
pub thinking: Option<String>,
|
|
||||||
pub error: Option<String>,
|
#[serde(rename = "thinking")]
|
||||||
pub message_id: Option<String>,
|
Thinking { content: String },
|
||||||
|
|
||||||
|
#[serde(rename = "error")]
|
||||||
|
Error { error: String },
|
||||||
|
|
||||||
|
#[serde(rename = "done")]
|
||||||
|
Done { message_id: String },
|
||||||
|
|
||||||
|
#[serde(rename = "tool_call")]
|
||||||
|
ToolCall {
|
||||||
|
tool_name: String,
|
||||||
|
tool_id: String,
|
||||||
|
arguments: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "tool_executing")]
|
||||||
|
ToolExecuting { tool_name: String, tool_id: String },
|
||||||
|
|
||||||
|
#[serde(rename = "tool_result")]
|
||||||
|
ToolResult {
|
||||||
|
tool_name: String,
|
||||||
|
tool_id: String,
|
||||||
|
status: String,
|
||||||
|
result: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "checkpoint")]
|
||||||
|
Checkpoint {
|
||||||
|
checkpoint_id: String,
|
||||||
|
data: serde_json::Value,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "simulation_result")]
|
||||||
|
SimulationResult { simulation: serde_json::Value },
|
||||||
|
|
||||||
|
#[serde(rename = "debug")]
|
||||||
|
Debug { content: String },
|
||||||
|
|
||||||
|
#[serde(rename = "handshake")]
|
||||||
|
Handshake {
|
||||||
|
protocol_version: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
warmup: Option<bool>,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[serde(rename = "task_complete")]
|
||||||
|
TaskComplete,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StreamEvent {
|
impl StreamEvent {
|
||||||
pub fn content(content: String) -> Self {
|
pub fn content(content: String) -> Self {
|
||||||
Self {
|
Self::Content { content }
|
||||||
event_type: "content".to_string(),
|
|
||||||
content: Some(content),
|
|
||||||
thinking: None,
|
|
||||||
error: None,
|
|
||||||
message_id: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thinking(thinking: String) -> Self {
|
pub fn thinking(content: String) -> Self {
|
||||||
Self {
|
Self::Thinking { content }
|
||||||
event_type: "thinking".to_string(),
|
|
||||||
content: None,
|
|
||||||
thinking: Some(thinking),
|
|
||||||
error: None,
|
|
||||||
message_id: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(error: String) -> Self {
|
pub fn error(error: String) -> Self {
|
||||||
Self {
|
Self::Error { error }
|
||||||
event_type: "error".to_string(),
|
|
||||||
content: None,
|
|
||||||
thinking: None,
|
|
||||||
error: Some(error),
|
|
||||||
message_id: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn done(message_id: String) -> Self {
|
pub fn done(message_id: String) -> Self {
|
||||||
Self {
|
Self::Done { message_id }
|
||||||
event_type: "done".to_string(),
|
}
|
||||||
content: None,
|
|
||||||
thinking: None,
|
pub fn tool_call(tool_name: String, tool_id: String, arguments: String) -> Self {
|
||||||
error: None,
|
Self::ToolCall {
|
||||||
message_id: Some(message_id),
|
tool_name,
|
||||||
|
tool_id,
|
||||||
|
arguments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool_executing(tool_name: String, tool_id: String) -> Self {
|
||||||
|
Self::ToolExecuting { tool_name, tool_id }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tool_result(
|
||||||
|
tool_name: String,
|
||||||
|
tool_id: String,
|
||||||
|
status: String,
|
||||||
|
result: String,
|
||||||
|
) -> Self {
|
||||||
|
Self::ToolResult {
|
||||||
|
tool_name,
|
||||||
|
tool_id,
|
||||||
|
status,
|
||||||
|
result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn checkpoint(checkpoint_id: String, data: serde_json::Value) -> Self {
|
||||||
|
Self::Checkpoint {
|
||||||
|
checkpoint_id,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simulation_result(simulation: serde_json::Value) -> Self {
|
||||||
|
Self::SimulationResult { simulation }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug(content: String) -> Self {
|
||||||
|
Self::Debug { content }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handshake(protocol_version: String, warmup: Option<bool>) -> Self {
|
||||||
|
Self::Handshake {
|
||||||
|
protocol_version,
|
||||||
|
warmup,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn task_complete() -> Self {
|
||||||
|
Self::TaskComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_type(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Content { .. } => "content",
|
||||||
|
Self::Thinking { .. } => "thinking",
|
||||||
|
Self::Error { .. } => "error",
|
||||||
|
Self::Done { .. } => "done",
|
||||||
|
Self::ToolCall { .. } => "tool_call",
|
||||||
|
Self::ToolExecuting { .. } => "tool_executing",
|
||||||
|
Self::ToolResult { .. } => "tool_result",
|
||||||
|
Self::Checkpoint { .. } => "checkpoint",
|
||||||
|
Self::SimulationResult { .. } => "simulation_result",
|
||||||
|
Self::Debug { .. } => "debug",
|
||||||
|
Self::Handshake { .. } => "handshake",
|
||||||
|
Self::TaskComplete => "task_complete",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
src/enums.rs
32
src/enums.rs
|
|
@ -1,6 +1,38 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ToDoMode {
|
||||||
|
Discussion,
|
||||||
|
Finalized,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ToDoMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
ToDoMode::Discussion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ToDoMode {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ToDoMode::Discussion => write!(f, "discussion"),
|
||||||
|
ToDoMode::Finalized => write!(f, "finalized"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for ToDoMode {
|
||||||
|
type Err = String;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"discussion" => Ok(ToDoMode::Discussion),
|
||||||
|
"finalized" => Ok(ToDoMode::Finalized),
|
||||||
|
_ => Err(format!("unknown mode: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum ToDoStatus {
|
pub enum ToDoStatus {
|
||||||
Pending,
|
Pending,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,21 @@ pub enum ValidationError {
|
||||||
InvalidField(String),
|
InvalidField(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ValidationError {
|
||||||
|
pub fn http_status(&self) -> u16 {
|
||||||
|
match self {
|
||||||
|
ValidationError::EmptyTitle
|
||||||
|
| ValidationError::TitleTooLong
|
||||||
|
| ValidationError::DescriptionTooLong
|
||||||
|
| ValidationError::InvalidPriority
|
||||||
|
| ValidationError::InvalidStatusTransition { .. }
|
||||||
|
| ValidationError::InvalidField(_) => 400,
|
||||||
|
ValidationError::CircularDependency(_)
|
||||||
|
| ValidationError::DependencyNotFound(_) => 409,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
#[derive(Debug, Clone, Error)]
|
||||||
pub enum ShoalError {
|
pub enum ShoalError {
|
||||||
#[error("storage error: {0}")]
|
#[error("storage error: {0}")]
|
||||||
|
|
@ -38,6 +53,20 @@ pub enum ShoalError {
|
||||||
InternalError(String),
|
InternalError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShoalError {
|
||||||
|
pub fn http_status(&self) -> u16 {
|
||||||
|
match self {
|
||||||
|
ShoalError::ValidationError(_) => 400,
|
||||||
|
ShoalError::NotFound(_) => 404,
|
||||||
|
ShoalError::Unauthorized(_) => 401,
|
||||||
|
ShoalError::StorageError(_)
|
||||||
|
| ShoalError::NetworkError(_)
|
||||||
|
| ShoalError::DatabaseError(_)
|
||||||
|
| ShoalError::InternalError(_) => 500,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ValidationError> for ShoalError {
|
impl From<ValidationError> for ShoalError {
|
||||||
fn from(e: ValidationError) -> Self {
|
fn from(e: ValidationError) -> Self {
|
||||||
ShoalError::ValidationError(e.to_string())
|
ShoalError::ValidationError(e.to_string())
|
||||||
|
|
|
||||||
11
src/krill.rs
11
src/krill.rs
|
|
@ -3,6 +3,15 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::enums::ModelType;
|
use crate::enums::ModelType;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum PodProtocolVersion {
|
||||||
|
V1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PodProtocolVersion {
|
||||||
|
fn default() -> Self { Self::V1 }
|
||||||
|
}
|
||||||
|
|
||||||
pub type KrillId = Uuid;
|
pub type KrillId = Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -76,12 +85,14 @@ impl KrillDescriptor {
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct KrillConfig {
|
pub struct KrillConfig {
|
||||||
pub settings: serde_json::Value,
|
pub settings: serde_json::Value,
|
||||||
|
pub pod_protocol_version: PodProtocolVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KrillConfig {
|
impl KrillConfig {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
settings: serde_json::json!({}),
|
settings: serde_json::json!({}),
|
||||||
|
pod_protocol_version: PodProtocolVersion::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
35
src/lib.rs
35
src/lib.rs
|
|
@ -28,17 +28,44 @@ pub use conclusion::{
|
||||||
pub use coral::{Coral, CoralId};
|
pub use coral::{Coral, CoralId};
|
||||||
pub use enums::*;
|
pub use enums::*;
|
||||||
pub use errors::{ShoalError, ValidationError};
|
pub use errors::{ShoalError, ValidationError};
|
||||||
pub use krill::{KrillConfig, KrillDescriptor, KrillId};
|
pub use krill::{KrillConfig, KrillDescriptor, KrillId, PodProtocolVersion};
|
||||||
pub use mutations::FileMutation;
|
pub use mutations::FileMutation;
|
||||||
pub use project::{Project, ProjectFile, ProjectId, ProjectSettings};
|
pub use project::{Project, ProjectFile, ProjectId, ProjectSettings};
|
||||||
pub use task::{Task, TaskResult};
|
pub use task::{Task, TaskResult};
|
||||||
pub use todo::{Dependency, ToDo};
|
pub use todo::{Dependency, ToDo};
|
||||||
pub use tools::{
|
pub use tools::{
|
||||||
format_tool_error, format_tool_result, format_tools_json, is_global_tool, is_reef_proxy_tool,
|
compute_tools_hash, format_tool_error, format_tool_result, format_tools_json,
|
||||||
|
is_global_tool, is_reef_proxy_tool,
|
||||||
parse_tool_call_blocks, parse_tool_call_stream, tool_definitions, tool_ids_for_agent_type,
|
parse_tool_call_blocks, parse_tool_call_stream, tool_definitions, tool_ids_for_agent_type,
|
||||||
ApprovalRequirement, CompositionStep, ContextVisibility, ExecutionContext,
|
ApprovalRequirement, CompositionStep, ContextVisibility, ExecutionContext,
|
||||||
MarketplaceSearchResults, ParsedToolCall, TestAction, ToolComposition, ToolDefinition,
|
MarketplaceSearchResults, ParsedToolCall, TestAction, ToolComposition, ToolDefinition,
|
||||||
ToolDependency, ToolDocumentation, ToolExample, ToolExecutor, ToolListing, ToolParser,
|
ToolDependency, ToolDocumentation, ToolExample, ToolExecutor, ToolListing, ToolParser,
|
||||||
ToolPlugin, ToolRegistry, ToolTest, ToolTestResult, ToolTestSuite, ToolTestSuiteResult,
|
ToolPlugin, ToolRegistry, ToolState, ToolTest, ToolTestResult, ToolTestSuite,
|
||||||
ToolVersion, GLOBAL_TOOLS, REEF_PROXY_TOOLS,
|
ToolTestSuiteResult, ToolVersion, GLOBAL_TOOLS, REEF_PROXY_TOOLS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typemap_contains_expected_types() {
|
||||||
|
let tm = mtp::type_map::TypeMap::latest();
|
||||||
|
assert!(
|
||||||
|
tm.data_id_enum(DataType::ProjectId).is_some(),
|
||||||
|
"TypeMap missing ProjectId"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
tm.comm_id_enum(CommunicationType::AuthRequest).is_some(),
|
||||||
|
"TypeMap missing AuthRequest"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
tm.comm_id_enum(CommunicationType::PasswordAuthRequest).is_some(),
|
||||||
|
"TypeMap missing PasswordAuthRequest"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
tm.data_id_enum(DataType::DockId).is_some(),
|
||||||
|
"TypeMap missing DockId"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ pub struct ProjectSettings {
|
||||||
pub language: Option<String>,
|
pub language: Option<String>,
|
||||||
pub build_command: Option<String>,
|
pub build_command: Option<String>,
|
||||||
pub run_command: Option<String>,
|
pub run_command: Option<String>,
|
||||||
|
/// Conventional subject/body template used for generated git commits.
|
||||||
|
pub git_commit_template: Option<String>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub extra: serde_json::Value,
|
pub extra: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +122,7 @@ impl ProjectSettings {
|
||||||
language: None,
|
language: None,
|
||||||
build_command: None,
|
build_command: None,
|
||||||
run_command: None,
|
run_command: None,
|
||||||
|
git_commit_template: None,
|
||||||
extra: serde_json::json!({}),
|
extra: serde_json::json!({}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,6 +142,11 @@ impl ProjectSettings {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_git_commit_template(mut self, template: String) -> Self {
|
||||||
|
self.git_commit_template = Some(template);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_extra(&mut self, key: &str, value: serde_json::Value) {
|
pub fn set_extra(&mut self, key: &str, value: serde_json::Value) {
|
||||||
if let Some(obj) = self.extra.as_object_mut() {
|
if let Some(obj) = self.extra.as_object_mut() {
|
||||||
obj.insert(key.to_string(), value);
|
obj.insert(key.to_string(), value);
|
||||||
|
|
|
||||||
71
src/task.rs
71
src/task.rs
|
|
@ -183,6 +183,61 @@ pub struct ConnectorConfig {
|
||||||
pub temperature: Option<f32>,
|
pub temperature: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConnectorConfig {
|
||||||
|
pub const MIN_API_KEY_LEN: usize = 20;
|
||||||
|
|
||||||
|
/// Validate the connector configuration fields. Returns a list of human-readable
|
||||||
|
/// error messages; an empty vec means the config is valid.
|
||||||
|
pub fn validate(&self) -> Vec<String> {
|
||||||
|
let mut errors = Vec::new();
|
||||||
|
|
||||||
|
if self.api_key.trim().len() < Self::MIN_API_KEY_LEN {
|
||||||
|
errors.push(format!(
|
||||||
|
"api_key must be non-empty and at least {} characters",
|
||||||
|
Self::MIN_API_KEY_LEN
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
match url::Url::parse(&self.base_url) {
|
||||||
|
Ok(parsed) => {
|
||||||
|
if parsed.scheme() != "https" && parsed.scheme() != "http" {
|
||||||
|
errors.push(format!(
|
||||||
|
"base_url must use https or http scheme, got '{}'",
|
||||||
|
parsed.scheme()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
errors.push(format!("base_url is not a valid URL: {}", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.model.trim().is_empty() {
|
||||||
|
errors.push("model must be non-empty".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tokens) = self.max_tokens {
|
||||||
|
if tokens <= 0 {
|
||||||
|
errors.push(format!(
|
||||||
|
"max_tokens must be > 0, got {}",
|
||||||
|
tokens
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(temp) = self.temperature {
|
||||||
|
if !(0.0..=2.0).contains(&temp) {
|
||||||
|
errors.push(format!(
|
||||||
|
"temperature must be in [0.0, 2.0], got {}",
|
||||||
|
temp
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct AgentTaskSpec {
|
pub struct AgentTaskSpec {
|
||||||
pub task_id: Uuid,
|
pub task_id: Uuid,
|
||||||
|
|
@ -200,6 +255,10 @@ pub struct AgentTaskSpec {
|
||||||
pub pre_approved_plan_id: Option<Uuid>,
|
pub pre_approved_plan_id: Option<Uuid>,
|
||||||
pub execution_token: Option<Uuid>,
|
pub execution_token: Option<Uuid>,
|
||||||
pub session_budget: Option<SessionBudget>,
|
pub session_budget: Option<SessionBudget>,
|
||||||
|
/// Maximum number of checklist tasks this agent run may add. `None` leaves
|
||||||
|
/// task creation unconstrained for backwards-compatible callers.
|
||||||
|
#[serde(default)]
|
||||||
|
pub task_budget: Option<u32>,
|
||||||
pub agent_type: Option<AgentType>,
|
pub agent_type: Option<AgentType>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub suggested_test_files: Vec<String>,
|
pub suggested_test_files: Vec<String>,
|
||||||
|
|
@ -209,10 +268,19 @@ pub struct AgentTaskSpec {
|
||||||
pub connector_config: Option<ConnectorConfig>,
|
pub connector_config: Option<ConnectorConfig>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub tools_json: Option<String>,
|
pub tools_json: Option<String>,
|
||||||
|
/// blake3-style hash of `tools_json` for deduplication across dispatches.
|
||||||
|
/// When present, the receiver may skip the full payload if the hash is cached.
|
||||||
|
#[serde(default)]
|
||||||
|
pub tools_hash: Option<String>,
|
||||||
/* Overrides the agent-type default system prompt when set. Takes highest
|
/* Overrides the agent-type default system prompt when set. Takes highest
|
||||||
precedence in the resolution chain (above DB overrides and defaults). */
|
precedence in the resolution chain (above DB overrides and defaults). */
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub system_prompt: Option<String>,
|
pub system_prompt: Option<String>,
|
||||||
|
/// When set, the Pod reads the latest checkpoint from SQLite and injects the
|
||||||
|
/// completed tool calls into the system message so the LLM resumes instead
|
||||||
|
/// of restarting from scratch on retry.
|
||||||
|
#[serde(default)]
|
||||||
|
pub resume_from_checkpoint: Option<Uuid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentTaskSpec {
|
impl AgentTaskSpec {
|
||||||
|
|
@ -238,12 +306,15 @@ impl AgentTaskSpec {
|
||||||
pre_approved_plan_id: None,
|
pre_approved_plan_id: None,
|
||||||
execution_token: None,
|
execution_token: None,
|
||||||
session_budget: None,
|
session_budget: None,
|
||||||
|
task_budget: None,
|
||||||
agent_type: None,
|
agent_type: None,
|
||||||
suggested_test_files: Vec::new(),
|
suggested_test_files: Vec::new(),
|
||||||
project_id: None,
|
project_id: None,
|
||||||
connector_config: None,
|
connector_config: None,
|
||||||
tools_json: None,
|
tools_json: None,
|
||||||
|
tools_hash: None,
|
||||||
system_prompt: None,
|
system_prompt: None,
|
||||||
|
resume_from_checkpoint: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::enums::{ToDoSource, ToDoStatus};
|
use crate::enums::{ToDoMode, ToDoSource, ToDoStatus};
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
@ -36,6 +36,7 @@ pub struct ToDo {
|
||||||
pub subtask_ids: Vec<Uuid>,
|
pub subtask_ids: Vec<Uuid>,
|
||||||
pub affected_files: Vec<String>,
|
pub affected_files: Vec<String>,
|
||||||
pub source: ToDoSource,
|
pub source: ToDoSource,
|
||||||
|
pub mode: ToDoMode,
|
||||||
pub automation_chain_id: Option<Uuid>,
|
pub automation_chain_id: Option<Uuid>,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
pub estimated_tokens: u32,
|
pub estimated_tokens: u32,
|
||||||
|
|
@ -62,6 +63,7 @@ impl Default for ToDo {
|
||||||
subtask_ids: Vec::new(),
|
subtask_ids: Vec::new(),
|
||||||
affected_files: Vec::new(),
|
affected_files: Vec::new(),
|
||||||
source: ToDoSource::User,
|
source: ToDoSource::User,
|
||||||
|
mode: ToDoMode::default(),
|
||||||
automation_chain_id: None,
|
automation_chain_id: None,
|
||||||
tags: Vec::new(),
|
tags: Vec::new(),
|
||||||
estimated_tokens: 0,
|
estimated_tokens: 0,
|
||||||
|
|
@ -90,6 +92,7 @@ impl ToDo {
|
||||||
subtask_ids: Vec::new(),
|
subtask_ids: Vec::new(),
|
||||||
affected_files: Vec::new(),
|
affected_files: Vec::new(),
|
||||||
source: ToDoSource::User,
|
source: ToDoSource::User,
|
||||||
|
mode: ToDoMode::default(),
|
||||||
automation_chain_id: None,
|
automation_chain_id: None,
|
||||||
tags: Vec::new(),
|
tags: Vec::new(),
|
||||||
estimated_tokens: 0,
|
estimated_tokens: 0,
|
||||||
|
|
@ -199,6 +202,8 @@ impl ToDo {
|
||||||
(ToDoStatus::Failed, ToDoStatus::ReadyForAgent) => true,
|
(ToDoStatus::Failed, ToDoStatus::ReadyForAgent) => true,
|
||||||
(ToDoStatus::PendingApproval, ToDoStatus::InProgress) => true,
|
(ToDoStatus::PendingApproval, ToDoStatus::InProgress) => true,
|
||||||
(ToDoStatus::PendingApproval, ToDoStatus::Blocked) => true,
|
(ToDoStatus::PendingApproval, ToDoStatus::Blocked) => true,
|
||||||
|
(ToDoStatus::Draft, ToDoStatus::Pending) => true,
|
||||||
|
(ToDoStatus::Pending, ToDoStatus::Draft) => true,
|
||||||
_ => self.status == status,
|
_ => self.status == status,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
365
src/tools.rs
365
src/tools.rs
|
|
@ -516,6 +516,48 @@ impl Default for ToolVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dynamic runtime state of a tool, managed per-project by `ToolStateManager`.
|
||||||
|
This replaces the static `deprecated` bool on `ToolDefinition` with a richer
|
||||||
|
taxonomy that operators can toggle without redeploying. */
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum ToolState {
|
||||||
|
Enabled,
|
||||||
|
Disabled,
|
||||||
|
Deprecated,
|
||||||
|
Experimental,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ToolState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToolState {
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Enabled => "enabled",
|
||||||
|
Self::Disabled => "disabled",
|
||||||
|
Self::Deprecated => "deprecated",
|
||||||
|
Self::Experimental => "experimental",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_str(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"disabled" => Self::Disabled,
|
||||||
|
"deprecated" => Self::Deprecated,
|
||||||
|
"experimental" => Self::Experimental,
|
||||||
|
_ => Self::Enabled,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_available(&self) -> bool {
|
||||||
|
matches!(self, Self::Enabled | Self::Experimental)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Tool category classification for UI grouping and filtering. */
|
/* Tool category classification for UI grouping and filtering. */
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
|
@ -849,7 +891,13 @@ pub const PLANNER_ONLY_TOOLS: &[&str] = &[
|
||||||
Mutating tools (write_file, edit_file, bash, delete_workspace) are intentionally
|
Mutating tools (write_file, edit_file, bash, delete_workspace) are intentionally
|
||||||
NOT here: they stay Everywhere so direct chat can call them under approval routing
|
NOT here: they stay Everywhere so direct chat can call them under approval routing
|
||||||
(Phase 4). Only genuinely agent-internal collaboration tools are agent-only. */
|
(Phase 4). Only genuinely agent-internal collaboration tools are agent-only. */
|
||||||
pub const AGENT_ONLY_TOOLS: &[&str] = &["submit_batch_plan", "report_completion"];
|
pub const AGENT_ONLY_TOOLS: &[&str] = &[
|
||||||
|
"submit_batch_plan",
|
||||||
|
"report_completion",
|
||||||
|
"kanban_add_task",
|
||||||
|
"kanban_complete_task",
|
||||||
|
"kanban_remove_task",
|
||||||
|
];
|
||||||
|
|
||||||
/* Tools that proxy to the Reef API when a `REEF_URL` / `REEF_API_URL` is
|
/* Tools that proxy to the Reef API when a `REEF_URL` / `REEF_API_URL` is
|
||||||
configured. These tools have both a local implementation and a Reef-backed
|
configured. These tools have both a local implementation and a Reef-backed
|
||||||
|
|
@ -899,7 +947,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"read_file",
|
"read_file",
|
||||||
"Read the content of a file with optional pagination",
|
"Read the content of a file with optional pagination",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -914,7 +964,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"write_file",
|
"write_file",
|
||||||
"Create or overwrite a file with content",
|
"Create or overwrite a file with content",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
true, true, false,
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -929,7 +981,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"list_directory",
|
"list_directory",
|
||||||
"List directory contents with optional filtering",
|
"List directory contents with optional filtering",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -944,7 +998,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"edit_file",
|
"edit_file",
|
||||||
"Edit file contents with line-based operations (replace, insert, delete)",
|
"Edit file contents with line-based operations (replace, insert, delete)",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
true, true, false,
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -971,7 +1027,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"search_files",
|
"search_files",
|
||||||
"Search for text patterns in files (grep-like)",
|
"Search for text patterns in files (grep-like)",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -982,7 +1040,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["path", "pattern"]
|
"required": ["path", "pattern"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Execution Tools
|
// Execution Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -990,7 +1047,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"bash",
|
"bash",
|
||||||
"Execute a shell command and capture output",
|
"Execute a shell command and capture output",
|
||||||
"execution",
|
"execution",
|
||||||
true, true, false,
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1001,7 +1060,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["command"]
|
"required": ["command"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Git Tools
|
// Git Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1009,7 +1067,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"git_status",
|
"git_status",
|
||||||
"Show working tree status in a git repository",
|
"Show working tree status in a git repository",
|
||||||
"git",
|
"git",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1022,7 +1082,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"git_diff",
|
"git_diff",
|
||||||
"Show changes between commits, commit and working tree, etc.",
|
"Show changes between commits, commit and working tree, etc.",
|
||||||
"git",
|
"git",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1036,7 +1098,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"git_log",
|
"git_log",
|
||||||
"Show commit history in a git repository",
|
"Show commit history in a git repository",
|
||||||
"git",
|
"git",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1049,7 +1113,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"git_branch",
|
"git_branch",
|
||||||
"List or manage git branches",
|
"List or manage git branches",
|
||||||
"git",
|
"git",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1058,7 +1124,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Build & Test Tools
|
// Build & Test Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1066,7 +1131,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"cargo_check",
|
"cargo_check",
|
||||||
"Run cargo check on a Rust project to verify compilation",
|
"Run cargo check on a Rust project to verify compilation",
|
||||||
"build",
|
"build",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1079,7 +1146,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"npm_build",
|
"npm_build",
|
||||||
"Run npm build script in a JavaScript/TypeScript project",
|
"Run npm build script in a JavaScript/TypeScript project",
|
||||||
"build",
|
"build",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1092,7 +1161,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"python_check",
|
"python_check",
|
||||||
"Check Python syntax or run linting on a Python file",
|
"Check Python syntax or run linting on a Python file",
|
||||||
"build",
|
"build",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1105,7 +1176,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"test_runner",
|
"test_runner",
|
||||||
"Run project tests with a test runner like pytest",
|
"Run project tests with a test runner like pytest",
|
||||||
"build",
|
"build",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1115,7 +1188,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Network Tools
|
// Network Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1123,7 +1195,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"web_search",
|
"web_search",
|
||||||
"Search the web for information using a search provider",
|
"Search the web for information using a search provider",
|
||||||
"network",
|
"network",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1138,7 +1212,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"web_fetch",
|
"web_fetch",
|
||||||
"Fetch and parse web pages from URLs",
|
"Fetch and parse web pages from URLs",
|
||||||
"network",
|
"network",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1152,7 +1228,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"web_api",
|
"web_api",
|
||||||
"Make HTTP API requests to external services",
|
"Make HTTP API requests to external services",
|
||||||
"network",
|
"network",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1163,7 +1241,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["url", "method"]
|
"required": ["url", "method"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Workspace Tools
|
// Workspace Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1171,7 +1248,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"create_workspace",
|
"create_workspace",
|
||||||
"Create an ephemeral workspace directory for isolated operations",
|
"Create an ephemeral workspace directory for isolated operations",
|
||||||
"workspace",
|
"workspace",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1184,7 +1263,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"delete_workspace",
|
"delete_workspace",
|
||||||
"Delete an ephemeral workspace and all its contents",
|
"Delete an ephemeral workspace and all its contents",
|
||||||
"workspace",
|
"workspace",
|
||||||
true, true, false,
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1198,7 +1279,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"create_venv",
|
"create_venv",
|
||||||
"Create a Python virtual environment",
|
"Create a Python virtual environment",
|
||||||
"workspace",
|
"workspace",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1212,7 +1295,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"install_dependencies",
|
"install_dependencies",
|
||||||
"Install Python dependencies from requirements.txt or specified packages",
|
"Install Python dependencies from requirements.txt or specified packages",
|
||||||
"workspace",
|
"workspace",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1226,7 +1311,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"workspace_info",
|
"workspace_info",
|
||||||
"Get information and statistics about a workspace directory",
|
"Get information and statistics about a workspace directory",
|
||||||
"workspace",
|
"workspace",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1235,7 +1322,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["path"]
|
"required": ["path"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Kanban Tools
|
// Kanban Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1243,7 +1329,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_list_board",
|
"kanban_list_board",
|
||||||
"List all columns and todos in the Kanban board",
|
"List all columns and todos in the Kanban board",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1257,7 +1345,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_create_todo",
|
"kanban_create_todo",
|
||||||
"Create a new todo item in a Kanban board",
|
"Create a new todo item in a Kanban board",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1280,7 +1370,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_update_todo",
|
"kanban_update_todo",
|
||||||
"Update a todo item's title, description, status, or priority",
|
"Update a todo item's title, description, status, or priority",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1298,7 +1390,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_delete_todo",
|
"kanban_delete_todo",
|
||||||
"Delete a todo item from the Kanban board",
|
"Delete a todo item from the Kanban board",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1312,7 +1406,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_move_todo",
|
"kanban_move_todo",
|
||||||
"Move a todo item to a different status",
|
"Move a todo item to a different status",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1328,7 +1424,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_create_task",
|
"kanban_create_task",
|
||||||
"Create a sub-task within a todo",
|
"Create a sub-task within a todo",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1344,7 +1442,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"kanban_update_task",
|
"kanban_update_task",
|
||||||
"Update a sub-task's title, description, or status",
|
"Update a sub-task's title, description, or status",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1357,11 +1457,64 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["project_id", "task_id"]
|
"required": ["project_id", "task_id"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
tool!(
|
||||||
|
"kanban_add_task",
|
||||||
|
"Add a checklist task to the todo owned by this agent run",
|
||||||
|
"kanban",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
serde_json::json!({
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": { "type": "string", "description": "Project ID" },
|
||||||
|
"todo_id": { "type": "string", "description": "ID of the parent todo" },
|
||||||
|
"title": { "type": "string", "description": "Checklist task title" },
|
||||||
|
"description": { "type": "string", "description": "Optional description" }
|
||||||
|
},
|
||||||
|
"required": ["project_id", "todo_id", "title"]
|
||||||
|
})
|
||||||
|
),
|
||||||
|
tool!(
|
||||||
|
"kanban_complete_task",
|
||||||
|
"Mark a checklist task complete or incomplete on the todo owned by this agent run",
|
||||||
|
"kanban",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
serde_json::json!({
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": { "type": "string", "description": "Project ID" },
|
||||||
|
"task_id": { "type": "string", "description": "Checklist task ID" },
|
||||||
|
"status": { "type": "string", "enum": ["completed", "pending"], "description": "Target status (defaults to completed)" }
|
||||||
|
},
|
||||||
|
"required": ["project_id", "task_id"]
|
||||||
|
})
|
||||||
|
),
|
||||||
|
tool!(
|
||||||
|
"kanban_remove_task",
|
||||||
|
"Remove a checklist task from the todo owned by this agent run",
|
||||||
|
"kanban",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
serde_json::json!({
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project_id": { "type": "string", "description": "Project ID" },
|
||||||
|
"task_id": { "type": "string", "description": "Checklist task ID" }
|
||||||
|
},
|
||||||
|
"required": ["project_id", "task_id"]
|
||||||
|
})
|
||||||
|
),
|
||||||
tool!(
|
tool!(
|
||||||
"kanban_add_tag",
|
"kanban_add_tag",
|
||||||
"Add a tag to a todo item",
|
"Add a tag to a todo item",
|
||||||
"kanban",
|
"kanban",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1380,7 +1533,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"document_file",
|
"document_file",
|
||||||
"Analyze and generate documentation for a file",
|
"Analyze and generate documentation for a file",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1394,7 +1549,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"document_project",
|
"document_project",
|
||||||
"Generate a comprehensive summary of all project files",
|
"Generate a comprehensive summary of all project files",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1407,7 +1564,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"find_references",
|
"find_references",
|
||||||
"Find all references to a symbol across the project",
|
"Find all references to a symbol across the project",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1423,7 +1582,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"file_dependencies",
|
"file_dependencies",
|
||||||
"Get incoming or outgoing dependencies for a file",
|
"Get incoming or outgoing dependencies for a file",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1438,7 +1599,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"documentation_tree",
|
"documentation_tree",
|
||||||
"Build a directory tree showing documentation coverage",
|
"Build a directory tree showing documentation coverage",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1452,7 +1615,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"verify_documentation",
|
"verify_documentation",
|
||||||
"Verify documentation freshness and compute coverage stats",
|
"Verify documentation freshness and compute coverage stats",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1465,7 +1630,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"document_folder",
|
"document_folder",
|
||||||
"Document all files within a folder",
|
"Document all files within a folder",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1479,7 +1646,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"store_file_doc",
|
"store_file_doc",
|
||||||
"Store documentation for a file",
|
"Store documentation for a file",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1502,7 +1671,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"get_documentation_context",
|
"get_documentation_context",
|
||||||
"Get the documentation context for a file",
|
"Get the documentation context for a file",
|
||||||
"documentation",
|
"documentation",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1512,7 +1683,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["project_id", "file_path"]
|
"required": ["project_id", "file_path"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// File Tools
|
// File Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1520,7 +1690,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"list_files",
|
"list_files",
|
||||||
"List all files in a project",
|
"List all files in a project",
|
||||||
"files",
|
"files",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1530,7 +1702,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"required": ["project_id"]
|
"required": ["project_id"]
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Strategic Tools
|
// Strategic Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1538,7 +1709,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"propose_strategic_item",
|
"propose_strategic_item",
|
||||||
"Propose a new high-level strategic goal or todo",
|
"Propose a new high-level strategic goal or todo",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, true, true,
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1555,7 +1728,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"split_task",
|
"split_task",
|
||||||
"Split a Pending todo into multiple subtasks with proper dependency tracking, depth validation, and cycle detection. Each subtask should be independently deployable to an agent.",
|
"Split a Pending todo into multiple subtasks with proper dependency tracking, depth validation, and cycle detection. Each subtask should be independently deployable to an agent.",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1583,7 +1758,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"change_planner_mode",
|
"change_planner_mode",
|
||||||
"Switch the Planner's working mode. Modes: cooperative (fast shipping), critical (audit), red_team (pre-mortem), socratic (discovery), execution (task decomposition).",
|
"Switch the Planner's working mode. Modes: cooperative (fast shipping), critical (audit), red_team (pre-mortem), socratic (discovery), execution (task decomposition).",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, true, true,
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1598,7 +1775,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"audit_assumptions",
|
"audit_assumptions",
|
||||||
"List the user's current assumptions about the project and identify the weakest ones",
|
"List the user's current assumptions about the project and identify the weakest ones",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1611,7 +1790,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"identify_blind_spots",
|
"identify_blind_spots",
|
||||||
"Query project data for missing dependency chains, undocumented risks, and recurring blockers",
|
"Query project data for missing dependency chains, undocumented risks, and recurring blockers",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1624,7 +1805,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"check_dependencies",
|
"check_dependencies",
|
||||||
"Analyze todo dependency chains for circular or missing dependencies",
|
"Analyze todo dependency chains for circular or missing dependencies",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1637,7 +1820,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"evaluate_plan_risk",
|
"evaluate_plan_risk",
|
||||||
"Score the current plan for feasibility, edge-case coverage, and alignment",
|
"Score the current plan for feasibility, edge-case coverage, and alignment",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, true,
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1650,7 +1835,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"compare_project_patterns",
|
"compare_project_patterns",
|
||||||
"Compare kanban structures across projects to detect inconsistencies",
|
"Compare kanban structures across projects to detect inconsistencies",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1662,7 +1849,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"find_similar_risks",
|
"find_similar_risks",
|
||||||
"Search across projects for similar risk patterns",
|
"Search across projects for similar risk patterns",
|
||||||
"strategic",
|
"strategic",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1671,7 +1860,6 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// Agent Tools
|
// Agent Tools
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1679,7 +1867,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"report_completion",
|
"report_completion",
|
||||||
"Report completion status of a todo back to the Bridge",
|
"Report completion status of a todo back to the Bridge",
|
||||||
"agent",
|
"agent",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1697,7 +1887,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
"submit_batch_plan",
|
"submit_batch_plan",
|
||||||
"Submit a batch plan of mutations for pre-approval before execution",
|
"Submit a batch plan of mutations for pre-approval before execution",
|
||||||
"agent",
|
"agent",
|
||||||
false, false, false,
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -1798,6 +1990,9 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
("kanban_move_todo", 2),
|
("kanban_move_todo", 2),
|
||||||
("kanban_create_task", 2),
|
("kanban_create_task", 2),
|
||||||
("kanban_update_task", 2),
|
("kanban_update_task", 2),
|
||||||
|
("kanban_add_task", 1),
|
||||||
|
("kanban_complete_task", 1),
|
||||||
|
("kanban_remove_task", 1),
|
||||||
("create_workspace", 2),
|
("create_workspace", 2),
|
||||||
("split_task", 2),
|
("split_task", 2),
|
||||||
// Depth 3 — needs deep reasoning
|
// Depth 3 — needs deep reasoning
|
||||||
|
|
@ -1933,11 +2128,37 @@ pub fn format_tools_json(tools: &[ToolDefinition]) -> Option<String> {
|
||||||
serde_json::to_string(&formatted).ok()
|
serde_json::to_string(&formatted).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deterministic hash of a tools JSON string using std DefaultHasher.
|
||||||
|
/// The hex-encoded result is used as a deduplication key across dispatch/pod.
|
||||||
|
pub fn compute_tools_hash(tools_json: &str) -> String {
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
tools_json.hash(&mut hasher);
|
||||||
|
format!("{:016x}", hasher.finish())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_tools_hash_deterministic() {
|
||||||
|
let input = r#"[{"type":"function","function":{"name":"foo","description":"bar","parameters":{}}}]"#;
|
||||||
|
let h1 = compute_tools_hash(input);
|
||||||
|
let h2 = compute_tools_hash(input);
|
||||||
|
assert_eq!(h1, h2);
|
||||||
|
assert_eq!(h1.len(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_tools_hash_different_inputs() {
|
||||||
|
let a = compute_tools_hash(r#"aaa"#);
|
||||||
|
let b = compute_tools_hash(r#"bbb"#);
|
||||||
|
assert_ne!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_single_block() {
|
fn test_parse_single_block() {
|
||||||
let text = r#"
|
let text = r#"
|
||||||
|
|
@ -2213,10 +2434,12 @@ Done with tools.
|
||||||
let results = parse_tool_call_blocks(text);
|
let results = parse_tool_call_blocks(text);
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
assert_eq!(results[0].call_id, "call_01");
|
assert_eq!(results[0].call_id, "call_01");
|
||||||
assert!(results[0].payload["content"]
|
assert!(
|
||||||
|
results[0].payload["content"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
.contains("🎉"));
|
.contains("🎉")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -2465,6 +2688,22 @@ Done with tools.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn checklist_task_tools_are_agent_only_at_depth_one() {
|
||||||
|
for id in [
|
||||||
|
"kanban_add_task",
|
||||||
|
"kanban_complete_task",
|
||||||
|
"kanban_remove_task",
|
||||||
|
] {
|
||||||
|
let tool = tool_definitions()
|
||||||
|
.into_iter()
|
||||||
|
.find(|tool| tool.id == id)
|
||||||
|
.expect("checklist task tool must be registered");
|
||||||
|
assert_eq!(tool.context_visibility, ContextVisibility::AgentOnly);
|
||||||
|
assert_eq!(tool.required_depth, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_category_backstop_keeps_sensitive_tools_fail_closed() {
|
fn test_category_backstop_keeps_sensitive_tools_fail_closed() {
|
||||||
/* Invariant enforced by the category backstop: no strategic tool is ever
|
/* Invariant enforced by the category backstop: no strategic tool is ever
|
||||||
|
|
|
||||||
118
type-maps.yaml
118
type-maps.yaml
|
|
@ -1,118 +0,0 @@
|
||||||
protocol_version: "1.0"
|
|
||||||
|
|
||||||
type_maps:
|
|
||||||
"1.0":
|
|
||||||
CommunicationTypes:
|
|
||||||
ReservoirHeartbeat: 32
|
|
||||||
ReservoirRequest: 33
|
|
||||||
ReservoirStore: 34
|
|
||||||
AuthRequest: 35
|
|
||||||
AuthResponse: 36
|
|
||||||
ProjectRequest: 37
|
|
||||||
ProjectResponse: 38
|
|
||||||
KanbanRequest: 39
|
|
||||||
KanbanResponse: 40
|
|
||||||
DiscussRequest: 41
|
|
||||||
DiscussResponse: 42
|
|
||||||
DiscussStreamChunk: 43
|
|
||||||
DiscussStreamDone: 44
|
|
||||||
ToolRequest: 45
|
|
||||||
ToolResponse: 46
|
|
||||||
AgentRequest: 47
|
|
||||||
AgentResponse: 48
|
|
||||||
AdminRequest: 49
|
|
||||||
AdminResponse: 50
|
|
||||||
SyncRequest: 51
|
|
||||||
SyncResponse: 52
|
|
||||||
PodRequest: 53
|
|
||||||
PodResponse: 54
|
|
||||||
LookoutEvent: 55
|
|
||||||
EventBroadcast: 56
|
|
||||||
ErrorResponse: 57
|
|
||||||
KrillIoInitialize: 58
|
|
||||||
KrillIoInitialized: 59
|
|
||||||
KrillIoAdvertiseSkills: 60
|
|
||||||
KrillIoSkillsAdvertised: 61
|
|
||||||
KrillIoQuerySkills: 62
|
|
||||||
KrillIoQuerySkillsResponse: 63
|
|
||||||
KrillIoMessage: 64
|
|
||||||
KrillIoMessageResponse: 65
|
|
||||||
KrillIoToolCallRequest: 66
|
|
||||||
KrillIoToolCallResponse: 67
|
|
||||||
KrillIoListTools: 68
|
|
||||||
KrillIoListToolsResponse: 69
|
|
||||||
KrillIoPauseSession: 70
|
|
||||||
KrillIoResumeSession: 71
|
|
||||||
KrillIoTerminateSession: 72
|
|
||||||
KrillIoSessionStateChanged: 73
|
|
||||||
KrillIoHeartbeat: 74
|
|
||||||
KrillIoHeartbeatResponse: 75
|
|
||||||
KrillIoLoadModel: 76
|
|
||||||
KrillIoModelLoaded: 77
|
|
||||||
KrillIoUnloadModel: 78
|
|
||||||
KrillIoMemoryReport: 79
|
|
||||||
KrillIoImmediateKill: 80
|
|
||||||
KrillIoKilled: 81
|
|
||||||
PodTaskAvailable: 82
|
|
||||||
PodDiscussAbort: 83
|
|
||||||
DataTypes:
|
|
||||||
ProjectId: 32
|
|
||||||
RequestType: 33
|
|
||||||
ResponseData: 34
|
|
||||||
Data: 35
|
|
||||||
FilePath: 36
|
|
||||||
FileData: 37
|
|
||||||
SessionId: 38
|
|
||||||
KrillId: 39
|
|
||||||
KrillIoVersion: 40
|
|
||||||
MaxHistoryLength: 41
|
|
||||||
DefaultTimeoutMs: 42
|
|
||||||
Enabled: 43
|
|
||||||
ToolError: 44
|
|
||||||
SkillsJson: 45
|
|
||||||
Content: 46
|
|
||||||
MessageRole: 47
|
|
||||||
Response: 48
|
|
||||||
TokensUsed: 49
|
|
||||||
ToolId: 50
|
|
||||||
ToolCallId: 51
|
|
||||||
ToolArguments: 52
|
|
||||||
Timeout: 53
|
|
||||||
ToolSuccess: 54
|
|
||||||
ExecutionTimeMs: 55
|
|
||||||
ToolResult: 56
|
|
||||||
ToolDefinitionsList: 57
|
|
||||||
Graceful: 58
|
|
||||||
SessionState: 59
|
|
||||||
ModelPath: 60
|
|
||||||
LoadIntoVram: 61
|
|
||||||
WeightsPath: 62
|
|
||||||
Path: 63
|
|
||||||
RamUsageMb: 64
|
|
||||||
VramMb: 65
|
|
||||||
KillReason: 66
|
|
||||||
SaveCheckpoint: 67
|
|
||||||
AuthToken: 68
|
|
||||||
UserId: 69
|
|
||||||
Username: 70
|
|
||||||
Email: 71
|
|
||||||
Password: 72
|
|
||||||
BoardId: 73
|
|
||||||
TodoId: 74
|
|
||||||
TaskId: 75
|
|
||||||
TagId: 76
|
|
||||||
ChatId: 77
|
|
||||||
MessageId: 78
|
|
||||||
AgentRunId: 79
|
|
||||||
Payload: 80
|
|
||||||
EventType: 81
|
|
||||||
EventPayload: 82
|
|
||||||
StreamSessionId: 83
|
|
||||||
ContentChunk: 84
|
|
||||||
StreamComplete: 85
|
|
||||||
FileHash: 86
|
|
||||||
FileSize: 87
|
|
||||||
FileContent: 88
|
|
||||||
ErrorCode: 89
|
|
||||||
PageOffset: 90
|
|
||||||
PageLimit: 91
|
|
||||||
Loading…
Reference in a new issue