272 lines
9.6 KiB
TypeScript
272 lines
9.6 KiB
TypeScript
/**
|
||
* 协议 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}`,
|
||
/** 执行追溯(A4.5):按 executionId 追到人、参数、审批与回执 */
|
||
executionTrace: (executionId: string) => `/v1/executions/${executionId}/trace`,
|
||
approval: (approvalId: string) => `/v1/approvals/${approvalId}`,
|
||
bindings: '/v1/bindings',
|
||
bindingStart: (providerId: string) => `/v1/bindings/${providerId}/start`,
|
||
bindingComplete: (providerId: string) => `/v1/bindings/${providerId}/complete`,
|
||
binding: (providerId: string) => `/v1/bindings/${providerId}`,
|
||
} as const;
|
||
|
||
/** 端点规格:给实现与文档比对用的机器可读表(方法、路径、请求体、响应体) */
|
||
export interface EndpointSpec {
|
||
method: 'GET' | 'POST' | 'DELETE';
|
||
/** 路径;路径参数用 {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: 'GET', path: '/v1/executions/{executionId}/trace', request: '—', response: 'ExecutionTraceResponse', summary: '执行追溯:人、参数、审批与回执' },
|
||
{ method: 'POST', path: '/v1/approvals/{approvalId}', request: 'ApprovalDecisionRequest', response: 'ApprovalDecisionResponse', summary: '确认卡响应' },
|
||
{ method: 'GET', path: '/v1/bindings', request: '—', response: 'BindingListResponse', summary: '我绑定的业务系统账号与登录态' },
|
||
{ method: 'POST', path: '/v1/bindings/{providerId}/start', request: '—', response: 'BindingStartResponse', summary: '发起账号绑定(按 Provider 声明的登录方式)' },
|
||
{ method: 'POST', path: '/v1/bindings/{providerId}/complete', request: 'BindingCompleteRequest', response: 'BindingCompleteResponse', summary: '完成绑定:换取凭据并加密保存' },
|
||
{ method: 'DELETE', path: '/v1/bindings/{providerId}', request: '—', response: 'BindingDeleteResponse', summary: '解绑并删除凭据' },
|
||
];
|
||
|
||
/** 能力标识,形如 `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;
|
||
}
|
||
|
||
export interface ProjectSummary {
|
||
projectId: string;
|
||
name: string;
|
||
status: 'active' | 'archived';
|
||
/** 项目内可写;个人会话只读(ADR-0003) */
|
||
writable: boolean;
|
||
}
|
||
|
||
export interface ProjectListResponse {
|
||
projects: ProjectSummary[];
|
||
}
|
||
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;
|
||
}
|
||
|
||
/** 审计链上的一条记录(A4.5):只追加,改一条就断链 */
|
||
export interface ExecutionTraceEntry {
|
||
seq: number;
|
||
ts: number;
|
||
/** 事件类型:策略拒绝、确认、开始执行、结束执行、业务系统拒绝 */
|
||
event: string;
|
||
/** 谁发起或谁决定的 */
|
||
actorUserId: string;
|
||
capabilityId?: string;
|
||
providerId?: string;
|
||
/** 参数摘要,不是参数明文 */
|
||
paramsDigest?: string;
|
||
decision?: string;
|
||
detail?: Record<string, unknown>;
|
||
}
|
||
|
||
/** 确认卡的持久记录(A4.4):重启后仍在,按 executionId 可追 */
|
||
export interface ExecutionApprovalRecord {
|
||
approvalId: string;
|
||
status: string;
|
||
decision?: 'approved' | 'rejected' | 'expired';
|
||
decidedBy?: string;
|
||
decidedAt?: number;
|
||
/** 目标数据版本;版本变了确认就失效 */
|
||
revision: number;
|
||
expiresAt: number;
|
||
}
|
||
|
||
/** 一次执行的追溯视图(A4.5):审计链 + 确认记录 + 回执,一个端点看全 */
|
||
export interface ExecutionTraceResponse {
|
||
executionId: string;
|
||
/** 没有走过确认卡的执行这里是 null */
|
||
approval: ExecutionApprovalRecord | null;
|
||
entries: ExecutionTraceEntry[];
|
||
/** 审计链校验结果:false 表示有记录被改过 */
|
||
chainOk: boolean;
|
||
receipt?: ExecutionReceipt;
|
||
}
|
||
|
||
export interface ApprovalDecisionRequest {
|
||
decision: 'approve' | 'reject';
|
||
/** 目标数据版本;版本变了确认就失效 */
|
||
revision: number;
|
||
idempotencyKey: string;
|
||
note?: string;
|
||
}
|
||
|
||
export interface ApprovalDecisionResponse {
|
||
approvalId: string;
|
||
decision: 'approved' | 'rejected' | 'expired';
|
||
receipt?: ExecutionReceipt;
|
||
}
|
||
|
||
/** 绑定状态:unbound 表示这个系统还没绑(列表里会出现,界面提示去绑) */
|
||
export interface BindingSummary {
|
||
providerId: string;
|
||
accountId: string | null;
|
||
displayName: string | null;
|
||
status: 'active' | 'expired' | 'disabled' | 'unbound';
|
||
/** Provider 声明的登录方式(ADR-0012) */
|
||
authKind?: 'oauth' | 'password-exchange' | 'apikey';
|
||
updatedAt?: number;
|
||
}
|
||
|
||
/** 发起绑定:oauth 会带 authorizationUrl 让客户端跳转;密码类直接进 complete */
|
||
export interface BindingStartResponse {
|
||
providerId: string;
|
||
authKind: 'oauth' | 'password-exchange' | 'apikey';
|
||
authorizationUrl?: string;
|
||
}
|
||
|
||
/**
|
||
* 完成绑定。password 只在这一条请求里出现一次,服务端不落盘、不写日志;
|
||
* oauth 则用 code + state。
|
||
*/
|
||
export interface BindingCompleteRequest {
|
||
accountId: string;
|
||
password?: string;
|
||
code?: string;
|
||
state?: string;
|
||
}
|
||
|
||
export interface BindingCompleteResponse {
|
||
binding: BindingSummary;
|
||
}
|
||
|
||
export interface BindingListResponse {
|
||
bindings: BindingSummary[];
|
||
}
|
||
|
||
export interface BindingDeleteResponse {
|
||
providerId: string;
|
||
removed: boolean;
|
||
}
|
||
|
||
export interface ErrorEnvelope {
|
||
error: {
|
||
code: string;
|
||
message: string;
|
||
retryable: boolean;
|
||
detail?: unknown;
|
||
};
|
||
} |