huskies: merge 855

This commit is contained in:
dave
2026-04-29 21:35:55 +00:00
parent a7b1572693
commit 4d24b5b661
17 changed files with 204 additions and 973 deletions
+42 -31
View File
@@ -1,26 +1,25 @@
//! `tools/call` MCP method — dispatches a tool name to the appropriate `*_tools` module.
use serde_json::{Value, json};
use serde_json::Value;
use super::JsonRpcResponse;
use super::{
agent_tools, diagnostics, git_tools, merge_tools, qa_tools, shell_tools, status_tools,
story_tools, wizard_tools,
};
use crate::http::context::AppContext;
use crate::slog_warn;
// ── Tool dispatch ─────────────────────────────────────────────────
pub(super) async fn handle_tools_call(
id: Option<Value>,
params: &Value,
/// Execute an MCP tool by name, returning the text result or an error string.
///
/// This is the shared dispatch entry point used by both the WebSocket
/// rendezvous channel and API-based agent runtimes (Gemini, OpenAI).
pub async fn dispatch_tool_call(
tool_name: &str,
args: Value,
ctx: &AppContext,
) -> JsonRpcResponse {
let tool_name = params.get("name").and_then(|v| v.as_str()).unwrap_or("");
let args = params.get("arguments").cloned().unwrap_or(json!({}));
let result = match tool_name {
) -> Result<String, String> {
match tool_name {
// Workflow tools
"create_story" => story_tools::tool_create_story(&args, ctx),
"validate_stories" => story_tools::tool_validate_stories(ctx),
@@ -120,31 +119,43 @@ pub(super) async fn handle_tools_call(
"wizard_skip" => wizard_tools::tool_wizard_skip(ctx),
"wizard_retry" => wizard_tools::tool_wizard_retry(ctx),
_ => Err(format!("Unknown tool: {tool_name}")),
};
match result {
Ok(content) => JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": content }]
}),
),
Err(msg) => {
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": msg }],
"isError": true
}),
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::http::gateway::jsonrpc::JsonRpcResponse;
use crate::slog_warn;
use serde_json::json;
/// Test helper: invoke a `tools/call` JSON-RPC request and return the response.
pub(in crate::http::mcp) async fn handle_tools_call(
id: Option<serde_json::Value>,
params: &serde_json::Value,
ctx: &crate::http::context::AppContext,
) -> JsonRpcResponse {
let tool_name = params.get("name").and_then(|v| v.as_str()).unwrap_or("");
let args = params.get("arguments").cloned().unwrap_or(json!({}));
match super::dispatch_tool_call(tool_name, args, ctx).await {
Ok(content) => JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": content }]
}),
),
Err(msg) => {
slog_warn!("[mcp] Tool call failed: tool={tool_name} error={msg}");
JsonRpcResponse::success(
id,
json!({
"content": [{ "type": "text", "text": msg }],
"isError": true
}),
)
}
}
}
use crate::http::test_helpers::test_ctx;
#[test]