alexhancock/rmcp-tools-annotations (#3617)
This commit is contained in:
@@ -42,8 +42,9 @@ use crate::providers::errors::ProviderError;
|
||||
use crate::recipe::{Author, Recipe, Response, Settings, SubRecipe};
|
||||
use crate::scheduler_trait::SchedulerTrait;
|
||||
use crate::tool_monitor::{ToolCall, ToolMonitor};
|
||||
use mcp_core::{protocol::GetPromptResult, tool::Tool, ToolError, ToolResult};
|
||||
use mcp_core::{protocol::GetPromptResult, ToolError, ToolResult};
|
||||
use regex::Regex;
|
||||
use rmcp::model::Tool;
|
||||
use rmcp::model::{Content, JsonRpcMessage, Prompt};
|
||||
use serde_json::Value;
|
||||
use tokio::sync::{mpsc, Mutex, RwLock};
|
||||
@@ -538,10 +539,10 @@ impl Agent {
|
||||
let mut frontend_tools = self.frontend_tools.lock().await;
|
||||
for tool in tools {
|
||||
let frontend_tool = FrontendTool {
|
||||
name: tool.name.clone(),
|
||||
name: tool.name.to_string(),
|
||||
tool: tool.clone(),
|
||||
};
|
||||
frontend_tools.insert(tool.name.clone(), frontend_tool);
|
||||
frontend_tools.insert(tool.name.to_string(), frontend_tool);
|
||||
}
|
||||
// Store instructions if provided, using "frontend" as the key
|
||||
let mut frontend_instructions = self.frontend_instructions.lock().await;
|
||||
@@ -1181,7 +1182,10 @@ impl Agent {
|
||||
.map(|tool| {
|
||||
ToolInfo::new(
|
||||
&tool.name,
|
||||
&tool.description,
|
||||
tool.description
|
||||
.as_ref()
|
||||
.map(|d| d.as_ref())
|
||||
.unwrap_or_default(),
|
||||
get_parameter_names(&tool),
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use mcp_client::client::Error as ClientError;
|
||||
use mcp_core::tool::Tool;
|
||||
use rmcp::model::Tool;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -19,8 +19,8 @@ use crate::config::{Config, ExtensionConfigManager};
|
||||
use crate::prompt_template;
|
||||
use mcp_client::client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait};
|
||||
use mcp_client::transport::{SseTransport, StdioTransport, StreamableHttpTransport, Transport};
|
||||
use mcp_core::{Tool, ToolCall, ToolError};
|
||||
use rmcp::model::{Content, Prompt, Resource, ResourceContents};
|
||||
use mcp_core::{ToolCall, ToolError};
|
||||
use rmcp::model::{Content, Prompt, Resource, ResourceContents, Tool};
|
||||
use serde_json::Value;
|
||||
|
||||
// By default, we set it to Jan 1, 2020 if the resource does not have a timestamp
|
||||
@@ -380,13 +380,18 @@ impl ExtensionManager {
|
||||
let mut client_tools = client_guard.list_tools(None).await?;
|
||||
|
||||
loop {
|
||||
for tool in client_tools.tools {
|
||||
tools.push(Tool::new(
|
||||
format!("{}__{}", name, tool.name),
|
||||
&tool.description,
|
||||
tool.input_schema,
|
||||
tool.annotations,
|
||||
));
|
||||
for client_tool in client_tools.tools {
|
||||
let mut tool = Tool::new(
|
||||
format!("{}__{}", name, client_tool.name),
|
||||
client_tool.description.unwrap_or_default(),
|
||||
client_tool.input_schema,
|
||||
);
|
||||
|
||||
if tool.annotations.is_some() {
|
||||
tool = tool.annotate(client_tool.annotations.unwrap())
|
||||
}
|
||||
|
||||
tools.push(tool);
|
||||
}
|
||||
|
||||
// Exit loop when there are no more pages
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use crate::agents::tool_execution::ToolCallResult;
|
||||
use crate::recipe::Response;
|
||||
use indoc::formatdoc;
|
||||
use mcp_core::{
|
||||
tool::{Tool, ToolAnnotations},
|
||||
ToolCall, ToolError,
|
||||
};
|
||||
use rmcp::model::Content;
|
||||
use mcp_core::{ToolCall, ToolError};
|
||||
use rmcp::model::{Content, Tool, ToolAnnotations};
|
||||
use serde_json::Value;
|
||||
|
||||
pub const FINAL_OUTPUT_TOOL_NAME: &str = "recipe__final_output";
|
||||
@@ -64,15 +61,21 @@ impl FinalOutputTool {
|
||||
Tool::new(
|
||||
FINAL_OUTPUT_TOOL_NAME.to_string(),
|
||||
instructions,
|
||||
self.response.json_schema.as_ref().unwrap().clone(),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Final Output".to_string()),
|
||||
read_only_hint: false,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: true,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
self.response
|
||||
.json_schema
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.clone(),
|
||||
)
|
||||
.annotate(ToolAnnotations {
|
||||
title: Some("Final Output".to_string()),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(true),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn system_prompt(&self) -> String {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use indoc::indoc;
|
||||
use mcp_core::tool::{Tool, ToolAnnotations};
|
||||
use serde_json::json;
|
||||
use rmcp::model::{Tool, ToolAnnotations};
|
||||
use rmcp::object;
|
||||
|
||||
pub const PLATFORM_READ_RESOURCE_TOOL_NAME: &str = "platform__read_resource";
|
||||
pub const PLATFORM_LIST_RESOURCES_TOOL_NAME: &str = "platform__list_resources";
|
||||
@@ -20,22 +20,21 @@ pub fn read_resource_tool() -> Tool {
|
||||
resource URI in the provided extension, and reads in the resource content. If no extension
|
||||
is provided, the tool will search all extensions for the resource.
|
||||
"#}.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": ["uri"],
|
||||
"properties": {
|
||||
"uri": {"type": "string", "description": "Resource URI"},
|
||||
"extension_name": {"type": "string", "description": "Optional extension name"}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Read a resource".to_string()),
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Read a resource".to_string()),
|
||||
read_only_hint: Some(true),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list_resources_tool() -> Tool {
|
||||
@@ -50,20 +49,20 @@ pub fn list_resources_tool() -> Tool {
|
||||
is provided, the tool will search all extensions for the resource.
|
||||
"#}
|
||||
.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"extension_name": {"type": "string", "description": "Optional extension name"}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("List resources".to_string()),
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
.annotate(ToolAnnotations {
|
||||
title: Some("List resources".to_string()),
|
||||
read_only_hint: Some(true),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn search_available_extensions_tool() -> Tool {
|
||||
@@ -73,19 +72,18 @@ pub fn search_available_extensions_tool() -> Tool {
|
||||
Use this tool when you're unable to find a specific feature or functionality you need to complete your task, or when standard approaches aren't working.
|
||||
These extensions might provide the exact tools needed to solve your problem.
|
||||
If you find a relevant one, consider using your tools to enable it.".to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"properties": {}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Discover extensions".to_string()),
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Discover extensions".to_string()),
|
||||
read_only_hint: Some(true),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn manage_extensions_tool() -> Tool {
|
||||
@@ -96,7 +94,7 @@ pub fn manage_extensions_tool() -> Tool {
|
||||
Enable or disable an extension by providing the extension name.
|
||||
"
|
||||
.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": ["action", "extension_name"],
|
||||
"properties": {
|
||||
@@ -104,14 +102,13 @@ pub fn manage_extensions_tool() -> Tool {
|
||||
"extension_name": {"type": "string", "description": "The name of the extension to enable"}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Enable or disable an extension".to_string()),
|
||||
read_only_hint: false,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Enable or disable an extension".to_string()),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn manage_schedule_tool() -> Tool {
|
||||
@@ -133,7 +130,7 @@ pub fn manage_schedule_tool() -> Tool {
|
||||
- "session_content": Get the full content (messages) of a specific session
|
||||
"#}
|
||||
.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": ["action"],
|
||||
"properties": {
|
||||
@@ -149,12 +146,11 @@ pub fn manage_schedule_tool() -> Tool {
|
||||
"session_id": {"type": "string", "description": "Session identifier for session_content action"}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Manage scheduled recipes".to_string()),
|
||||
read_only_hint: false,
|
||||
destructive_hint: true, // Can kill jobs
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Manage scheduled recipes".to_string()),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(true), // Can kill jobs
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
use crate::agents::subagent_execution_tool::tasks_manager::TasksManager;
|
||||
use crate::agents::subagent_execution_tool::{lib::ExecutionMode, task_types::Task};
|
||||
use crate::agents::tool_execution::ToolCallResult;
|
||||
use mcp_core::{tool::ToolAnnotations, Tool, ToolError};
|
||||
use rmcp::model::Content;
|
||||
use mcp_core::ToolError;
|
||||
use rmcp::model::{Content, Tool, ToolAnnotations};
|
||||
use rmcp::object;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub const DYNAMIC_TASK_TOOL_NAME_PREFIX: &str = "dynamic_task__create_task";
|
||||
@@ -35,7 +36,7 @@ pub fn create_dynamic_task_tool() -> Tool {
|
||||
text_instruction: Get weather for Los Angeles.
|
||||
text_instruction: Get weather for San Francisco.
|
||||
".to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task_parameters": {
|
||||
@@ -56,15 +57,14 @@ pub fn create_dynamic_task_tool() -> Tool {
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Dynamic Task Creation".to_string()),
|
||||
read_only_hint: false,
|
||||
destructive_hint: true,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: true,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Dynamic Task Creation".to_string()),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(true),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(true),
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_task_parameters(params: &Value) -> Vec<Value> {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use mcp_core::tool::{Tool, ToolAnnotations};
|
||||
use rmcp::model::{Tool, ToolAnnotations};
|
||||
use serde_json::{json, Map, Value};
|
||||
|
||||
use crate::agents::subagent_execution_tool::lib::{ExecutionMode, Task};
|
||||
@@ -15,6 +16,7 @@ pub const SUB_RECIPE_TASK_TOOL_NAME_PREFIX: &str = "subrecipe__create_task";
|
||||
|
||||
pub fn create_sub_recipe_task_tool(sub_recipe: &SubRecipe) -> Tool {
|
||||
let input_schema = get_input_schema(sub_recipe).unwrap();
|
||||
|
||||
Tool::new(
|
||||
format!("{}_{}", SUB_RECIPE_TASK_TOOL_NAME_PREFIX, sub_recipe.name),
|
||||
format!(
|
||||
@@ -27,15 +29,17 @@ pub fn create_sub_recipe_task_tool(sub_recipe: &SubRecipe) -> Tool {
|
||||
After creating the tasks and execution_mode is provided, pass them to the task executor to run these tasks",
|
||||
sub_recipe.name
|
||||
),
|
||||
input_schema,
|
||||
Some(ToolAnnotations {
|
||||
title: Some(format!("create multiple sub recipe tasks for {}", sub_recipe.name)),
|
||||
read_only_hint: false,
|
||||
destructive_hint: true,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: true,
|
||||
}),
|
||||
)
|
||||
Arc::new(input_schema.as_object().unwrap().clone())
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some(format!(
|
||||
"create multiple sub recipe tasks for {}",
|
||||
sub_recipe.name
|
||||
)),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(true),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(true),
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_task_parameters(params: &Value) -> Vec<Value> {
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::providers::toolshim::{
|
||||
modify_system_prompt_for_tool_json, OllamaInterpreter,
|
||||
};
|
||||
use crate::session;
|
||||
use mcp_core::tool::Tool;
|
||||
use rmcp::model::Tool;
|
||||
|
||||
use super::super::agents::Agent;
|
||||
|
||||
@@ -110,11 +110,11 @@ impl Agent {
|
||||
.iter()
|
||||
.fold((HashSet::new(), HashSet::new()), |mut acc, tool| {
|
||||
match &tool.annotations {
|
||||
Some(annotations) if annotations.read_only_hint => {
|
||||
acc.0.insert(tool.name.clone());
|
||||
Some(annotations) if annotations.read_only_hint.unwrap_or(false) => {
|
||||
acc.0.insert(tool.name.to_string());
|
||||
}
|
||||
_ => {
|
||||
acc.1.insert(tool.name.clone());
|
||||
acc.1.insert(tool.name.to_string());
|
||||
}
|
||||
}
|
||||
acc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use mcp_core::tool::Tool;
|
||||
use mcp_core::ToolError;
|
||||
use rmcp::model::Content;
|
||||
use rmcp::model::Tool;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
@@ -128,7 +128,15 @@ impl RouterToolSelector for VectorToolSelector {
|
||||
.map(|tool| {
|
||||
let schema_str = serde_json::to_string_pretty(&tool.input_schema)
|
||||
.unwrap_or_else(|_| "{}".to_string());
|
||||
format!("{} {} {}", tool.name, tool.description, schema_str)
|
||||
format!(
|
||||
"{} {} {}",
|
||||
tool.name,
|
||||
tool.description
|
||||
.as_ref()
|
||||
.map(|d| d.as_ref())
|
||||
.unwrap_or_default(),
|
||||
schema_str
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -154,8 +162,12 @@ impl RouterToolSelector for VectorToolSelector {
|
||||
let schema_str = serde_json::to_string_pretty(&tool.input_schema)
|
||||
.unwrap_or_else(|_| "{}".to_string());
|
||||
crate::agents::tool_vectordb::ToolRecord {
|
||||
tool_name: tool.name.clone(),
|
||||
description: tool.description.clone(),
|
||||
tool_name: tool.name.to_string(),
|
||||
description: tool
|
||||
.description
|
||||
.as_ref()
|
||||
.map(|d| d.to_string())
|
||||
.unwrap_or_default(),
|
||||
schema: schema_str,
|
||||
vector,
|
||||
extension_name: extension_name.to_string(),
|
||||
@@ -305,7 +317,10 @@ impl RouterToolSelector for LLMToolSelector {
|
||||
let tool_string = format!(
|
||||
"Tool: {}\nDescription: {}\nSchema: {}",
|
||||
tool.name,
|
||||
tool.description,
|
||||
tool.description
|
||||
.as_ref()
|
||||
.map(|d| d.as_ref())
|
||||
.unwrap_or_default(),
|
||||
serde_json::to_string_pretty(&tool.input_schema)
|
||||
.unwrap_or_else(|_| "{}".to_string())
|
||||
);
|
||||
|
||||
@@ -3,8 +3,8 @@ use super::platform_tools::{
|
||||
PLATFORM_READ_RESOURCE_TOOL_NAME, PLATFORM_SEARCH_AVAILABLE_EXTENSIONS_TOOL_NAME,
|
||||
};
|
||||
use indoc::indoc;
|
||||
use mcp_core::tool::{Tool, ToolAnnotations};
|
||||
use serde_json::json;
|
||||
use rmcp::model::{Tool, ToolAnnotations};
|
||||
use rmcp::object;
|
||||
|
||||
pub const ROUTER_VECTOR_SEARCH_TOOL_NAME: &str = "router__vector_search";
|
||||
pub const ROUTER_LLM_SEARCH_TOOL_NAME: &str = "router__llm_search";
|
||||
@@ -24,7 +24,7 @@ pub fn vector_search_tool() -> Tool {
|
||||
Extension name is not optional, it is required.
|
||||
"#}
|
||||
.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": ["query", "extension_name"],
|
||||
"properties": {
|
||||
@@ -32,15 +32,14 @@ pub fn vector_search_tool() -> Tool {
|
||||
"k": {"type": "integer", "description": "The number of tools to retrieve (defaults to 5)", "default": 5},
|
||||
"extension_name": {"type": "string", "description": "Name of the extension to filter tools by"}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Vector search for relevant tools".to_string()),
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Vector search for relevant tools".to_string()),
|
||||
read_only_hint: Some(true),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn vector_search_tool_prompt() -> String {
|
||||
@@ -81,7 +80,7 @@ pub fn llm_search_tool() -> Tool {
|
||||
The returned result will be a list of tool names, descriptions, and schemas from which you, the agent can select the most relevant tool to invoke.
|
||||
"#}
|
||||
.to_string(),
|
||||
json!({
|
||||
object!({
|
||||
"type": "object",
|
||||
"required": ["query", "extension_name"],
|
||||
"properties": {
|
||||
@@ -89,15 +88,14 @@ pub fn llm_search_tool() -> Tool {
|
||||
"query": {"type": "string", "description": "The query to search for the most relevant tools based on the user's messages"},
|
||||
"k": {"type": "integer", "description": "The number of tools to retrieve (defaults to 5)", "default": 5}
|
||||
}
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("LLM search for relevant tools".to_string()),
|
||||
read_only_hint: true,
|
||||
destructive_hint: false,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: false,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("LLM search for relevant tools".to_string()),
|
||||
read_only_hint: Some(true),
|
||||
destructive_hint: Some(false),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(false),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn llm_search_tool_prompt() -> String {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use mcp_core::{Tool, ToolError};
|
||||
use mcp_core::ToolError;
|
||||
use rmcp::model::Content;
|
||||
use rmcp::model::Tool;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ use crate::{
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use chrono::{DateTime, Utc};
|
||||
use mcp_core::{handler::ToolError, tool::Tool};
|
||||
use mcp_core::handler::ToolError;
|
||||
use rmcp::model::Tool;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use serde_json::{self};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
@@ -336,10 +337,10 @@ impl SubAgent {
|
||||
let tools_with_descriptions: Vec<String> = available_tools
|
||||
.iter()
|
||||
.map(|t| {
|
||||
if t.description.is_empty() {
|
||||
t.name.clone()
|
||||
if let Some(description) = &t.description {
|
||||
format!("{}: {}", t.name, description)
|
||||
} else {
|
||||
format!("{}: {}", t.name, t.description)
|
||||
t.name.to_string()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use mcp_core::{tool::ToolAnnotations, Tool, ToolError};
|
||||
use rmcp::model::Content;
|
||||
use mcp_core::ToolError;
|
||||
use rmcp::model::{Content, Tool, ToolAnnotations};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::agents::subagent_task_config::TaskConfig;
|
||||
@@ -9,6 +9,7 @@ use crate::agents::{
|
||||
subagent_execution_tool::tasks_manager::TasksManager, tool_execution::ToolCallResult,
|
||||
};
|
||||
use rmcp::model::JsonRpcMessage;
|
||||
use rmcp::object;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
@@ -18,21 +19,21 @@ pub fn create_subagent_execute_task_tool() -> Tool {
|
||||
Tool::new(
|
||||
SUBAGENT_EXECUTE_TASK_TOOL_NAME,
|
||||
"Only use the subagent__execute_task tool when you execute sub recipe task or dynamic task.
|
||||
EXECUTION STRATEGY DECISION:
|
||||
1. If the tasks are created with execution_mode, use the execution_mode.
|
||||
2. Execute tasks sequentially unless user explicitly requests parallel execution. PARALLEL: User uses keywords like 'parallel', 'simultaneously', 'at the same time', 'concurrently'
|
||||
EXECUTION STRATEGY DECISION:
|
||||
1. If the tasks are created with execution_mode, use the execution_mode.
|
||||
2. Execute tasks sequentially unless user explicitly requests parallel execution. PARALLEL: User uses keywords like 'parallel', 'simultaneously', 'at the same time', 'concurrently'
|
||||
|
||||
IMPLEMENTATION:
|
||||
- Sequential execution: Call this tool multiple times, passing exactly ONE task per call
|
||||
- Parallel execution: Call this tool once, passing an ARRAY of all tasks
|
||||
IMPLEMENTATION:
|
||||
- Sequential execution: Call this tool multiple times, passing exactly ONE task per call
|
||||
- Parallel execution: Call this tool once, passing an ARRAY of all tasks
|
||||
|
||||
EXAMPLES:
|
||||
User Intent Based:
|
||||
- User: 'get weather and tell me a joke' → Sequential (2 separate tool calls, 1 task each)
|
||||
- User: 'get weather and joke in parallel' → Parallel (1 tool call with array of 2 tasks)
|
||||
- User: 'run these simultaneously' → Parallel (1 tool call with task array)
|
||||
- User: 'do task A then task B' → Sequential (2 separate tool calls)",
|
||||
serde_json::json!({
|
||||
EXAMPLES:
|
||||
User Intent Based:
|
||||
- User: 'get weather and tell me a joke' → Sequential (2 separate tool calls, 1 task each)
|
||||
- User: 'get weather and joke in parallel' → Parallel (1 tool call with array of 2 tasks)
|
||||
- User: 'run these simultaneously' → Parallel (1 tool call with task array)
|
||||
- User: 'do task A then task B' → Sequential (2 separate tool calls)",
|
||||
object!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"execution_mode": {
|
||||
@@ -50,15 +51,14 @@ User Intent Based:
|
||||
}
|
||||
},
|
||||
"required": ["task_ids"]
|
||||
}),
|
||||
Some(ToolAnnotations {
|
||||
title: Some("Run tasks in parallel".to_string()),
|
||||
read_only_hint: false,
|
||||
destructive_hint: true,
|
||||
idempotent_hint: false,
|
||||
open_world_hint: true,
|
||||
}),
|
||||
)
|
||||
})
|
||||
).annotate(ToolAnnotations {
|
||||
title: Some("Run tasks in parallel".to_string()),
|
||||
read_only_hint: Some(false),
|
||||
destructive_hint: Some(true),
|
||||
idempotent_hint: Some(false),
|
||||
open_world_hint: Some(true),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn run_tasks(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::session;
|
||||
use mcp_core::{Tool, ToolResult};
|
||||
use rmcp::model::Content;
|
||||
use mcp_core::ToolResult;
|
||||
use rmcp::model::{Content, Tool};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
Reference in New Issue
Block a user