Tool reply meta (#6074)
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -354,6 +354,8 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::routes::agent::start_agent,
|
||||
super::routes::agent::resume_agent,
|
||||
super::routes::agent::get_tools,
|
||||
super::routes::agent::read_resource,
|
||||
super::routes::agent::call_tool,
|
||||
super::routes::agent::update_from_session,
|
||||
super::routes::agent::agent_add_extension,
|
||||
super::routes::agent::agent_remove_extension,
|
||||
@@ -514,6 +516,10 @@ derive_utoipa!(Icon as IconSchema);
|
||||
goose::agents::types::SuccessCheck,
|
||||
super::routes::agent::UpdateProviderRequest,
|
||||
super::routes::agent::GetToolsQuery,
|
||||
super::routes::agent::ReadResourceRequest,
|
||||
super::routes::agent::ReadResourceResponse,
|
||||
super::routes::agent::CallToolRequest,
|
||||
super::routes::agent::CallToolResponse,
|
||||
super::routes::agent::UpdateRouterToolSelectorRequest,
|
||||
super::routes::agent::StartAgentRequest,
|
||||
super::routes::agent::ResumeAgentRequest,
|
||||
|
||||
@@ -25,12 +25,14 @@ use goose::{
|
||||
agents::{extension::ToolInfo, extension_manager::get_parameter_names},
|
||||
config::permission::PermissionLevel,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use rmcp::model::{CallToolRequestParam, Content};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{error, warn};
|
||||
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
@@ -90,6 +92,32 @@ pub struct RemoveExtensionRequest {
|
||||
session_id: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct ReadResourceRequest {
|
||||
session_id: String,
|
||||
extension_name: String,
|
||||
uri: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct ReadResourceResponse {
|
||||
html: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, utoipa::ToSchema)]
|
||||
pub struct CallToolRequest {
|
||||
session_id: String,
|
||||
name: String,
|
||||
arguments: Value,
|
||||
}
|
||||
|
||||
#[derive(Serialize, utoipa::ToSchema)]
|
||||
pub struct CallToolResponse {
|
||||
content: Vec<Content>,
|
||||
structured_content: Option<Value>,
|
||||
is_error: bool,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/agent/start",
|
||||
@@ -484,7 +512,7 @@ async fn update_router_tool_selector(
|
||||
.update_router_tool_selector(None, Some(true))
|
||||
.await
|
||||
.map_err(|e| {
|
||||
tracing::error!("Failed to update tool selection strategy: {}", e);
|
||||
error!("Failed to update tool selection strategy: {}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
})?;
|
||||
|
||||
@@ -564,11 +592,94 @@ async fn stop_agent(
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/agent/read_resource",
|
||||
request_body = ReadResourceRequest,
|
||||
responses(
|
||||
(status = 200, description = "Resource read successfully", body = ReadResourceResponse),
|
||||
(status = 401, description = "Unauthorized - invalid secret key"),
|
||||
(status = 424, description = "Agent not initialized"),
|
||||
(status = 404, description = "Resource not found"),
|
||||
(status = 500, description = "Internal server error")
|
||||
)
|
||||
)]
|
||||
async fn read_resource(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(payload): Json<ReadResourceRequest>,
|
||||
) -> Result<Json<ReadResourceResponse>, StatusCode> {
|
||||
let agent = state
|
||||
.get_agent_for_route(payload.session_id.clone())
|
||||
.await?;
|
||||
|
||||
let html = agent
|
||||
.extension_manager
|
||||
.read_ui_resource(
|
||||
&payload.uri,
|
||||
&payload.extension_name,
|
||||
CancellationToken::default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_e| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(ReadResourceResponse { html }))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/agent/call_tool",
|
||||
request_body = CallToolRequest,
|
||||
responses(
|
||||
(status = 200, description = "Resource read successfully", body = CallToolResponse),
|
||||
(status = 401, description = "Unauthorized - invalid secret key"),
|
||||
(status = 424, description = "Agent not initialized"),
|
||||
(status = 404, description = "Resource not found"),
|
||||
(status = 500, description = "Internal server error")
|
||||
)
|
||||
)]
|
||||
async fn call_tool(
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(payload): Json<CallToolRequest>,
|
||||
) -> Result<Json<CallToolResponse>, StatusCode> {
|
||||
let agent = state
|
||||
.get_agent_for_route(payload.session_id.clone())
|
||||
.await?;
|
||||
|
||||
let arguments = match payload.arguments {
|
||||
Value::Object(map) => Some(map),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: payload.name.into(),
|
||||
arguments,
|
||||
};
|
||||
|
||||
let tool_result = agent
|
||||
.extension_manager
|
||||
.dispatch_tool_call(tool_call, CancellationToken::default())
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
let result = tool_result
|
||||
.result
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(CallToolResponse {
|
||||
content: result.content,
|
||||
structured_content: result.structured_content,
|
||||
is_error: result.is_error.unwrap_or(false),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn routes(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route("/agent/start", post(start_agent))
|
||||
.route("/agent/resume", post(resume_agent))
|
||||
.route("/agent/tools", get(get_tools))
|
||||
.route("/agent/read_resource", post(read_resource))
|
||||
.route("/agent/call_tool", post(call_tool))
|
||||
.route("/agent/update_provider", post(update_agent_provider))
|
||||
.route(
|
||||
"/agent/update_router_tool_selector",
|
||||
|
||||
@@ -3,6 +3,7 @@ use axum::{
|
||||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use goose::config::ConfigError;
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
@@ -37,3 +38,9 @@ impl From<anyhow::Error> for ErrorResponse {
|
||||
Self::internal(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigError> for ErrorResponse {
|
||||
fn from(err: ConfigError) -> Self {
|
||||
Self::internal(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user