@ai-zen/agents-host 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +759 -2
  4. package/dist/app.d.ts +384 -0
  5. package/dist/app.js +1148 -0
  6. package/dist/cli.d.ts +21 -0
  7. package/dist/cli.js +353 -0
  8. package/dist/config.d.ts +97 -0
  9. package/dist/config.js +171 -0
  10. package/dist/handlers/agentHandlers.d.ts +18 -0
  11. package/dist/handlers/agentHandlers.js +20 -0
  12. package/dist/handlers/assetHandlers.d.ts +29 -0
  13. package/dist/handlers/assetHandlers.js +35 -0
  14. package/dist/handlers/capabilities.d.ts +26 -0
  15. package/dist/handlers/capabilities.js +138 -0
  16. package/dist/handlers/completionHandlers.d.ts +18 -0
  17. package/dist/handlers/completionHandlers.js +13 -0
  18. package/dist/handlers/configHandlers.d.ts +31 -0
  19. package/dist/handlers/configHandlers.js +59 -0
  20. package/dist/handlers/conversationHandlers.d.ts +118 -0
  21. package/dist/handlers/conversationHandlers.js +314 -0
  22. package/dist/handlers/handoffHandlers.d.ts +17 -0
  23. package/dist/handlers/handoffHandlers.js +14 -0
  24. package/dist/handlers/hostHandlers.d.ts +39 -0
  25. package/dist/handlers/hostHandlers.js +56 -0
  26. package/dist/handlers/index.d.ts +128 -0
  27. package/dist/handlers/index.js +92 -0
  28. package/dist/handlers/messageHandlers.d.ts +11 -0
  29. package/dist/handlers/messageHandlers.js +10 -0
  30. package/dist/handlers/modelHandlers.d.ts +17 -0
  31. package/dist/handlers/modelHandlers.js +19 -0
  32. package/dist/handlers/noticeHandlers.d.ts +24 -0
  33. package/dist/handlers/noticeHandlers.js +24 -0
  34. package/dist/handlers/questionHandlers.d.ts +16 -0
  35. package/dist/handlers/questionHandlers.js +16 -0
  36. package/dist/handlers/searchHandlers.d.ts +12 -0
  37. package/dist/handlers/searchHandlers.js +12 -0
  38. package/dist/handlers/workspaceHandlers.d.ts +29 -0
  39. package/dist/handlers/workspaceHandlers.js +47 -0
  40. package/dist/i18n/en.d.ts +243 -0
  41. package/dist/i18n/en.js +270 -0
  42. package/dist/i18n/index.d.ts +43 -0
  43. package/dist/i18n/index.js +72 -0
  44. package/dist/i18n/zh.d.ts +240 -0
  45. package/dist/i18n/zh.js +257 -0
  46. package/dist/index.d.ts +17 -0
  47. package/dist/index.js +15 -0
  48. package/dist/net/UploadReceiver.d.ts +186 -0
  49. package/dist/net/UploadReceiver.js +494 -0
  50. package/dist/net/WsHub.d.ts +231 -0
  51. package/dist/net/WsHub.js +689 -0
  52. package/dist/net/auth.d.ts +73 -0
  53. package/dist/net/auth.js +74 -0
  54. package/dist/net/discovery.d.ts +72 -0
  55. package/dist/net/discovery.js +171 -0
  56. package/dist/net/index.d.ts +14 -0
  57. package/dist/net/index.js +10 -0
  58. package/dist/runtime/ChatRunner.d.ts +374 -0
  59. package/dist/runtime/ChatRunner.js +1204 -0
  60. package/dist/runtime/ConversationDrafts.d.ts +43 -0
  61. package/dist/runtime/ConversationDrafts.js +47 -0
  62. package/dist/runtime/RunRegistry.d.ts +79 -0
  63. package/dist/runtime/RunRegistry.js +108 -0
  64. package/dist/runtime/ScopeRegistry.d.ts +153 -0
  65. package/dist/runtime/ScopeRegistry.js +259 -0
  66. package/dist/runtime/TransientRunner.d.ts +90 -0
  67. package/dist/runtime/TransientRunner.js +179 -0
  68. package/dist/runtime/index.d.ts +14 -0
  69. package/dist/runtime/index.js +10 -0
  70. package/dist/services/AgentService.d.ts +150 -0
  71. package/dist/services/AgentService.js +718 -0
  72. package/dist/services/AssetService.d.ts +338 -0
  73. package/dist/services/AssetService.js +739 -0
  74. package/dist/services/AutoNaming.d.ts +92 -0
  75. package/dist/services/AutoNaming.js +235 -0
  76. package/dist/services/CompletionService.d.ts +122 -0
  77. package/dist/services/CompletionService.js +442 -0
  78. package/dist/services/ConfigService.d.ts +171 -0
  79. package/dist/services/ConfigService.js +695 -0
  80. package/dist/services/ConversationService.d.ts +274 -0
  81. package/dist/services/ConversationService.js +902 -0
  82. package/dist/services/CredentialService.d.ts +33 -0
  83. package/dist/services/CredentialService.js +86 -0
  84. package/dist/services/DiscoveryService.d.ts +182 -0
  85. package/dist/services/DiscoveryService.js +998 -0
  86. package/dist/services/HandoffService.d.ts +189 -0
  87. package/dist/services/HandoffService.js +414 -0
  88. package/dist/services/Logger.d.ts +130 -0
  89. package/dist/services/Logger.js +256 -0
  90. package/dist/services/MessageService.d.ts +88 -0
  91. package/dist/services/MessageService.js +280 -0
  92. package/dist/services/ModelService.d.ts +89 -0
  93. package/dist/services/ModelService.js +489 -0
  94. package/dist/services/NoticeService.d.ts +93 -0
  95. package/dist/services/NoticeService.js +217 -0
  96. package/dist/services/QuestionService.d.ts +184 -0
  97. package/dist/services/QuestionService.js +457 -0
  98. package/dist/services/SearchService.d.ts +54 -0
  99. package/dist/services/SearchService.js +117 -0
  100. package/dist/services/WorkspaceService.d.ts +96 -0
  101. package/dist/services/WorkspaceService.js +213 -0
  102. package/dist/services/imageSize.d.ts +41 -0
  103. package/dist/services/imageSize.js +146 -0
  104. package/dist/services/index.d.ts +20 -0
  105. package/dist/services/index.js +15 -0
  106. package/dist/services/secretMask.d.ts +24 -0
  107. package/dist/services/secretMask.js +34 -0
  108. package/dist/storage/AssetRepository.d.ts +87 -0
  109. package/dist/storage/AssetRepository.js +180 -0
  110. package/dist/storage/ConversationRepository.d.ts +55 -0
  111. package/dist/storage/ConversationRepository.js +128 -0
  112. package/dist/storage/CredentialRepository.d.ts +28 -0
  113. package/dist/storage/CredentialRepository.js +47 -0
  114. package/dist/storage/Database.d.ts +95 -0
  115. package/dist/storage/Database.js +180 -0
  116. package/dist/storage/MessageRepository.d.ts +104 -0
  117. package/dist/storage/MessageRepository.js +323 -0
  118. package/dist/storage/MetaRepository.d.ts +21 -0
  119. package/dist/storage/MetaRepository.js +33 -0
  120. package/dist/storage/NoticeRepository.d.ts +31 -0
  121. package/dist/storage/NoticeRepository.js +89 -0
  122. package/dist/storage/QuestionRepository.d.ts +34 -0
  123. package/dist/storage/QuestionRepository.js +96 -0
  124. package/dist/storage/WorkspaceRepository.d.ts +25 -0
  125. package/dist/storage/WorkspaceRepository.js +44 -0
  126. package/dist/storage/dbWorker.d.ts +10 -0
  127. package/dist/storage/dbWorker.js +132 -0
  128. package/dist/storage/index.d.ts +20 -0
  129. package/dist/storage/index.js +16 -0
  130. package/dist/storage/migrations.d.ts +26 -0
  131. package/dist/storage/migrations.js +207 -0
  132. package/dist/storage/types.d.ts +298 -0
  133. package/dist/storage/types.js +14 -0
  134. package/dist/wire/errors.d.ts +105 -0
  135. package/dist/wire/errors.js +143 -0
  136. package/dist/wire/events.d.ts +102 -0
  137. package/dist/wire/events.js +13 -0
  138. package/dist/wire/frames.d.ts +106 -0
  139. package/dist/wire/frames.js +156 -0
  140. package/dist/wire/index.d.ts +31 -0
  141. package/dist/wire/index.js +31 -0
  142. package/dist/wire/methods.d.ts +1896 -0
  143. package/dist/wire/methods.js +99 -0
  144. package/dist/wire/states.d.ts +487 -0
  145. package/dist/wire/states.js +61 -0
  146. package/package.json +63 -3
