MTP tools & Centralizing
This commit is contained in:
parent
c325a7bc4f
commit
3e6fcec171
9 changed files with 1549 additions and 291 deletions
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[env]
|
||||||
|
MTP_TYPE_MAPS = { value = "type-maps.yaml", relative = true }
|
||||||
1484
Cargo.lock
generated
1484
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@ 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"
|
||||||
stp-core = { git = "https://git.methanium.net/shoal/stp.git" }
|
mtp = { path = "../mtp-npm", features = [] }
|
||||||
tokio = "1"
|
tokio = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
||||||
171
src/agents.rs
171
src/agents.rs
|
|
@ -1,5 +1,7 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/* ExploreAgent is intentionally limited to read-only tools so it can be
|
||||||
|
dispatched without approval for safe, unrestricted codebase exploration. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum AgentType {
|
pub enum AgentType {
|
||||||
|
|
@ -8,6 +10,8 @@ pub enum AgentType {
|
||||||
BuildAgent,
|
BuildAgent,
|
||||||
ChatAgent,
|
ChatAgent,
|
||||||
TestJudge,
|
TestJudge,
|
||||||
|
/* Lightweight read-only agent for exploration tasks. Never mutates files. */
|
||||||
|
ExploreAgent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentType {
|
impl AgentType {
|
||||||
|
|
@ -18,6 +22,7 @@ impl AgentType {
|
||||||
AgentType::BuildAgent => "build_agent",
|
AgentType::BuildAgent => "build_agent",
|
||||||
AgentType::ChatAgent => "chat",
|
AgentType::ChatAgent => "chat",
|
||||||
AgentType::TestJudge => "test_judge",
|
AgentType::TestJudge => "test_judge",
|
||||||
|
AgentType::ExploreAgent => "explore_agent",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,6 +33,7 @@ impl AgentType {
|
||||||
"build_agent" => Some(AgentType::BuildAgent),
|
"build_agent" => Some(AgentType::BuildAgent),
|
||||||
"chat" => Some(AgentType::ChatAgent),
|
"chat" => Some(AgentType::ChatAgent),
|
||||||
"test_judge" => Some(AgentType::TestJudge),
|
"test_judge" => Some(AgentType::TestJudge),
|
||||||
|
"explore_agent" => Some(AgentType::ExploreAgent),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +125,171 @@ impl AgentPolicy {
|
||||||
allowed_tools: vec![],
|
allowed_tools: vec![],
|
||||||
forbidden_mutations: vec![],
|
forbidden_mutations: vec![],
|
||||||
},
|
},
|
||||||
|
/* ExploreAgent: auto-approved, read-only tools only, short timeout.
|
||||||
|
Forbidden mutations set to wildcard to block all writes. */
|
||||||
|
AgentType::ExploreAgent => Self {
|
||||||
|
agent_type: agent_type.clone(),
|
||||||
|
auto_approve: true,
|
||||||
|
max_depth: 1,
|
||||||
|
require_preview: false,
|
||||||
|
timeout_seconds: 30,
|
||||||
|
max_tokens: 4096,
|
||||||
|
allowed_tools: vec![
|
||||||
|
"read_file".into(),
|
||||||
|
"list_directory".into(),
|
||||||
|
"search_files".into(),
|
||||||
|
"list_files".into(),
|
||||||
|
"web_search".into(),
|
||||||
|
"web_fetch".into(),
|
||||||
|
],
|
||||||
|
forbidden_mutations: vec!["*".into()],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Per-agent prompt configuration. Stored in the DB and resolved on task
|
||||||
|
dispatch. Resolution order: task instructions > DB override > this config
|
||||||
|
> compiled-in default > tool protocol. */
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AgentPromptConfig {
|
||||||
|
pub agent_type: AgentType,
|
||||||
|
/* Replaces or extends the compiled-in default prompt when set. */
|
||||||
|
pub system_prompt: Option<String>,
|
||||||
|
/* Rules appended after the main prompt, one per item. */
|
||||||
|
pub append_rules: Vec<String>,
|
||||||
|
/* When true, system_prompt fully replaces the default rather than appending. */
|
||||||
|
pub override_defaults: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AgentPromptConfig {
|
||||||
|
pub fn new(agent_type: AgentType) -> Self {
|
||||||
|
Self {
|
||||||
|
agent_type,
|
||||||
|
system_prompt: None,
|
||||||
|
append_rules: Vec::new(),
|
||||||
|
override_defaults: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Applies this config on top of a base prompt. Returns the merged result. */
|
||||||
|
pub fn apply(&self, base: &str) -> String {
|
||||||
|
let body = if self.override_defaults {
|
||||||
|
self.system_prompt.as_deref().unwrap_or(base).to_string()
|
||||||
|
} else {
|
||||||
|
match &self.system_prompt {
|
||||||
|
Some(p) => format!("{}\n\n{}", base, p),
|
||||||
|
None => base.to_string(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.append_rules.is_empty() {
|
||||||
|
body
|
||||||
|
} else {
|
||||||
|
format!("{}\n\n{}", body, self.append_rules.join("\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_type_as_str_roundtrip() {
|
||||||
|
let types = [
|
||||||
|
AgentType::Planner,
|
||||||
|
AgentType::DocAgent,
|
||||||
|
AgentType::BuildAgent,
|
||||||
|
AgentType::ChatAgent,
|
||||||
|
AgentType::TestJudge,
|
||||||
|
AgentType::ExploreAgent,
|
||||||
|
];
|
||||||
|
for agent_type in &types {
|
||||||
|
let s = agent_type.as_str();
|
||||||
|
let parsed = AgentType::from_str(s);
|
||||||
|
assert_eq!(parsed.as_ref(), Some(agent_type), "roundtrip failed for {:?}", agent_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_type_from_str_unknown() {
|
||||||
|
assert!(AgentType::from_str("unknown_agent").is_none());
|
||||||
|
assert!(AgentType::from_str("").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_defaults_for_all_types() {
|
||||||
|
let types = [
|
||||||
|
AgentType::Planner,
|
||||||
|
AgentType::DocAgent,
|
||||||
|
AgentType::BuildAgent,
|
||||||
|
AgentType::ChatAgent,
|
||||||
|
AgentType::TestJudge,
|
||||||
|
AgentType::ExploreAgent,
|
||||||
|
];
|
||||||
|
for agent_type in &types {
|
||||||
|
let policy = AgentPolicy::defaults_for(agent_type);
|
||||||
|
assert_eq!(&policy.agent_type, agent_type);
|
||||||
|
assert!(policy.timeout_seconds > 0);
|
||||||
|
assert!(policy.max_tokens > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_explore_agent_is_auto_approved_read_only() {
|
||||||
|
let policy = AgentPolicy::defaults_for(&AgentType::ExploreAgent);
|
||||||
|
assert!(policy.auto_approve);
|
||||||
|
assert_eq!(policy.max_depth, 1);
|
||||||
|
assert!(policy.allowed_tools.contains(&"read_file".to_string()));
|
||||||
|
assert!(policy.allowed_tools.contains(&"search_files".to_string()));
|
||||||
|
assert!(!policy.allowed_tools.contains(&"write_file".to_string()));
|
||||||
|
assert!(!policy.allowed_tools.contains(&"edit_file".to_string()));
|
||||||
|
assert!(policy.forbidden_mutations.contains(&"*".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_agent_requires_approval() {
|
||||||
|
let policy = AgentPolicy::defaults_for(&AgentType::BuildAgent);
|
||||||
|
assert!(!policy.auto_approve);
|
||||||
|
assert!(policy.max_tokens > 8192);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_prompt_config_apply_override() {
|
||||||
|
let mut config = AgentPromptConfig::new(AgentType::BuildAgent);
|
||||||
|
config.system_prompt = Some("Custom prompt".to_string());
|
||||||
|
config.override_defaults = true;
|
||||||
|
|
||||||
|
let result = config.apply("Original base");
|
||||||
|
assert_eq!(result, "Custom prompt");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_prompt_config_apply_append() {
|
||||||
|
let mut config = AgentPromptConfig::new(AgentType::DocAgent);
|
||||||
|
config.system_prompt = Some("Extension".to_string());
|
||||||
|
config.override_defaults = false;
|
||||||
|
|
||||||
|
let result = config.apply("Base prompt");
|
||||||
|
assert!(result.starts_with("Base prompt"));
|
||||||
|
assert!(result.contains("Extension"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_prompt_config_apply_rules() {
|
||||||
|
let mut config = AgentPromptConfig::new(AgentType::Planner);
|
||||||
|
config.append_rules = vec!["Rule 1".to_string(), "Rule 2".to_string()];
|
||||||
|
|
||||||
|
let result = config.apply("Base");
|
||||||
|
assert!(result.contains("Rule 1"));
|
||||||
|
assert!(result.contains("Rule 2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_agent_prompt_config_no_overrides() {
|
||||||
|
let config = AgentPromptConfig::new(AgentType::ChatAgent);
|
||||||
|
let result = config.apply("Base prompt");
|
||||||
|
assert_eq!(result, "Base prompt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub use chrono::{DateTime, Utc};
|
pub use chrono::{DateTime, Utc};
|
||||||
pub use stp_core::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
pub use mtp::codec::{CommunicationValue, DataValue};
|
||||||
|
pub use mtp::type_map::{CommunicationType, DataType};
|
||||||
pub use uuid::Uuid;
|
pub use uuid::Uuid;
|
||||||
|
|
||||||
pub mod agents;
|
pub mod agents;
|
||||||
|
|
@ -15,7 +16,7 @@ pub mod task;
|
||||||
pub mod todo;
|
pub mod todo;
|
||||||
pub mod tools;
|
pub mod tools;
|
||||||
|
|
||||||
pub use agents::{AgentPolicy, AgentType, ApprovalMode, PlannedAction, SimulationResult};
|
pub use agents::{AgentPolicy, AgentPromptConfig, AgentType, ApprovalMode, PlannedAction, SimulationResult};
|
||||||
pub use ai_response::{Conversation, Message};
|
pub use ai_response::{Conversation, Message};
|
||||||
pub use conclusion::{
|
pub use conclusion::{
|
||||||
Artifact, ArtifactType, ConclusionCard, ConclusionMetrics, ConclusionTrigger,
|
Artifact, ArtifactType, ConclusionCard, ConclusionMetrics, ConclusionTrigger,
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,10 @@ 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>,
|
||||||
|
/* Overrides the agent-type default system prompt when set. Takes highest
|
||||||
|
precedence in the resolution chain (above DB overrides and defaults). */
|
||||||
|
#[serde(default)]
|
||||||
|
pub system_prompt: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentTaskSpec {
|
impl AgentTaskSpec {
|
||||||
|
|
@ -239,6 +243,7 @@ impl AgentTaskSpec {
|
||||||
project_id: None,
|
project_id: None,
|
||||||
connector_config: None,
|
connector_config: None,
|
||||||
tools_json: None,
|
tools_json: None,
|
||||||
|
system_prompt: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
41
src/todo.rs
41
src/todo.rs
|
|
@ -4,7 +4,6 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::enums::{ToDoSource, ToDoStatus};
|
use crate::enums::{ToDoSource, ToDoStatus};
|
||||||
use crate::errors::ValidationError;
|
use crate::errors::ValidationError;
|
||||||
use crate::{CommunicationType, CommunicationValue, DataTypes, DataValue};
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
const MAX_TITLE_LENGTH: usize = 500;
|
const MAX_TITLE_LENGTH: usize = 500;
|
||||||
|
|
@ -132,8 +131,8 @@ impl ToDo {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs full graph cycle detection given a map of todo_id -> dependencies.
|
/* DFS cycle detection over a full dependency graph. Returns the first
|
||||||
/// Returns the ID of the first todo that would participate in a cycle, or None.
|
todo_id found in a cycle, or None when the graph is acyclic. */
|
||||||
pub fn detect_cycle_in_graph(deps: &std::collections::HashMap<Uuid, Vec<Uuid>>) -> Option<Uuid> {
|
pub fn detect_cycle_in_graph(deps: &std::collections::HashMap<Uuid, Vec<Uuid>>) -> Option<Uuid> {
|
||||||
let mut visited: HashSet<Uuid> = HashSet::new();
|
let mut visited: HashSet<Uuid> = HashSet::new();
|
||||||
let mut in_stack: HashSet<Uuid> = HashSet::new();
|
let mut in_stack: HashSet<Uuid> = HashSet::new();
|
||||||
|
|
@ -250,42 +249,6 @@ impl ToDo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ToDo> for CommunicationValue {
|
|
||||||
fn from(todo: ToDo) -> Self {
|
|
||||||
let mut cv = CommunicationValue::new(CommunicationType::todo);
|
|
||||||
cv = cv.add_data(DataTypes::id, DataValue::Str(todo.id.to_string()));
|
|
||||||
cv = cv.add_data(DataTypes::title, DataValue::Str(todo.title));
|
|
||||||
cv = cv.add_data(DataTypes::description, DataValue::Str(todo.description));
|
|
||||||
cv = cv.add_data(DataTypes::status, DataValue::Str(todo.status.to_string()));
|
|
||||||
cv = cv.add_data(DataTypes::todo_id, DataValue::Number(todo.priority as i64));
|
|
||||||
|
|
||||||
let depends: Vec<DataValue> = todo
|
|
||||||
.depends_on
|
|
||||||
.iter()
|
|
||||||
.map(|u| DataValue::Str(u.to_string()))
|
|
||||||
.collect();
|
|
||||||
cv = cv.add_data(DataTypes::depends_on, DataValue::Array(depends));
|
|
||||||
|
|
||||||
cv = cv.add_data(
|
|
||||||
DataTypes::created_at,
|
|
||||||
DataValue::Str(todo.created_at.to_rfc3339()),
|
|
||||||
);
|
|
||||||
cv = cv.add_data(
|
|
||||||
DataTypes::updated_at,
|
|
||||||
DataValue::Str(todo.updated_at.to_rfc3339()),
|
|
||||||
);
|
|
||||||
cv = cv.add_data(
|
|
||||||
DataTypes::user_id,
|
|
||||||
DataValue::Str(todo.created_by.to_string()),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(pid) = todo.project_id {
|
|
||||||
cv = cv.add_data(DataTypes::project_id, DataValue::Str(pid.to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
|
||||||
66
src/tools.rs
66
src/tools.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Context in which a tool should be available
|
/* Context in which a tool should be available */
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ExecutionContext {
|
pub enum ExecutionContext {
|
||||||
|
|
@ -165,7 +165,7 @@ impl ToolDefinition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple semver comparison (major.minor.patch)
|
/* Simple semver comparison (major.minor.patch) */
|
||||||
fn compare_versions(a: &str, b: &str) -> std::cmp::Ordering {
|
fn compare_versions(a: &str, b: &str) -> std::cmp::Ordering {
|
||||||
let parse_version = |v: &str| -> Vec<u64> {
|
let parse_version = |v: &str| -> Vec<u64> {
|
||||||
v.split('.')
|
v.split('.')
|
||||||
|
|
@ -407,8 +407,8 @@ pub struct ToolErrorInfo {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended version tracking for tool definitions.
|
/* Extended version tracking for tool definitions.
|
||||||
/// Provides schema versioning, deprecation notices, and migration guidance.
|
Provides schema versioning, deprecation notices, and migration guidance. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolVersion {
|
pub struct ToolVersion {
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
|
@ -431,8 +431,8 @@ impl Default for ToolVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execution context for tool filtering.
|
/* Execution context for tool filtering. Determines which tools are
|
||||||
/// Determines which tools are available in which execution environment.
|
available in which execution environment (Reef vs. Krill vs. both). */
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ToolContext {
|
pub enum ToolContext {
|
||||||
|
|
@ -447,7 +447,7 @@ impl Default for ToolContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tool category classification for UI 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")]
|
||||||
pub enum ToolCategory {
|
pub enum ToolCategory {
|
||||||
|
|
@ -482,8 +482,8 @@ impl ToolCategory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A composed workflow of multiple tool steps executed in sequence
|
/* A composed workflow of multiple tool steps executed in sequence
|
||||||
/// with dependency-based ordering.
|
with dependency-based ordering. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolComposition {
|
pub struct ToolComposition {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
@ -499,21 +499,20 @@ const fn default_composition_timeout_ms() -> u64 {
|
||||||
60000
|
60000
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single step within a tool composition.
|
/* A single step within a tool composition. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct CompositionStep {
|
pub struct CompositionStep {
|
||||||
pub tool: String,
|
pub tool: String,
|
||||||
pub arguments: serde_json::Value,
|
pub arguments: serde_json::Value,
|
||||||
/// Indices of steps this step depends on (0-based).
|
/* Indices (0-based) of steps this step depends on. None = no dependencies. */
|
||||||
/// If None, the step has no dependencies and can run immediately.
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub depends_on: Option<Vec<usize>>,
|
pub depends_on: Option<Vec<usize>>,
|
||||||
/// Optional label for referencing step outputs
|
/* Optional label for referencing step outputs. */
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declares a dependency of one tool on another tool version.
|
/* Declares a dependency of one tool on another tool version. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolDependency {
|
pub struct ToolDependency {
|
||||||
pub tool: String,
|
pub tool: String,
|
||||||
|
|
@ -587,17 +586,21 @@ macro_rules! tool {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for implementing custom tool plugins.
|
/* Trait for implementing custom tool plugins.
|
||||||
/// Plugins can be registered at runtime to extend the tool ecosystem.
|
Plugins register at runtime to extend the tool ecosystem. */
|
||||||
pub trait ToolPlugin: Send + Sync {
|
pub trait ToolPlugin: Send + Sync {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
fn description(&self) -> &str;
|
fn description(&self) -> &str;
|
||||||
fn category(&self) -> &str;
|
fn category(&self) -> &str;
|
||||||
fn schema(&self) -> serde_json::Value;
|
fn schema(&self) -> serde_json::Value;
|
||||||
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, String>;
|
fn execute(&self, args: serde_json::Value) -> Result<serde_json::Value, String>;
|
||||||
|
/* Defaults to true (dangerous) — safe default for unknown plugins. */
|
||||||
|
fn dangerous(&self) -> bool { true }
|
||||||
|
/* Defaults to true; callers must explicitly opt out of approval prompts. */
|
||||||
|
fn requires_approval(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A marketplace listing for a published tool.
|
/* A marketplace listing for a published tool. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolListing {
|
pub struct ToolListing {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
@ -624,7 +627,7 @@ pub struct ToolListing {
|
||||||
pub published_at: String,
|
pub published_at: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Results from a marketplace search.
|
/* Results from a marketplace search. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct MarketplaceSearchResults {
|
pub struct MarketplaceSearchResults {
|
||||||
pub listings: Vec<ToolListing>,
|
pub listings: Vec<ToolListing>,
|
||||||
|
|
@ -633,7 +636,7 @@ pub struct MarketplaceSearchResults {
|
||||||
pub page_size: usize,
|
pub page_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A documented example for a tool.
|
/* A documented example for a tool. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolExample {
|
pub struct ToolExample {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
@ -652,7 +655,7 @@ pub struct ToolExample {
|
||||||
pub author: String,
|
pub author: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single test case for a tool.
|
/* A single test case for a tool. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolTest {
|
pub struct ToolTest {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
@ -669,7 +672,7 @@ const fn default_test_timeout() -> u64 {
|
||||||
30000
|
30000
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A suite of tests for a specific tool.
|
/* A suite of tests for a specific tool. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolTestSuite {
|
pub struct ToolTestSuite {
|
||||||
pub tool_name: String,
|
pub tool_name: String,
|
||||||
|
|
@ -680,14 +683,14 @@ pub struct ToolTestSuite {
|
||||||
pub teardown_actions: Vec<TestAction>,
|
pub teardown_actions: Vec<TestAction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A setup or teardown action for a test suite.
|
/* A setup or teardown action for a test suite. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct TestAction {
|
pub struct TestAction {
|
||||||
pub tool: String,
|
pub tool: String,
|
||||||
pub arguments: serde_json::Value,
|
pub arguments: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of running a single tool test.
|
/* Result of running a single tool test. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolTestResult {
|
pub struct ToolTestResult {
|
||||||
pub test_name: String,
|
pub test_name: String,
|
||||||
|
|
@ -699,7 +702,7 @@ pub struct ToolTestResult {
|
||||||
pub duration_ms: u64,
|
pub duration_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Results of running a full test suite.
|
/* Results of running a full test suite. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolTestSuiteResult {
|
pub struct ToolTestSuiteResult {
|
||||||
pub tool_name: String,
|
pub tool_name: String,
|
||||||
|
|
@ -710,7 +713,7 @@ pub struct ToolTestSuiteResult {
|
||||||
pub total_duration_ms: u64,
|
pub total_duration_ms: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generated documentation for a tool.
|
/* Generated documentation for a tool. */
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ToolDocumentation {
|
pub struct ToolDocumentation {
|
||||||
pub tool_name: String,
|
pub tool_name: String,
|
||||||
|
|
@ -731,7 +734,7 @@ pub struct ToolDocumentation {
|
||||||
pub examples: Vec<ToolExample>,
|
pub examples: Vec<ToolExample>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all built-in tool definitions across all categories.
|
/* Returns all built-in tool definitions across all categories. */
|
||||||
pub fn tool_definitions() -> Vec<ToolDefinition> {
|
pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
vec![
|
vec![
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -1534,8 +1537,8 @@ pub fn tool_definitions() -> Vec<ToolDefinition> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the tool IDs appropriate for a given agent type.
|
/* Returns the tool IDs appropriate for a given agent type.
|
||||||
/// Used by the dispatcher to embed tool definitions in task specs.
|
Used by the dispatcher to embed tool definitions in task specs. */
|
||||||
pub fn tool_ids_for_agent_type(agent_type: &crate::agents::AgentType) -> Option<Vec<&'static str>> {
|
pub fn tool_ids_for_agent_type(agent_type: &crate::agents::AgentType) -> Option<Vec<&'static str>> {
|
||||||
Some(match agent_type {
|
Some(match agent_type {
|
||||||
crate::agents::AgentType::BuildAgent => vec![
|
crate::agents::AgentType::BuildAgent => vec![
|
||||||
|
|
@ -1565,10 +1568,15 @@ pub fn tool_ids_for_agent_type(agent_type: &crate::agents::AgentType) -> Option<
|
||||||
"store_file_doc", "read_file",
|
"store_file_doc", "read_file",
|
||||||
],
|
],
|
||||||
crate::agents::AgentType::ChatAgent => return None,
|
crate::agents::AgentType::ChatAgent => return None,
|
||||||
|
/* ExploreAgent only receives read-only tools — no write, edit, or bash. */
|
||||||
|
crate::agents::AgentType::ExploreAgent => vec![
|
||||||
|
"read_file", "list_directory", "search_files", "list_files",
|
||||||
|
"web_search", "web_fetch",
|
||||||
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats tool definitions as OpenAI-compatible tools JSON.
|
/* Formats tool definitions as OpenAI-compatible function-calling JSON. */
|
||||||
pub fn format_tools_json(tools: &[ToolDefinition]) -> Option<String> {
|
pub fn format_tools_json(tools: &[ToolDefinition]) -> Option<String> {
|
||||||
let formatted: Vec<serde_json::Value> = tools
|
let formatted: Vec<serde_json::Value> = tools
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
116
type-maps.yaml
Normal file
116
type-maps.yaml
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
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
|
||||||
|
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