2026-09-23 20:00:47 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 协议 v1 的 HTTP 表面(JSON Schema 为准,这里是 TS 镜像)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 服务端与客户端之间只认这一套接口;引擎协议(Pi 的 JSONL、Codex 的 app-server)不越过适配层。
|
|
|
|
|
|
* 端点与规则见 docs/spec/protocol.md。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** 路径前缀:协议改版就换前缀,不原地改语义 */
|
|
|
|
|
|
export const PROTOCOL_PREFIX = '/v1' as const;
|
|
|
|
|
|
|
|
|
|
|
|
export const ENDPOINTS = {
|
|
|
|
|
|
health: '/v1/health',
|
|
|
|
|
|
me: '/v1/me',
|
|
|
|
|
|
projects: '/v1/projects',
|
|
|
|
|
|
sessions: '/v1/sessions',
|
|
|
|
|
|
session: (sessionId: string) => `/v1/sessions/${sessionId}`,
|
|
|
|
|
|
/** SSE:回放 + 实时事件流 */
|
|
|
|
|
|
sessionEvents: (sessionId: string) => `/v1/sessions/${sessionId}/events`,
|
|
|
|
|
|
sessionMessages: (sessionId: string) => `/v1/sessions/${sessionId}/messages`,
|
|
|
|
|
|
sessionCancel: (sessionId: string) => `/v1/sessions/${sessionId}/cancel`,
|
|
|
|
|
|
capabilities: '/v1/capabilities',
|
|
|
|
|
|
execution: (executionId: string) => `/v1/executions/${executionId}`,
|
|
|
|
|
|
approval: (approvalId: string) => `/v1/approvals/${approvalId}`,
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
2026-09-23 20:52:24 +08:00
|
|
|
|
/** 端点规格:给实现与文档比对用的机器可读表(方法、路径、请求体、响应体) */
|
|
|
|
|
|
export interface EndpointSpec {
|
|
|
|
|
|
method: 'GET' | 'POST';
|
|
|
|
|
|
/** 路径;路径参数用 {name} 占位 */
|
|
|
|
|
|
path: string;
|
|
|
|
|
|
/** 请求体类型名;没有请求体写 '—' */
|
|
|
|
|
|
request: string;
|
|
|
|
|
|
/** 响应体类型名;事件流写 'SSE' */
|
|
|
|
|
|
response: string;
|
|
|
|
|
|
summary: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const ENDPOINT_SPECS: readonly EndpointSpec[] = [
|
|
|
|
|
|
{ method: 'GET', path: '/v1/health', request: '—', response: 'HealthResponse', summary: '健康检查' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/me', request: '—', response: 'MeResponse', summary: '当前身份与客户端形态' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/projects', request: '—', response: 'ProjectListResponse', summary: '可见项目' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/sessions', request: '—', response: 'SessionListResponse', summary: '会话列表' },
|
|
|
|
|
|
{ method: 'POST', path: '/v1/sessions', request: 'CreateSessionRequest', response: 'CreateSessionResponse', summary: '建会话' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/sessions/{id}', request: '—', response: 'SessionDetailResponse', summary: '会话详情与最近消息' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/sessions/{id}/events', request: '—', response: 'SSE', summary: '回放 + 实时事件流' },
|
|
|
|
|
|
{ method: 'POST', path: '/v1/sessions/{id}/messages', request: 'SendMessageRequest', response: 'SendMessageResponse', summary: '发消息' },
|
|
|
|
|
|
{ method: 'POST', path: '/v1/sessions/{id}/cancel', request: '—', response: 'CancelResponse', summary: '取消当前运行' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/capabilities', request: '—', response: 'CapabilitiesResponse', summary: '按身份过滤的能力清单' },
|
|
|
|
|
|
{ method: 'GET', path: '/v1/executions/{executionId}', request: '—', response: 'ExecutionReceipt', summary: '执行状态与回执' },
|
|
|
|
|
|
{ method: 'POST', path: '/v1/approvals/{approvalId}', request: 'ApprovalDecisionRequest', response: 'ApprovalDecisionResponse', summary: '确认卡响应' },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
2026-09-23 20:00:47 +08:00
|
|
|
|
/** 能力标识,形如 `aps.schedule.preview` */
|
|
|
|
|
|
export type CapabilityId = string;
|
|
|
|
|
|
|
|
|
|
|
|
export interface HealthResponse {
|
|
|
|
|
|
status: 'ok';
|
|
|
|
|
|
version: string;
|
|
|
|
|
|
protocolVersion: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface MeResponse {
|
|
|
|
|
|
userId: string;
|
|
|
|
|
|
tenantId: string;
|
|
|
|
|
|
displayName: string;
|
|
|
|
|
|
/** 桌面端与浏览器共用同一身份模型,登录方式不同(见协议文档第 2 节) */
|
|
|
|
|
|
clientKind: 'desktop' | 'browser';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 能力条目:按身份过滤后返回;描述七要素见 docs/spec/capability-description.md */
|
|
|
|
|
|
export interface CapabilitySummary {
|
|
|
|
|
|
id: CapabilityId;
|
|
|
|
|
|
providerId: string;
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
purpose: string;
|
|
|
|
|
|
effect: 'read' | 'draft' | 'write';
|
|
|
|
|
|
inputSchema?: Record<string, unknown>;
|
|
|
|
|
|
synonyms?: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CapabilitiesResponse {
|
|
|
|
|
|
capabilities: CapabilitySummary[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 会话概要(ADR-0003:个人会话只读,写操作必须在项目会话内) */
|
|
|
|
|
|
export interface SessionSummary {
|
|
|
|
|
|
sessionId: string;
|
|
|
|
|
|
projectId: string | null;
|
|
|
|
|
|
scope: 'personal' | 'project';
|
|
|
|
|
|
status: 'active' | 'archived';
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
createdAt: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-23 20:00:59 +08:00
|
|
|
|
export interface ProjectSummary {
|
|
|
|
|
|
projectId: string;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
status: 'active' | 'archived';
|
|
|
|
|
|
/** 项目内可写;个人会话只读(ADR-0003) */
|
|
|
|
|
|
writable: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ProjectListResponse {
|
|
|
|
|
|
projects: ProjectSummary[];
|
|
|
|
|
|
}
|
2026-09-23 20:00:47 +08:00
|
|
|
|
export interface CreateSessionRequest {
|
|
|
|
|
|
projectId?: string;
|
|
|
|
|
|
scope: 'personal' | 'project';
|
|
|
|
|
|
title?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CreateSessionResponse {
|
|
|
|
|
|
session: SessionSummary;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface SessionListResponse {
|
|
|
|
|
|
sessions: SessionSummary[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface SessionDetailResponse {
|
|
|
|
|
|
session: SessionSummary;
|
|
|
|
|
|
/** 最近一段消息;完整历史走事件流回放 */
|
|
|
|
|
|
messages: ChatMessage[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ChatMessage {
|
|
|
|
|
|
messageId: string;
|
|
|
|
|
|
role: 'user' | 'assistant' | 'system';
|
|
|
|
|
|
ts: number;
|
|
|
|
|
|
text: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface SendMessageRequest {
|
|
|
|
|
|
text: string;
|
|
|
|
|
|
/** 同一写请求重试不重复生效 */
|
|
|
|
|
|
idempotencyKey: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface SendMessageResponse {
|
|
|
|
|
|
accepted: true;
|
|
|
|
|
|
messageId: string;
|
|
|
|
|
|
runId: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CancelResponse {
|
|
|
|
|
|
state: 'cancelling' | 'idle';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 能力调用的统一回执(架构设计 4.2) */
|
|
|
|
|
|
export interface ExecutionReceipt {
|
|
|
|
|
|
executionId: string;
|
|
|
|
|
|
status: 'accepted' | 'pending-confirmation' | 'succeeded' | 'failed';
|
|
|
|
|
|
result?: unknown;
|
|
|
|
|
|
errorKind?: string;
|
|
|
|
|
|
/** status = pending-confirmation 时给出待确认动作标识 */
|
|
|
|
|
|
approvalId?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ApprovalDecisionRequest {
|
|
|
|
|
|
decision: 'approve' | 'reject';
|
|
|
|
|
|
/** 目标数据版本;版本变了确认就失效 */
|
|
|
|
|
|
revision: number;
|
|
|
|
|
|
idempotencyKey: string;
|
|
|
|
|
|
note?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ApprovalDecisionResponse {
|
|
|
|
|
|
approvalId: string;
|
|
|
|
|
|
decision: 'approved' | 'rejected' | 'expired';
|
|
|
|
|
|
receipt?: ExecutionReceipt;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ErrorEnvelope {
|
|
|
|
|
|
error: {
|
|
|
|
|
|
code: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
retryable: boolean;
|
|
|
|
|
|
detail?: unknown;
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|