huskies: merge 769
This commit is contained in:
@@ -73,6 +73,39 @@ async function gatewayRequest<T>(
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
|
||||
let _mcpRequestId = 1;
|
||||
|
||||
/// Call a gateway MCP tool via JSON-RPC and return the result.
|
||||
async function gatewayMcpCall<T>(
|
||||
toolName: string,
|
||||
args: Record<string, unknown> = {},
|
||||
): Promise<T> {
|
||||
const id = _mcpRequestId++;
|
||||
const body = JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id,
|
||||
method: "tools/call",
|
||||
params: { name: toolName, arguments: args },
|
||||
});
|
||||
const res = await fetch("/mcp", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body,
|
||||
});
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(text || `MCP request failed (${res.status})`);
|
||||
}
|
||||
const json = (await res.json()) as {
|
||||
result?: Record<string, unknown>;
|
||||
error?: { message: string };
|
||||
};
|
||||
if (json.error) {
|
||||
throw new Error(json.error.message);
|
||||
}
|
||||
return json.result as T;
|
||||
}
|
||||
|
||||
export const gatewayApi = {
|
||||
/// Returns `{ mode: "gateway" }` if this server is a gateway, otherwise rejects.
|
||||
getServerMode(): Promise<ServerMode> {
|
||||
@@ -88,7 +121,9 @@ export const gatewayApi = {
|
||||
|
||||
/// List all build agents that have registered with this gateway.
|
||||
listAgents(): Promise<JoinedAgent[]> {
|
||||
return gatewayRequest<JoinedAgent[]>("/gateway/agents");
|
||||
return gatewayMcpCall<{ agents: JoinedAgent[] }>("agents.list").then(
|
||||
(result) => result.agents ?? [],
|
||||
);
|
||||
},
|
||||
|
||||
/// Remove a registered build agent by its ID.
|
||||
|
||||
@@ -55,7 +55,6 @@ pub fn build_gateway_route(state_arc: Arc<GatewayState>) -> impl poem::Endpoint
|
||||
// Agent registration via CRDT-sync WebSocket.
|
||||
.at("/crdt-sync", poem::get(gateway_crdt_sync_handler))
|
||||
// Agent management REST endpoints.
|
||||
.at("/gateway/agents", poem::get(gateway_list_agents_handler))
|
||||
.at(
|
||||
"/gateway/agents/:id/assign",
|
||||
poem::post(gateway_assign_agent_handler),
|
||||
|
||||
@@ -19,6 +19,7 @@ const GATEWAY_TOOLS: &[&str] = &[
|
||||
"gateway_health",
|
||||
"init_project",
|
||||
"aggregate_pipeline_status",
|
||||
"agents.list",
|
||||
];
|
||||
|
||||
/// Gateway tool definitions.
|
||||
@@ -84,6 +85,14 @@ pub(crate) fn gateway_tool_definitions() -> Vec<Value> {
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "agents.list",
|
||||
"description": "List all alive build agents currently registered with this gateway. Returns an array of agent objects with id, label, address, registered_at, last_seen, and assigned_project fields.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -245,6 +254,7 @@ async fn handle_gateway_tool(
|
||||
"gateway_health" => handle_gateway_health_tool(state, id).await,
|
||||
"init_project" => handle_init_project_tool(params, state, id).await,
|
||||
"aggregate_pipeline_status" => handle_aggregate_pipeline_status_tool(state, id).await,
|
||||
"agents.list" => handle_agents_list_tool(id),
|
||||
_ => JsonRpcResponse::error(id, -32601, format!("Unknown gateway tool: {tool_name}")),
|
||||
}
|
||||
}
|
||||
@@ -426,6 +436,22 @@ async fn handle_aggregate_pipeline_status_tool(
|
||||
)
|
||||
}
|
||||
|
||||
/// Handle the `agents.list` gateway tool — returns all alive build agents from the CRDT.
|
||||
fn handle_agents_list_tool(id: Option<Value>) -> JsonRpcResponse {
|
||||
let agents = gateway::list_agents();
|
||||
let agents_json = serde_json::to_value(&agents).unwrap_or(json!([]));
|
||||
JsonRpcResponse::success(
|
||||
id,
|
||||
json!({
|
||||
"content": [{
|
||||
"type": "text",
|
||||
"text": serde_json::to_string_pretty(&agents).unwrap_or_default()
|
||||
}],
|
||||
"agents": agents_json,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Handle the `pipeline.get` read-RPC — returns the same shape as the old
|
||||
/// `GET /api/gateway/pipeline` endpoint: `{ "active": "...", "projects": {...} }`.
|
||||
async fn handle_pipeline_get(state: &GatewayState, id: Option<Value>) -> JsonRpcResponse {
|
||||
|
||||
@@ -18,7 +18,7 @@ pub use mcp::{gateway_mcp_get_handler, gateway_mcp_post_handler};
|
||||
pub use rest::{
|
||||
gateway_add_project_handler, gateway_api_handler, gateway_assign_agent_handler,
|
||||
gateway_bot_config_get_handler, gateway_bot_config_page_handler,
|
||||
gateway_bot_config_save_handler, gateway_generate_token_handler, gateway_list_agents_handler,
|
||||
gateway_mode_handler, gateway_remove_project_handler,
|
||||
gateway_bot_config_save_handler, gateway_generate_token_handler, gateway_mode_handler,
|
||||
gateway_remove_project_handler,
|
||||
};
|
||||
pub use websocket::{gateway_crdt_sync_handler, gateway_event_push_handler};
|
||||
|
||||
@@ -33,17 +33,6 @@ pub async fn gateway_generate_token_handler(state: Data<&Arc<GatewayState>>) ->
|
||||
.body(Body::from(serde_json::to_vec(&body).unwrap_or_default()))
|
||||
}
|
||||
|
||||
/// `GET /gateway/agents` — list all alive build agents registered in the CRDT.
|
||||
#[handler]
|
||||
pub async fn gateway_list_agents_handler(_state: Data<&Arc<GatewayState>>) -> Response {
|
||||
let agents = gateway::list_agents();
|
||||
let body = serde_json::to_vec(&agents).unwrap_or_default();
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(Body::from(body))
|
||||
}
|
||||
|
||||
/// Request body for assigning an agent to a project.
|
||||
#[derive(Deserialize)]
|
||||
struct AssignAgentRequest {
|
||||
|
||||
Reference in New Issue
Block a user