import type { IncomingMessage, ServerResponse } from "node:http"; import { type A2ATaskState } from "@sema-agent/core"; import type { A2aServeConfig } from "../../config-types.js"; import { type RunRecord } from "../../plugins/store-contracts.js"; import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js"; /** 本实现说的 A2A 协议版本 —— 卡的 `protocolVersion` 与每条 RPC 响应的 `a2a-version` 头同源(单点)。 */ export declare const A2A_PROTOCOL_VERSION = "1.0"; /** 版本头名。**读**请求侧的它只是诊断材料(开集容忍:认识与否都照常答),**写**响应侧的它是我们自报 * 家门 —— 设计稿 §4-1 版本槽。 */ export declare const A2A_VERSION_HEADER = "a2a-version"; /** 卡上的一条 skill —— **投影**,不是配置形。`scenario` 在这里结构性地不存在(不是「记得别加」,是 * 这个类型里没有那个键):自动枚举内部场景名给公网是设计稿 §3.1 唯一点名禁止的事。 */ interface A2aCardSkill { id: string; name: string; description?: string; } /** A2A AgentCard 的 server 铸面。**具名字段 + 允许未来 additive**(设计稿 §4-5 数据形扩展槽)。 */ interface A2aAgentCard { name: string; description?: string; protocolVersion: string; url: string; preferredTransport: "JSONRPC"; skills: A2aCardSkill[]; } /** 配置 → 卡(纯投影,零 I/O、零存量读)。`build*`:返回纯数据。 */ export declare function buildAgentCard(serve: A2aServeConfig): A2aAgentCard; /** * 域入口①:公开发现面。**位置即契约** —— 必须挂在 `server.ts` 的全局 service-credential 门**之前** * (R-11「公网匿名可发现」;挂在门后等于要凭据才能发现,协商第一步就断)。 * * 命名:本模块有**两个**域入口(卡在凭据门外、RPC 在门内),而 `route-shape-roster` 层E 的判据是 * 「域名词干 ⊆ 某个 capability 位名」。两个名字都取成 `capabilities.a2aServe` 的**子串** * (`a2aServe` / `a2a`),于是两条都被那道门如实认出来 —— 而不是去放宽那道门的判据。 */ export declare function handleA2aServe(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; /** * 🔴 **反枚举不变式([ref])在本模块的执行点**:`tasks/get` 的「这条 task 不存在」与「这条 task 不是 * 你的」必须**逐字节**同形 —— 同一个 code、同一条 message、同一个(缺席的)data。两臂共用**这一个** * 常量就是那条不变式的机制支撑:任何一臂想说得更具体,都得先改这里,而改这里会被 * `a2a-serve-rpc.test.ts` 的逐字节比对当场钉住。 * * (同族先例:`route-ctx.ts` 的 `RUN_NOT_FOUND_MESSAGE` —— [ref] 抓到的正是两臂**文案长度**不同就足以 * 枚举他人 run id 的存在性。JSON-RPC 侧一模一样,只是载体从 HTTP body 换成了 error 对象。) */ export declare const A2A_TASK_NOT_FOUND_MESSAGE = "task not found"; /** * run 行 → A2A 任务态。词表槽(设计稿 §4-2):我们是铸点,只发 core `A2A_TASK_STATES` 九词闭集。 * * 判据分工:park 与否问**属主谓词**;其余按 {@link A2A_STATE_BY_RUN_STATUS} 投影(那张表的 * `satisfies` 是词表增删两向的编译期执行点)。 * * park → `input-required` 的语义:协议的「等调用方给点什么」在本引擎被**收窄**成「等一个审批决议」, * 而那个决议走的是持久审批口、不是一条回信 —— 与 core 对自己 `parked` 行的裁词同源。A2A 调用方因此 * **不能**靠再发一条 message 解开它(附录 C.3 的表里成文写着这句)。 */ export declare function a2aStateForRun(run: Pick, stale: boolean): A2ATaskState; /** * 域入口②:JSON-RPC 端点。**位置即契约** —— 挂在全局 service-credential 门**之后**(R-11「持服务凭据 * 才可调」),且在 drain / model-roster-pending 两道 503 门之后(`/v1/a2a` 进 `isBillableSubmitPath`: * `message/send` 会烧模型)。 * * ⚠️ 代价成文:端点是**单 URL** 的(卡上只能公告一个 `url`),所以排空期 `tasks/get` 也一并 503。 * 方向取「宁紧」—— 让一台正在下线的副本开新模型工作,正是那几道门存在的全部理由;而读面的补偿是 * 现成的:行是 durable 的,调用方按 A2A 的传输层重试语义换一台副本读同一条行即可。 * * 命名(`handleA2a`,与 `handleA2aServe` 同族):见域入口①的命名注 —— 两个名字都取成 * `capabilities.a2aServe` 的子串,好让 `route-shape-roster` 层E 如实认出它们。 */ export declare function handleA2a(req: IncomingMessage, res: ServerResponse, match: RouteMatch, ctx: RouteCtx): Promise; /** 九词闭集的对外可见锚(测试用它证明我们只发闭集词;也让「加一个自造词」在这里就被看见)。 */ export declare const A2A_SERVE_TASK_STATES: readonly A2ATaskState[]; export declare const A2A_SERVE_ROUTES: readonly [{ readonly id: "a2a-agent-card"; readonly path: "/.well-known/agent-card.json"; readonly methods: readonly ["GET"]; }]; /** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽(漏一口 = 编译红)。 */ export type A2aServeRouteId = RouteIdsOf; export declare const A2A_RPC_ROUTES: readonly [{ readonly id: "a2a-rpc"; readonly path: "/v1/a2a"; readonly billable: true; readonly methodDispatched: true; readonly methods: readonly ["POST"]; }]; export type A2aRpcRouteId = RouteIdsOf; export {}; //# sourceMappingURL=a2a-serve.d.ts.map