api.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. // 对外 API 的数据结构(docs/design/04-api.md)
  2. import type { InteractionRequest, ProviderId, UsagePayload } from './events'
  3. export type PermissionMode = 'ask' | 'auto' | 'readonly'
  4. export type SessionStatus = 'idle' | 'running' | 'waiting_input'
  5. export type RunStatus = 'queued' | 'running' | 'waiting_input' | 'completed' | 'failed' | 'interrupted'
  6. export interface SessionDto {
  7. id: string
  8. title: string
  9. provider: ProviderId
  10. model: string
  11. profileId: string | null
  12. status: SessionStatus
  13. archived: boolean
  14. source: string
  15. lastSeq: number
  16. createdAt: string
  17. updatedAt: string
  18. }
  19. export interface SessionDetailDto extends SessionDto {
  20. activeRunId: string | null
  21. pendingInteractions: InteractionRequest[]
  22. /** 实际生效的权限模式:会话覆盖值(仅后台可设)或 Profile 的设置 */
  23. permissionMode: PermissionMode
  24. permissionModeOverridden: boolean
  25. systemPromptAppend: string
  26. }
  27. export interface CreateSessionBody {
  28. profileId?: string
  29. model?: string
  30. title?: string
  31. permissionMode?: PermissionMode
  32. systemPromptAppend?: string
  33. }
  34. export interface SendMessageBody {
  35. text: string
  36. attachments?: string[]
  37. }
  38. export interface RunDto {
  39. id: string
  40. sessionId: string
  41. status: RunStatus
  42. startedAt: string | null
  43. endedAt: string | null
  44. usage: UsagePayload | null
  45. error: string | null
  46. }
  47. export interface FileDto {
  48. id: string
  49. sessionId: string
  50. path: string
  51. origin: 'upload' | 'agent'
  52. mime: string
  53. size: number
  54. createdAt: string
  55. updatedAt: string
  56. }
  57. export interface FileAccessPolicy {
  58. mode: 'restricted' | 'broad'
  59. read: PathRule[]
  60. write: PathRule[]
  61. deny: string[]
  62. }
  63. export type PathRule = { knowledgeRootId: string } | { path: string }
  64. export interface ProfileDto {
  65. id: string
  66. name: string
  67. description: string
  68. provider: ProviderId
  69. model: string
  70. systemPrompt: string
  71. permissionMode: PermissionMode
  72. allowedTools: string[]
  73. disallowedTools: string[]
  74. skills: string[] | 'all'
  75. fileAccess: FileAccessPolicy
  76. knowledgeRootIds: string[]
  77. /** 可以使用的第三方 MCP 服务(内置工具始终可用) */
  78. mcpServerIds: string[]
  79. isDefault: boolean
  80. /** 内置 Profile(通用助手)不可删除 */
  81. builtin: boolean
  82. /** 内置 Profile 的种类:null 为通用助手,lead 为工作组的组长 */
  83. builtinKey: 'lead' | null
  84. version: number
  85. updatedAt: string
  86. }
  87. export type ProfileInput = Omit<ProfileDto, 'id' | 'version' | 'updatedAt' | 'builtin' | 'builtinKey' | 'mcpServerIds'> & { mcpServerIds?: string[] }
  88. /** Profile 历史版本的内容(不含"是否默认") */
  89. export type ProfileSnapshot = Omit<ProfileInput, 'isDefault'>
  90. export interface ProfileVersionDto {
  91. version: number
  92. createdAt: string
  93. snapshot: ProfileSnapshot
  94. /** 与上一个版本相比改动的字段 */
  95. changed: (keyof ProfileSnapshot)[]
  96. }
  97. export interface KnowledgeRootDto {
  98. id: string
  99. name: string
  100. path: string
  101. description: string
  102. access: 'read' | 'write'
  103. enabled: boolean
  104. check: PathCheck
  105. }
  106. export interface PathCheck {
  107. exists: boolean
  108. readable: boolean
  109. isDirectory: boolean
  110. /** 命中的全局禁止项 */
  111. denied: string | null
  112. /** 位于 home 下,systemd ProtectHome 部署时需要额外绑定 */
  113. underHome: boolean
  114. message: string | null
  115. }
  116. export interface ProviderStatusDto {
  117. id: ProviderId
  118. enabled: boolean
  119. available: boolean
  120. loggedIn: boolean | null
  121. account: string | null
  122. cliPath: string
  123. version: string | null
  124. models: string[]
  125. defaultModel: string
  126. /** 模型的显示名与实际版本,如 sonnet → "Sonnet 5.5 · claude-sonnet-5-5"(引擎能提供时) */
  127. modelLabels?: Record<string, string>
  128. message: string | null
  129. }
  130. /** 订阅额度的一个计量窗口(如 5 小时、7 天) */
  131. export interface QuotaWindowDto {
  132. key: string
  133. label: string
  134. /** 已用百分比 0-100;引擎没有给出时为 null */
  135. usedPercent: number | null
  136. resetsAt: string | null
  137. }
  138. /** 引擎账户的订阅额度(ChatGPT / Claude 订阅的用量限制) */
  139. export interface ProviderQuotaDto {
  140. provider: ProviderId
  141. /** 订阅类型,如 team、plus */
  142. plan: string | null
  143. windows: QuotaWindowDto[]
  144. /** live:刚从引擎查询;last-run:查询失败,显示最近一次对话中引擎报告的数值 */
  145. source: 'live' | 'last-run'
  146. fetchedAt: string
  147. message: string | null
  148. }
  149. export interface ResolvedAccessDto {
  150. readable: string[]
  151. writable: string[]
  152. denied: string[]
  153. mode: FileAccessPolicy['mode']
  154. }
  155. export interface ApiKeyDto {
  156. id: string
  157. name: string
  158. prefix: string
  159. enabled: boolean
  160. allowedProfileIds: string[]
  161. defaultProfileId: string | null
  162. createdAt: string
  163. lastUsedAt: string | null
  164. }
  165. export interface ApiErrorBody {
  166. error: { code: string; message: string; details?: unknown }
  167. }
  168. export interface Page<T> {
  169. items: T[]
  170. nextCursor: string | null
  171. }
  172. // ---- 技能与插件(通过 Claude Code 官方插件机制安装,ADR-0013)----
  173. export type LicenseKind = 'open' | 'restricted' | 'unknown'
  174. export interface SkillInfo {
  175. /** 带插件前缀的技能 ID,例如 agent-skills:report-conventions、document-skills:xlsx */
  176. id: string
  177. name: string
  178. description: string
  179. plugin: string
  180. /** local 本地技能目录;plugin Claude 插件;official 从官方仓库安装(Codex);system 引擎自带;community 第三方技能;custom 自定义技能(后两者两个引擎共用) */
  181. source: 'local' | 'plugin' | 'official' | 'system' | 'community' | 'custom'
  182. /** 需要在 Profile 中单独勾选(选择"全部技能"时不包含) */
  183. optIn?: boolean
  184. license: LicenseKind
  185. }
  186. export interface InstalledPluginDto {
  187. id: string
  188. name: string
  189. marketplace: string
  190. version: string | null
  191. enabled: boolean
  192. installPath: string
  193. installedAt: string | null
  194. lastUpdated: string | null
  195. skills: SkillInfo[]
  196. license: { kind: LicenseKind; summary: string | null }
  197. }
  198. export interface AvailablePluginDto {
  199. pluginId: string
  200. name: string
  201. description: string
  202. marketplaceName: string
  203. version: string | null
  204. installed: boolean
  205. }
  206. export interface MarketplaceDto {
  207. name: string
  208. source: string
  209. location: string | null
  210. }
  211. export interface PluginStateDto {
  212. cliPath: string
  213. installed: InstalledPluginDto[]
  214. available: AvailablePluginDto[]
  215. marketplaces: MarketplaceDto[]
  216. localSkills: SkillInfo[]
  217. error: string | null
  218. }
  219. export type PluginAction =
  220. | { action: 'marketplace-add'; source: string }
  221. | { action: 'marketplace-remove' | 'marketplace-update'; name: string }
  222. | { action: 'install' | 'uninstall' | 'update' | 'enable' | 'disable'; plugin: string }
  223. export interface ApiKeyProfiles {
  224. allowedProfileIds: string[]
  225. defaultProfileId: string
  226. }
  227. export interface CodexCatalogSkillDto {
  228. name: string
  229. description: string
  230. license: LicenseKind
  231. licenseName: string | null
  232. installed: boolean
  233. installedSha: string | null
  234. updatable: boolean
  235. }
  236. export interface CodexSkillCatalogDto {
  237. repo: string
  238. sha: string | null
  239. fetchedAt: string | null
  240. skills: CodexCatalogSkillDto[]
  241. unmanaged: string[]
  242. }
  243. // ---- 第三方技能(skills.sh 目录,从 GitHub 按提交安装,两个引擎共用,ADR-0017)----
  244. /** 第三方技能的插件名,技能 ID 形如 community-skills:<name> */
  245. export const COMMUNITY_SKILL_PLUGIN = 'community-skills'
  246. export interface CommunitySearchResultDto {
  247. /** GitHub 仓库 owner/repo */
  248. source: string
  249. skillId: string
  250. name: string
  251. installs: number
  252. installed: boolean
  253. /** 不能从这里安装的原因(如官方技能仓库应在对应引擎的页面安装) */
  254. blocked: string | null
  255. }
  256. export interface CommunitySkillPreviewDto {
  257. source: string
  258. skillId: string
  259. /** 安装后的技能名(取自 SKILL.md 的 name) */
  260. name: string
  261. description: string
  262. sha: string
  263. /** 技能在仓库中的路径 */
  264. path: string
  265. skillMd: string
  266. files: { path: string; size: number }[]
  267. /** 技能包含可执行脚本(.py / .sh / .js 等) */
  268. hasScripts: boolean
  269. license: LicenseKind
  270. licenseName: string | null
  271. /** 许可证来自哪里:技能目录、SKILL.md 声明或仓库根目录 */
  272. licenseFrom: 'skill' | 'frontmatter' | 'repo' | null
  273. installed: { sha: string } | null
  274. /** 同名技能已从其他来源安装 */
  275. conflict: string | null
  276. }
  277. export interface CommunitySkillDto {
  278. id: string
  279. name: string
  280. description: string
  281. source: string
  282. skillId: string
  283. path: string
  284. sha: string
  285. license: string | null
  286. installedAt: string
  287. }
  288. // ---- Codex 插件(OpenAI 官方 openai-curated 目录,只在 Playground 中使用,ADR-0018)----
  289. export interface CodexPluginDto {
  290. /** 插件 ID(plugin/uninstall 使用),形如 gmail@openai-curated-remote */
  291. id: string
  292. name: string
  293. displayName: string
  294. description: string
  295. category: string | null
  296. developer: string | null
  297. marketplace: string
  298. installed: boolean
  299. enabled: boolean
  300. /** NOT_AVAILABLE / AVAILABLE / INSTALLED_BY_DEFAULT */
  301. installPolicy: string
  302. /** AVAILABLE / DISABLED_BY_ADMIN */
  303. availability: string
  304. logoUrl: string | null
  305. }
  306. export interface CodexPluginCatalogDto {
  307. items: CodexPluginDto[]
  308. /** 符合筛选条件的总数 */
  309. total: number
  310. categories: string[]
  311. fetchedAt: string | null
  312. error: string | null
  313. }
  314. export interface CodexPluginDetailDto extends CodexPluginDto {
  315. longDescription: string | null
  316. skills: { name: string; description: string }[]
  317. apps: { id: string; name: string; description: string | null; installUrl: string | null }[]
  318. mcpServers: string[]
  319. websiteUrl: string | null
  320. privacyPolicyUrl: string | null
  321. termsOfServiceUrl: string | null
  322. }
  323. export interface CodexPluginInstallResultDto {
  324. /** 需要在 ChatGPT 中授权的应用(打开 installUrl 完成连接) */
  325. appsNeedingAuth: { id: string; name: string; installUrl: string | null }[]
  326. }
  327. // ---- 用量统计 ----
  328. export interface UsageTotals {
  329. runs: number
  330. failed: number
  331. interrupted: number
  332. inputTokens: number
  333. outputTokens: number
  334. cacheReadTokens: number
  335. cacheWriteTokens: number
  336. /** 订阅登录下为引擎给出的估算值 */
  337. costUsd: number
  338. durationMs: number
  339. }
  340. export interface UsageSummaryDto {
  341. /** 统计区间(含首尾,服务器本地日期) */
  342. from: string
  343. to: string
  344. total: UsageTotals
  345. today: UsageTotals
  346. /** 每天一项,没有用量的日期也会列出 */
  347. daily: ({ date: string } & UsageTotals)[]
  348. /** 按来源:API Key(平台)或后台 Playground(source = admin) */
  349. bySource: ({ source: string; name: string } & UsageTotals)[]
  350. byModel: ({ provider: string; model: string } & UsageTotals)[]
  351. /** 按引擎:今天与整个区间 */
  352. byProvider: { provider: string; today: UsageTotals; total: UsageTotals }[]
  353. }
  354. export interface RecentErrorDto {
  355. runId: string
  356. sessionId: string
  357. sessionTitle: string
  358. source: string
  359. provider: string
  360. error: string
  361. endedAt: string | null
  362. }
  363. // ---- 浏览器令牌(业务平台后端用 API Key 换取,交给浏览器使用,ADR-0019)----
  364. export interface CreateBrowserTokenBody {
  365. /** 有效期(秒),默认 3600,最长 43200 */
  366. ttlSeconds?: number
  367. }
  368. export interface BrowserTokenDto {
  369. token: string
  370. expiresAt: string
  371. }
  372. // ---- 对外 API 协议参考(后台"API 协议"页面,数据见 apps/server/src/api-reference/reference.ts)----
  373. export interface ApiField {
  374. name: string
  375. type: string
  376. required?: boolean
  377. desc: string
  378. }
  379. export interface ApiEndpoint {
  380. method: 'GET' | 'POST' | 'PATCH' | 'DELETE'
  381. path: string
  382. summary: string
  383. desc?: string
  384. query?: ApiField[]
  385. body?: ApiField[]
  386. /** 请求体不是 JSON 时的说明(如 multipart) */
  387. bodyNote?: string
  388. response: { status: number; type: string; desc?: string }
  389. errors?: string[]
  390. example?: string
  391. /** 后台"调试"时预填的请求体 */
  392. sampleBody?: unknown
  393. }
  394. export interface ApiEndpointGroup {
  395. id: string
  396. title: string
  397. desc?: string
  398. endpoints: ApiEndpoint[]
  399. }
  400. export interface ApiTypeDef {
  401. name: string
  402. desc?: string
  403. fields: ApiField[]
  404. }
  405. export interface ApiEventDef {
  406. type: string
  407. payload: string
  408. desc: string
  409. persisted: boolean
  410. }
  411. export interface ApiErrorDef {
  412. status: number
  413. code: string
  414. desc: string
  415. }
  416. /** 概述中的条目:`代码`、**加粗** 两种标记;$BASE 替换为服务地址 */
  417. export interface ApiOverview {
  418. points: string[]
  419. flow: string[]
  420. }
  421. /** 一套协议:Agent API(/v1,会话)或 Bot API(/bot/v1,机器人与工作组) */
  422. export interface ApiSpec {
  423. id: 'agent' | 'bot'
  424. title: string
  425. /** 一句话说明,以及使用哪种 Key */
  426. summary: string
  427. overview: ApiOverview
  428. groups: ApiEndpointGroup[]
  429. /** 事件信封的类型名(数据结构中的一项) */
  430. eventEnvelope: string
  431. types: ApiTypeDef[]
  432. events: ApiEventDef[]
  433. errors: ApiErrorDef[]
  434. }
  435. export interface ApiReferenceDto {
  436. version: string
  437. specs: ApiSpec[]
  438. }
  439. // ---- MCP 服务(经 MCP Gateway 转接,两个引擎共用,ADR-0021)----
  440. /** 工具策略:auto 直接调用;ask 跟随权限模式(需审批时询问);off 不提供 */
  441. export type McpToolPolicy = 'auto' | 'ask' | 'off'
  442. export interface McpToolDto {
  443. name: string
  444. description: string
  445. /** 服务声明的只读工具(annotations.readOnlyHint);只读模式下只能调用这类工具 */
  446. readOnly: boolean
  447. policy: McpToolPolicy
  448. /** 总是在后台执行(长时间运行的工具,docs/design/15-background-calls.md) */
  449. background: boolean
  450. }
  451. /** 密钥类的值(请求头、环境变量):读取时只返回是否已设置 */
  452. export interface McpSecretEntry {
  453. name: string
  454. /** 写入时为新值;读取时为 null(不返回密钥)。更新时传 null 表示保留原值 */
  455. value: string | null
  456. isSet?: boolean
  457. }
  458. export interface McpServerInput {
  459. /** 工具名前缀:小写字母、数字、下划线、连字符,1-32 位 */
  460. name: string
  461. title: string
  462. description: string
  463. transport: 'http' | 'stdio'
  464. enabled: boolean
  465. /** http:服务地址 */
  466. url: string
  467. headers: McpSecretEntry[]
  468. /** stdio:命令、参数、环境变量 */
  469. command: string
  470. args: string[]
  471. env: McpSecretEntry[]
  472. /** stdio:沙箱内是否允许联网 */
  473. allowNetwork: boolean
  474. /** stdio:沙箱内额外只读 / 可写的路径 */
  475. readPaths: string[]
  476. writePaths: string[]
  477. }
  478. export interface McpServerDto extends McpServerInput {
  479. id: string
  480. tools: McpToolDto[]
  481. toolsUpdatedAt: string | null
  482. status: 'connected' | 'idle' | 'error'
  483. lastError: string | null
  484. /** 本地进程最近的错误输出 */
  485. stderrTail: string | null
  486. /** 勾选了这个服务的 Profile */
  487. profileNames: string[]
  488. createdAt: string
  489. updatedAt: string
  490. }
  491. export interface McpBuiltinToolDto {
  492. name: string
  493. description: string
  494. readOnly: boolean
  495. }
  496. export interface McpStateDto {
  497. builtin: McpBuiltinToolDto[]
  498. servers: McpServerDto[]
  499. /** 本地进程沙箱(bubblewrap)是否可用 */
  500. sandboxAvailable: boolean
  501. }
  502. export interface McpTestResultDto {
  503. ok: boolean
  504. tools: McpToolDto[]
  505. error: string | null
  506. stderrTail: string | null
  507. ms: number
  508. }
  509. // ---- 自定义技能(导入或在后台编写,两个引擎共用,docs/design/12-custom-skills.md)----
  510. /** 自定义技能的插件名,技能 ID 形如 custom-skills:<name> */
  511. export const CUSTOM_SKILL_PLUGIN = 'custom-skills'
  512. export interface CustomSkillFileDto {
  513. path: string
  514. size: number
  515. sha: string
  516. /** 可以在后台以文本方式编辑 */
  517. text: boolean
  518. }
  519. export interface FileChangesDto {
  520. added: string[]
  521. modified: string[]
  522. removed: string[]
  523. }
  524. export interface CustomSkillVersionDto {
  525. version: number
  526. createdAt: string
  527. /** create 新建;edit 编辑保存;import 首次导入;sync 同步;restore 恢复 */
  528. reason: 'create' | 'edit' | 'import' | 'sync' | 'restore'
  529. changed: FileChangesDto
  530. fileCount: number
  531. size: number
  532. }
  533. export interface CustomSkillDto {
  534. id: string
  535. /** 技能名,也是目录名;技能 ID 为 custom-skills:<name> */
  536. name: string
  537. description: string
  538. origin: 'authored' | 'imported'
  539. sourceId: string | null
  540. sourceName: string | null
  541. enabled: boolean
  542. /** 包含在 Profile 的"全部技能"中(默认否,需要单独勾选) */
  543. includeInAll: boolean
  544. /** 运行时生效的版本;null 表示还没有发布 */
  545. publishedVersion: number | null
  546. latestVersion: number
  547. /** 编辑中、尚未保存为版本的改动 */
  548. hasUnsavedChanges: boolean
  549. profileNames: string[]
  550. createdAt: string
  551. updatedAt: string
  552. }
  553. export interface CustomSkillDetailDto extends CustomSkillDto {
  554. /** 编辑中的文件(未保存的改动也在这里) */
  555. files: CustomSkillFileDto[]
  556. versions: CustomSkillVersionDto[]
  557. }
  558. export interface SkillSourceInput {
  559. name: string
  560. description: string
  561. /** 服务器上的绝对路径 */
  562. path: string
  563. syncMode: 'manual' | 'auto'
  564. intervalMin: number
  565. }
  566. export interface SkillSourceDto extends SkillSourceInput {
  567. id: string
  568. /** directory 服务器目录;upload 上传的 zip(一次性) */
  569. kind: 'directory' | 'upload'
  570. lastSyncAt: string | null
  571. status: 'never' | 'ok' | 'error'
  572. lastError: string | null
  573. /** 从这个来源导入的技能 */
  574. skillNames: string[]
  575. createdAt: string
  576. }
  577. export interface SkillScanItemDto {
  578. name: string
  579. description: string
  580. /** 在来源中的相对路径 */
  581. path: string
  582. fileCount: number
  583. size: number
  584. /** new 新技能;changed 有变化;unchanged 无变化;conflict 同名技能已存在且来源不同;invalid 不能导入 */
  585. status: 'new' | 'changed' | 'unchanged' | 'conflict' | 'invalid'
  586. reason: string | null
  587. changes: FileChangesDto
  588. warnings: string[]
  589. }
  590. export interface SkillScanDto {
  591. sourceId: string
  592. /** 导入时回传,扫描结果变化时拒绝导入(避免导入未审阅的内容) */
  593. digest: string
  594. skills: SkillScanItemDto[]
  595. /** 从这个来源导入过、但来源中已不存在的技能 */
  596. missing: string[]
  597. /** 跳过的文件(符号链接、特殊文件等) */
  598. skipped: string[]
  599. }
  600. export interface FileDiffDto {
  601. path: string
  602. status: 'added' | 'removed' | 'modified'
  603. binary: boolean
  604. /** 文本文件的统一差异格式 */
  605. patch: string | null
  606. }
  607. // ---- 后台文件管理(管理员)----
  608. export interface FsRootDto {
  609. /** workspaces、kb:<资料库 id>、skills、runtime */
  610. id: string
  611. name: string
  612. kind: 'workspaces' | 'knowledge' | 'readonly'
  613. writable: boolean
  614. description: string
  615. exists: boolean
  616. }
  617. export interface FsShortcutDto {
  618. label: string
  619. rootId: string
  620. path: string
  621. /** codicon 名称 */
  622. icon: string
  623. }
  624. export interface FsEntryDto {
  625. name: string
  626. /** link:指向位置之外的符号链接(不跟随) */
  627. type: 'file' | 'dir' | 'link' | 'other'
  628. size: number | null
  629. mtime: string
  630. /** 会话工作区根目录下的会话目录:会话标题 */
  631. label?: string
  632. }