aps-agent/server/provider-sdk/index.ts

171 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Provider 契约(架构设计第 6 节):业务系统接入平台的唯一形状。
*
* Provider 是能力适配器,不是业务系统,也不承载模型上下文。三个方法:
* describe() 声明自己有哪些能力
* invoke() 执行一次能力调用
* health() 健康状态
* 能力怎么描述见 docs/spec/capability-description.md,错误分类见 ./errors.js。
*/
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[];
}
export interface ProviderManifest {
id: string;
displayName: string;
version: string;
/** 兼容的平台协议版本(当前 1) */
platformVersion: number;
/**
* 调用这个系统要不要平台用户先绑定本系统账号(A4.1)。
* 缺省 true:真实系统默认要绑定;只有无账号概念的自建/联调 Provider 才写 false。
*/
requiresIdentity?: boolean;
/**
* 登录方式声明(ADR-0012):平台按它走同一条绑定流程,不自己实现业务系统的登录页。
* 不声明 = 该系统没有账号概念(与 requiresIdentity: false 等价)。
*/
auth?: ProviderAuthSpec;
capabilities: Capability[];
}
/** 平台用户在该系统里的身份(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>;
}
/** 一次调用的上下文:Core 注入,Provider 不自己找身份与凭据 */
export interface ExecutionContext {
executionId: string;
sessionId: string;
projectId: string | null;
/** 平台用户与租户 */
subject: { userId: string; tenantId: string };
/** 平台用户在该系统的账号映射结果(A4.1);未绑定时策略层已经拒绝,这里不会缺 */
identity?: ExecutionIdentity;
/** 一次性凭据句柄(A4.3);没有配凭据的系统不传 */
credentials?: CredentialHandle;
/** 幂等键: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;
}
/**
* 登录方式(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;
}
export interface Provider {
describe(): Promise<ProviderManifest>;
invoke(context: ExecutionContext, call: CapabilityCall): Promise<ExecutionReceipt>;
health(): Promise<HealthStatus>;
/**
* 可选:写能力的影响预览(A4.4 确认卡)。
* 不实现时平台用能力描述兜底(只影响确认卡信息量,不影响策略判定)。
*/
preview?(context: ExecutionContext, call: CapabilityCall): Promise<ImpactPreview>;
/**
* 可选:账号绑定时的凭据交换(ADR-0012)。
* 声明了 auth 的 Provider 必须实现它,否则平台无法完成绑定。
*/
exchange?(request: AuthExchangeRequest): Promise<AuthExchangeResult>;
/**
* 可选:凭据体检。平台在绑定完成时与登录态疑似失效时调用它,
* 返回 ok=false 就把绑定标记为"需要重新绑定",后续调用在策略层直接被拒。
*/
checkCredential?(secret: Record<string, string>): Promise<CredentialCheck>;
}
/** 可选的执行状态查询:异步能力(mode=async)应实现 */
export interface ExecutionStatusProvider {
status(executionId: string): Promise<ExecutionReceipt>;
}