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

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 +22 -0
  7. package/dist/cli.js +354 -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,11 @@
1
+ /**
2
+ * `message.*`:历史(PRD L5 / A12 / F-I7)。
3
+ *
4
+ * 取法(含自身最新内容、id 不存在就全量)已经在 `MessageService` 里定死,这里只转发。
5
+ */
6
+ import type { HandlerTable } from "../net/index.js";
7
+ import type { MessageService } from "../services/MessageService.js";
8
+ export interface MessageHandlerDeps {
9
+ messages: MessageService;
10
+ }
11
+ export declare function createMessageHandlers(deps: MessageHandlerDeps): HandlerTable;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `message.*`:历史(PRD L5 / A12 / F-I7)。
3
+ *
4
+ * 取法(含自身最新内容、id 不存在就全量)已经在 `MessageService` 里定死,这里只转发。
5
+ */
6
+ export function createMessageHandlers(deps) {
7
+ return {
8
+ "message.list": async (context) => await deps.messages.list(context.params),
9
+ };
10
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `model.*` 的接线壳(F-F3 / F-F4 / F-F7 / F-B8)。
3
+ *
4
+ * 业务判断在 `services/ModelService.ts`;这里只转发 + 按连接语言重渲染句子(D8)。
5
+ */
6
+ import type { HandlerTable } from "../net/WsHub.js";
7
+ import type { ModelService } from "../services/ModelService.js";
8
+ /** 本文件负责的方法名 */
9
+ export type ModelHandlerName = "model.list" | "model.listImages" | "model.create" | "model.update" | "model.delete" | "model.restoreFactory" | "model.saveImage" | "model.deleteImage";
10
+ /** 本文件产出的 handler 表片段 */
11
+ export type ModelHandlers = Pick<HandlerTable, ModelHandlerName>;
12
+ /** 接线壳的依赖 */
13
+ export interface ModelHandlerDeps {
14
+ models: ModelService;
15
+ }
16
+ /** 造出 `model.*` 的 handler 表 */
17
+ export declare function createModelHandlers(deps: ModelHandlerDeps): ModelHandlers;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `model.*` 的接线壳(F-F3 / F-F4 / F-F7 / F-B8)。
3
+ *
4
+ * 业务判断在 `services/ModelService.ts`;这里只转发 + 按连接语言重渲染句子(D8)。
5
+ */
6
+ import { localizeLocalizedTexts } from "./configHandlers.js";
7
+ /** 造出 `model.*` 的 handler 表 */
8
+ export function createModelHandlers(deps) {
9
+ return {
10
+ "model.list": async (context) => localizeLocalizedTexts(await deps.models.list(context.params), context.connection.language),
11
+ "model.listImages": async (context) => localizeLocalizedTexts(await deps.models.listImages(), context.connection.language),
12
+ "model.create": async (context) => localizeLocalizedTexts(await deps.models.create(context.params), context.connection.language),
13
+ "model.update": async (context) => localizeLocalizedTexts(await deps.models.update(context.params), context.connection.language),
14
+ "model.delete": async (context) => localizeLocalizedTexts(await deps.models.delete(context.params), context.connection.language),
15
+ "model.restoreFactory": async (context) => localizeLocalizedTexts(await deps.models.restoreFactory(context.params), context.connection.language),
16
+ "model.saveImage": async (context) => localizeLocalizedTexts(await deps.models.saveImage(context.params), context.connection.language),
17
+ "model.deleteImage": async (context) => localizeLocalizedTexts(await deps.models.deleteImage(context.params), context.connection.language),
18
+ };
19
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `notice.*` 三个方法的接线(PRD L3 / F-I8)。
3
+ *
4
+ * handler 只做两件事:把连接的**语言**递给服务层(D8:语言挂在连接上,文案在读出时渲染),
5
+ * 以及把服务层的返回值原样交回。业务事实全在 `NoticeService` 里,这里不做判断 ——
6
+ * 一层只解释一次,多一层翻译就多一处会漂的地方。
7
+ */
8
+ import type { HandlerTable } from "../net/WsHub.js";
9
+ import type { EventLocalizer } from "../services/NoticeService.js";
10
+ import type { NoticeService } from "../services/NoticeService.js";
11
+ export interface NoticeHandlerDeps {
12
+ /** 只要本域用到的那三个方法(结构上 `NoticeService` 满足,用例可以给替身) */
13
+ notices: Pick<NoticeService, "list" | "dismiss" | "clear">;
14
+ }
15
+ /** 本域注册的方法 */
16
+ export type NoticeHandlers = Pick<HandlerTable, "notice.list" | "notice.dismiss" | "notice.clear">;
17
+ export declare function createNoticeHandlers(deps: NoticeHandlerDeps): NoticeHandlers;
18
+ /**
19
+ * 事件出网前的按连接本地化(`WsHub` 的 `localizeEvent` 注入点)。
20
+ *
21
+ * 通知与问题的统一入口在这里:两类事件都带 `LocalizedText`,语言是连接的事,
22
+ * 所以「产生时按缺省语言渲染、出网时换成这条连接的语言」这一步落在接线层。
23
+ */
24
+ export declare function createNoticeEventLocalizer(): EventLocalizer;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `notice.*` 三个方法的接线(PRD L3 / F-I8)。
3
+ *
4
+ * handler 只做两件事:把连接的**语言**递给服务层(D8:语言挂在连接上,文案在读出时渲染),
5
+ * 以及把服务层的返回值原样交回。业务事实全在 `NoticeService` 里,这里不做判断 ——
6
+ * 一层只解释一次,多一层翻译就多一处会漂的地方。
7
+ */
8
+ import { createEventLocalizer } from "../services/NoticeService.js";
9
+ export function createNoticeHandlers(deps) {
10
+ return {
11
+ "notice.list": async (context) => await deps.notices.list(context.params, context.connection.language),
12
+ "notice.dismiss": async (context) => await deps.notices.dismiss(context.params),
13
+ "notice.clear": async (context) => await deps.notices.clear(context.params),
14
+ };
15
+ }
16
+ /**
17
+ * 事件出网前的按连接本地化(`WsHub` 的 `localizeEvent` 注入点)。
18
+ *
19
+ * 通知与问题的统一入口在这里:两类事件都带 `LocalizedText`,语言是连接的事,
20
+ * 所以「产生时按缺省语言渲染、出网时换成这条连接的语言」这一步落在接线层。
21
+ */
22
+ export function createNoticeEventLocalizer() {
23
+ return createEventLocalizer();
24
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `question.*` 两个方法的接线(PRD D22 / D23 / F-I9)。
3
+ *
4
+ * 两个事实只在这一层才拿得到,所以由 handler 递给服务层:
5
+ * - 这条连接的**语言**(`hello` 里协商出来,断开即忘,D8);
6
+ * - 这条连接的 **id**(多端同时看一个问题时,「谁答的」要写进回答里)。
7
+ */
8
+ import type { HandlerTable } from "../net/WsHub.js";
9
+ import type { QuestionService } from "../services/QuestionService.js";
10
+ export interface QuestionHandlerDeps {
11
+ /** 只要本域用到的那两个方法(结构上 `QuestionService` 满足,用例可以给替身) */
12
+ questions: Pick<QuestionService, "list" | "answer">;
13
+ }
14
+ /** 本域注册的方法 */
15
+ export type QuestionHandlers = Pick<HandlerTable, "question.list" | "question.answer">;
16
+ export declare function createQuestionHandlers(deps: QuestionHandlerDeps): QuestionHandlers;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `question.*` 两个方法的接线(PRD D22 / D23 / F-I9)。
3
+ *
4
+ * 两个事实只在这一层才拿得到,所以由 handler 递给服务层:
5
+ * - 这条连接的**语言**(`hello` 里协商出来,断开即忘,D8);
6
+ * - 这条连接的 **id**(多端同时看一个问题时,「谁答的」要写进回答里)。
7
+ */
8
+ export function createQuestionHandlers(deps) {
9
+ return {
10
+ "question.list": async (context) => await deps.questions.list(context.params, context.connection.language),
11
+ "question.answer": async (context) => await deps.questions.answer(context.params, {
12
+ language: context.connection.language,
13
+ answeredBy: context.connection.id,
14
+ }),
15
+ };
16
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `search.*`:找得到旧对话(PRD F-C6 / D16)。
3
+ *
4
+ * 名称搜与全文搜的取数、分词退化(少于 3 字走 `LIKE`)都在 `SearchService` 里,
5
+ * 这里只转发。
6
+ */
7
+ import type { HandlerTable } from "../net/index.js";
8
+ import type { SearchService } from "../services/SearchService.js";
9
+ export interface SearchHandlerDeps {
10
+ search: SearchService;
11
+ }
12
+ export declare function createSearchHandlers(deps: SearchHandlerDeps): HandlerTable;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `search.*`:找得到旧对话(PRD F-C6 / D16)。
3
+ *
4
+ * 名称搜与全文搜的取数、分词退化(少于 3 字走 `LIKE`)都在 `SearchService` 里,
5
+ * 这里只转发。
6
+ */
7
+ export function createSearchHandlers(deps) {
8
+ return {
9
+ "search.conversations": async (context) => await deps.search.conversations(context.params),
10
+ "search.messages": async (context) => await deps.search.messages(context.params),
11
+ };
12
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `workspace.*`:项目(PRD D9 / D10 / D11 / D12)。
3
+ *
4
+ * 薄到只有一层:参数交给 `WorkspaceService`,结果原样回去。唯一在接线层补的是删项目之后的
5
+ * 两件事(回收它的 Scope、逐段对话推 `deleted`)—— 那两样分别属于运行时与接线层,服务层只负责
6
+ * 删行并算出代价(裁定 R43 / R33)。素材字节的清理不在这里:挂引用归零之后由素材层删。
7
+ */
8
+ import type { HandlerTable } from "../net/index.js";
9
+ import type { ChatEventEmitter, ChatRunner, ScopeRegistry } from "../runtime/index.js";
10
+ import type { ConversationService } from "../services/ConversationService.js";
11
+ import type { WorkspaceService } from "../services/WorkspaceService.js";
12
+ /** `workspace.*` 的实现要的持有者 */
13
+ export interface WorkspaceHandlerDeps {
14
+ workspaces: WorkspaceService;
15
+ /** 删项目要连带它的对话一起清(PRD D11):删之前先记下名下有哪几段 */
16
+ conversations: ConversationService;
17
+ /** 名下的对话在运行时里可能还留着现场,删之前一并丢掉 */
18
+ runner: ChatRunner;
19
+ /** 删项目要把它的 Scope 一起回收(MCP 连接在这里断开) */
20
+ scopes: ScopeRegistry;
21
+ /**
22
+ * 推 `conversation.changed`(L5 / D22:删项目带走的那几段对话也要让别的窗口知道)。
23
+ * 不注入时不推。
24
+ */
25
+ emit?: ChatEventEmitter;
26
+ /** 时间戳(`conversation.changed.at`);缺省用 `Date.now` */
27
+ now?: () => string;
28
+ }
29
+ export declare function createWorkspaceHandlers(deps: WorkspaceHandlerDeps): HandlerTable;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `workspace.*`:项目(PRD D9 / D10 / D11 / D12)。
3
+ *
4
+ * 薄到只有一层:参数交给 `WorkspaceService`,结果原样回去。唯一在接线层补的是删项目之后的
5
+ * 两件事(回收它的 Scope、逐段对话推 `deleted`)—— 那两样分别属于运行时与接线层,服务层只负责
6
+ * 删行并算出代价(裁定 R43 / R33)。素材字节的清理不在这里:挂引用归零之后由素材层删。
7
+ */
8
+ export function createWorkspaceHandlers(deps) {
9
+ return {
10
+ "workspace.list": async (context) => await deps.workspaces.list(context.params),
11
+ "workspace.create": async (context) => await deps.workspaces.create(context.params),
12
+ "workspace.get": async (context) => await deps.workspaces.get(context.params),
13
+ "workspace.rename": async (context) => await deps.workspaces.rename(context.params),
14
+ "workspace.remove": async (context) => await removeWorkspace(deps, context.params),
15
+ };
16
+ }
17
+ /**
18
+ * 删项目(PRD D11 / D17 / F-F9 / R43)。
19
+ *
20
+ * 顺序是有意的:
21
+ * 1. 先记下名下的对话(删完就问不出来了,而运行时里它们的现场要一起丢);
22
+ * 2. 服务层删行(它顺带让运行时忘掉那几段对话的临时覆盖,以及删完之后清归零的素材字节);
23
+ * 3. 逐段对话丢掉这一轮的现场,并推一条 `deleted`(多端在线时对方界面靠它去拉);
24
+ * 4. 回收这个 Workspace 的 Scope —— MCP 连接在这里断开(architecture §4 三因之二)。
25
+ *
26
+ * `dryRun` 只走第 2 步:它要的只是代价,不该有任何副作用。
27
+ */
28
+ async function removeWorkspace(deps, params) {
29
+ const doomed = params.dryRun === true
30
+ ? []
31
+ : (await deps.conversations.list({ workspaceId: params.workspaceId })).conversations;
32
+ const report = await deps.workspaces.remove(params);
33
+ if (params.dryRun !== true && report.removed) {
34
+ for (const conversation of doomed) {
35
+ deps.runner.forget(conversation.id);
36
+ deps.emit?.("conversation.changed", {
37
+ conversationId: conversation.id,
38
+ workspaceId: params.workspaceId,
39
+ change: "deleted",
40
+ messageCount: null,
41
+ at: (deps.now ?? (() => new Date().toISOString()))(),
42
+ });
43
+ }
44
+ await deps.scopes.disposeWorkspace(params.workspaceId);
45
+ }
46
+ return { removed: report.removed, consequences: report.consequences };
47
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * 英文文案表 —— 键的真相源(key 的集合以本文件为准,`zh` 与它逐键对应,类型层面拦住漂移)。
3
+ *
4
+ * 写作口径(PRD §1「它说人话」):一句能直接摆在用户面前的话,说「发生了什么」以及
5
+ * 「用户可以怎么做」,不写 `Error: undefined`、不写 `E_XXX` 这类机器码,也不写
6
+ * 「请求失败」这种没有信息量的话。占位符用 `{name}` 形式,值与含义在键旁的注释里。
7
+ *
8
+ * 文案只描述事实,不做取舍判断(例如目录不存在时只说「目录已不存在」,是否只读由客户端定,
9
+ * PRD D12);凡是「宿主给事实、客户端给表现」的地方,事实都在结构化字段里,文案只是给人看的那一层。
10
+ */
11
+ export declare const en: {
12
+ readonly "error.unauthorized": "That access key wasn't accepted. Check the key and try again.";
13
+ readonly "error.invalidParams": "Part of this request doesn't look right: {field}.";
14
+ readonly "error.notFound": "There's no {entity} with that id.";
15
+ readonly "error.busy": "This conversation is still working on the previous turn. Stop it or wait for it to finish.";
16
+ readonly "error.payloadTooLarge": "That file is {size}, which is over the {limit} limit.";
17
+ readonly "error.unsupported": "The host can't handle {what}.";
18
+ readonly "error.internal": "Something broke on the host. The log has the details.";
19
+ readonly "error.configInvalid": "The settings aren't usable yet: {reason}.";
20
+ readonly "error.portInvalid": "That port number can't be used: {value} (from {source}). It has to be a whole number from 1 to 65535 — 0 means \"let the system pick one\" and only works on the command line.";
21
+ readonly "error.modelUnresolved": "No model could be resolved for this assistant — pick a model for it, or set a default model in the settings.";
22
+ readonly "error.notFactoryModel": "\"{id}\" isn't part of the factory model list, so there's no factory version to restore.";
23
+ readonly "error.mcpUnavailable": "{name} isn't answering, so its tools are missing this turn. Everything else still works.";
24
+ readonly "error.modelUnsupported": "{model} can't take the images already in this conversation, so the switch was refused.";
25
+ readonly "error.handoffDeclined": "Handoff was declined, so this conversation carries on as it is.";
26
+ readonly "error.questionPending": "There's an unanswered question ({question}). Answer it before sending something new.";
27
+ readonly "error.contextGuard": "This conversation reached its {limit}-token limit at {used} tokens, so the request was stopped before it could fail.";
28
+ readonly "notice.settingsSaved": "Settings saved.";
29
+ readonly "notice.settingsApplied": "Settings applied — no restart needed.";
30
+ readonly "notice.conversationDeleted": "Conversation deleted.";
31
+ readonly "notice.workspaceDeleted": "Project removed, along with its {count} conversation(s). The folder itself was left alone.";
32
+ readonly "notice.assetsUploaded": "{count} image(s) uploaded.";
33
+ readonly "notice.attachmentDropped": "{name} couldn't be sent and was left out of the message.";
34
+ readonly "notice.upgradeRestarting": "Updated to {version}. Restarting now.";
35
+ readonly "notice.logWarning": "Host warning: {summary}";
36
+ readonly "notice.logError": "Host error: {summary}";
37
+ readonly "notice.handoffWritten": "Handoff document written to {path}.";
38
+ readonly "notice.autoNamed": "Named this conversation \"{name}\".";
39
+ readonly "notice.languageChanged": "This connection now speaks {language}.";
40
+ readonly "notice.hardLimitHit": "This turn stopped at the {limit}-token limit. Nothing was lost — the conversation is waiting for you.";
41
+ readonly "status.connected": "Connected";
42
+ readonly "status.awaitingFirstToken": "Connected — waiting for the first word";
43
+ readonly "status.thinking": "Thinking…";
44
+ readonly "status.generating": "Writing…";
45
+ readonly "status.assemblingToolCalls": "Putting together {count} tool call(s)…";
46
+ readonly "status.awaitingTools": "Waiting on {tools}";
47
+ readonly "status.idle": "Ready";
48
+ readonly "status.done": "Finished";
49
+ readonly "status.aborted": "Stopped";
50
+ readonly "status.error": "Stopped by an error";
51
+ readonly "question.handoff.prompt": "This conversation is at {percent}% of the context budget set for it. How should we continue?";
52
+ readonly "question.handoff.self": "Let the assistant write the handoff itself";
53
+ readonly "question.handoff.selfDetail": "Uses the full conversation and its tools — the best result, at the price of one more full input.";
54
+ readonly "question.handoff.summary": "Summarise the history instead";
55
+ readonly "question.handoff.summaryDetail": "Cheaper and predictable, but the document is less faithful.";
56
+ readonly "question.handoff.decline": "Keep going in this conversation";
57
+ readonly "question.confirm.prompt": "{action} can't be undone. Go ahead?";
58
+ readonly "question.confirm.accept": "Yes, do it";
59
+ readonly "question.confirm.decline": "Cancel";
60
+ readonly "question.blocking": "This question is holding the conversation. Answer it to continue.";
61
+ readonly "message.reverted": "Removed {count} message(s). The text is back in your input.";
62
+ readonly "message.cwdMissing": "This project's folder no longer exists ({cwd}). The conversation and its history are still here.";
63
+ readonly "message.injectedContext": "Sent by the host, not typed by you: {summary}";
64
+ readonly "message.injectedContext.cwd": "the current folder is {cwd}";
65
+ readonly "message.subagentFailed": "The helper agent {name} failed: {reason}";
66
+ readonly "message.subagentFinished": "The helper agent {name} finished.";
67
+ readonly "message.imageAsText": "{model} can't look at images, so {name} was described in text instead.";
68
+ readonly "message.attachmentTooMany": "A message carries at most {limit} images. {name} was left out.";
69
+ readonly "usage.turn": "{value} tokens this turn";
70
+ readonly "usage.total": "{value} tokens in total";
71
+ readonly "usage.rate": "{value} tokens/s";
72
+ readonly "usage.withSubAgents": "the total includes {value} from helper agents";
73
+ readonly "label.agent": "Assistant";
74
+ readonly "label.model": "Model";
75
+ readonly "label.thinking": "Thinking";
76
+ readonly "label.context": "Context";
77
+ readonly "label.usage": "Usage";
78
+ readonly "label.cwd": "Folder";
79
+ readonly "label.tools": "Tools running";
80
+ readonly "label.subagents": "Helper agents";
81
+ readonly "completion.scanning": "Still reading the project's file list — a few more characters and it will fill in.";
82
+ readonly "completion.timedOut": "The file list took longer than {seconds}s to build, so it may be incomplete.";
83
+ readonly "completion.unavailable": "The file list isn't available here: {reason}";
84
+ readonly "completion.noFolder": "this project's folder isn't there anymore";
85
+ readonly "completion.truncated": "Only the first {limit} files are listed; narrow what you type to see the rest.";
86
+ readonly "config.referenced": "Still used by {count} item(s), so it can't be removed: {names}";
87
+ readonly "config.fileBroken": "{path} can't be read as settings: {reason}";
88
+ readonly "endpoint.missing": "{id} isn't in the endpoint list anymore, so this can't be reached.";
89
+ readonly "endpoint.noKey": "{endpoint} has no access key yet, so its models can't answer.";
90
+ readonly "model.endpointMissing": "{model} points to an endpoint ({id}) that isn't in the endpoint list anymore.";
91
+ readonly "agent.modelMissing": "This assistant is bound to a model ({id}) that isn't in the model list anymore.";
92
+ readonly "agent.fileBroken": "{name} can't be read as an assistant definition: {reason}";
93
+ readonly "agent.notFactory": "\"{id}\" isn't part of the factory assistant list, so there's no factory version to restore.";
94
+ readonly "config.issue.thresholdOrder": "{name} has its handoff line ({handoff} tokens) at or above its hard limit ({guard} tokens).";
95
+ readonly "config.issue.defaultMissing": "{field} points to {id}, which isn't in that list anymore.";
96
+ readonly "config.issue.defaultAgentMissing": "The default assistant ({id}) isn't among the assistant definitions anymore.";
97
+ readonly "discovery.notADirectory": "{path} isn't a directory, so nothing was read from it.";
98
+ readonly "discovery.shadowed": "This entry is overridden by the closer {path}.";
99
+ readonly "discovery.mcpEntryInvalid": "{name} has neither a transport nor a command, so it can't be connected.";
100
+ readonly "discovery.skillBroken": "{name} has a SKILL.md that can't be used as a skill: {reason}";
101
+ readonly "discovery.toolUnloadable": "{name} couldn't be loaded as a tool: {reason}";
102
+ readonly "discovery.subAgentBroken": "{name} isn't a usable sub-agent definition: {reason}";
103
+ readonly "model.unavailable": "{name} is listed but can't be used right now: {reason}";
104
+ readonly "model.visionRequired": "{model} can't read images, and this conversation has some.";
105
+ readonly "handoff.degraded": "The handoff fell back to {mode}: {reason}";
106
+ readonly "handoff.declined": "No handoff this time.";
107
+ readonly "handoff.noDocuments": "No handoff documents in this project yet.";
108
+ readonly "workspace.removalCost": "This removes {conversations} conversation(s) and their {messages} message(s). The folder on disk stays.";
109
+ readonly "attachment.tooLarge": "Each image can be at most {limit}; {name} is {size}.";
110
+ readonly "attachment.tooMany": "A message carries at most {limit} images.";
111
+ readonly "notice.unknown": "A notice from the host ({code}).";
112
+ readonly "error.handoffFailed": "The handoff didn't go through: {reason}";
113
+ readonly "error.transientFailed": "That one-off request didn't finish: {reason}";
114
+ readonly "handoff.newConversationSummary": "This conversation continues an earlier one. The handoff document is at {path} — read it first, then carry on with the task.\n\nSummary of the handoff:\n{summary}";
115
+ readonly "handoff.degradeReason.fallback": "the assistant couldn't write the document itself this time";
116
+ readonly "autoName.failed": "No name came out of it, so the original one stays: {reason}";
117
+ readonly "capability.host.hello": "Connect to the host";
118
+ readonly "capability.host.hello.detail": "Opens a connection with an access key and fixes the language this connection speaks.";
119
+ readonly "capability.host.version": "Show the host version";
120
+ readonly "capability.host.version.detail": "The running version and the protocol version, so an upgrade can be checked.";
121
+ readonly "capability.host.upgrade": "Restart into a newer version";
122
+ readonly "capability.host.upgrade.detail": "Compares the version on disk with the running one and restarts when the update has really landed.";
123
+ readonly "capability.host.shutdown": "Shut the host down";
124
+ readonly "capability.host.shutdown.detail": "Stops serving once nothing is left running — open connections are closed.";
125
+ readonly "capability.host.capabilities": "List what the host can do";
126
+ readonly "capability.host.capabilities.detail": "The list this help page is drawn from: what each ability does and whether it blocks or can't be undone.";
127
+ readonly "capability.host.reload": "Reload from disk";
128
+ readonly "capability.host.reload.detail": "Re-read configuration, assistants, tools, skills or MCP entries: affected projects rebuild their capabilities, nothing restarts.";
129
+ readonly "capability.host.setLanguage": "Switch language for this connection";
130
+ readonly "capability.host.setLanguage.detail": "Every message on this connection is rendered in the chosen language; a reconnect forgets it.";
131
+ readonly "capability.workspace.list": "List projects";
132
+ readonly "capability.workspace.list.detail": "Every project on this machine, including the ones whose folder is gone.";
133
+ readonly "capability.workspace.create": "Add a project";
134
+ readonly "capability.workspace.create.detail": "Registers a folder as a project; the same folder can only be added once.";
135
+ readonly "capability.workspace.get": "Show a project";
136
+ readonly "capability.workspace.get.detail": "One project by id, with whether its folder still exists.";
137
+ readonly "capability.workspace.rename": "Rename a project";
138
+ readonly "capability.workspace.rename.detail": "Changes the display name only; the folder path never changes.";
139
+ readonly "capability.workspace.remove": "Remove a project";
140
+ readonly "capability.workspace.remove.detail": "Deletes the project and every conversation in it; the folder on disk is left alone.";
141
+ readonly "capability.conversation.list": "List conversations";
142
+ readonly "capability.conversation.list.detail": "Newest first, pinned ones on top; can be narrowed to one project.";
143
+ readonly "capability.conversation.create": "Start a conversation";
144
+ readonly "capability.conversation.create.detail": "Fixes the project, the assistant and the model for this conversation up front.";
145
+ readonly "capability.conversation.get": "Open a conversation";
146
+ readonly "capability.conversation.get.detail": "One conversation by id — how you pick up where you left off.";
147
+ readonly "capability.conversation.state": "Show what is happening right now";
148
+ readonly "capability.conversation.state.detail": "The six-state run, context thresholds, pending questions and usage in one snapshot.";
149
+ readonly "capability.conversation.rename": "Rename a conversation";
150
+ readonly "capability.conversation.rename.detail": "Changes the name only; identity and order stay as they were.";
151
+ readonly "capability.conversation.pin": "Pin a conversation";
152
+ readonly "capability.conversation.pin.detail": "Keeps it at the top of the sidebar without changing anything else.";
153
+ readonly "capability.conversation.delete": "Delete a conversation";
154
+ readonly "capability.conversation.delete.detail": "Removes the conversation and its messages for good, and cleans up its images.";
155
+ readonly "capability.conversation.send": "Send a message";
156
+ readonly "capability.conversation.send.detail": "Starts one turn: you get the message ids back at once, the answer streams in after.";
157
+ readonly "capability.conversation.abort": "Stop the current turn";
158
+ readonly "capability.conversation.abort.detail": "Stops the answer that is being written; what was written so far stays.";
159
+ readonly "capability.conversation.revert": "Take back messages";
160
+ readonly "capability.conversation.revert.detail": "Deletes everything after a chosen message and puts that text back in your input.";
161
+ readonly "capability.conversation.setModel": "Switch model for this conversation";
162
+ readonly "capability.conversation.setModel.detail": "Without touching the assistant's default and without restarting the conversation.";
163
+ readonly "capability.conversation.setThinking": "Set how hard the model thinks";
164
+ readonly "capability.conversation.setThinking.detail": "Turns a thinking level into request parameters for this conversation only.";
165
+ readonly "capability.conversation.transient": "Ask once without a conversation";
166
+ readonly "capability.conversation.transient.detail": "One request, one answer, nothing saved and no conversation created.";
167
+ readonly "capability.message.list": "Show messages";
168
+ readonly "capability.message.list.detail": "The whole history of a conversation, or everything from a given message on, helper agents included.";
169
+ readonly "capability.question.list": "Show open questions";
170
+ readonly "capability.question.list.detail": "Questions waiting for an answer; every window sees the same ones.";
171
+ readonly "capability.question.answer": "Answer a question";
172
+ readonly "capability.question.answer.detail": "Records the answer and carries on: a handoff question starts the handoff by itself.";
173
+ readonly "capability.notice.list": "Show notices";
174
+ readonly "capability.notice.list.detail": "The notices still on screen — separate from the message stream.";
175
+ readonly "capability.notice.dismiss": "Dismiss a notice";
176
+ readonly "capability.notice.dismiss.detail": "Clears one notice; timed notices go away on their own.";
177
+ readonly "capability.notice.clear": "Clear all notices";
178
+ readonly "capability.notice.clear.detail": "Clears a batch at once, either the whole list or one conversation's.";
179
+ readonly "capability.config.get": "Show settings";
180
+ readonly "capability.config.get.detail": "Endpoints (keys masked), models, defaults and what is misconfigured, in one read.";
181
+ readonly "capability.config.patch": "Change settings";
182
+ readonly "capability.config.patch.detail": "Writes the change and applies it right away — no restart, no save button.";
183
+ readonly "capability.config.setDefaults": "Set the defaults";
184
+ readonly "capability.config.setDefaults.detail": "Default assistant, fallback model, migration model, image model and naming model.";
185
+ readonly "capability.config.getDiscovery": "Show where abilities come from";
186
+ readonly "capability.config.getDiscovery.detail": "The MCP layers, Skills, tools and helpers that are actually found, plus the files that can't be read.";
187
+ readonly "capability.config.saveMcp": "Save an MCP server";
188
+ readonly "capability.config.saveMcp.detail": "Creates it if the id is new, edits it otherwise — one entry at a time, with its transport and that transport's parameters; fields this version doesn't know are kept as they are.";
189
+ readonly "capability.config.deleteMcp": "Delete an MCP server";
190
+ readonly "capability.config.deleteMcp.detail": "Removes one entry from one of the two editable scopes; says so plainly when it wasn't there.";
191
+ readonly "capability.config.saveEndpoint": "Save an endpoint";
192
+ readonly "capability.config.saveEndpoint.detail": "Creates or edits an endpoint; leave the key out to keep the current one.";
193
+ readonly "capability.config.deleteEndpoint": "Delete an endpoint";
194
+ readonly "capability.config.deleteEndpoint.detail": "Refuses while models still point at it and lists who does.";
195
+ readonly "capability.agent.list": "List assistants";
196
+ readonly "capability.agent.list.detail": "Every assistant, including the ones that can't be used right now and why.";
197
+ readonly "capability.agent.get": "Show an assistant";
198
+ readonly "capability.agent.get.detail": "One assistant definition by id, straight from its file.";
199
+ readonly "capability.agent.create": "Create an assistant";
200
+ readonly "capability.agent.create.detail": "Writes a new definition file — one file per assistant, editable by hand.";
201
+ readonly "capability.agent.update": "Edit an assistant";
202
+ readonly "capability.agent.update.detail": "Changes the definition file; from then on it counts as your own, not the factory one.";
203
+ readonly "capability.agent.delete": "Delete an assistant";
204
+ readonly "capability.agent.delete.detail": "Removes the definition and says who else points at it first.";
205
+ readonly "capability.agent.setModel": "Set an assistant's model";
206
+ readonly "capability.agent.setModel.detail": "Changes the assistant's default model, which affects conversations started later.";
207
+ readonly "capability.agent.setThinking": "Set an assistant's thinking level";
208
+ readonly "capability.agent.setThinking.detail": "Writes the expanded request parameters into the assistant definition.";
209
+ readonly "capability.agent.restoreFactory": "Restore an assistant to factory settings";
210
+ readonly "capability.agent.restoreFactory.detail": "Puts the whole assistant definition — prompt, model, permissions and thinking settings — back to the one that shipped with the host. You can look at the result before it's written.";
211
+ readonly "capability.model.list": "List models";
212
+ readonly "capability.model.list.detail": "Factory-managed and custom models with thresholds, thinking presets and availability.";
213
+ readonly "capability.model.listImages": "List image models";
214
+ readonly "capability.model.listImages.detail": "The models used for image generation, plus which one is the default.";
215
+ readonly "capability.model.create": "Create a model";
216
+ readonly "capability.model.create.detail": "Adds a model bound to an endpoint; a new one counts as custom right away.";
217
+ readonly "capability.model.update": "Edit a model";
218
+ readonly "capability.model.update.detail": "Editing a factory model turns it into a custom one so later updates leave it alone.";
219
+ readonly "capability.model.delete": "Delete a model";
220
+ readonly "capability.model.delete.detail": "Refuses while an assistant still points at it, and fixes the defaults when it goes.";
221
+ readonly "capability.model.restoreFactory": "Restore a model to factory settings";
222
+ readonly "capability.model.restoreFactory.detail": "Replaces the whole model definition with the factory one in a single step.";
223
+ readonly "capability.model.saveImage": "Create or edit an image model";
224
+ readonly "capability.model.saveImage.detail": "Binds an image model to an endpoint with its default size and quality.";
225
+ readonly "capability.model.deleteImage": "Delete an image model";
226
+ readonly "capability.model.deleteImage.detail": "Refuses while it is the default image model.";
227
+ readonly "capability.asset.begin": "Start an upload";
228
+ readonly "capability.asset.begin.detail": "Declares the size and type of a file; anything over the limit is refused right here.";
229
+ readonly "capability.asset.end": "Finish an upload";
230
+ readonly "capability.asset.end.detail": "Checks length and digest, then turns the file into something a message can reference.";
231
+ readonly "capability.asset.get": "Fetch an asset";
232
+ readonly "capability.asset.get.detail": "Returns the stored bytes so any model can replay an image from history; the thumbnail variant currently equals the original.";
233
+ readonly "capability.completion.files": "Complete file paths";
234
+ readonly "capability.completion.files.detail": "The project's file list behind the `@` menu; says so when it is still reading.";
235
+ readonly "capability.handoff.start": "Write a handoff document";
236
+ readonly "capability.handoff.start.detail": "Writes the document and, if asked, opens the next conversation; the old one stays complete.";
237
+ readonly "capability.handoff.listDocuments": "List handoff documents";
238
+ readonly "capability.handoff.listDocuments.detail": "The documents already written in this project, ready to be refined again.";
239
+ readonly "capability.search.conversations": "Search conversations by name";
240
+ readonly "capability.search.conversations.detail": "Finds old conversations by what they are called, optionally within one project.";
241
+ readonly "capability.search.messages": "Search inside conversations";
242
+ readonly "capability.search.messages.detail": "Full-text search over what was said, with a snippet of each hit.";
243
+ };