@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.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +759 -2
- package/dist/app.d.ts +384 -0
- package/dist/app.js +1148 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.js +353 -0
- package/dist/config.d.ts +97 -0
- package/dist/config.js +171 -0
- package/dist/handlers/agentHandlers.d.ts +18 -0
- package/dist/handlers/agentHandlers.js +20 -0
- package/dist/handlers/assetHandlers.d.ts +29 -0
- package/dist/handlers/assetHandlers.js +35 -0
- package/dist/handlers/capabilities.d.ts +26 -0
- package/dist/handlers/capabilities.js +138 -0
- package/dist/handlers/completionHandlers.d.ts +18 -0
- package/dist/handlers/completionHandlers.js +13 -0
- package/dist/handlers/configHandlers.d.ts +31 -0
- package/dist/handlers/configHandlers.js +59 -0
- package/dist/handlers/conversationHandlers.d.ts +118 -0
- package/dist/handlers/conversationHandlers.js +314 -0
- package/dist/handlers/handoffHandlers.d.ts +17 -0
- package/dist/handlers/handoffHandlers.js +14 -0
- package/dist/handlers/hostHandlers.d.ts +39 -0
- package/dist/handlers/hostHandlers.js +56 -0
- package/dist/handlers/index.d.ts +128 -0
- package/dist/handlers/index.js +92 -0
- package/dist/handlers/messageHandlers.d.ts +11 -0
- package/dist/handlers/messageHandlers.js +10 -0
- package/dist/handlers/modelHandlers.d.ts +17 -0
- package/dist/handlers/modelHandlers.js +19 -0
- package/dist/handlers/noticeHandlers.d.ts +24 -0
- package/dist/handlers/noticeHandlers.js +24 -0
- package/dist/handlers/questionHandlers.d.ts +16 -0
- package/dist/handlers/questionHandlers.js +16 -0
- package/dist/handlers/searchHandlers.d.ts +12 -0
- package/dist/handlers/searchHandlers.js +12 -0
- package/dist/handlers/workspaceHandlers.d.ts +29 -0
- package/dist/handlers/workspaceHandlers.js +47 -0
- package/dist/i18n/en.d.ts +243 -0
- package/dist/i18n/en.js +270 -0
- package/dist/i18n/index.d.ts +43 -0
- package/dist/i18n/index.js +72 -0
- package/dist/i18n/zh.d.ts +240 -0
- package/dist/i18n/zh.js +257 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +15 -0
- package/dist/net/UploadReceiver.d.ts +186 -0
- package/dist/net/UploadReceiver.js +494 -0
- package/dist/net/WsHub.d.ts +231 -0
- package/dist/net/WsHub.js +689 -0
- package/dist/net/auth.d.ts +73 -0
- package/dist/net/auth.js +74 -0
- package/dist/net/discovery.d.ts +72 -0
- package/dist/net/discovery.js +171 -0
- package/dist/net/index.d.ts +14 -0
- package/dist/net/index.js +10 -0
- package/dist/runtime/ChatRunner.d.ts +374 -0
- package/dist/runtime/ChatRunner.js +1204 -0
- package/dist/runtime/ConversationDrafts.d.ts +43 -0
- package/dist/runtime/ConversationDrafts.js +47 -0
- package/dist/runtime/RunRegistry.d.ts +79 -0
- package/dist/runtime/RunRegistry.js +108 -0
- package/dist/runtime/ScopeRegistry.d.ts +153 -0
- package/dist/runtime/ScopeRegistry.js +259 -0
- package/dist/runtime/TransientRunner.d.ts +90 -0
- package/dist/runtime/TransientRunner.js +179 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.js +10 -0
- package/dist/services/AgentService.d.ts +150 -0
- package/dist/services/AgentService.js +718 -0
- package/dist/services/AssetService.d.ts +338 -0
- package/dist/services/AssetService.js +739 -0
- package/dist/services/AutoNaming.d.ts +92 -0
- package/dist/services/AutoNaming.js +235 -0
- package/dist/services/CompletionService.d.ts +122 -0
- package/dist/services/CompletionService.js +442 -0
- package/dist/services/ConfigService.d.ts +171 -0
- package/dist/services/ConfigService.js +695 -0
- package/dist/services/ConversationService.d.ts +274 -0
- package/dist/services/ConversationService.js +902 -0
- package/dist/services/CredentialService.d.ts +33 -0
- package/dist/services/CredentialService.js +86 -0
- package/dist/services/DiscoveryService.d.ts +182 -0
- package/dist/services/DiscoveryService.js +998 -0
- package/dist/services/HandoffService.d.ts +189 -0
- package/dist/services/HandoffService.js +414 -0
- package/dist/services/Logger.d.ts +130 -0
- package/dist/services/Logger.js +256 -0
- package/dist/services/MessageService.d.ts +88 -0
- package/dist/services/MessageService.js +280 -0
- package/dist/services/ModelService.d.ts +89 -0
- package/dist/services/ModelService.js +489 -0
- package/dist/services/NoticeService.d.ts +93 -0
- package/dist/services/NoticeService.js +217 -0
- package/dist/services/QuestionService.d.ts +184 -0
- package/dist/services/QuestionService.js +457 -0
- package/dist/services/SearchService.d.ts +54 -0
- package/dist/services/SearchService.js +117 -0
- package/dist/services/WorkspaceService.d.ts +96 -0
- package/dist/services/WorkspaceService.js +213 -0
- package/dist/services/imageSize.d.ts +41 -0
- package/dist/services/imageSize.js +146 -0
- package/dist/services/index.d.ts +20 -0
- package/dist/services/index.js +15 -0
- package/dist/services/secretMask.d.ts +24 -0
- package/dist/services/secretMask.js +34 -0
- package/dist/storage/AssetRepository.d.ts +87 -0
- package/dist/storage/AssetRepository.js +180 -0
- package/dist/storage/ConversationRepository.d.ts +55 -0
- package/dist/storage/ConversationRepository.js +128 -0
- package/dist/storage/CredentialRepository.d.ts +28 -0
- package/dist/storage/CredentialRepository.js +47 -0
- package/dist/storage/Database.d.ts +95 -0
- package/dist/storage/Database.js +180 -0
- package/dist/storage/MessageRepository.d.ts +104 -0
- package/dist/storage/MessageRepository.js +323 -0
- package/dist/storage/MetaRepository.d.ts +21 -0
- package/dist/storage/MetaRepository.js +33 -0
- package/dist/storage/NoticeRepository.d.ts +31 -0
- package/dist/storage/NoticeRepository.js +89 -0
- package/dist/storage/QuestionRepository.d.ts +34 -0
- package/dist/storage/QuestionRepository.js +96 -0
- package/dist/storage/WorkspaceRepository.d.ts +25 -0
- package/dist/storage/WorkspaceRepository.js +44 -0
- package/dist/storage/dbWorker.d.ts +10 -0
- package/dist/storage/dbWorker.js +132 -0
- package/dist/storage/index.d.ts +20 -0
- package/dist/storage/index.js +16 -0
- package/dist/storage/migrations.d.ts +26 -0
- package/dist/storage/migrations.js +207 -0
- package/dist/storage/types.d.ts +298 -0
- package/dist/storage/types.js +14 -0
- package/dist/wire/errors.d.ts +105 -0
- package/dist/wire/errors.js +143 -0
- package/dist/wire/events.d.ts +102 -0
- package/dist/wire/events.js +13 -0
- package/dist/wire/frames.d.ts +106 -0
- package/dist/wire/frames.js +156 -0
- package/dist/wire/index.d.ts +31 -0
- package/dist/wire/index.js +31 -0
- package/dist/wire/methods.d.ts +1896 -0
- package/dist/wire/methods.js +99 -0
- package/dist/wire/states.d.ts +487 -0
- package/dist/wire/states.js +61 -0
- package/package.json +63 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent.*` 的接线壳(F-B1…F-B7 / F-F5 / F-G3)。
|
|
3
|
+
*
|
|
4
|
+
* 与 `config.*` 同一套口径:入参直接交给服务,出参里的句子按这条连接的语言重渲染
|
|
5
|
+
* (D8)。业务判断在 `services/AgentService.ts`。
|
|
6
|
+
*/
|
|
7
|
+
import { localizeLocalizedTexts } from "./configHandlers.js";
|
|
8
|
+
/** 造出 `agent.*` 的 handler 表 */
|
|
9
|
+
export function createAgentHandlers(deps) {
|
|
10
|
+
return {
|
|
11
|
+
"agent.list": async (context) => localizeLocalizedTexts(await deps.agents.list(context.params), context.connection.language),
|
|
12
|
+
"agent.get": async (context) => localizeLocalizedTexts(await deps.agents.get(context.params), context.connection.language),
|
|
13
|
+
"agent.create": async (context) => localizeLocalizedTexts(await deps.agents.create(context.params), context.connection.language),
|
|
14
|
+
"agent.update": async (context) => localizeLocalizedTexts(await deps.agents.update(context.params), context.connection.language),
|
|
15
|
+
"agent.delete": async (context) => localizeLocalizedTexts(await deps.agents.delete(context.params), context.connection.language),
|
|
16
|
+
"agent.setModel": async (context) => localizeLocalizedTexts(await deps.agents.setModel(context.params), context.connection.language),
|
|
17
|
+
"agent.setThinking": async (context) => localizeLocalizedTexts(await deps.agents.setThinking(context.params), context.connection.language),
|
|
18
|
+
"agent.restoreFactory": async (context) => localizeLocalizedTexts(await deps.agents.restoreFactory(context.params), context.connection.language),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `asset.*`:上传入口与取回(PRD D5 / F-H7 / F-H8)。
|
|
3
|
+
*
|
|
4
|
+
* `asset.begin` / `asset.end` 不在这张表里:它们长在 WebSocket 上(分片要直接写进 `assets/`
|
|
5
|
+
* 的临时文件、要能按连接清理),由接线层(`net/WsHub` + `net/UploadReceiver`)直接接管,
|
|
6
|
+
* 这里再注册一份就成了两处实现,客户端会看到两个不同的答案。
|
|
7
|
+
*
|
|
8
|
+
* `asset.get` 在这一格里:它不需要连接状态(不问「你是谁这条连接在做什么」),一条 WS 上的
|
|
9
|
+
* JSON 请求/响应就够 —— 内容走 base64 回包,因此不涉及二进制下行帧的关联问题。
|
|
10
|
+
*
|
|
11
|
+
* 这一域还有一件翻译工作留在这里:附件结局(`AttachmentOutcome`)里的句子是在素材层(不知道
|
|
12
|
+
* 收件人是谁)按默认语言渲染的,重渲染发生在接线层。
|
|
13
|
+
*/
|
|
14
|
+
import type { Language } from "../i18n/index.js";
|
|
15
|
+
import type { HandlerTable } from "../net/index.js";
|
|
16
|
+
import type { AssetService } from "../services/AssetService.js";
|
|
17
|
+
import type { AttachmentOutcome } from "../wire/index.js";
|
|
18
|
+
/** `asset.*` 的 handler 依赖 */
|
|
19
|
+
export interface AssetHandlerDeps {
|
|
20
|
+
assets: AssetService;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `asset.*` 的 handler 表。
|
|
24
|
+
*
|
|
25
|
+
* 只有 `asset.get`:另外两个方法由接线层接管(见文件头),返回空表才是结论而不是占位。
|
|
26
|
+
*/
|
|
27
|
+
export declare function createAssetHandlers(deps: AssetHandlerDeps): HandlerTable;
|
|
28
|
+
/** 一个附件结局的句子按这条连接的语言重渲染(码与参数不动,PRD D8) */
|
|
29
|
+
export declare function localizeOutcome(outcome: AttachmentOutcome, language: Language): AttachmentOutcome;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `asset.*`:上传入口与取回(PRD D5 / F-H7 / F-H8)。
|
|
3
|
+
*
|
|
4
|
+
* `asset.begin` / `asset.end` 不在这张表里:它们长在 WebSocket 上(分片要直接写进 `assets/`
|
|
5
|
+
* 的临时文件、要能按连接清理),由接线层(`net/WsHub` + `net/UploadReceiver`)直接接管,
|
|
6
|
+
* 这里再注册一份就成了两处实现,客户端会看到两个不同的答案。
|
|
7
|
+
*
|
|
8
|
+
* `asset.get` 在这一格里:它不需要连接状态(不问「你是谁这条连接在做什么」),一条 WS 上的
|
|
9
|
+
* JSON 请求/响应就够 —— 内容走 base64 回包,因此不涉及二进制下行帧的关联问题。
|
|
10
|
+
*
|
|
11
|
+
* 这一域还有一件翻译工作留在这里:附件结局(`AttachmentOutcome`)里的句子是在素材层(不知道
|
|
12
|
+
* 收件人是谁)按默认语言渲染的,重渲染发生在接线层。
|
|
13
|
+
*/
|
|
14
|
+
import { render } from "../i18n/index.js";
|
|
15
|
+
/**
|
|
16
|
+
* `asset.*` 的 handler 表。
|
|
17
|
+
*
|
|
18
|
+
* 只有 `asset.get`:另外两个方法由接线层接管(见文件头),返回空表才是结论而不是占位。
|
|
19
|
+
*/
|
|
20
|
+
export function createAssetHandlers(deps) {
|
|
21
|
+
return {
|
|
22
|
+
// 按 id 取回内容:`assets` 是资源的唯一真相,历史里的 `__asset_id` 靠它重放
|
|
23
|
+
"asset.get": async (context) => await deps.assets.getAsset(context.params),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** 一个附件结局的句子按这条连接的语言重渲染(码与参数不动,PRD D8) */
|
|
27
|
+
export function localizeOutcome(outcome, language) {
|
|
28
|
+
if (outcome.problem === null)
|
|
29
|
+
return outcome;
|
|
30
|
+
const problem = {
|
|
31
|
+
...outcome.problem,
|
|
32
|
+
message: render(language, outcome.problem.messageKey, outcome.problem.params),
|
|
33
|
+
};
|
|
34
|
+
return { ...outcome, problem };
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 能力清单(PRD F-E5 / F-E6 / F-F9,裁定 R6)。
|
|
3
|
+
*
|
|
4
|
+
* 清单是「帮助页与指令菜单渲染用的那一份真相」,所以它必须与契约同步:每一项对应
|
|
5
|
+
* `MethodMap` 里的一个方法名,编号取 PRD §4 那一行的能力号(`wire/methods.ts` 里每个方法
|
|
6
|
+
* 的注释就写着自己的编号)。没有编号的方法用契约注释里记的那条决定编号(`workspace.*` 是
|
|
7
|
+
* `D9`/`D10`/`D11`:PRD §4 当初没给项目单列能力行),不另编一个。
|
|
8
|
+
*
|
|
9
|
+
* 三件事刻意分开:
|
|
10
|
+
* - **标题与说明**:`LocalizedText`,按连接语言渲染(D8),文案键在 `i18n/`;
|
|
11
|
+
* - **`blocking`**:执行期间会不会占住这段对话(F-E6 让界面显示「正在执行什么」);
|
|
12
|
+
* - **`destructive`**:有不可撤销的后果(F-F9 的二次确认)。
|
|
13
|
+
*
|
|
14
|
+
* 编号撞车的场合(几个方法服务同一条能力,例如 `config.saveEndpoint` / `config.deleteEndpoint`
|
|
15
|
+
* 都属于 F-F2)用 `<编号>#<动作>` 做 id:编号仍是 PRD 的那个,id 保持唯一,客户端可以按 id 存
|
|
16
|
+
* 展开状态。顺序与 `METHOD_NAMES` 一致,帮助页读起来就是「按域分组的办法清单」。
|
|
17
|
+
*/
|
|
18
|
+
import type { Language } from "../i18n/index.js";
|
|
19
|
+
import type { CapabilityView } from "../wire/index.js";
|
|
20
|
+
/**
|
|
21
|
+
* 造能力清单。
|
|
22
|
+
*
|
|
23
|
+
* 默认语言渲染一份:`host.hello` 与 `host.capabilities` 的出参都要能在不知道收件人语言时
|
|
24
|
+
* 先给出形状,客户端按自己的语言用 `messageKey` + `params` 重渲染(D8 的同一套口径)。
|
|
25
|
+
*/
|
|
26
|
+
export declare function createCapabilities(language?: Language): CapabilityView[];
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 能力清单(PRD F-E5 / F-E6 / F-F9,裁定 R6)。
|
|
3
|
+
*
|
|
4
|
+
* 清单是「帮助页与指令菜单渲染用的那一份真相」,所以它必须与契约同步:每一项对应
|
|
5
|
+
* `MethodMap` 里的一个方法名,编号取 PRD §4 那一行的能力号(`wire/methods.ts` 里每个方法
|
|
6
|
+
* 的注释就写着自己的编号)。没有编号的方法用契约注释里记的那条决定编号(`workspace.*` 是
|
|
7
|
+
* `D9`/`D10`/`D11`:PRD §4 当初没给项目单列能力行),不另编一个。
|
|
8
|
+
*
|
|
9
|
+
* 三件事刻意分开:
|
|
10
|
+
* - **标题与说明**:`LocalizedText`,按连接语言渲染(D8),文案键在 `i18n/`;
|
|
11
|
+
* - **`blocking`**:执行期间会不会占住这段对话(F-E6 让界面显示「正在执行什么」);
|
|
12
|
+
* - **`destructive`**:有不可撤销的后果(F-F9 的二次确认)。
|
|
13
|
+
*
|
|
14
|
+
* 编号撞车的场合(几个方法服务同一条能力,例如 `config.saveEndpoint` / `config.deleteEndpoint`
|
|
15
|
+
* 都属于 F-F2)用 `<编号>#<动作>` 做 id:编号仍是 PRD 的那个,id 保持唯一,客户端可以按 id 存
|
|
16
|
+
* 展开状态。顺序与 `METHOD_NAMES` 一致,帮助页读起来就是「按域分组的办法清单」。
|
|
17
|
+
*/
|
|
18
|
+
import { DEFAULT_LANGUAGE, render } from "../i18n/index.js";
|
|
19
|
+
import { methodDomain } from "../wire/index.js";
|
|
20
|
+
/**
|
|
21
|
+
* 清单本体:**每个方法一条**,且与 `METHOD_NAMES` 一一对应(用例会钉住这条)。
|
|
22
|
+
*
|
|
23
|
+
* `blocking` 只标「跑起来时这段对话不能发下一条」的那几个:一轮对话、交接回合、
|
|
24
|
+
* 临时对话(它借的 Scope 与项目共用,跑的时候同样不能被打断)。
|
|
25
|
+
* `destructive` 只标「做下去就回不来」的那几个:删项目 / 删对话 / 撤回 / 删端点 /
|
|
26
|
+
* 删助手 / 删模型(含图片模型)/ 删 MCP 条目 / 恢复出厂。清通知不算:它清的是
|
|
27
|
+
* 界面上的一条提示,为它弹二次确认反而是打扰。
|
|
28
|
+
*
|
|
29
|
+
* 两样东西刻意不在这份清单里(裁定 2026-11-13):
|
|
30
|
+
* - `host.usage`:「按项目 / 整机」的用量聚合没有任何客户端消费,F-I5 的落点在
|
|
31
|
+
* `conversation.state` 的 `usage`;
|
|
32
|
+
* - `credential.*`:凭据由宿主自己管理(`agents-host token create|list|revoke`),
|
|
33
|
+
* 客户端只有「连接管理 + 记住密码」,那里没有可渲染的能力。
|
|
34
|
+
*/
|
|
35
|
+
const FACTS = [
|
|
36
|
+
{ method: "host.hello", prd: "F-A1", blocking: false, destructive: false },
|
|
37
|
+
{ method: "host.version", prd: "F-E3", blocking: false, destructive: false },
|
|
38
|
+
{ method: "host.upgrade", prd: "F-E3", blocking: false, destructive: false },
|
|
39
|
+
{ method: "host.shutdown", prd: "F-E1", blocking: false, destructive: false },
|
|
40
|
+
{ method: "host.capabilities", prd: "F-E5", blocking: false, destructive: false },
|
|
41
|
+
{ method: "host.reload", prd: "F-E1", blocking: false, destructive: false },
|
|
42
|
+
{ method: "host.setLanguage", prd: "F-E4", blocking: false, destructive: false },
|
|
43
|
+
{ method: "workspace.list", prd: "D9", blocking: false, destructive: false },
|
|
44
|
+
{ method: "workspace.create", prd: "D10", blocking: false, destructive: false },
|
|
45
|
+
{ method: "workspace.get", prd: "D9", blocking: false, destructive: false },
|
|
46
|
+
{ method: "workspace.rename", prd: "D9", blocking: false, destructive: false },
|
|
47
|
+
{ method: "workspace.remove", prd: "D11", blocking: false, destructive: true },
|
|
48
|
+
{ method: "conversation.list", prd: "F-C5", blocking: false, destructive: false },
|
|
49
|
+
{ method: "conversation.create", prd: "F-C7", blocking: false, destructive: false },
|
|
50
|
+
{ method: "conversation.get", prd: "F-A6", blocking: false, destructive: false },
|
|
51
|
+
{ method: "conversation.state", prd: "F-I3", blocking: false, destructive: false },
|
|
52
|
+
{ method: "conversation.rename", prd: "F-C3", blocking: false, destructive: false },
|
|
53
|
+
{ method: "conversation.pin", prd: "F-C5", blocking: false, destructive: false },
|
|
54
|
+
{ method: "conversation.delete", prd: "F-C10", blocking: false, destructive: true },
|
|
55
|
+
{ method: "conversation.send", prd: "F-C2", blocking: true, destructive: false },
|
|
56
|
+
{ method: "conversation.abort", prd: "F-E1", blocking: false, destructive: false },
|
|
57
|
+
{ method: "conversation.revert", prd: "F-C8", blocking: false, destructive: true },
|
|
58
|
+
{ method: "conversation.setModel", prd: "F-B4", blocking: false, destructive: false },
|
|
59
|
+
{ method: "conversation.setThinking", prd: "F-B6", blocking: false, destructive: false },
|
|
60
|
+
{ method: "conversation.transient", prd: "F-A2", blocking: true, destructive: false },
|
|
61
|
+
{ method: "message.list", prd: "F-I7", blocking: false, destructive: false },
|
|
62
|
+
{ method: "question.list", prd: "F-I9", blocking: false, destructive: false },
|
|
63
|
+
{ method: "question.answer", prd: "F-I9", blocking: false, destructive: false },
|
|
64
|
+
{ method: "notice.list", prd: "F-I8", blocking: false, destructive: false },
|
|
65
|
+
{ method: "notice.dismiss", prd: "F-I8", blocking: false, destructive: false },
|
|
66
|
+
{ method: "notice.clear", prd: "F-I8", blocking: false, destructive: false },
|
|
67
|
+
{ method: "config.get", prd: "F-F1", blocking: false, destructive: false },
|
|
68
|
+
{ method: "config.patch", prd: "F-F1", blocking: false, destructive: false },
|
|
69
|
+
{ method: "config.setDefaults", prd: "F-F7", blocking: false, destructive: false },
|
|
70
|
+
{ method: "config.getDiscovery", prd: "F-G1", blocking: false, destructive: false },
|
|
71
|
+
{ method: "config.saveMcp", prd: "F-F6", blocking: false, destructive: false },
|
|
72
|
+
{ method: "config.deleteMcp", prd: "F-G1", blocking: false, destructive: true },
|
|
73
|
+
{ method: "config.saveEndpoint", prd: "F-F2", blocking: false, destructive: false },
|
|
74
|
+
{ method: "config.deleteEndpoint", prd: "F-F2", blocking: false, destructive: true },
|
|
75
|
+
{ method: "agent.list", prd: "F-B2", blocking: false, destructive: false },
|
|
76
|
+
{ method: "agent.get", prd: "F-B2", blocking: false, destructive: false },
|
|
77
|
+
{ method: "agent.create", prd: "F-B2", blocking: false, destructive: false },
|
|
78
|
+
{ method: "agent.update", prd: "F-B2", blocking: false, destructive: false },
|
|
79
|
+
{ method: "agent.delete", prd: "F-F5", blocking: false, destructive: true },
|
|
80
|
+
{ method: "agent.setModel", prd: "F-B4", blocking: false, destructive: false },
|
|
81
|
+
{ method: "agent.setThinking", prd: "F-B6", blocking: false, destructive: false },
|
|
82
|
+
{ method: "agent.restoreFactory", prd: "F-F5", blocking: false, destructive: true },
|
|
83
|
+
{ method: "model.list", prd: "F-F3", blocking: false, destructive: false },
|
|
84
|
+
{ method: "model.listImages", prd: "F-F4", blocking: false, destructive: false },
|
|
85
|
+
{ method: "model.create", prd: "F-F3", blocking: false, destructive: false },
|
|
86
|
+
{ method: "model.update", prd: "F-F3", blocking: false, destructive: false },
|
|
87
|
+
{ method: "model.delete", prd: "F-F3", blocking: false, destructive: true },
|
|
88
|
+
{ method: "model.restoreFactory", prd: "F-F3", blocking: false, destructive: true },
|
|
89
|
+
{ method: "model.saveImage", prd: "F-F4", blocking: false, destructive: false },
|
|
90
|
+
{ method: "model.deleteImage", prd: "F-F4", blocking: false, destructive: true },
|
|
91
|
+
{ method: "asset.begin", prd: "F-H8", blocking: false, destructive: false },
|
|
92
|
+
{ method: "asset.end", prd: "F-H8", blocking: false, destructive: false },
|
|
93
|
+
{ method: "asset.get", prd: "F-H7", blocking: false, destructive: false },
|
|
94
|
+
{ method: "completion.files", prd: "F-H5", blocking: false, destructive: false },
|
|
95
|
+
{ method: "handoff.start", prd: "F-D5", blocking: true, destructive: false },
|
|
96
|
+
{ method: "handoff.listDocuments", prd: "F-D6", blocking: false, destructive: false },
|
|
97
|
+
{ method: "search.conversations", prd: "F-C6", blocking: false, destructive: false },
|
|
98
|
+
{ method: "search.messages", prd: "F-C6", blocking: false, destructive: false },
|
|
99
|
+
];
|
|
100
|
+
/** 标题的文案键(`capability.<方法名>`) */
|
|
101
|
+
function titleKey(method) {
|
|
102
|
+
return `capability.${method}`;
|
|
103
|
+
}
|
|
104
|
+
/** 说明的文案键(`capability.<方法名>.detail`) */
|
|
105
|
+
function detailKey(method) {
|
|
106
|
+
return `capability.${method}.detail`;
|
|
107
|
+
}
|
|
108
|
+
/** 一句话:码 + 参数 + 按给定语言渲染的句子(存码不存句子,D8) */
|
|
109
|
+
function text(key, language) {
|
|
110
|
+
return { code: key, messageKey: key, params: {}, message: render(language, key) };
|
|
111
|
+
}
|
|
112
|
+
/** 动作名(`conversation.send` → `send`),编号撞车时用来给 id 去重 */
|
|
113
|
+
function actionOf(method) {
|
|
114
|
+
return method.slice(method.indexOf(".") + 1);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 造能力清单。
|
|
118
|
+
*
|
|
119
|
+
* 默认语言渲染一份:`host.hello` 与 `host.capabilities` 的出参都要能在不知道收件人语言时
|
|
120
|
+
* 先给出形状,客户端按自己的语言用 `messageKey` + `params` 重渲染(D8 的同一套口径)。
|
|
121
|
+
*/
|
|
122
|
+
export function createCapabilities(language = DEFAULT_LANGUAGE) {
|
|
123
|
+
const used = new Set();
|
|
124
|
+
return FACTS.map((fact) => {
|
|
125
|
+
// 同一个编号下的第二个及以后的方法:`<编号>#<动作>`
|
|
126
|
+
const id = used.has(fact.prd) ? `${fact.prd}#${actionOf(fact.method)}` : fact.prd;
|
|
127
|
+
used.add(fact.prd);
|
|
128
|
+
return {
|
|
129
|
+
id,
|
|
130
|
+
domain: methodDomain(fact.method),
|
|
131
|
+
title: text(titleKey(fact.method), language),
|
|
132
|
+
description: text(detailKey(fact.method), language),
|
|
133
|
+
method: fact.method,
|
|
134
|
+
blocking: fact.blocking,
|
|
135
|
+
destructive: fact.destructive,
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `completion.*` 的接线壳(F-H5 / D7):`@` 补全的数据来源。
|
|
3
|
+
*
|
|
4
|
+
* 业务判断在 `services/CompletionService.ts`;这里只转发 + 按连接语言重渲染「未就绪要说话」
|
|
5
|
+
* 的那句说明(D8)。
|
|
6
|
+
*/
|
|
7
|
+
import type { HandlerTable } from "../net/WsHub.js";
|
|
8
|
+
import type { CompletionService } from "../services/CompletionService.js";
|
|
9
|
+
/** 本文件负责的方法名 */
|
|
10
|
+
export type CompletionHandlerName = "completion.files";
|
|
11
|
+
/** 本文件产出的 handler 表片段 */
|
|
12
|
+
export type CompletionHandlers = Pick<HandlerTable, CompletionHandlerName>;
|
|
13
|
+
/** 接线壳的依赖 */
|
|
14
|
+
export interface CompletionHandlerDeps {
|
|
15
|
+
completion: CompletionService;
|
|
16
|
+
}
|
|
17
|
+
/** 造出 `completion.*` 的 handler 表 */
|
|
18
|
+
export declare function createCompletionHandlers(deps: CompletionHandlerDeps): CompletionHandlers;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `completion.*` 的接线壳(F-H5 / D7):`@` 补全的数据来源。
|
|
3
|
+
*
|
|
4
|
+
* 业务判断在 `services/CompletionService.ts`;这里只转发 + 按连接语言重渲染「未就绪要说话」
|
|
5
|
+
* 的那句说明(D8)。
|
|
6
|
+
*/
|
|
7
|
+
import { localizeLocalizedTexts } from "./configHandlers.js";
|
|
8
|
+
/** 造出 `completion.*` 的 handler 表 */
|
|
9
|
+
export function createCompletionHandlers(deps) {
|
|
10
|
+
return {
|
|
11
|
+
"completion.files": async (context) => localizeLocalizedTexts(await deps.completion.files(context.params), context.connection.language),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `config.*` 的接线壳(F-F1 / F-F2 / F-F6 / F-F7 / F-E2 / F-A8)。
|
|
3
|
+
*
|
|
4
|
+
* 这一层只做两件事:把入参交给服务,把出参里那些「已经按默认语言渲染好的句子」按**这条连接**
|
|
5
|
+
* 的语言重渲染一次(PRD D8:语言挂在连接上,服务层存的是码 + 参数)。
|
|
6
|
+
*
|
|
7
|
+
* 业务判断都在 `services/ConfigService.ts`;这里没有一条分支是在决定「该怎么算」。
|
|
8
|
+
*/
|
|
9
|
+
import { type Language } from "../i18n/index.js";
|
|
10
|
+
import type { HandlerTable, MethodHandler } from "../net/WsHub.js";
|
|
11
|
+
import type { ConfigService } from "../services/ConfigService.js";
|
|
12
|
+
/** 本文件负责的方法名(其余域各有各的文件) */
|
|
13
|
+
export type ConfigHandlerName = "config.get" | "config.patch" | "config.setDefaults" | "config.getDiscovery" | "config.saveMcp" | "config.deleteMcp" | "config.saveEndpoint" | "config.deleteEndpoint";
|
|
14
|
+
/** 本文件产出的 handler 表片段(单根把它摊进总表) */
|
|
15
|
+
export type ConfigHandlers = Pick<HandlerTable, ConfigHandlerName>;
|
|
16
|
+
/** 接线壳的依赖 */
|
|
17
|
+
export interface ConfigHandlerDeps {
|
|
18
|
+
config: ConfigService;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 把一段结构化结果里所有 `LocalizedText` 的句子换成目标语言。
|
|
22
|
+
*
|
|
23
|
+
* 判定按形状(`code` + `messageKey` + `params` + `message`)而不是认某个类:这些事实要能穿过
|
|
24
|
+
* JSON-RPC 边界,形状本身就是契约(`wire/states.ts` 的 `LocalizedText`)。认不出来的原样留着
|
|
25
|
+
* —— 渲染不出来时保留原句子比丢字段好。
|
|
26
|
+
*/
|
|
27
|
+
export declare function localizeLocalizedTexts<T>(value: T, language: Language): T;
|
|
28
|
+
/** 造出 `config.*` 的 handler 表 */
|
|
29
|
+
export declare function createConfigHandlers(deps: ConfigHandlerDeps): ConfigHandlers;
|
|
30
|
+
/** 单个方法也导出,便于用例直接调(不必造整张表) */
|
|
31
|
+
export type ConfigMethodHandler<M extends ConfigHandlerName> = MethodHandler<M>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `config.*` 的接线壳(F-F1 / F-F2 / F-F6 / F-F7 / F-E2 / F-A8)。
|
|
3
|
+
*
|
|
4
|
+
* 这一层只做两件事:把入参交给服务,把出参里那些「已经按默认语言渲染好的句子」按**这条连接**
|
|
5
|
+
* 的语言重渲染一次(PRD D8:语言挂在连接上,服务层存的是码 + 参数)。
|
|
6
|
+
*
|
|
7
|
+
* 业务判断都在 `services/ConfigService.ts`;这里没有一条分支是在决定「该怎么算」。
|
|
8
|
+
*/
|
|
9
|
+
import { hasMessage, render } from "../i18n/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* 把一段结构化结果里所有 `LocalizedText` 的句子换成目标语言。
|
|
12
|
+
*
|
|
13
|
+
* 判定按形状(`code` + `messageKey` + `params` + `message`)而不是认某个类:这些事实要能穿过
|
|
14
|
+
* JSON-RPC 边界,形状本身就是契约(`wire/states.ts` 的 `LocalizedText`)。认不出来的原样留着
|
|
15
|
+
* —— 渲染不出来时保留原句子比丢字段好。
|
|
16
|
+
*/
|
|
17
|
+
export function localizeLocalizedTexts(value, language) {
|
|
18
|
+
return walk(value, language, 0);
|
|
19
|
+
}
|
|
20
|
+
function walk(value, language, depth) {
|
|
21
|
+
if (depth > 12)
|
|
22
|
+
return value;
|
|
23
|
+
if (Array.isArray(value))
|
|
24
|
+
return value.map((item) => walk(item, language, depth + 1));
|
|
25
|
+
if (typeof value !== "object" || value === null)
|
|
26
|
+
return value;
|
|
27
|
+
const record = value;
|
|
28
|
+
if (isLocalizedText(record) && hasMessage(record.messageKey)) {
|
|
29
|
+
const message = render(language, record.messageKey, record.params);
|
|
30
|
+
const detail = "detail" in record ? { detail: walk(record.detail, language, depth + 1) } : {};
|
|
31
|
+
return { ...record, message, ...detail };
|
|
32
|
+
}
|
|
33
|
+
const result = {};
|
|
34
|
+
for (const [key, item] of Object.entries(record)) {
|
|
35
|
+
result[key] = walk(item, language, depth + 1);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function isLocalizedText(record) {
|
|
40
|
+
return (typeof record.code === "string" &&
|
|
41
|
+
typeof record.messageKey === "string" &&
|
|
42
|
+
typeof record.message === "string" &&
|
|
43
|
+
typeof record.params === "object" &&
|
|
44
|
+
record.params !== null &&
|
|
45
|
+
!Array.isArray(record.params));
|
|
46
|
+
}
|
|
47
|
+
/** 造出 `config.*` 的 handler 表 */
|
|
48
|
+
export function createConfigHandlers(deps) {
|
|
49
|
+
return {
|
|
50
|
+
"config.get": async (context) => localizeLocalizedTexts(await deps.config.get(context.params), context.connection.language),
|
|
51
|
+
"config.patch": async (context) => localizeLocalizedTexts(await deps.config.patch(context.params), context.connection.language),
|
|
52
|
+
"config.setDefaults": async (context) => localizeLocalizedTexts(await deps.config.setDefaults(context.params), context.connection.language),
|
|
53
|
+
"config.getDiscovery": async (context) => localizeLocalizedTexts(await deps.config.getDiscovery(context.params), context.connection.language),
|
|
54
|
+
"config.saveMcp": async (context) => localizeLocalizedTexts(await deps.config.saveMcp(context.params), context.connection.language),
|
|
55
|
+
"config.deleteMcp": async (context) => localizeLocalizedTexts(await deps.config.deleteMcp(context.params), context.connection.language),
|
|
56
|
+
"config.saveEndpoint": async (context) => localizeLocalizedTexts(await deps.config.saveEndpoint(context.params), context.connection.language),
|
|
57
|
+
"config.deleteEndpoint": async (context) => localizeLocalizedTexts(await deps.config.deleteEndpoint(context.params), context.connection.language),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `conversation.*`:一段对话的身份、历史与一轮的运行。
|
|
3
|
+
*
|
|
4
|
+
* 这里只做「参数 → 交给服务/运行时 → 把结果翻译成契约形状」。业务判断在
|
|
5
|
+
* `ConversationService` 与 `ChatRunner` 里:比如「忙就拒」在 `RunRegistry`、
|
|
6
|
+
* 「模型解析不出来」在服务层,本文件不重新判断一遍。
|
|
7
|
+
*
|
|
8
|
+
* 唯一在接线层做的拼装是 `conversation.state` 的现场快照:它要把三处事实合起来
|
|
9
|
+
* (服务层给的视图、运行时给的这一轮、库里消息求和的用量),而这三样分别属于三个持有者,
|
|
10
|
+
* 只有接线层同时看得见它们。
|
|
11
|
+
*
|
|
12
|
+
* 一段对话的三处跨界钩子也在这里接(它们分属三个服务,契约里的位置却是同一对方法):
|
|
13
|
+
* - `conversation.send` 之前问一句「有挡着的问题吗」(D23);
|
|
14
|
+
* - 结算之后起一次自动命名(D2,幂等);
|
|
15
|
+
* - `conversation.transient` 走不落库的那条执行路径(R1 / R49)。
|
|
16
|
+
*/
|
|
17
|
+
import type { AgentNS } from "@ai-zen/agents-core";
|
|
18
|
+
import type { AppConfig } from "@ai-zen/agents-sdk";
|
|
19
|
+
import type { Language } from "../i18n/index.js";
|
|
20
|
+
import type { HandlerTable } from "../net/index.js";
|
|
21
|
+
import type { ChatRunner } from "../runtime/index.js";
|
|
22
|
+
import type { AgentDescription } from "../services/AgentService.js";
|
|
23
|
+
import type { ConversationService } from "../services/ConversationService.js";
|
|
24
|
+
import type { MessageService } from "../services/MessageService.js";
|
|
25
|
+
import type { ContextState, ConversationTransientParams, ConversationTransientResult, ConversationView, QuestionView, RunState, StatusBlock, UsageSnapshot } from "../wire/index.js";
|
|
26
|
+
/** `conversation.*` 的实现要的持有者 */
|
|
27
|
+
export interface ConversationHandlerDeps {
|
|
28
|
+
conversations: ConversationService;
|
|
29
|
+
messages: MessageService;
|
|
30
|
+
/** 一轮的执行者(受理、现场、中止、忘掉) */
|
|
31
|
+
runner: ChatRunner;
|
|
32
|
+
/** 挂在这段对话上的问题(`conversation.state` 现场快照的一部分,D22;不注入时为空) */
|
|
33
|
+
questionsFor?: (conversationId: string) => Promise<QuestionView[]>;
|
|
34
|
+
/** 读配置:上下文阈值跟着模型走(PRD F-D1) */
|
|
35
|
+
readConfig: () => Promise<AppConfig>;
|
|
36
|
+
/**
|
|
37
|
+
* 读助手定义那一层的最小事实(名字 + 能不能用,PRD F-I6 的状态栏助手块)。
|
|
38
|
+
*
|
|
39
|
+
* 只用到 `describe`(`AgentService.describe` 是唯一实现者):接线层不碰定义文件,
|
|
40
|
+
* 也不把 `AgentService` 整个搬进来。不注入时助手块的名字与可用性都是 `null`。
|
|
41
|
+
*/
|
|
42
|
+
agents?: {
|
|
43
|
+
describe: (agentId: string) => Promise<AgentDescription | null>;
|
|
44
|
+
};
|
|
45
|
+
/** 刷新思考档位表快照(`setThinking` 之前调一次:改完读回的参数要用当前表) */
|
|
46
|
+
refreshThinkingPresets: () => Promise<void>;
|
|
47
|
+
/** 时钟(ISO 8601 时间戳) */
|
|
48
|
+
now: () => string;
|
|
49
|
+
/** 一轮结算之后的通知点:单根据此重算退出判据 */
|
|
50
|
+
onTurnSettled: () => void;
|
|
51
|
+
/** 有挡着的问题就拒绝(`QuestionService.assertSendable`,D23);不注入时不检查 */
|
|
52
|
+
assertSendable?: (conversationId: string) => Promise<void>;
|
|
53
|
+
/** 一轮结算之后起一次自动命名(`AutoNaming.afterTurn`,D2:幂等,可无条件调) */
|
|
54
|
+
autoNameAfterTurn?: (conversationId: string, language: Language) => Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* 结算后钩子的失败去处(命名没跑成不影响这一轮,但要让组装层看得见)。
|
|
57
|
+
*
|
|
58
|
+
* 不注入时静默:钩子是「顺手做的事」,它的失败不能反过来把已经结算的一轮弄成失败。
|
|
59
|
+
*/
|
|
60
|
+
onHookError?: (error: unknown, hook: string) => void;
|
|
61
|
+
/** 临时对话的执行者(`TransientRunner`,D3 / R49);不注入时这个方法回 `unsupported` */
|
|
62
|
+
runTransient?: (params: ConversationTransientParams, language: Language) => Promise<ConversationTransientResult>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 注册 `conversation.*`。
|
|
66
|
+
*
|
|
67
|
+
* `conversation.transient`(临时对话,PRD D3)注册的前提是注入了 `runTransient`:
|
|
68
|
+
* 不注入时这个方法仍然落到接线层的 `unsupported`(裁定 R11)。
|
|
69
|
+
*/
|
|
70
|
+
export declare function createConversationHandlers(deps: ConversationHandlerDeps): HandlerTable;
|
|
71
|
+
/** 造状态栏块要的那几处事(每一项都已经在别处算好了,这里只负责装箱) */
|
|
72
|
+
export interface StatusBlockInput {
|
|
73
|
+
/** 服务层给的对话视图(身份、模型、思考档、目录事实) */
|
|
74
|
+
conversation: ConversationView;
|
|
75
|
+
/**
|
|
76
|
+
* 助手块的两条事实(名字 / 能不能用),由 {@link conversationStateOf} 从助手定义那一层读来。
|
|
77
|
+
* 拿不到时两格都是 `null`(助手已被删、或定义文件读不出来)。
|
|
78
|
+
*/
|
|
79
|
+
agent: {
|
|
80
|
+
name: string | null;
|
|
81
|
+
available: boolean | null;
|
|
82
|
+
};
|
|
83
|
+
/** 这一轮的快照(六态、工具、子 Agent、本轮用量) */
|
|
84
|
+
run: RunState;
|
|
85
|
+
/** 上下文占用与两条阈值 */
|
|
86
|
+
context: ContextState;
|
|
87
|
+
/** 累计用量 */
|
|
88
|
+
usage: UsageSnapshot;
|
|
89
|
+
/** 收件人的语言(块的标签是给人看的一句话) */
|
|
90
|
+
language: Language;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 按 `STATUS_BLOCK_IDS` 的顺序拼装状态栏的块(PRD F-I6 / 裁定 R65)。
|
|
94
|
+
*
|
|
95
|
+
* 这里**不产生新事实**:每一块装的都是别处已经算好的那份 —— 对话视图里的身份 / 模型 / 思考档 /
|
|
96
|
+
* 目录、`conversation.state` 里的上下文与用量、以及这一轮快照里的六态与子 Agent。工具块只取
|
|
97
|
+
* `awaiting_tools` 态里还在跑的那几个(并行时有几个列几个,正是 L8 要的语义);其余态下没有
|
|
98
|
+
* 工具在跑,列表就是空的。
|
|
99
|
+
*
|
|
100
|
+
* 助手块的 `name` / `available` 由调用方(`conversationStateOf`)先从助手定义那一层读好传进来
|
|
101
|
+
* (`input.agent`):本函数保持同步纯函数,不在这里做 IO。
|
|
102
|
+
*/
|
|
103
|
+
export declare function statusBlocksOf(input: StatusBlockInput): StatusBlock[];
|
|
104
|
+
/** 空闲的现场:没有在跑的一轮,但历史用量还在 */
|
|
105
|
+
export declare function idleRunState(conversationId: string, usage: UsageSnapshot): RunState;
|
|
106
|
+
/**
|
|
107
|
+
* 一批消息的用量快照。
|
|
108
|
+
*
|
|
109
|
+
* `total` 与 `subAgent` 用 core 的口径求和(含子 Agent,与计费同口径);`turn` 在「没有一轮
|
|
110
|
+
* 在跑」时是零值(没有这一轮这件事,就是零),速率同理。
|
|
111
|
+
*/
|
|
112
|
+
export declare function usageOfMessages(messages: readonly AgentNS.Message[], now: string): UsageSnapshot;
|
|
113
|
+
/**
|
|
114
|
+
* 上下文占用:最近一次请求的用量 + 这个模型的两条阈值(PRD F-D1 / D27)。
|
|
115
|
+
*
|
|
116
|
+
* 阈值跟着模型走;模型在配置里被删掉时两条线都是 0(「没有阈值」而不是「阈值为零就超了」)。
|
|
117
|
+
*/
|
|
118
|
+
export declare function contextOf(messages: readonly AgentNS.Message[], model: AppConfig["models"][number] | undefined): ContextState;
|