/** * 导入工具的通用实现 —— 「实现对系统」的兜底一件(编码规范 §3;语义出处 OS 7.3)。 * * 第一方工具各有各的处理器;**导入进来的自定义工具**没有处理器, * 但它在契约里申报了 `endpoint` 连接键 —— 这个处理器就把入参 POST 到那个端点。 * * 运行时受限照旧:只拿得到申报的连接目标,没有别的环境能力。 * 端点不通 = 试运行审不过 = 进不了目录 —— 这是**门**,不是障碍: * 一件调不通的工具入了目录,活动调它时才失败,那才是真的坏。 */ import type { ToolHandler } from '@modules/toolbox'; /** 未在第一方注册的工具:申报了 endpoint 就按 HTTP 调,没申报就如实说没有实现 */ export const httpToolHandler: ToolHandler = async ({ input, connection, operation, idempotencyKey }) => { const endpoint = connection['endpoint']; if (endpoint === undefined || endpoint.trim() === '') { return { ok: false, error: { code: 'tool-unimplemented', retryable: false, message: '工具无实现:未申报 endpoint 连接键,系统侧也没有第一方处理器', }, }; } if (!/^https?:\/\//.test(endpoint)) { return { ok: false, error: { code: 'endpoint-invalid', retryable: false, message: `端点须是 http(s) 地址:${endpoint}` }, }; } try { const response = await fetch(endpoint, { method: 'POST', headers: { 'content-type': 'application/json', // 幂等键透传给对端:写类动作重投时由对端去重(契约声明 idempotent 才有意义) ...(idempotencyKey === undefined ? {} : { 'idempotency-key': idempotencyKey }), }, body: JSON.stringify({ input, ...(operation === undefined ? {} : { operation }) }), }); if (!response.ok) { return { ok: false, error: { code: `http-${response.status}`, // 5xx 可重试,4xx 是我们自己请求得不对,重试没用 retryable: response.status >= 500, message: `端点返回 ${response.status}`, }, }; } const body: unknown = await response.json(); if (typeof body !== 'object' || body === null || Array.isArray(body)) { return { ok: false, error: { code: 'output-invalid', retryable: false, message: '端点返回的不是 JSON 对象' } }; } return { ok: true, output: body as Record }; } catch (error) { return { ok: false, error: { code: 'endpoint-unreachable', retryable: true, message: `端点调用失败:${error instanceof Error ? error.message : String(error)}`, }, }; } };