@@ -0,0 +1,99 @@
1
+ /**
2
+ * 方法表:方法名 → 入参 / 出参。
3
+ *
4
+ * 命名按 `<域>.<动作>`(architecture §6)。每一段前的注释写清它服务 PRD §4 的哪条能力
5
+ * 编号,以及那条能力的落点为什么在宿主 —— 这是接线与前端对齐时唯一的索引。
6
+ *
7
+ * 两条贯穿全表的口径:
8
+ * 1. 出参只给**结构化事实**,需要句子时给 `LocalizedText`;不把句子当数据结构(PRD §3 尺子 ④⑤)。
9
+ * 2. 各域的「读」返回完整对象、「写」返回写后的完整对象,这样客户端拿到响应就能直接替换本地状态。
10
+ *
11
+ * 消息相关的出参用的就是 core 的类型:消息本体 `AgentNS.Message`、内容 `AgentNS.MessageContent` /
12
+ * `AgentNS.MessageContentSection`、增量 `AgentNS.Delta`、用量 `AgentNS.Usage`。这里只包外壳
13
+ * (哪个对话、哪个工作站、受理了什么)。
14
+ */
15
+ // ---------------------------------------------------------------------------
16
+ // 通用
17
+ // ---------------------------------------------------------------------------
18
+ /** 协议版本:宿主与客户端同一版发布(PRD L1),版本号用来挡掉错配的连接 */
19
+ export const PROTOCOL_VERSION = "1";
20
+ /**
21
+ * 全部方法名(分发注册、帮助渲染、测试遍历用)。
22
+ *
23
+ * 用 `as const satisfies` 是为了让「表里漏了一个方法」在编译期就能被抓到:
24
+ * 测试里做 `Exclude<MethodName, (typeof METHOD_NAMES)[number]>` 时,漏掉的名字会留在
25
+ * 那个差集里而不是被抹成 `never`。
26
+ */
27
+ export const METHOD_NAMES = [
28
+ "host.hello",
29
+ "host.version",
30
+ "host.upgrade",
31
+ "host.shutdown",
32
+ "host.capabilities",
33
+ "host.reload",
34
+ "host.setLanguage",
35
+ "workspace.list",
36
+ "workspace.create",
37
+ "workspace.get",
38
+ "workspace.rename",
39
+ "workspace.remove",
40
+ "conversation.list",
41
+ "conversation.create",
42
+ "conversation.get",
43
+ "conversation.state",
44
+ "conversation.rename",
45
+ "conversation.pin",
46
+ "conversation.delete",
47
+ "conversation.send",
48
+ "conversation.abort",
49
+ "conversation.revert",
50
+ "conversation.setModel",
51
+ "conversation.setThinking",
52
+ "conversation.transient",
53
+ "message.list",
54
+ "question.list",
55
+ "question.answer",
56
+ "notice.list",
57
+ "notice.dismiss",
58
+ "notice.clear",
59
+ "config.get",
60
+ "config.patch",
61
+ "config.setDefaults",
62
+ "config.getDiscovery",
63
+ "config.saveMcp",
64
+ "config.deleteMcp",
65
+ "config.saveEndpoint",
66
+ "config.deleteEndpoint",
67
+ "agent.list",
68
+ "agent.get",
69
+ "agent.create",
70
+ "agent.update",
71
+ "agent.delete",
72
+ "agent.setModel",
73
+ "agent.setThinking",
74
+ "agent.restoreFactory",
75
+ "model.list",
76
+ "model.listImages",
77
+ "model.create",
78
+ "model.update",
79
+ "model.delete",
80
+ "model.restoreFactory",
81
+ "model.saveImage",
82
+ "model.deleteImage",
83
+ "asset.begin",
84
+ "asset.end",
85
+ "asset.get",
86
+ "completion.files",
87
+ "handoff.start",
88
+ "handoff.listDocuments",
89
+ "search.conversations",
90
+ "search.messages",
91
+ ];
92
+ /** 运行时判断一个字符串是不是已知方法名 */
93
+ export function isMethodName(value) {
94
+ return typeof value === "string" && METHOD_NAMES.includes(value);
95
+ }
96
+ /** 方法名属于哪个域(`conversation.send` → `conversation`) */
97
+ export function methodDomain(method) {
98
+ return method.slice(0, method.indexOf("."));
99
+ }
@@ -0,0 +1,487 @@
1
+ import type { AgentNS } from "@ai-zen/agents-core";
2
+ import type { MessageKey } from "../i18n/index.js";
3
+ /**
4
+ * 产品形状(wire 的下半截):事件与方法出参里那些「给人看 / 给界面排」的结构。
5
+ *
6
+ * 这一层的思想来源是 PRD §3 的尺子 ④⑤:**宿主给事实、客户端给表现**。
7
+ * 于是这里的每个字段都只承载一种事实(数字是数字、列表是列表、状态是状态),
8
+ * 需要句子的时候给 `LocalizedText`(码 + 参数 + 已渲染的一句),而不是把句子当数据结构。
9
+ *
10
+ * 消息相关的概念不在这里定义,直接用 core 的导出:
11
+ * - 消息本体 = `AgentNS.Message`(正文 / 思考 / 工具调用 / 状态 / 角色 / 结束原因 / 用量都在里面);
12
+ * - 消息内容 = `AgentNS.MessageContent`、`AgentNS.MessageContentSection`(`text` / `image_url` / `file`);
13
+ * - 工具调用 = `AgentNS.ToolCall`、`AgentNS.FunctionCall`;
14
+ * - 消息状态 / 角色 / 结束原因 = `AgentNS.MessageStatus` / `AgentNS.Role` / `AgentNS.FinishReason`;
15
+ * - 流式增量 = `AgentNS.Delta`;用量 = `AgentNS.Usage`(求和用 core 的 `sumUsage`)。
16
+ *
17
+ * 本文件只装 core 没有的**产品事实**:生成六态、通知分档、问题对象、上下文阈值、
18
+ * 状态栏块、素材引用,以及「哪个对话 / 哪一轮」这类薄外壳。外壳里的消息、内容、工具调用、
19
+ * 用量字段装的就是 core 的那几个类型,没有第二份定义。
20
+ *
21
+ * 时间用 ISO 8601 字符串(与 SDK 的 `createdAt` / `updatedAt` 同口径);id 是字符串,
22
+ * 由宿主分配(PRD L6)。
23
+ */
24
+ /**
25
+ * 宿主存「码 + 参数」、读出时按连接语言渲染的那一层(PRD D8 / F-J1)。
26
+ *
27
+ * `code` 是稳定码(客户端按它挑图标、分支),`messageKey` 是文案键,`params` 是渲染参数,
28
+ * `message` 是**当前连接语言**下的成品句子。四样都给,是因为同一份数据要同时满足
29
+ * 「界面显示」「客户端重排」「换个语言连回来重渲染」三种需要。
30
+ */
31
+ export interface LocalizedText {
32
+ /** 稳定码(如 `notice.settingsSaved`、`tool.failed`),与文案键分开,便于客户端分支 */
33
+ code: string;
34
+ /** 文案键(`i18n` 的键空间) */
35
+ messageKey: MessageKey;
36
+ /** 渲染参数 */
37
+ params: Record<string, unknown>;
38
+ /** 已按当前连接语言渲染好的句子 */
39
+ message: string;
40
+ }
41
+ /**
42
+ * 失败/降级这类「有事发生了」的事实。
43
+ *
44
+ * 在 `LocalizedText` 之上多一个 `detail`:结构化的原因(哪个工具、哪条错误、还差什么),
45
+ * 让客户端能做出「点一下把失败的工具重跑」这种交互,而不必去解析句子。
46
+ */
47
+ export interface ProblemFact extends LocalizedText {
48
+ detail?: unknown;
49
+ }
50
+ /** 拼装中的工具调用:名字已到、参数还在流里 */
51
+ export interface AssemblingToolCall {
52
+ /** 正在拼的那个调用,core 原样(`id` / `index` / `function.name` / `function.arguments`) */
53
+ toolCall: AgentNS.ToolCall;
54
+ /** 已收到的参数字符数,用来给「正在拼」一个可见的进度 */
55
+ argumentsChars: number;
56
+ }
57
+ /** 正在跑的工具:等工具态里列出来的就是这些(并行时只含还在跑的,PRD L8) */
58
+ export interface RunningTool {
59
+ /** 被执行的调用,core 原样(工具名在 `function.name` 上) */
60
+ toolCall: AgentNS.ToolCall;
61
+ startedAt: string;
62
+ /** 该工具是子 Agent 委派时带上它的快照(PRD F-I7) */
63
+ subagent?: SubAgentSnapshot;
64
+ }
65
+ /**
66
+ * 生成六态。每一态带它自己那份事实,取一个态就够画状态栏,不必再回头问别处。
67
+ *
68
+ * 六态与 PRD L8 的六个说法一一对应:连上 / 等首字 / 在想 / 在输出 / 拼工具调用 / 等工具。
69
+ * 「等哪几个工具」是列表而不是布尔:并行时有几个还在跑就列几个(PRD L8 括注)。
70
+ */
71
+ export type GenerationState = {
72
+ phase: "connected";
73
+ since: string;
74
+ } | {
75
+ phase: "awaiting_first_token";
76
+ since: string;
77
+ } | {
78
+ phase: "thinking";
79
+ since: string;
80
+ chars: number;
81
+ } | {
82
+ phase: "generating";
83
+ since: string;
84
+ chars: number;
85
+ } | {
86
+ phase: "assembling_tool_calls";
87
+ since: string;
88
+ toolCalls: AssemblingToolCall[];
89
+ } | {
90
+ phase: "awaiting_tools";
91
+ since: string;
92
+ runningTools: RunningTool[];
93
+ };
94
+ /** 六态的名字(客户端按它取图标/文案,事件里也用这组值) */
95
+ export type GenerationPhaseName = GenerationState["phase"];
96
+ /** 六态的取值表,运行时校验与测试遍历用 */
97
+ export declare const GENERATION_PHASES: readonly GenerationPhaseName[];
98
+ /** 一轮的结局;`aborted` 是用户的显式动作,和 `error` 不是一回事(PRD D14) */
99
+ export type RunOutcome = "completed" | "aborted" | "error";
100
+ /** 这段对话当前的运行状态:空闲 / 在跑 / 已结束 */
101
+ export type RunStatus = "idle" | "running" | "settled";
102
+ /**
103
+ * 一轮的运行状态快照(`run.state` 事件的载荷、`conversation.state` 的一部分)。
104
+ *
105
+ * 重连的客户端靠它把界面恢复成「正在发生什么」(PRD L5):`status` 说这一轮在不在跑,
106
+ * `generation` 说跑到哪一态,`usage` 说花了多少,`subagents` 说有哪些子 Agent 在跑/跑过。
107
+ */
108
+ export interface RunState {
109
+ conversationId: string;
110
+ status: RunStatus;
111
+ /** 本轮那条助手消息的 id(请求发出前就分配,PRD L6);空闲时为空 */
112
+ assistantMessageId: string | null;
113
+ startedAt: string | null;
114
+ settledAt: string | null;
115
+ /** `status === "running"` 时是六态之一;其余情况为空 */
116
+ generation: GenerationState | null;
117
+ /** `status === "settled"` 时的结局 */
118
+ outcome: RunOutcome | null;
119
+ /** 出错停下时的原因(`status === "settled"` 且 `outcome === "error"`) */
120
+ problem: ProblemFact | null;
121
+ /** 本轮涉及的全部子 Agent(PRD F-I7:存在、状态、失败要显示失败) */
122
+ subagents: SubAgentSnapshot[];
123
+ /** 本轮用量(PRD F-I5 的「本轮」一侧) */
124
+ usage: UsageSnapshot;
125
+ }
126
+ /** 子 Agent 的运行状态:跑完就是跑完,失败就是失败,不合并成一个「结束」 */
127
+ export type SubAgentStatus = "running" | "done" | "error" | "aborted";
128
+ /**
129
+ * 子 Agent 的快照:某次委派产生的一个子 Agent。
130
+ *
131
+ * `toolCallId` 是它挂在哪一个工具调用下面(客户端据此把它塞进对应工具调用的折叠区),
132
+ * `messageCount` 说明它有几句可回看的话,取用 `message.list` 带上 `toolCallId`。
133
+ *
134
+ * `usage` 是这一个子 Agent(含其孙级)的求和结果,形状就是 core 的 `Usage`
135
+ * (求和使用 core 的 `sumUsage`)。
136
+ */
137
+ export interface SubAgentSnapshot {
138
+ toolCallId: string;
139
+ name: string;
140
+ status: SubAgentStatus;
141
+ startedAt: string;
142
+ finishedAt: string | null;
143
+ messageCount: number;
144
+ usage: AgentNS.Usage | null;
145
+ problem: ProblemFact | null;
146
+ }
147
+ /** 速率的统计口径:按输出 token 算,还是按总量算 */
148
+ export type RateBasis = "completion" | "total";
149
+ /**
150
+ * 用量快照:本轮 / 累计 / 速率(PRD F-I5)。
151
+ *
152
+ * 三个口径里装的是同一份 core `Usage`,字段名与取值照 core(`prompt_tokens` /
153
+ * `completion_tokens` / `total_tokens`):
154
+ * - `turn`:当前这一轮请求;
155
+ * - `total`:这段对话至今,含子 Agent(含孙级)—— 这是 PRD 明确要求的:漏了子 Agent,
156
+ * 用户会发现账单比界面大;
157
+ * - `subAgent`:累计里由子 Agent 贡献的那部分,单独再给一份是为了让「累计里有多少是
158
+ * 子 Agent 花的」这件事本身可见。
159
+ */
160
+ export interface UsageSnapshot {
161
+ /** 本轮(当前这一轮请求) */
162
+ turn: AgentNS.Usage;
163
+ /** 累计(这段对话至今,含子 Agent) */
164
+ total: AgentNS.Usage;
165
+ /** 累计里由子 Agent 贡献的部分 */
166
+ subAgent: AgentNS.Usage;
167
+ /** 速率 */
168
+ rate: {
169
+ value: number;
170
+ unit: "tokens_per_second";
171
+ basis: RateBasis;
172
+ };
173
+ /** 这份快照算到哪一刻 */
174
+ updatedAt: string;
175
+ }
176
+ /** 一份零值用量快照(三个口径都是 core 的零值 `Usage`) */
177
+ export declare function zeroUsage(now: string): UsageSnapshot;
178
+ /**
179
+ * 上下文占用的当轮事实:最近一次请求的用量 + 两条线的绝对值(PRD F-D1 / D27)。
180
+ *
181
+ * 比例由客户端自己算(前端不做算术的另一面是:宿主把原始数字给全)。
182
+ * 「还装得下多少」看的是 `usage.prompt_tokens`;`overHandoff` / `overGuard` 是宿主
183
+ * 判定出的结论,客户端不必自己比大小。
184
+ */
185
+ export interface ContextState {
186
+ /** 最近一次请求的用量,core 原样 */
187
+ usage: AgentNS.Usage;
188
+ /** 交接线(软线,SDK 的 `tokenThresholds.handoff`) */
189
+ handoffThreshold: number;
190
+ /** 硬线(`tokenThresholds.guard`) */
191
+ guardThreshold: number;
192
+ /** 是否已过交接线(该问用户要不要交接了) */
193
+ overHandoff: boolean;
194
+ /** 是否已过硬线(这一轮不再发出请求,PRD F-D1 / D23) */
195
+ overGuard: boolean;
196
+ }
197
+ /** 思考强度的取值来源:跟随默认 / 手动设了某档 / 这个模型不可调(PRD F-B7) */
198
+ export type ThinkingSource = "following_default" | "manual" | "not_adjustable";
199
+ /**
200
+ * 思考强度的状态(PRD F-B6 / F-B7)。
201
+ *
202
+ * `levels` 是该模型可选的全部档位名(来自思考策略表);`selected` 是当前档位;
203
+ * `params` 是这一档**展开后的请求参数**(档位名存在会话行上,展开发生在装配 agent 那一刻)。
204
+ * `following_default` 表示这段会话没设过档位,用的是助手定义上的那份参数。
205
+ */
206
+ export interface ThinkingState {
207
+ /** 引用的思考策略名(模型上配的那个) */
208
+ preset: string | null;
209
+ /** 可选档位名;空数组表示这个模型没有思考档位 */
210
+ levels: string[];
211
+ /** 当前档位名;`not_adjustable` 时为空 */
212
+ selected: string | null;
213
+ /** 这个值从哪来 */
214
+ source: ThinkingSource;
215
+ /** 当前档位展开后的参数补丁 */
216
+ params: Record<string, unknown>;
217
+ }
218
+ /**
219
+ * 一段会话现在用的模型来自哪里(PRD F-B4 里「会话级」与「助手定义」两个动作的区别)。
220
+ *
221
+ * `agent` = 会话行上那个模型就是助手定义绑的那个(没换过);
222
+ * `conversation` = 会话行上是另一个模型(创建时点名,或 `conversation.setModel` 改过)。
223
+ */
224
+ export type ModelSource = "agent" | "conversation";
225
+ /**
226
+ * 模型块的事实(PRD F-I6 的状态栏块)。
227
+ *
228
+ * `modelId` / `name` / `vision` 是这段会话**现在**用的那个模型,`source` 说明它是助手定义
229
+ * 给的还是这段会话自己定的。
230
+ */
231
+ export interface ModelState {
232
+ modelId: string;
233
+ name: string;
234
+ /** 这个模型能不能看图(PRD D20 / F-B8 的判定依据) */
235
+ vision: boolean;
236
+ source: ModelSource;
237
+ }
238
+ /**
239
+ * 通知的三档语气。
240
+ *
241
+ * 语气决定界面怎么摆(颜色、要不要打断),内容才是 `NoticeView.text`。
242
+ * `error` 与 `warning` 也是宿主日志上浮的通道(PRD F-J2)。
243
+ */
244
+ export type NoticeLevel = "info" | "warning" | "error";
245
+ /** 三档语气表 */
246
+ export declare const NOTICE_LEVELS: readonly NoticeLevel[];
247
+ /**
248
+ * 一条通知。
249
+ *
250
+ * `duration` 是秒数:给了则到点自动消失,`null` 表示不自动消失、靠手动清除(PRD L3)。
251
+ * 通知是独立通道,不进消息流(PRD F-I8)。
252
+ */
253
+ export interface NoticeView {
254
+ id: string;
255
+ level: NoticeLevel;
256
+ /** 秒;`null` 表示永久,直到被手动清掉 */
257
+ duration: number | null;
258
+ text: LocalizedText;
259
+ /** 与哪段对话有关;`null` 表示全局通知 */
260
+ conversationId: string | null;
261
+ createdAt: string;
262
+ }
263
+ /**
264
+ * 问题的种类。
265
+ *
266
+ * - `handoff`:到交接线时问「自交接 / 独立摘要 / 不交接」(PRD F-D2);
267
+ * - `confirmation`:不可撤销的动作前确认(PRD F-F9)。
268
+ */
269
+ export type QuestionKind = "handoff" | "confirmation";
270
+ /** 问题的种类表 */
271
+ export declare const QUESTION_KINDS: readonly QuestionKind[];
272
+ /**
273
+ * 问题的生命周期状态:挂在那里等人答 / 已答 / 过期 / 被取消。
274
+ *
275
+ * 状态是宿主的事:多端看同一个问题时看到的是同一个状态(PRD D22)。
276
+ */
277
+ export type QuestionState = "pending" | "answered" | "expired" | "cancelled";
278
+ /** 问题状态表 */
279
+ export declare const QUESTION_STATES: readonly QuestionState[];
280
+ /** 一个候选答案:值 + 显示用的两句(标题与补充说明) */
281
+ export interface QuestionOption {
282
+ /** 提交回答时回传的值 */
283
+ value: string;
284
+ label: LocalizedText;
285
+ detail: LocalizedText | null;
286
+ }
287
+ /** 已有的回答;`answeredBy` 是回答它的那条连接(多端时用来显示「别的窗口答了」) */
288
+ export interface QuestionAnswer {
289
+ value: string;
290
+ answeredAt: string;
291
+ answeredBy: string | null;
292
+ }
293
+ /**
294
+ * 问题对象:有 id、类型、候选、状态、答案(PRD D22)。
295
+ *
296
+ * `blocking` 表示这道题正挡着对话:在它被回答之前,发消息会被拒(PRD D23 / F-D10),
297
+ * 拒绝时用的业务码是 `question_pending`。
298
+ */
299
+ export interface QuestionView {
300
+ id: string;
301
+ /** 与哪段对话有关:问题总是为某一段对话停下来问的 */
302
+ conversationId: string;
303
+ kind: QuestionKind;
304
+ state: QuestionState;
305
+ prompt: LocalizedText;
306
+ options: QuestionOption[];
307
+ answer: QuestionAnswer | null;
308
+ /** 是否在挡着对话 */
309
+ blocking: boolean;
310
+ createdAt: string;
311
+ updatedAt: string;
312
+ }
313
+ /**
314
+ * 目录的事实:路径 + 还在不在。
315
+ *
316
+ * 目录不存在时对话与历史照常可用,只是不能读文件;「那就只读吧」这个判断归客户端(PRD D12),
317
+ * 宿主只给这两个字段。
318
+ */
319
+ export interface FolderFact {
320
+ cwd: string;
321
+ exists: boolean;
322
+ }
323
+ /** 一张图片 / 一个文件的上限:20MB(PRD D5 / F-H8) */
324
+ export declare const MAX_ASSET_BYTES: number;
325
+ /** 一条消息最多带几张图片(PRD D5) */
326
+ export declare const MAX_ASSETS_PER_MESSAGE = 4;
327
+ /**
328
+ * 内容段上的**本地扩展**:以 `__` 开头的键只在本机有意义(指回数据根下的一份素材)。
329
+ * 发给厂商的那一份由 core 的 `formatContent` 按字段白名单重建(`__` 开头的键因此不在里面)。
330
+ *
331
+ * 目前只有一个:`__asset_id` 指向 `assets` 表的一行。它取代了早先把 `asset://<id>` 塞进
332
+ * `image_url.url` / `file.file_id` 的做法:那两个字段是**真字段**,装一个假 scheme 会让
333
+ * 「这一段的 url 是空的」与「这一段的 url 指向本机素材」看起来是同一件事。
334
+ */
335
+ export interface LocalSectionExtensions {
336
+ /** 这一段引用的素材 id(缺省 / 空串表示「这一段不引用素材」) */
337
+ __asset_id?: string;
338
+ }
339
+ /**
340
+ * 带本地扩展的内容段:core 的内容段 + `__` 开头的本机字段(交叉类型,不改 core)。
341
+ *
342
+ * 落库形态(`messages.content` 的 JSON):
343
+ *
344
+ * ```json
345
+ * { "index": 1, "type": "image_url", "image_url": { "url": "" }, "__asset_id": "9f3c…" }
346
+ * { "index": 2, "type": "file", "filename": "报表.pdf", "__asset_id": "c3d4…" }
347
+ * ```
348
+ */
349
+ export type LocalMessageContentSection = AgentNS.MessageContentSection & LocalSectionExtensions;
350
+ /** 带本地扩展的正文:字符串原样,数组里的每一段可能带 `__` 字段 */
351
+ export type LocalMessageContent = string | LocalMessageContentSection[];
352
+ /**
353
+ * 一个内容段里的素材 id(没有这个扩展字段时为空)。
354
+ *
355
+ * 判断依据就是「有没有这个字段」,不解析任何 scheme:段上的 url 是什么都不影响这个结论。
356
+ */
357
+ export declare function localAssetIdOf(section: AgentNS.MessageContentSection): string | null;
358
+ /**
359
+ * 素材引用:库与消息里存的是引用,字节落数据根的 `assets/`(PRD L2 / F-H8)。
360
+ *
361
+ * 带 `bytes` / `mime` / 尺寸这些事实,客户端据此排占位框,不必先下载再量。
362
+ * 它是**上传的产物**(`asset.end` 回的),也是**去重命中时的答案**(`asset.begin` 的 `asset`)。
363
+ * 消息里持久化的是段上的本地扩展字段 `__asset_id`(见 {@link LocalMessageContentSection}),
364
+ * 不是这个对象本身:内容要回了原图、要换模型重发时都从 `assets` 这一份真相重算
365
+ * (`asset.get` 取字节)。
366
+ */
367
+ export interface AssetRef {
368
+ assetId: string;
369
+ /** MIME 类型,如 `image/png` */
370
+ mime: string;
371
+ /** 字节数 */
372
+ bytes: number;
373
+ /** 原始文件名(可缺) */
374
+ name: string | null;
375
+ width: number | null;
376
+ height: number | null;
377
+ }
378
+ /**
379
+ * 一次用户输入。
380
+ *
381
+ * 内容本体就是 core 的那一份:`AgentNS.MessageContent`(纯文本字符串,或
382
+ * `text` / `image_url` / `file` 内容段数组)。这里只补一样 core 没有的东西:已上传但还没
383
+ * 变成内容段的素材 id —— 素材怎么变成内容段(文件引用 / 内联 / 退化成文字)由宿主按
384
+ * 实发模型决定(PRD F-H7),客户端只说「用了哪几张」。
385
+ *
386
+ * 落库的 content 里素材写成段上的 `__asset_id`(`image_url.url` / `file.file_id` 留空):
387
+ * 厂商的 `file_id`、base64、绝对路径都是「这一次发送的产物」,不进库。
388
+ */
389
+ export interface MessageInput {
390
+ /** 用户输入的内容,core 原样 */
391
+ content: AgentNS.MessageContent;
392
+ /** 已上传、待转成内容段的素材 id(顺序即用户的摆放顺序);没有素材时省略 */
393
+ assetIds?: string[];
394
+ }
395
+ /** 附件真正发出去时用的路径:文件引用 / 内联 / 退化成文字 / 没发出去 */
396
+ export type AttachmentDelivery = "file_reference" | "inline" | "text_fallback" | "dropped";
397
+ /**
398
+ * 一个附件这一轮的结局(PRD F-H7:失败要告警、全失败退回纯文本、不假成功)。
399
+ *
400
+ * 宿主说清「它最后是怎么走的」「变成了哪个内容段」与「没成功的原因」,客户端据此显示
401
+ * 告警或保持沉默。`section` 用的是 core 的内容段类型:内联图片是 `image_url` 段、
402
+ * Files API 是 `file` 段、降级成文字是 `text` 段。
403
+ */
404
+ export interface AttachmentOutcome {
405
+ assetId: string;
406
+ deliveredAs: AttachmentDelivery;
407
+ /** 真正拼进消息的那个内容段,core 原样;没发出去时为空 */
408
+ section: AgentNS.MessageContentSection | null;
409
+ /** 没送达/降级时的人话原因 */
410
+ problem: ProblemFact | null;
411
+ }
412
+ /**
413
+ * 状态栏每一块的事实。块名固定,块内结构按块名不同而不同(判别式联合)。
414
+ *
415
+ * 这样的好处是:宿主给的是可排版的块,客户端决定摆哪几块、摆在哪(PRD F-I6 /
416
+ * 「宿主给能力、客户端给交互」),双方都不需要解析一整行字符串。
417
+ */
418
+ export type StatusBlock = {
419
+ id: "agent";
420
+ label: LocalizedText;
421
+ /**
422
+ * 助手块的三个事实。
423
+ *
424
+ * `agentId` 是这段对话的身份(创建时定死,L7);`name` 与 `available` 由 `conversation.state`
425
+ * 现读助手定义得出(`AgentService.describe`)。定义已经没了(助手被删,L7 允许对话留着旧 id)
426
+ * 或文件读不出来时,这两项都是 `null` —— 说「不知道」而不是编一个值。
427
+ */
428
+ facts: {
429
+ agentId: string;
430
+ name: string | null;
431
+ available: boolean | null;
432
+ };
433
+ } | {
434
+ id: "model";
435
+ label: LocalizedText;
436
+ facts: ModelState;
437
+ } | {
438
+ id: "thinking";
439
+ label: LocalizedText;
440
+ facts: ThinkingState;
441
+ } | {
442
+ id: "context";
443
+ label: LocalizedText;
444
+ facts: ContextState;
445
+ } | {
446
+ id: "usage";
447
+ label: LocalizedText;
448
+ facts: UsageSnapshot;
449
+ } | {
450
+ id: "cwd";
451
+ label: LocalizedText;
452
+ facts: FolderFact;
453
+ } | {
454
+ id: "tools";
455
+ label: LocalizedText;
456
+ facts: {
457
+ running: RunningTool[];
458
+ };
459
+ } | {
460
+ id: "subagents";
461
+ label: LocalizedText;
462
+ facts: {
463
+ items: SubAgentSnapshot[];
464
+ };
465
+ };
466
+ /** 状态栏块的 id */
467
+ export type StatusBlockId = StatusBlock["id"];
468
+ /** 全部块 id,按建议的摆放顺序 */
469
+ export declare const STATUS_BLOCK_IDS: readonly StatusBlockId[];
470
+ /**
471
+ * 一段对话的现场:在跑哪一轮、上下文用了多少、有没有问题挂着、用量多少。
472
+ *
473
+ * 重连的客户端拿这一份就能把界面摆回原样,再按 `message.list`(带 `after`)补齐消息。
474
+ */
475
+ export interface ConversationState {
476
+ conversationId: string;
477
+ run: RunState;
478
+ context: ContextState;
479
+ thinking: ThinkingState;
480
+ usage: UsageSnapshot;
481
+ /** 挂在这段对话上的问题(含已回答/已过期的,客户端按状态决定要不要显示) */
482
+ questions: QuestionView[];
483
+ /** 状态栏的块(PRD F-I6) */
484
+ statusBlocks: StatusBlock[];
485
+ /** 这份快照的时间 */
486
+ updatedAt: string;
487
+ }
@@ -0,0 +1,61 @@
1
+ import { ZERO_USAGE } from "@ai-zen/agents-core";
2
+ /** 六态的取值表,运行时校验与测试遍历用 */
3
+ export const GENERATION_PHASES = [
4
+ "connected",
5
+ "awaiting_first_token",
6
+ "thinking",
7
+ "generating",
8
+ "assembling_tool_calls",
9
+ "awaiting_tools",
10
+ ];
11
+ /** 一份零值用量快照(三个口径都是 core 的零值 `Usage`) */
12
+ export function zeroUsage(now) {
13
+ return {
14
+ turn: { ...ZERO_USAGE },
15
+ total: { ...ZERO_USAGE },
16
+ subAgent: { ...ZERO_USAGE },
17
+ rate: { value: 0, unit: "tokens_per_second", basis: "completion" },
18
+ updatedAt: now,
19
+ };
20
+ }
21
+ /** 三档语气表 */
22
+ export const NOTICE_LEVELS = ["info", "warning", "error"];
23
+ /** 问题的种类表 */
24
+ export const QUESTION_KINDS = ["handoff", "confirmation"];
25
+ /** 问题状态表 */
26
+ export const QUESTION_STATES = [
27
+ "pending",
28
+ "answered",
29
+ "expired",
30
+ "cancelled",
31
+ ];
32
+ // ---------------------------------------------------------------------------
33
+ // 素材与用户输入(PRD F-H7 / F-H8 / D5)
34
+ // ---------------------------------------------------------------------------
35
+ /** 一张图片 / 一个文件的上限:20MB(PRD D5 / F-H8) */
36
+ export const MAX_ASSET_BYTES = 20 * 1024 * 1024;
37
+ /** 一条消息最多带几张图片(PRD D5) */
38
+ export const MAX_ASSETS_PER_MESSAGE = 4;
39
+ /**
40
+ * 一个内容段里的素材 id(没有这个扩展字段时为空)。
41
+ *
42
+ * 判断依据就是「有没有这个字段」,不解析任何 scheme:段上的 url 是什么都不影响这个结论。
43
+ */
44
+ export function localAssetIdOf(section) {
45
+ const value = section.__asset_id;
46
+ if (typeof value !== "string")
47
+ return null;
48
+ const trimmed = value.trim();
49
+ return trimmed === "" ? null : trimmed;
50
+ }
51
+ /** 全部块 id,按建议的摆放顺序 */
52
+ export const STATUS_BLOCK_IDS = [
53
+ "agent",
54
+ "model",
55
+ "thinking",
56
+ "context",
57
+ "usage",
58
+ "cwd",
59
+ "tools",
60
+ "subagents",
61
+ ];