@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,143 @@
1
+ import { DEFAULT_LANGUAGE, render, } from "../i18n/index.js";
2
+ /** 全部业务码;用于校验与测试遍历 */
3
+ export const BIZ_CODES = [
4
+ "unauthorized",
5
+ "invalid_params",
6
+ "not_found",
7
+ "busy",
8
+ "payload_too_large",
9
+ "unsupported",
10
+ "internal",
11
+ "config_invalid",
12
+ "mcp_unavailable",
13
+ "model_unsupported",
14
+ "handoff_declined",
15
+ "question_pending",
16
+ "context_guard",
17
+ ];
18
+ /** 业务码 → 默认文案键(`HostError` 不指定 `messageKey` 时用它) */
19
+ const DEFAULT_MESSAGE_KEY = {
20
+ unauthorized: "error.unauthorized",
21
+ invalid_params: "error.invalidParams",
22
+ not_found: "error.notFound",
23
+ busy: "error.busy",
24
+ payload_too_large: "error.payloadTooLarge",
25
+ unsupported: "error.unsupported",
26
+ internal: "error.internal",
27
+ config_invalid: "error.configInvalid",
28
+ mcp_unavailable: "error.mcpUnavailable",
29
+ model_unsupported: "error.modelUnsupported",
30
+ handoff_declined: "error.handoffDeclined",
31
+ question_pending: "error.questionPending",
32
+ context_guard: "error.contextGuard",
33
+ };
34
+ /**
35
+ * 业务码 → JSON-RPC 数字码。
36
+ *
37
+ * 标准里只有少数几个数字码有意义(-32700 解析、-32600 非法请求、-32601 无此方法、
38
+ * -32602 参数、-32603 内部);产品层面的处境统一落在 `-32000 .. -32099` 这段
39
+ * 「实现自定义」区间,真伪以 `data.code` 为准(PRD A4:不按标准的错误码空间走)。
40
+ */
41
+ const JSON_RPC_CODE = {
42
+ invalid_params: -32602,
43
+ internal: -32603,
44
+ unauthorized: -32001,
45
+ not_found: -32004,
46
+ busy: -32005,
47
+ payload_too_large: -32006,
48
+ unsupported: -32601,
49
+ config_invalid: -32008,
50
+ mcp_unavailable: -32009,
51
+ model_unsupported: -32010,
52
+ handoff_declined: -32011,
53
+ question_pending: -32012,
54
+ context_guard: -32013,
55
+ };
56
+ /** 业务码对应的 JSON-RPC 数字码 */
57
+ export function jsonRpcCode(code) {
58
+ return JSON_RPC_CODE[code];
59
+ }
60
+ /** 业务码对应的默认文案键 */
61
+ export function defaultMessageKey(code) {
62
+ return DEFAULT_MESSAGE_KEY[code];
63
+ }
64
+ /** 运行时判断一个值是不是已知业务码 */
65
+ export function isBizCode(value) {
66
+ return typeof value === "string" && BIZ_CODES.includes(value);
67
+ }
68
+ /**
69
+ * 宿主抛给接线的错误:带业务码、文案键与渲染参数,出网时按连接语言渲染。
70
+ *
71
+ * 业务层只管用码与参数描述「哪里不对」,不拼句子、不碰语言 —— 语言是连接的事。
72
+ */
73
+ export class HostError extends Error {
74
+ code;
75
+ messageKey;
76
+ params;
77
+ detail;
78
+ constructor(code, options = {}) {
79
+ const messageKey = options.messageKey ?? defaultMessageKey(code);
80
+ // `Error.message` 只给日志和调试看:固定用默认语言渲染一份,免得日志里出现空消息
81
+ super(render(DEFAULT_LANGUAGE, messageKey, options.params));
82
+ this.name = "HostError";
83
+ this.code = code;
84
+ this.messageKey = messageKey;
85
+ this.params = options.params;
86
+ this.detail = options.detail;
87
+ if (options.cause !== undefined) {
88
+ this.cause = options.cause;
89
+ }
90
+ }
91
+ /** 渲染成错误帧里的 `data`(PRD D8:按连接语言出人话) */
92
+ toErrorData(language = DEFAULT_LANGUAGE) {
93
+ const params = this.params ?? {};
94
+ const data = {
95
+ code: this.code,
96
+ message: render(language, this.messageKey, params),
97
+ params,
98
+ };
99
+ if (this.detail !== undefined) {
100
+ data.detail = this.detail;
101
+ }
102
+ return data;
103
+ }
104
+ /** 换一条更适合当前上下文的文案键(例如带上具体实体名),返回新实例 */
105
+ withMessage(messageKey, params) {
106
+ return new HostError(this.code, {
107
+ messageKey,
108
+ params: params ?? this.params,
109
+ detail: this.detail,
110
+ cause: this.cause,
111
+ });
112
+ }
113
+ /** 追加结构化事实后返回新实例 */
114
+ withDetail(detail) {
115
+ return new HostError(this.code, {
116
+ messageKey: this.messageKey,
117
+ params: this.params,
118
+ detail,
119
+ cause: this.cause,
120
+ });
121
+ }
122
+ /** 判断任意值是不是 `HostError`(跨模块实例判断用不到 `instanceof` 的场合) */
123
+ static is(value) {
124
+ return value instanceof HostError;
125
+ }
126
+ }
127
+ /**
128
+ * 把任意抛出物收敛成 `ErrorData`。
129
+ *
130
+ * 接线层只会写一次 `catch`,其它错误(`TypeError`、SDK 抛的、字符串)都在这里被兜成
131
+ * `internal`,原始信息进 `detail.reason` 供排查 —— 于是界面上是一句人话,而不是一堆堆栈。
132
+ */
133
+ export function toErrorData(error, language = DEFAULT_LANGUAGE) {
134
+ if (HostError.is(error))
135
+ return error.toErrorData(language);
136
+ const reason = error instanceof Error ? error.message : String(error);
137
+ return {
138
+ code: "internal",
139
+ message: render(language, "error.internal"),
140
+ params: {},
141
+ detail: { reason },
142
+ };
143
+ }
@@ -0,0 +1,102 @@
1
+ import type { AgentNS } from "@ai-zen/agents-core";
2
+ import type { NoticeView, QuestionView, RunState, UsageSnapshot } from "./states.js";
3
+ /**
4
+ * 事件(宿主 → 客户端的推送,见 architecture §7)。
5
+ *
6
+ * 推送是 JSON-RPC 通知(无 id),`params` 里带事件名与数据;不重放、不需要 ack —— 断线即作废,
7
+ * 重连由客户端按 D5 自己拉状态与消息。所以这里的每个事件都只是「在线时的一脚提醒」:
8
+ * 真正的事实要能从 `conversation.state` / `message.list` 再拉出来(PRD L5)。
9
+ *
10
+ * 一条约定:事件只描述「发生了什么变化」,客户端需要完整对象时回宿主拉 ——
11
+ * 这样多端同时在线时不会出现「一份数据在推送里长成另一种形状」。
12
+ *
13
+ * 流式增量的载荷是 core 的 `AgentNS.Delta` 原样:它描述的正是一片 chunk 带来了什么
14
+ * (`content` / `reasoning_content` / `tool_calls` / …),`applyChunk` 吃的是同一份,
15
+ * 所以客户端攒出来的消息与宿主存下来的那条逐字一致。
16
+ */
17
+ /**
18
+ * `run.state`:一段对话的运行状态变化(六态见 `states.ts` 的 `GenerationState`)。
19
+ *
20
+ * 发全量快照而不是「变成第几态」的差量:客户端任何时刻拿到一条就能直接替换本地状态,
21
+ * 不必先对齐历史(重连时尤其要紧,PRD L5)。
22
+ */
23
+ export interface RunStatePayload {
24
+ conversationId: string;
25
+ run: RunState;
26
+ /** 生成这份快照的时刻 */
27
+ at: string;
28
+ }
29
+ /**
30
+ * `message.delta`:一条消息的流式增量(PRD L5:在线时推送;断线后靠 `message.list` 补拉)。
31
+ *
32
+ * 增量本体是 core 的 `AgentNS.Delta`,这一片属于哪一段由它自己带的字段说明:`content` 是
33
+ * 正文、`reasoning_content` 是思考、`tool_calls` 是工具调用(PRD F-I2 的那三段)。
34
+ * 外壳只带定位信息:哪个对话、哪条消息、这条消息内的第几片。
35
+ *
36
+ * `seq` 是这条消息内的递增序号,客户端用它发现「漏了一片」并在重连后重拉整条。
37
+ */
38
+ export interface MessageDeltaPayload {
39
+ conversationId: string;
40
+ messageId: string;
41
+ /** 这条消息内的序号,从 0 开始递增 */
42
+ seq: number;
43
+ /** 这一片增量,core 原样 */
44
+ delta: AgentNS.Delta;
45
+ /** 这次推送的时刻 */
46
+ at: string;
47
+ }
48
+ /**
49
+ * 结构变化的种类。客户端看到它就去拉对应的东西(PRD L5 / `conversation.changed`)。
50
+ *
51
+ * 事件的用途是「告诉客户端该去拉了」,所以这里只给变化的名字与够用的定位信息,
52
+ * 不试图把变化后的整个对象塞进推送里。
53
+ */
54
+ export type ConversationChangeKind = "created" | "renamed" | "pinned" | "messages_persisted" | "message_removed" | "settings_changed" | "deleted";
55
+ /** `conversation.changed`:改名、置顶、新增消息已落库、删除等结构变化 */
56
+ export interface ConversationChangedPayload {
57
+ conversationId: string;
58
+ /** 所属 Workspace;对话被删后仍带上,便于客户端把它从对应列表里摘掉 */
59
+ workspaceId: string | null;
60
+ change: ConversationChangeKind;
61
+ /** 变化后这段对话的消息条数(删掉整段对话时为空) */
62
+ messageCount: number | null;
63
+ at: string;
64
+ }
65
+ /** `notice`:新通知(三档语气 + `duration`,PRD L3 / F-I8) */
66
+ export interface NoticePayload {
67
+ notice: NoticeView;
68
+ at: string;
69
+ }
70
+ /** `question`:问题对象被创建或被回答(多端看到同一个,PRD D22 / F-I9) */
71
+ export interface QuestionPayload {
72
+ question: QuestionView;
73
+ at: string;
74
+ }
75
+ /** `usage`:用量变化(本轮 / 累计 / 速率,PRD F-I5) */
76
+ export interface UsagePayload {
77
+ conversationId: string;
78
+ usage: UsageSnapshot;
79
+ at: string;
80
+ }
81
+ /**
82
+ * 事件名 → 载荷。
83
+ *
84
+ * 名称按 architecture §7 定:`run.state`、`message.delta`、`conversation.changed`、
85
+ * `notice`、`question`、`usage`。
86
+ */
87
+ export interface EventMap {
88
+ "run.state": RunStatePayload;
89
+ "message.delta": MessageDeltaPayload;
90
+ "conversation.changed": ConversationChangedPayload;
91
+ notice: NoticePayload;
92
+ question: QuestionPayload;
93
+ usage: UsagePayload;
94
+ }
95
+ /** 事件名 */
96
+ export type EventName = keyof EventMap;
97
+ /** 取某个事件的载荷类型 */
98
+ export type EventPayload<E extends EventName> = EventMap[E];
99
+ /** 全部事件名(接线层注册推送、测试遍历用) */
100
+ export declare const EVENT_NAMES: readonly ["run.state", "message.delta", "conversation.changed", "notice", "question", "usage"];
101
+ /** 运行时判断一个字符串是不是已知事件名 */
102
+ export declare function isEventName(value: unknown): value is EventName;
@@ -0,0 +1,13 @@
1
+ /** 全部事件名(接线层注册推送、测试遍历用) */
2
+ export const EVENT_NAMES = [
3
+ "run.state",
4
+ "message.delta",
5
+ "conversation.changed",
6
+ "notice",
7
+ "question",
8
+ "usage",
9
+ ];
10
+ /** 运行时判断一个字符串是不是已知事件名 */
11
+ export function isEventName(value) {
12
+ return typeof value === "string" && EVENT_NAMES.includes(value);
13
+ }
@@ -0,0 +1,106 @@
1
+ import type { Language } from "../i18n/index.js";
2
+ import { type ErrorData } from "./errors.js";
3
+ import type { EventName, EventPayload } from "./events.js";
4
+ /**
5
+ * JSON-RPC 2.0 帧(architecture §6)。
6
+ *
7
+ * 以标准为底,产品形状长在 `params` / `result`(PRD A4)。标准里对我们有负担的部分不用,
8
+ * 具体是:
9
+ * - **批量请求**:帧是数组时直接拒(`unsupported`)—— 一条连接上并发靠多条请求就够,
10
+ * 批量会带来「数组里部分成功」这种没法向用户解释的结果;
11
+ * - 强制错误码空间:数字码只做粗分类,真伪看 `error.data.code`(见 `errors.ts`);
12
+ * - 「通知必须无 id」:标准里带 id 的帧就是请求,而我们出网的通知不带 id(客户端也不需要回什么)。
13
+ *
14
+ * 入站只可能收到 request / notification;response 两种在客户端侧解析时用得着,
15
+ * 所以守卫函数也一并给全,客户端可以直接复用这一份代码。
16
+ */
17
+ /** 请求 id:字符串或数字(宿主分配或回显客户端给的;`null` 只出现在错误响应里) */
18
+ export type JsonRpcId = string | number;
19
+ /** 请求帧(要回一个响应) */
20
+ export interface JsonRpcRequestFrame {
21
+ jsonrpc: "2.0";
22
+ id: JsonRpcId;
23
+ method: string;
24
+ params?: unknown;
25
+ }
26
+ /** 通知帧(不需要响应) */
27
+ export interface JsonRpcNotificationFrame {
28
+ jsonrpc: "2.0";
29
+ method: string;
30
+ params?: unknown;
31
+ }
32
+ /** 错误对象:数字码 + 一句短描述 + `data`(业务码、人话、结构化事实) */
33
+ export interface JsonRpcError {
34
+ code: number;
35
+ message: string;
36
+ data: ErrorData;
37
+ }
38
+ /** 成功响应帧 */
39
+ export interface JsonRpcSuccessFrame {
40
+ jsonrpc: "2.0";
41
+ id: JsonRpcId;
42
+ result: unknown;
43
+ }
44
+ /** 错误响应帧;`id` 为 `null` 表示「连 id 都没解析出来」 */
45
+ export interface JsonRpcErrorFrame {
46
+ jsonrpc: "2.0";
47
+ id: JsonRpcId | null;
48
+ error: JsonRpcError;
49
+ }
50
+ /** 两种响应帧 */
51
+ export type JsonRpcResponseFrame = JsonRpcSuccessFrame | JsonRpcErrorFrame;
52
+ /**
53
+ * 解析后的帧:分好类、参数已挑出来。
54
+ *
55
+ * 分四类而不是三类,是因为「客户端发来的错误响应」在宿主看来是一种不该来的东西,
56
+ * 与「客户端发来的成功响应」需要分别处置;两者都保留形状,方便客户端复用本模块。
57
+ */
58
+ export type Frame = {
59
+ kind: "request";
60
+ id: JsonRpcId;
61
+ method: string;
62
+ params: unknown;
63
+ } | {
64
+ kind: "notification";
65
+ method: string;
66
+ params: unknown;
67
+ } | {
68
+ kind: "response";
69
+ id: JsonRpcId;
70
+ result: unknown;
71
+ } | {
72
+ kind: "error";
73
+ id: JsonRpcId | null;
74
+ error: JsonRpcError;
75
+ };
76
+ /** 是不是请求帧 */
77
+ export declare function isRequestFrame(value: unknown): value is JsonRpcRequestFrame;
78
+ /** 是不是通知帧(无 id,或 id 为 null —— 后者在标准里含糊,按通知处理) */
79
+ export declare function isNotificationFrame(value: unknown): value is JsonRpcNotificationFrame;
80
+ /** 是不是成功响应帧(含 `result`) */
81
+ export declare function isSuccessFrame(value: unknown): value is JsonRpcSuccessFrame;
82
+ /** 是不是错误响应帧(含 `error`) */
83
+ export declare function isErrorFrame(value: unknown): value is JsonRpcErrorFrame;
84
+ /** 是不是任一方向的响应帧 */
85
+ export declare function isResponseFrame(value: unknown): value is JsonRpcResponseFrame;
86
+ /**
87
+ * 把一条入站消息解析成 `Frame`。
88
+ *
89
+ * 三种拒绝各有稳定业务码:
90
+ * - 不是合法 JSON / 不是对象 → `invalid_params`(`detail.reason` 说明是哪一步坏的);
91
+ * - 数组(批量请求)→ `unsupported`,`detail.reason` 为 `batch_not_supported`;
92
+ * - 缺 `jsonrpc` / 缺 `method` / id 类型不对 → `invalid_params`,`detail.field` 指出字段。
93
+ */
94
+ export declare function parseFrame(input: unknown): Frame;
95
+ /** 成功响应 */
96
+ export declare function okResponse(id: JsonRpcId, result: unknown): JsonRpcSuccessFrame;
97
+ /**
98
+ * 错误响应。
99
+ *
100
+ * `error.message` 与 `error.data.message` 都是**按连接语言渲染好的那句话**:前者满足标准
101
+ * 对「一句短描述」的要求,后者是客户端真正显示的东西(PRD D8)。
102
+ * 传入非 `HostError` 时会被收敛成 `internal`(`detail.reason` 留着原始信息)。
103
+ */
104
+ export declare function errResponse(id: JsonRpcId | null, error: unknown, language: Language): JsonRpcErrorFrame;
105
+ /** 通知帧:宿主推送事件用(`notification("run.state", payload)`) */
106
+ export declare function notification<E extends EventName>(event: E, payload: EventPayload<E>): JsonRpcNotificationFrame;
@@ -0,0 +1,156 @@
1
+ import { HostError, jsonRpcCode, toErrorData } from "./errors.js";
2
+ // ---------------------------------------------------------------------------
3
+ // 守卫
4
+ // ---------------------------------------------------------------------------
5
+ function isRecord(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ function isId(value) {
9
+ return typeof value === "string" || (typeof value === "number" && Number.isFinite(value));
10
+ }
11
+ function hasProtocol(value) {
12
+ return value.jsonrpc === "2.0";
13
+ }
14
+ /** 是不是请求帧 */
15
+ export function isRequestFrame(value) {
16
+ if (!isRecord(value))
17
+ return false;
18
+ if (!hasProtocol(value))
19
+ return false;
20
+ return typeof value.method === "string" && value.method !== "" && isId(value.id);
21
+ }
22
+ /** 是不是通知帧(无 id,或 id 为 null —— 后者在标准里含糊,按通知处理) */
23
+ export function isNotificationFrame(value) {
24
+ if (!isRecord(value))
25
+ return false;
26
+ if (!hasProtocol(value))
27
+ return false;
28
+ if (typeof value.method !== "string" || value.method === "")
29
+ return false;
30
+ return value.id === undefined || value.id === null;
31
+ }
32
+ /** 是不是成功响应帧(含 `result`) */
33
+ export function isSuccessFrame(value) {
34
+ if (!isRecord(value))
35
+ return false;
36
+ if (!hasProtocol(value))
37
+ return false;
38
+ return isId(value.id) && "result" in value && !("error" in value);
39
+ }
40
+ /** 是不是错误响应帧(含 `error`) */
41
+ export function isErrorFrame(value) {
42
+ if (!isRecord(value))
43
+ return false;
44
+ if (!hasProtocol(value))
45
+ return false;
46
+ const id = value.id;
47
+ if (!(id === null || isId(id)))
48
+ return false;
49
+ return isRecord(value.error);
50
+ }
51
+ /** 是不是任一方向的响应帧 */
52
+ export function isResponseFrame(value) {
53
+ return isSuccessFrame(value) || isErrorFrame(value);
54
+ }
55
+ // ---------------------------------------------------------------------------
56
+ // 解析
57
+ // ---------------------------------------------------------------------------
58
+ function invalidFrame(detail, field) {
59
+ return new HostError("invalid_params", {
60
+ params: { field },
61
+ detail,
62
+ });
63
+ }
64
+ /**
65
+ * 把一条入站消息解析成 `Frame`。
66
+ *
67
+ * 三种拒绝各有稳定业务码:
68
+ * - 不是合法 JSON / 不是对象 → `invalid_params`(`detail.reason` 说明是哪一步坏的);
69
+ * - 数组(批量请求)→ `unsupported`,`detail.reason` 为 `batch_not_supported`;
70
+ * - 缺 `jsonrpc` / 缺 `method` / id 类型不对 → `invalid_params`,`detail.field` 指出字段。
71
+ */
72
+ export function parseFrame(input) {
73
+ let value = input;
74
+ if (typeof value === "string") {
75
+ try {
76
+ value = JSON.parse(value);
77
+ }
78
+ catch (error) {
79
+ throw invalidFrame({ reason: "not_json", text: error instanceof Error ? error.message : String(error) }, "jsonrpc");
80
+ }
81
+ }
82
+ if (Array.isArray(value)) {
83
+ throw new HostError("unsupported", {
84
+ params: { what: "batch requests" },
85
+ detail: { reason: "batch_not_supported", count: value.length },
86
+ });
87
+ }
88
+ if (!isRecord(value)) {
89
+ throw invalidFrame({ reason: "not_an_object" }, "jsonrpc");
90
+ }
91
+ if (!hasProtocol(value)) {
92
+ throw invalidFrame({ reason: "bad_protocol", got: value.jsonrpc ?? null }, "jsonrpc");
93
+ }
94
+ if (typeof value.method === "string") {
95
+ if (value.method === "") {
96
+ throw invalidFrame({ reason: "empty_method" }, "method");
97
+ }
98
+ const params = value.params ?? {};
99
+ if (isId(value.id)) {
100
+ return { kind: "request", id: value.id, method: value.method, params };
101
+ }
102
+ if (value.id === undefined || value.id === null) {
103
+ return { kind: "notification", method: value.method, params };
104
+ }
105
+ throw invalidFrame({ reason: "bad_id", got: value.id }, "id");
106
+ }
107
+ if ("error" in value) {
108
+ const error = value.error;
109
+ if (!isRecord(error)) {
110
+ throw invalidFrame({ reason: "bad_error_object" }, "error");
111
+ }
112
+ return { kind: "error", id: isId(value.id) ? value.id : null, error: parseErrorObject(error) };
113
+ }
114
+ if ("result" in value) {
115
+ if (!isId(value.id)) {
116
+ throw invalidFrame({ reason: "bad_id", got: value.id ?? null }, "id");
117
+ }
118
+ return { kind: "response", id: value.id, result: value.result };
119
+ }
120
+ throw invalidFrame({ reason: "neither_method_nor_result" }, "method");
121
+ }
122
+ /** 解析入站的错误对象;字段缺失时按 `internal` 兜底,让解析不至于半路炸掉 */
123
+ function parseErrorObject(value) {
124
+ const code = typeof value.code === "number" && Number.isFinite(value.code) ? value.code : -32603;
125
+ const message = typeof value.message === "string" ? value.message : "";
126
+ const data = isRecord(value.data) ? value.data : null;
127
+ return { code, message, data: data ?? { code: "internal", message, params: {} } };
128
+ }
129
+ // ---------------------------------------------------------------------------
130
+ // 构造
131
+ // ---------------------------------------------------------------------------
132
+ /** 成功响应 */
133
+ export function okResponse(id, result) {
134
+ return { jsonrpc: "2.0", id, result };
135
+ }
136
+ /**
137
+ * 错误响应。
138
+ *
139
+ * `error.message` 与 `error.data.message` 都是**按连接语言渲染好的那句话**:前者满足标准
140
+ * 对「一句短描述」的要求,后者是客户端真正显示的东西(PRD D8)。
141
+ * 传入非 `HostError` 时会被收敛成 `internal`(`detail.reason` 留着原始信息)。
142
+ */
143
+ export function errResponse(id, error, language) {
144
+ const data = toErrorData(error, language);
145
+ // 数字码表与 errors.ts 同源,一处维护
146
+ const numericCode = HostError.is(error) ? jsonRpcCode(error.code) : -32603;
147
+ return {
148
+ jsonrpc: "2.0",
149
+ id,
150
+ error: { code: numericCode, message: data.message, data },
151
+ };
152
+ }
153
+ /** 通知帧:宿主推送事件用(`notification("run.state", payload)`) */
154
+ export function notification(event, payload) {
155
+ return { jsonrpc: "2.0", method: event, params: payload };
156
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 契约层出口。
3
+ *
4
+ * 客户端照这份形状接线;宿主接线层(`net/`)按 `MethodMap` 分发、按 `EventMap` 推送。
5
+ * 这里只做再导出,不新增语义。
6
+ *
7
+ * core 的消息相关类型一并再导出:客户端 `import type { AgentNS } from "@ai-zen/agents-host"`
8
+ * 就能拿到消息、消息内容段、工具调用、状态、角色、结束原因、增量与用量的**同一份定义**,
9
+ * 不必自己再抄一份 —— 抄出来的第二份迟早与宿主存下来的那条对不上。
10
+ */
11
+ export * from "./errors.js";
12
+ export * from "./states.js";
13
+ export * from "./methods.js";
14
+ export * from "./events.js";
15
+ export * from "./frames.js";
16
+ /**
17
+ * `AgentNS` 既是类型空间的容器(`AgentNS.Message` / `AgentNS.MessageContent` /
18
+ * `AgentNS.ToolCall` / `AgentNS.Delta` / `AgentNS.Usage` …),也是运行期的枚举表
19
+ * (`AgentNS.Role` / `AgentNS.MessageStatus` / `AgentNS.FinishReason` 的取值)。
20
+ */
21
+ export { AgentNS } from "@ai-zen/agents-core";
22
+ /**
23
+ * 用量的零值、逐字段相加与求和:`sumUsage` 会把消息自身用量与子 Agent 用量一起累加,
24
+ * 累计口径与计费一致。客户端做本地估算时直接用它,免得自己写第二套加法。
25
+ */
26
+ export { ZERO_USAGE, addUsage, sumUsage } from "@ai-zen/agents-core";
27
+ /**
28
+ * 把一片增量攒进一条消息。宿主自己是这么攒的,客户端折 `message.delta` 时用同一份实现,
29
+ * 攒出来的消息与宿主存下来的逐字一致。
30
+ */
31
+ export { applyChunk } from "@ai-zen/agents-core";
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 契约层出口。
3
+ *
4
+ * 客户端照这份形状接线;宿主接线层(`net/`)按 `MethodMap` 分发、按 `EventMap` 推送。
5
+ * 这里只做再导出,不新增语义。
6
+ *
7
+ * core 的消息相关类型一并再导出:客户端 `import type { AgentNS } from "@ai-zen/agents-host"`
8
+ * 就能拿到消息、消息内容段、工具调用、状态、角色、结束原因、增量与用量的**同一份定义**,
9
+ * 不必自己再抄一份 —— 抄出来的第二份迟早与宿主存下来的那条对不上。
10
+ */
11
+ export * from "./errors.js";
12
+ export * from "./states.js";
13
+ export * from "./methods.js";
14
+ export * from "./events.js";
15
+ export * from "./frames.js";
16
+ /**
17
+ * `AgentNS` 既是类型空间的容器(`AgentNS.Message` / `AgentNS.MessageContent` /
18
+ * `AgentNS.ToolCall` / `AgentNS.Delta` / `AgentNS.Usage` …),也是运行期的枚举表
19
+ * (`AgentNS.Role` / `AgentNS.MessageStatus` / `AgentNS.FinishReason` 的取值)。
20
+ */
21
+ export { AgentNS } from "@ai-zen/agents-core";
22
+ /**
23
+ * 用量的零值、逐字段相加与求和:`sumUsage` 会把消息自身用量与子 Agent 用量一起累加,
24
+ * 累计口径与计费一致。客户端做本地估算时直接用它,免得自己写第二套加法。
25
+ */
26
+ export { ZERO_USAGE, addUsage, sumUsage } from "@ai-zen/agents-core";
27
+ /**
28
+ * 把一片增量攒进一条消息。宿主自己是这么攒的,客户端折 `message.delta` 时用同一份实现,
29
+ * 攒出来的消息与宿主存下来的逐字一致。
30
+ */
31
+ export { applyChunk } from "@ai-zen/agents-core";