2026-09-23 19:29:57 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Provider 契约(架构设计第 6 节):业务系统接入平台的唯一形状。
|
|
|
|
|
|
*
|
2026-09-24 15:48:45 +08:00
|
|
|
|
* Provider 是能力适配器,不是业务系统,也不承载模型上下文。三个方法:
|
|
|
|
|
|
* describe() 声明自己有哪些能力
|
|
|
|
|
|
* invoke() 执行一次能力调用
|
|
|
|
|
|
* health() 健康状态
|
|
|
|
|
|
* 能力怎么描述见 docs/spec/capability-description.md,错误分类见 ./errors.js。
|
2026-09-23 19:29:57 +08:00
|
|
|
|
*/
|
2026-09-24 15:48:45 +08:00
|
|
|
|
import type { ExecutionReceipt } from '@aps/contracts';
|
|
|
|
|
|
|
|
|
|
|
|
import type { ErrorKind } from './errors.js';
|
|
|
|
|
|
|
|
|
|
|
|
export type { ErrorKind } from './errors.js';
|
|
|
|
|
|
export { ERROR_KINDS, isErrorKind, ProviderError } from './errors.js';
|
|
|
|
|
|
|
|
|
|
|
|
/** 能力声明(架构设计 6):read 不改状态;draft 只写隔离草稿;write 必须绑定唯一目标与幂等键 */
|
|
|
|
|
|
export interface Capability {
|
|
|
|
|
|
/** 形如 aps.schedule.preview */
|
|
|
|
|
|
id: string;
|
|
|
|
|
|
/** 界面标题(可省,缺省用 description) */
|
|
|
|
|
|
title?: string;
|
|
|
|
|
|
/** 给模型看的一句话用途(40 字以内) */
|
|
|
|
|
|
description: string;
|
|
|
|
|
|
effect: 'read' | 'draft' | 'write';
|
|
|
|
|
|
mode: 'sync' | 'async';
|
|
|
|
|
|
/** 何时不用:同族能力的边界写在这里 */
|
|
|
|
|
|
whenNotToUse?: string;
|
|
|
|
|
|
/** 业务黑话与同义词 */
|
|
|
|
|
|
synonyms?: string[];
|
|
|
|
|
|
inputSchema: Record<string, unknown>;
|
|
|
|
|
|
outputSchema: Record<string, unknown>;
|
|
|
|
|
|
idempotency: 'none' | 'key' | 'natural';
|
|
|
|
|
|
/** 这个能力可能返回的错误分类 */
|
|
|
|
|
|
errors: ErrorKind[];
|
|
|
|
|
|
}
|
2026-09-23 19:29:57 +08:00
|
|
|
|
|
|
|
|
|
|
export interface ProviderManifest {
|
|
|
|
|
|
id: string;
|
2026-09-24 15:48:45 +08:00
|
|
|
|
displayName: string;
|
|
|
|
|
|
version: string;
|
|
|
|
|
|
/** 兼容的平台协议版本(当前 1) */
|
|
|
|
|
|
platformVersion: number;
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 调用这个系统要不要平台用户先绑定本系统账号(A4.1)。
|
|
|
|
|
|
* 缺省 true:真实系统默认要绑定;只有无账号概念的自建/联调 Provider 才写 false。
|
|
|
|
|
|
*/
|
|
|
|
|
|
requiresIdentity?: boolean;
|
2026-09-30 14:26:35 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 登录方式声明(ADR-0012):平台按它走同一条绑定流程,不自己实现业务系统的登录页。
|
|
|
|
|
|
* 不声明 = 该系统没有账号概念(与 requiresIdentity: false 等价)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
auth?: ProviderAuthSpec;
|
2026-09-24 15:48:45 +08:00
|
|
|
|
capabilities: Capability[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/** 平台用户在该系统里的身份(A4.1):只有账号标识,没有任何凭据 */
|
|
|
|
|
|
export interface ExecutionIdentity {
|
|
|
|
|
|
accountId: string;
|
|
|
|
|
|
displayName: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 一次性执行授权(A4.3):Provider 用它在这次调用里取凭据,过期即失效 */
|
|
|
|
|
|
export interface CredentialHandle {
|
|
|
|
|
|
grantId: string;
|
|
|
|
|
|
read(): Promise<Record<string, string> | undefined>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 影响预览(A4.4):写操作确认卡的正文来源。
|
|
|
|
|
|
* Provider 知道「要动什么、当前数据版本是多少」,这两个问题平台答不了,所以由它给。
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface ImpactPreview {
|
|
|
|
|
|
/** 一句话说清这次写会影响什么(确认卡主文案) */
|
|
|
|
|
|
impactSummary: string;
|
|
|
|
|
|
/** 目标数据版本;版本变了这次确认就失效 */
|
|
|
|
|
|
revision: number;
|
|
|
|
|
|
/** 关键参数摘要(脱敏后给确认卡看,不是完整参数) */
|
|
|
|
|
|
paramsPreview?: Record<string, unknown>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-24 15:48:45 +08:00
|
|
|
|
/** 一次调用的上下文:Core 注入,Provider 不自己找身份与凭据 */
|
|
|
|
|
|
export interface ExecutionContext {
|
|
|
|
|
|
executionId: string;
|
|
|
|
|
|
sessionId: string;
|
|
|
|
|
|
projectId: string | null;
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/** 平台用户与租户 */
|
2026-09-24 15:48:45 +08:00
|
|
|
|
subject: { userId: string; tenantId: string };
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/** 平台用户在该系统的账号映射结果(A4.1);未绑定时策略层已经拒绝,这里不会缺 */
|
|
|
|
|
|
identity?: ExecutionIdentity;
|
|
|
|
|
|
/** 一次性凭据句柄(A4.3);没有配凭据的系统不传 */
|
|
|
|
|
|
credentials?: CredentialHandle;
|
2026-09-24 15:48:45 +08:00
|
|
|
|
/** 幂等键:Provider 侧若支持幂等,应带回执里透传 */
|
|
|
|
|
|
idempotencyKey?: string;
|
|
|
|
|
|
/** 截止时间(epoch ms):超时由 Core 判定,Provider 应尽力遵守 */
|
|
|
|
|
|
deadlineAt: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface CapabilityCall {
|
|
|
|
|
|
capabilityId: string;
|
|
|
|
|
|
params: unknown;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface HealthStatus {
|
|
|
|
|
|
status: 'ok' | 'degraded' | 'down';
|
|
|
|
|
|
detail?: string;
|
|
|
|
|
|
checkedAt: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-30 14:26:35 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 登录方式(ADR-0012):
|
|
|
|
|
|
* - `oauth`:跳转业务系统授权登录,平台收回调
|
|
|
|
|
|
* - `password-exchange`:平台收一次账号密码,换成 token,密码用完即弃
|
|
|
|
|
|
* - `apikey`:管理员配置的长期密钥,挂在租户或实例上(不按人)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface ProviderAuthSpec {
|
|
|
|
|
|
kind: 'oauth' | 'password-exchange' | 'apikey';
|
|
|
|
|
|
/** oauth 用:授权入口与回调参数由 Provider 声明 */
|
|
|
|
|
|
authorizationUrl?: string;
|
|
|
|
|
|
scopes?: string[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 绑定请求:密码只在这一次调用的内存里存在,Provider 不得持久化 */
|
|
|
|
|
|
export interface AuthExchangeRequest {
|
|
|
|
|
|
accountId: string;
|
|
|
|
|
|
password?: string;
|
|
|
|
|
|
/** oauth 回调带回来的授权码 */
|
|
|
|
|
|
code?: string;
|
|
|
|
|
|
state?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 交换结果:平台把 secret 加密存进凭据代理,之后按 execution 签发一次性句柄 */
|
|
|
|
|
|
export interface AuthExchangeResult {
|
|
|
|
|
|
accountId: string;
|
|
|
|
|
|
displayName?: string;
|
|
|
|
|
|
secret: Record<string, string>;
|
|
|
|
|
|
/** 凭据到期时间(epoch ms);不填表示不过期 */
|
|
|
|
|
|
expiresAt?: number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 凭据体检结果:给"登录态失效"一个明确信号,而不是等调用失败才发现 */
|
|
|
|
|
|
export interface CredentialCheck {
|
|
|
|
|
|
ok: boolean;
|
|
|
|
|
|
reason?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-24 15:48:45 +08:00
|
|
|
|
export interface Provider {
|
|
|
|
|
|
describe(): Promise<ProviderManifest>;
|
|
|
|
|
|
invoke(context: ExecutionContext, call: CapabilityCall): Promise<ExecutionReceipt>;
|
|
|
|
|
|
health(): Promise<HealthStatus>;
|
2026-09-29 10:59:34 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 可选:写能力的影响预览(A4.4 确认卡)。
|
|
|
|
|
|
* 不实现时平台用能力描述兜底(只影响确认卡信息量,不影响策略判定)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
preview?(context: ExecutionContext, call: CapabilityCall): Promise<ImpactPreview>;
|
2026-09-30 14:26:35 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 可选:账号绑定时的凭据交换(ADR-0012)。
|
|
|
|
|
|
* 声明了 auth 的 Provider 必须实现它,否则平台无法完成绑定。
|
|
|
|
|
|
*/
|
|
|
|
|
|
exchange?(request: AuthExchangeRequest): Promise<AuthExchangeResult>;
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 可选:凭据体检。平台在绑定完成时与登录态疑似失效时调用它,
|
|
|
|
|
|
* 返回 ok=false 就把绑定标记为"需要重新绑定",后续调用在策略层直接被拒。
|
|
|
|
|
|
*/
|
|
|
|
|
|
checkCredential?(secret: Record<string, string>): Promise<CredentialCheck>;
|
2026-09-23 19:29:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-24 15:48:45 +08:00
|
|
|
|
/** 可选的执行状态查询:异步能力(mode=async)应实现 */
|
|
|
|
|
|
export interface ExecutionStatusProvider {
|
2026-09-23 19:29:57 +08:00
|
|
|
|
status(executionId: string): Promise<ExecutionReceipt>;
|
|
|
|
|
|
}
|