personal-bot 0.2.4 → 0.2.5

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 (214) hide show
  1. package/CONTEXT.md +9 -7
  2. package/README.md +13 -6
  3. package/README.zh-CN.md +13 -6
  4. package/docs/README.md +3 -1
  5. package/docs/agent-collaboration.md +26 -12
  6. package/docs/architecture-guidelines.md +2 -2
  7. package/docs/capability-design.md +6 -4
  8. package/docs/dsh-implementation-plan.md +158 -0
  9. package/docs/dsh-support-proposal.md +314 -0
  10. package/docs/dsh.md +103 -0
  11. package/docs/file-storage.md +14 -9
  12. package/docs/history.md +29 -18
  13. package/docs/installation-design.md +3 -1
  14. package/docs/interaction-design.md +13 -0
  15. package/docs/release.md +3 -3
  16. package/docs/technical-design.md +29 -15
  17. package/docs/validation.md +38 -2
  18. package/lib/client.js +1071 -0
  19. package/lib/common/files.d.ts +2 -0
  20. package/lib/common/files.js +44 -0
  21. package/lib/common/json.d.ts +6 -0
  22. package/lib/common/json.js +16 -0
  23. package/lib/common/markdown.d.ts +5 -0
  24. package/lib/common/markdown.js +26 -0
  25. package/lib/common/paths.d.ts +1 -0
  26. package/lib/common/paths.js +2 -0
  27. package/lib/common/validation.d.ts +3 -0
  28. package/lib/common/validation.js +14 -0
  29. package/lib/common/version.d.ts +3 -0
  30. package/lib/common/version.js +13 -0
  31. package/lib/dsh.d.ts +4 -0
  32. package/lib/dsh.js +22 -0
  33. package/lib/extension/dsh/agent-events.d.ts +24 -0
  34. package/lib/extension/dsh/agent-events.js +242 -0
  35. package/lib/extension/dsh/agent-runtime.d.ts +49 -0
  36. package/lib/extension/dsh/agent-runtime.js +348 -0
  37. package/lib/extension/dsh/command.d.ts +4 -0
  38. package/lib/extension/dsh/command.js +83 -0
  39. package/lib/extension/dsh/files.d.ts +5 -0
  40. package/lib/extension/dsh/files.js +67 -0
  41. package/lib/extension/dsh/history.d.ts +15 -0
  42. package/lib/extension/dsh/history.js +88 -0
  43. package/lib/extension/dsh/management.d.ts +21 -0
  44. package/lib/extension/dsh/management.js +217 -0
  45. package/lib/extension/dsh/workspace.d.ts +48 -0
  46. package/lib/extension/dsh/workspace.js +290 -0
  47. package/lib/integrations/agent-resources.d.ts +1 -0
  48. package/lib/integrations/agent-resources.js +18 -0
  49. package/lib/integrations/dsh/dsh-agents.d.ts +30 -0
  50. package/lib/integrations/dsh/dsh-agents.js +104 -0
  51. package/lib/integrations/dsh/history-summary.d.ts +11 -0
  52. package/lib/integrations/dsh/history-summary.js +40 -0
  53. package/lib/integrations/dsh/history.d.ts +16 -0
  54. package/lib/integrations/dsh/history.js +156 -0
  55. package/lib/integrations/dsh/input.d.ts +21 -0
  56. package/lib/integrations/dsh/input.js +62 -0
  57. package/lib/integrations/dsh/messages.d.ts +36 -0
  58. package/lib/integrations/dsh/messages.js +11 -0
  59. package/lib/integrations/dsh/notifications.d.ts +8 -0
  60. package/lib/integrations/dsh/notifications.js +55 -0
  61. package/lib/integrations/dsh/resources.d.ts +10 -0
  62. package/lib/integrations/dsh/resources.js +41 -0
  63. package/lib/integrations/dsh/schema.d.ts +7 -0
  64. package/lib/integrations/dsh/schema.js +28 -0
  65. package/lib/integrations/dsh/session.d.ts +14 -0
  66. package/lib/integrations/dsh/session.js +59 -0
  67. package/lib/integrations/history-summary.d.ts +2 -0
  68. package/lib/integrations/history-summary.js +21 -0
  69. package/lib/integrations/process.d.ts +14 -0
  70. package/lib/integrations/process.js +48 -0
  71. package/lib/integrations/python-activation.d.ts +2 -0
  72. package/lib/integrations/python-activation.js +29 -0
  73. package/lib/integrations/team-context.d.ts +18 -0
  74. package/lib/integrations/team-context.js +57 -0
  75. package/lib/model/agent.d.ts +92 -0
  76. package/lib/model/agent.js +1 -0
  77. package/lib/model/history.d.ts +43 -0
  78. package/lib/model/history.js +1 -0
  79. package/lib/model/team.d.ts +85 -0
  80. package/lib/model/team.js +1 -0
  81. package/lib/services/agents/agent-notices.d.ts +13 -0
  82. package/lib/services/agents/agent-notices.js +25 -0
  83. package/lib/services/agents/agent-run.d.ts +39 -0
  84. package/lib/services/agents/agent-run.js +138 -0
  85. package/lib/services/agents/agent-service.d.ts +166 -0
  86. package/lib/services/agents/agent-service.js +325 -0
  87. package/lib/services/agents/team-service.d.ts +168 -0
  88. package/lib/services/agents/team-service.js +343 -0
  89. package/lib/services/history/history-service.d.ts +103 -0
  90. package/lib/services/history/history-service.js +269 -0
  91. package/lib/services/workspace/python-environment-service.d.ts +15 -0
  92. package/lib/services/workspace/python-environment-service.js +50 -0
  93. package/lib/services/workspace/workspace-files.d.ts +2 -0
  94. package/lib/services/workspace/workspace-files.js +17 -0
  95. package/lib/services/workspace/workspace-preparation.d.ts +2 -0
  96. package/lib/services/workspace/workspace-preparation.js +18 -0
  97. package/lib/storage/agent-files.d.ts +30 -0
  98. package/lib/storage/agent-files.js +166 -0
  99. package/lib/storage/atomic-json.d.ts +11 -0
  100. package/lib/storage/atomic-json.js +101 -0
  101. package/lib/storage/file-access.d.ts +2 -0
  102. package/lib/storage/file-access.js +26 -0
  103. package/lib/storage/history-files.d.ts +10 -0
  104. package/lib/storage/history-files.js +63 -0
  105. package/lib/storage/team-files.d.ts +16 -0
  106. package/lib/storage/team-files.js +111 -0
  107. package/lib/tools/agents/actions.d.ts +52 -0
  108. package/lib/tools/agents/actions.js +49 -0
  109. package/lib/tools/agents/contract.d.ts +163 -0
  110. package/lib/tools/agents/contract.js +56 -0
  111. package/lib/tools/agents/dsh-contract.d.ts +52 -0
  112. package/lib/tools/agents/dsh-contract.js +15 -0
  113. package/lib/tools/agents/dsh-tool.d.ts +5 -0
  114. package/lib/tools/agents/dsh-tool.js +38 -0
  115. package/lib/tools/history/actions.d.ts +70 -0
  116. package/lib/tools/history/actions.js +7 -0
  117. package/lib/tools/history/contract.d.ts +81 -0
  118. package/lib/tools/history/contract.js +32 -0
  119. package/lib/tools/history/dsh-tool.d.ts +4 -0
  120. package/lib/tools/history/dsh-tool.js +22 -0
  121. package/lib/tools/result.d.ts +18 -0
  122. package/lib/tools/result.js +10 -0
  123. package/lib/tools/teams/actions.d.ts +24 -0
  124. package/lib/tools/teams/actions.js +38 -0
  125. package/lib/tools/teams/contract.d.ts +232 -0
  126. package/lib/tools/teams/contract.js +67 -0
  127. package/lib/tools/teams/dsh-tool.d.ts +8 -0
  128. package/lib/tools/teams/dsh-tool.js +49 -0
  129. package/lib/ui/dsh/attachments.d.ts +5 -0
  130. package/lib/ui/dsh/attachments.js +39 -0
  131. package/lib/ui/dsh/elements.d.ts +17 -0
  132. package/lib/ui/dsh/elements.js +79 -0
  133. package/lib/ui/dsh/index.d.ts +4 -0
  134. package/lib/ui/dsh/index.js +13 -0
  135. package/lib/ui/dsh/management.d.ts +4 -0
  136. package/lib/ui/dsh/management.js +711 -0
  137. package/lib/ui/dsh/remote.d.ts +15 -0
  138. package/lib/ui/dsh/remote.js +11 -0
  139. package/lib/ui/dsh/styles.d.ts +1 -0
  140. package/lib/ui/dsh/styles.js +132 -0
  141. package/lib/ui/presentation.d.ts +3 -0
  142. package/lib/ui/presentation.js +12 -0
  143. package/npm-shrinkwrap.json +11140 -830
  144. package/package.json +94 -12
  145. package/python/README.md +6 -6
  146. package/resources/agents/coordinator.md +1 -1
  147. package/resources/dsh/cordis.patch.yml +3 -0
  148. package/resources/prompts/workspace.md +1 -1
  149. package/resources/references/compute.md +1 -1
  150. package/resources/references/task-conductor.md +6 -4
  151. package/resources/skills/provider-connections/SKILL.md +10 -0
  152. package/scripts/README.md +9 -1
  153. package/src/dsh.ts +22 -0
  154. package/src/extension/agent-events.ts +51 -46
  155. package/src/extension/agents-command.ts +48 -34
  156. package/src/extension/command.ts +42 -23
  157. package/src/extension/dsh/agent-events.ts +148 -0
  158. package/src/extension/dsh/agent-runtime.ts +251 -0
  159. package/src/extension/dsh/command.ts +78 -0
  160. package/src/extension/dsh/files.ts +61 -0
  161. package/src/extension/dsh/history.ts +69 -0
  162. package/src/extension/dsh/management.ts +108 -0
  163. package/src/extension/dsh/workspace.ts +206 -0
  164. package/src/extension/events.ts +6 -4
  165. package/src/extension/history.ts +15 -12
  166. package/src/extension/subagent-entry.ts +34 -63
  167. package/src/extension/teams-command.ts +53 -46
  168. package/src/integrations/{pi/agent-resources.ts → agent-resources.ts} +2 -2
  169. package/src/integrations/dsh/dsh-agents.ts +97 -0
  170. package/src/integrations/dsh/history-summary.ts +43 -0
  171. package/src/integrations/dsh/history.ts +76 -0
  172. package/src/integrations/dsh/input.ts +66 -0
  173. package/src/integrations/dsh/messages.ts +22 -0
  174. package/src/integrations/dsh/notifications.ts +46 -0
  175. package/src/integrations/dsh/resources.ts +44 -0
  176. package/src/integrations/dsh/schema.ts +26 -0
  177. package/src/integrations/dsh/session.ts +67 -0
  178. package/src/integrations/history-summary.ts +20 -0
  179. package/src/integrations/pi/history.ts +4 -14
  180. package/src/integrations/pi/pi-agents.ts +17 -6
  181. package/src/integrations/pi/team-context.ts +6 -58
  182. package/src/integrations/team-context.ts +60 -0
  183. package/src/model/agent.ts +2 -0
  184. package/src/model/history.ts +3 -1
  185. package/src/pbot.ts +1 -1
  186. package/src/services/agents/agent-notices.ts +28 -0
  187. package/src/services/agents/agent-run.ts +114 -0
  188. package/src/services/agents/agent-service.ts +127 -64
  189. package/src/services/history/history-service.ts +120 -59
  190. package/src/storage/agent-files.ts +17 -4
  191. package/src/storage/history-files.ts +30 -5
  192. package/src/tools/agents/actions.ts +47 -0
  193. package/src/tools/agents/contract.ts +8 -5
  194. package/src/tools/agents/dsh-contract.ts +16 -0
  195. package/src/tools/agents/dsh-tool.ts +41 -0
  196. package/src/tools/agents/tool.ts +7 -43
  197. package/src/tools/history/actions.ts +9 -0
  198. package/src/tools/history/contract.ts +34 -0
  199. package/src/tools/history/dsh-tool.ts +22 -0
  200. package/src/tools/history/tool.ts +7 -30
  201. package/src/tools/teams/actions.ts +38 -0
  202. package/src/tools/teams/contract.ts +7 -3
  203. package/src/tools/teams/dsh-tool.ts +55 -0
  204. package/src/tools/teams/tool.ts +6 -31
  205. package/src/ui/agent-display.ts +7 -4
  206. package/src/ui/dsh/attachments.ts +42 -0
  207. package/src/ui/dsh/elements.ts +50 -0
  208. package/src/ui/dsh/index.ts +18 -0
  209. package/src/ui/dsh/management.ts +412 -0
  210. package/src/ui/dsh/remote.ts +20 -0
  211. package/src/ui/dsh/styles.ts +132 -0
  212. package/src/ui/pi/menu.ts +37 -0
  213. package/src/ui/pi/reader.ts +46 -0
  214. package/src/ui/presentation.ts +12 -0
@@ -0,0 +1,101 @@
1
+ import { constants, closeSync, fstatSync, fsyncSync, linkSync, lstatSync, openSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { canonical } from "../common/json.js";
5
+ import { requireThat } from "../common/validation.js";
6
+ /** The root must already exist. Never follow aliases inside internal storage. */
7
+ export function internalPath(directory, relative) {
8
+ const parts = relative.split("/");
9
+ requireThat(parts.every(part => part && part !== "." && part !== ".." && !/[\\\x00-\x1f]/.test(part)), "内部状态路径无效。");
10
+ const info = lstatSync(directory);
11
+ requireThat(info.isDirectory() && !info.isSymbolicLink(), "内部状态必须使用普通目录。");
12
+ let path = realpathSync(directory);
13
+ for (const [index, part] of parts.entries()) {
14
+ path = join(path, part);
15
+ try {
16
+ const info = lstatSync(path);
17
+ requireThat(!info.isSymbolicLink() && (index === parts.length - 1 ? info.isFile() : info.isDirectory()), "内部状态不能使用符号链接或特殊文件。");
18
+ }
19
+ catch (error) {
20
+ if (error.code !== "ENOENT" || index !== parts.length - 1)
21
+ throw error;
22
+ }
23
+ }
24
+ return path;
25
+ }
26
+ export function syncDirectory(directory) {
27
+ const fd = openSync(directory, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
28
+ try {
29
+ fsyncSync(fd);
30
+ }
31
+ finally {
32
+ closeSync(fd);
33
+ }
34
+ }
35
+ /** Validators return plain data and must reject incomplete contracts. */
36
+ export function readJsonFile(directory, relative, validate) {
37
+ const path = internalPath(directory, relative);
38
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
39
+ try {
40
+ requireThat(fstatSync(fd).isFile(), "内部状态必须是普通文件。");
41
+ let value;
42
+ try {
43
+ value = JSON.parse(readFileSync(fd, "utf8"));
44
+ }
45
+ catch (error) {
46
+ throw new Error("内部 JSON 文件不可读取:" + relative, { cause: error });
47
+ }
48
+ return validate(value);
49
+ }
50
+ finally {
51
+ closeSync(fd);
52
+ }
53
+ }
54
+ /**
55
+ * A failure after publication does not mean that the old value remains.
56
+ * Callers must stop writes/sends on I/O failure, even if a subsequent read succeeds.
57
+ * createOnly publishes by link, so an existing destination is never overwritten.
58
+ */
59
+ export function writeJsonFile(directory, relative, value, validate, createOnly = false) {
60
+ const validated = validate(value);
61
+ // Check before touching disk: JSON.stringify alone silently drops unsupported values.
62
+ const expected = canonical(validated);
63
+ const content = JSON.stringify(validated, null, 2) + "\n";
64
+ requireThat(canonical(JSON.parse(content)) === expected, "JSON 序列化不能改变状态值。");
65
+ const path = internalPath(directory, relative), parent = dirname(path);
66
+ const temporary = join(parent, `.tmp-${randomUUID()}`);
67
+ const fd = openSync(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
68
+ try {
69
+ try {
70
+ writeFileSync(fd, content, "utf8");
71
+ fsyncSync(fd);
72
+ }
73
+ finally {
74
+ closeSync(fd);
75
+ }
76
+ requireThat(internalPath(directory, relative) === path, "内部状态路径已变化。");
77
+ if (createOnly) {
78
+ try {
79
+ linkSync(temporary, path);
80
+ }
81
+ catch (error) {
82
+ if (error.code === "EEXIST")
83
+ return false;
84
+ throw error;
85
+ }
86
+ }
87
+ else
88
+ renameSync(temporary, path);
89
+ syncDirectory(parent);
90
+ return true;
91
+ }
92
+ finally {
93
+ try {
94
+ unlinkSync(temporary);
95
+ }
96
+ catch (error) {
97
+ if (error.code !== "ENOENT")
98
+ throw error;
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,2 @@
1
+ export declare function fileId(id: string): string;
2
+ export declare function privateDirectory(root: string, relative: string): void;
@@ -0,0 +1,26 @@
1
+ import { lstatSync, mkdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { requireThat } from "../common/validation.js";
4
+ import { syncDirectory } from "./atomic-json.js";
5
+ export function fileId(id) {
6
+ requireThat(/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(id), "内部记录 ID 无效。");
7
+ return id;
8
+ }
9
+ export function privateDirectory(root, relative) {
10
+ const parts = relative.split("/");
11
+ let parent = root;
12
+ for (const part of parts) {
13
+ fileId(part);
14
+ const path = join(parent, part);
15
+ try {
16
+ mkdirSync(path, { mode: 0o700 });
17
+ syncDirectory(parent);
18
+ }
19
+ catch (error) {
20
+ if (error.code !== "EEXIST")
21
+ throw error;
22
+ }
23
+ requireThat(lstatSync(path).isDirectory() && !lstatSync(path).isSymbolicLink(), "内部状态目录无效。");
24
+ parent = path;
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ import type { HistoryHost, HistoryRecord } from "../model/history.js";
2
+ export declare class HistoryFiles {
3
+ readonly directory: string;
4
+ readonly host: HistoryHost;
5
+ constructor(directory: string, host?: HistoryHost);
6
+ list(workspace?: string): HistoryRecord[];
7
+ /** The callback is synchronous: no SDK reads or model work can hold this source's write lock. */
8
+ control<T>(operation: () => T): T;
9
+ save(value: HistoryRecord): void;
10
+ }
@@ -0,0 +1,63 @@
1
+ import { existsSync, mkdirSync, readdirSync, rmdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { object } from "../common/json.js";
4
+ import { requireThat } from "../common/validation.js";
5
+ import { readJsonFile, writeJsonFile } from "./atomic-json.js";
6
+ import { fileId } from "./file-access.js";
7
+ const strings = (value) => Array.isArray(value) && value.every(item => typeof item === "string");
8
+ function record(value) {
9
+ requireThat(object(value) && typeof value.id === "string" && typeof value.sessionId === "string" &&
10
+ typeof value.name === "string" && Array.isArray(value.nodes), "历史索引无效。");
11
+ for (const node of value.nodes)
12
+ requireThat(object(node) && typeof node.id === "string" &&
13
+ ["session", "exchange", "summary"].includes(String(node.kind)) && Number.isInteger(node.level) &&
14
+ strings(node.entryIds) && strings(node.parents) && strings(node.children) && typeof node.text === "string" &&
15
+ typeof node.from === "string" && typeof node.to === "string" && typeof node.ready === "boolean" && typeof node.completed === "boolean", "历史节点无效。");
16
+ const result = value, ids = new Set(result.nodes.map(node => node.id));
17
+ requireThat(ids.size === result.nodes.length && result.nodes.some(node => node.id === result.id && node.kind === "session") &&
18
+ result.nodes.every(node => [...node.parents, ...node.children].every(id => ids.has(id))), "历史节点关系无效。");
19
+ return result;
20
+ }
21
+ export class HistoryFiles {
22
+ directory;
23
+ host;
24
+ constructor(directory, host = "pi") {
25
+ this.directory = directory;
26
+ this.host = host;
27
+ }
28
+ list(workspace) {
29
+ if (!existsSync(this.directory))
30
+ return [];
31
+ return readdirSync(this.directory).filter(name => name.endsWith(".json"))
32
+ .map(name => readJsonFile(this.directory, name, value => {
33
+ const result = record(value);
34
+ requireThat(this.host !== "dsh" || result.id.startsWith("dsh-"), "dsh 历史根 ID 缺少来源前缀。");
35
+ return result;
36
+ }))
37
+ .filter(value => workspace === undefined || ("workspace" in value && value.workspace === workspace));
38
+ }
39
+ /** The callback is synchronous: no SDK reads or model work can hold this source's write lock. */
40
+ control(operation) {
41
+ mkdirSync(this.directory, { recursive: true, mode: 0o700 });
42
+ const lock = join(this.directory, ".write");
43
+ try {
44
+ mkdirSync(lock, { mode: 0o700 });
45
+ }
46
+ catch (error) {
47
+ if (error.code === "EEXIST")
48
+ throw Object.assign(new Error("历史来源写锁被占用:" + this.host), { code: "PBOT_HISTORY_BUSY" });
49
+ throw error;
50
+ }
51
+ try {
52
+ return operation();
53
+ }
54
+ finally {
55
+ rmdirSync(lock);
56
+ }
57
+ }
58
+ save(value) {
59
+ requireThat(this.host !== "dsh" || value.id.startsWith("dsh-"), "dsh 历史根 ID 缺少来源前缀。");
60
+ mkdirSync(this.directory, { recursive: true, mode: 0o700 });
61
+ writeJsonFile(this.directory, fileId(value.id) + ".json", value, record);
62
+ }
63
+ }
@@ -0,0 +1,16 @@
1
+ import type { TeamRecord, TeamReady, TeamLink } from "../model/team.js";
2
+ import { AgentFiles } from "./agent-files.js";
3
+ export declare function teamReady(v: unknown): TeamReady;
4
+ export declare function teamRecord(v: unknown): TeamRecord;
5
+ export declare class TeamFiles {
6
+ readonly agents: AgentFiles;
7
+ readonly root: string;
8
+ constructor(agents: AgentFiles);
9
+ check(): void;
10
+ read(id: string): TeamRecord;
11
+ list(): TeamRecord[];
12
+ save(value: TeamRecord, create?: boolean): void;
13
+ ready(id: string): TeamReady | undefined;
14
+ setReady(id: string, generation: string, ready: boolean): void;
15
+ links(records?: TeamRecord[]): Map<string, TeamLink>;
16
+ }
@@ -0,0 +1,111 @@
1
+ import { existsSync, lstatSync, mkdirSync, readdirSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { object } from "../common/json.js";
4
+ import { requireThat } from "../common/validation.js";
5
+ import { AgentFiles } from "./agent-files.js";
6
+ import { readJsonFile, writeJsonFile } from "./atomic-json.js";
7
+ import { fileId, privateDirectory } from "./file-access.js";
8
+ const text = (v) => typeof v === "string" && v.length > 0;
9
+ const integer = (v, min = 0) => Number.isSafeInteger(v) && v >= min;
10
+ export function teamReady(v) {
11
+ requireThat(object(v) && text(v.generation) && typeof v.ready === "boolean", "团队就绪标记无效。");
12
+ return v;
13
+ }
14
+ export function teamRecord(v) {
15
+ requireThat(object(v) && text(v.teamId) && text(v.release) && text(v.workspace) && text(v.parentSessionId) &&
16
+ (v.parentLeaf === null || text(v.parentLeaf)) && text(v.name) && text(v.brief) && typeof v.closed === "boolean" &&
17
+ Array.isArray(v.members) && v.members.length > 0 && v.members.length <= 50 && Array.isArray(v.runs) && Array.isArray(v.messages), "团队记录无效。");
18
+ fileId(v.teamId);
19
+ const members = new Set(), runs = new Set(), requests = new Map(), operations = new Set();
20
+ for (const m of v.members) {
21
+ requireThat(object(m) && text(m.agentId) && text(m.role) && !members.has(m.agentId), "团队成员无效或重复。");
22
+ fileId(m.agentId);
23
+ members.add(m.agentId);
24
+ }
25
+ let running = 0;
26
+ for (const r of v.runs) {
27
+ requireThat(object(r) && text(r.runId) && !runs.has(r.runId) && text(r.instruction) &&
28
+ ["roundRobin", "parallel"].includes(String(r.mode)) && integer(r.rounds, 1) && r.rounds <= 10 &&
29
+ integer(r.maxConcurrent, 1) && r.maxConcurrent <= members.size && (r.mode !== "roundRobin" || r.maxConcurrent === 1) &&
30
+ integer(r.deadlineAt, 1) && ["running", "paused", "finished"].includes(String(r.state)) &&
31
+ (r.reason === undefined || text(r.reason)) && object(r.generations) && Array.isArray(r.issued), "团队批次无效。");
32
+ fileId(r.runId);
33
+ runs.add(r.runId);
34
+ requireThat(Object.keys(r.generations).length === members.size && [...members].every(id => text(r.generations[id])), "团队代次无效。");
35
+ if (r.state === "running")
36
+ running++;
37
+ const turns = new Set();
38
+ for (const q of r.issued) {
39
+ requireThat(object(q) && text(q.requestId) && !requests.has(q.requestId) && text(q.agentId) && members.has(q.agentId) &&
40
+ q.generation === r.generations[q.agentId] && integer(q.round, 1) && q.round <= r.rounds &&
41
+ integer(q.throughSeq) && q.throughSeq <= v.messages.length && !turns.has(q.agentId + ":" + q.round), "团队请求关联无效。");
42
+ fileId(q.requestId);
43
+ requests.set(q.requestId, { agentId: q.agentId, runId: r.runId });
44
+ turns.add(q.agentId + ":" + q.round);
45
+ }
46
+ }
47
+ requireThat(running <= 1 && (!v.closed || running === 0), "团队运行状态冲突。");
48
+ for (const [i, m] of v.messages.entries()) {
49
+ requireThat(object(m) && m.seq === i + 1 && text(m.operationId) && !operations.has(m.operationId) && typeof m.text === "string" &&
50
+ object(m.author) && ["user", "coordinator", "member"].includes(String(m.author.kind)) && text(m.author.name) &&
51
+ (m.author.kind === "member" ? text(m.author.agentId) && members.has(m.author.agentId) : m.author.agentId === undefined) &&
52
+ (m.replyTo === undefined || (integer(m.replyTo, 1) && m.replyTo <= i)) &&
53
+ (m.runId === undefined || (text(m.runId) && runs.has(m.runId))), "团队消息无效。");
54
+ if (m.source !== undefined)
55
+ requireThat(object(m.source) && text(m.source.requestId) && text(m.source.cycleId) &&
56
+ requests.get(m.source.requestId)?.agentId === m.author.agentId && requests.get(m.source.requestId)?.runId === m.runId, "团队报告关联无效。");
57
+ operations.add(m.operationId);
58
+ }
59
+ return v;
60
+ }
61
+ export class TeamFiles {
62
+ agents;
63
+ root;
64
+ constructor(agents) {
65
+ this.agents = agents;
66
+ this.root = join(dirname(agents.root), "teams");
67
+ }
68
+ check() { this.agents.check(); }
69
+ read(id) {
70
+ const value = readJsonFile(this.root, fileId(id) + "/team.json", teamRecord);
71
+ requireThat(value.teamId === id, "团队路径与身份不匹配。");
72
+ return value;
73
+ }
74
+ list() {
75
+ if (!existsSync(this.root))
76
+ return [];
77
+ return readdirSync(this.root, { withFileTypes: true }).filter(e => !e.name.startsWith(".")).map(e => this.read(e.name));
78
+ }
79
+ save(value, create = false) {
80
+ this.check();
81
+ teamRecord(value);
82
+ let published;
83
+ try {
84
+ mkdirSync(this.root, { recursive: true, mode: 0o700 });
85
+ const directory = lstatSync(this.root);
86
+ requireThat(directory.isDirectory() && !directory.isSymbolicLink(), "团队状态必须使用普通目录。");
87
+ if (create)
88
+ privateDirectory(this.root, fileId(value.teamId));
89
+ published = writeJsonFile(this.root, fileId(value.teamId) + "/team.json", value, teamRecord, create);
90
+ }
91
+ catch (error) {
92
+ this.agents.fail(error);
93
+ throw error;
94
+ }
95
+ requireThat(published, "团队已存在。");
96
+ }
97
+ ready(id) { return this.agents.optional(id, "team-ready.json", teamReady); }
98
+ setReady(id, generation, ready) {
99
+ this.agents.write(id, "team-ready.json", { generation, ready }, teamReady);
100
+ }
101
+ links(records = this.list()) {
102
+ const result = new Map();
103
+ for (const team of records)
104
+ for (const run of team.runs)
105
+ for (const request of run.issued) {
106
+ requireThat(!result.has(request.requestId), "团队请求 ID 重复。");
107
+ result.set(request.requestId, { team, run, request });
108
+ }
109
+ return result;
110
+ }
111
+ }
@@ -0,0 +1,52 @@
1
+ import type { Static } from "typebox";
2
+ import type { AgentService } from "../../services/agents/agent-service.js";
3
+ import type { AgentOptions, AgentOwner } from "../../model/agent.js";
4
+ import type { agentParametersSchema } from "./contract.js";
5
+ export type AgentInput = Omit<Static<typeof agentParametersSchema>, "thinking"> & {
6
+ thinking?: string;
7
+ };
8
+ export declare function executeAgent(service: AgentService, input: AgentInput, owner: AgentOwner, defaults?: AgentOptions): Promise<{
9
+ isError?: boolean;
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ details: import("../../common/json.js").Json;
15
+ structuredContent: import("../../common/json.js").Json;
16
+ } | {
17
+ details: {
18
+ agentReadKeys?: string[];
19
+ error?: string;
20
+ requestId?: string;
21
+ cycle?: {
22
+ error?: string;
23
+ finishedAt?: number;
24
+ state: "running" | "completed" | "failed" | "cancelled" | "interrupted";
25
+ startedAt: number;
26
+ cycleId: string;
27
+ requestIds: string[];
28
+ source: "parent" | "interactive" | "mixed";
29
+ };
30
+ report?: string;
31
+ messageStatus?: "queued";
32
+ cycles?: {
33
+ state: string;
34
+ cycleId: string;
35
+ }[];
36
+ totalLength?: number;
37
+ nextOffset?: number | null;
38
+ state: "starting" | "busy" | "idle" | "stopping" | "stopped" | "error";
39
+ agentId: string;
40
+ cwd: string;
41
+ createdAt: number;
42
+ name: string;
43
+ activity: string;
44
+ owned: boolean;
45
+ };
46
+ isError?: boolean;
47
+ content: {
48
+ type: "text";
49
+ text: string;
50
+ }[];
51
+ structuredContent: import("../../common/json.js").Json;
52
+ }>;
@@ -0,0 +1,49 @@
1
+ import { markdownResult } from "../result.js";
2
+ function agentOutput(view) {
3
+ const c = view.cycle;
4
+ return {
5
+ agentId: view.agentId, name: view.name, cwd: view.cwd, createdAt: view.createdAt,
6
+ owned: view.owned, state: view.state, activity: view.activity,
7
+ ...(c ? { cycle: { cycleId: c.cycleId, startedAt: c.startedAt, state: c.state, requestIds: c.requestIds, source: c.source,
8
+ ...(c.finishedAt === undefined ? {} : { finishedAt: c.finishedAt }), ...(c.error === undefined ? {} : { error: c.error }) } } : {}),
9
+ ...(view.error === undefined ? {} : { error: view.error }),
10
+ ...(view.requestId === undefined ? {} : { requestId: view.requestId }),
11
+ ...(view.messageStatus === undefined ? {} : { messageStatus: view.messageStatus }),
12
+ ...(view.cycles === undefined ? {} : { cycles: view.cycles }),
13
+ ...(view.report === undefined ? {} : { report: view.report }),
14
+ ...(view.totalLength === undefined ? {} : { totalLength: view.totalLength }),
15
+ ...(view.nextOffset === undefined ? {} : { nextOffset: view.nextOffset }),
16
+ };
17
+ }
18
+ export async function executeAgent(service, input, owner, defaults = {}) {
19
+ let value;
20
+ switch (input.action) {
21
+ case "start": {
22
+ const { action: _action, ...supplied } = input;
23
+ value = await service.start({ ...defaults, ...supplied }, owner);
24
+ break;
25
+ }
26
+ case "list": return markdownResult({ agents: service.list(owner).map(agentOutput) }, "子会话列表");
27
+ case "send":
28
+ value = service.send(input.agentId, input.message, input.delivery ?? "steer", owner);
29
+ break;
30
+ case "rename":
31
+ value = service.rename(input.agentId, input.name, owner);
32
+ break;
33
+ case "resume":
34
+ value = await service.resume(input.agentId, input.message, owner);
35
+ break;
36
+ case "stop":
37
+ value = service.stop(input.agentId, owner);
38
+ break;
39
+ case "status":
40
+ value = service.status(input.agentId, owner);
41
+ break;
42
+ case "read": {
43
+ const page = await service.read(input.agentId, owner, input.cycleId, input.offset, input.limit);
44
+ const data = agentOutput(page), output = markdownResult(data, "子会话报告");
45
+ return { ...output, details: { ...data, ...(page.cycle && page.cycle.state !== "running" ? { agentReadKeys: [page.agentId + ":" + page.cycle.cycleId] } : {}) } };
46
+ }
47
+ }
48
+ return markdownResult(agentOutput(value), "子会话状态");
49
+ }
@@ -0,0 +1,163 @@
1
+ import { Type } from "typebox";
2
+ export declare const agentDescription = "\u72EC\u7ACB\u4E13\u5BB6\u4F1A\u8BDD\uFF0C\u4E0D\u7EE7\u627F\u7236\u804A\u5929\u5386\u53F2\u3002start \u5B8C\u6210\u542F\u52A8\u540E\u8FD4\u56DE\uFF0C\u4E0D\u7B49\u5F85\u5DE5\u4F5C\u5B8C\u6210\uFF1B\u672A\u63D0\u4F9B message/prompts/files \u65F6\u53EA\u542F\u52A8\u5F85\u547D\u4F1A\u8BDD\uFF0C\u4E0D\u8C03\u7528\u6A21\u578B\u3002\u5B8C\u6210\u81EA\u52A8\u901A\u77E5\uFF0C\u65E0\u9700\u8F6E\u8BE2\u3002\u56E2\u961F\u5360\u7528\u671F\u95F4\u4E0D\u80FD\u79C1\u4EBA send\u3002send \u7EE7\u7EED\u5BF9\u8BDD\uFF0Crename \u6539\u540D\uFF0Cstatus/list \u67E5\u770B\u72B6\u6001\uFF0Cstatus \u8FD4\u56DE\u6700\u8FD1\u5468\u671F\u4E14\u4E0D\u8BFB\u53D6\u62A5\u544A\u6B63\u6587\u3002read \u975E\u963B\u585E\u8BFB\u53D6\u62A5\u544A\uFF1B\u8BFB\u53D6\u5DF2\u7ED3\u675F\u5468\u671F\u4F1A\u9886\u53D6\u8BE5\u5468\u671F\u7684\u5B8C\u6210\u901A\u77E5\uFF08\u5305\u62EC\u90E8\u5206\u8BFB\u53D6\uFF09\uFF0C\u540E\u7EED\u4E0D\u518D\u91CD\u590D\u901A\u77E5\u3002nextOffset \u975E\u7A7A\u65F6\u4EE5\u8FD4\u56DE\u7684 cycle.cycleId \u56FA\u5B9A\u5468\u671F\u7EED\u8BFB\u3002state \u662F\u6267\u884C\u72B6\u6001\uFF0Ccycle.state \u662F\u5DE5\u4F5C\u7ED3\u679C\uFF0Cqueued \u4EC5\u8868\u793A\u5165\u961F\u3002stop \u505C\u6B62\u5E76\u4FDD\u7559\u5386\u53F2\uFF0Cresume \u643A\u65B0 message \u6062\u590D\uFF0C\u4E0D\u91CD\u653E\u65E7\u5DE5\u4F5C\u3002\u72EC\u7ACB\u590D\u6838\u987B start \u65B0\u4E0A\u4E0B\u6587\u3002\u5B50\u4F1A\u8BDD\u4F7F\u7528\u539F\u751F CLI/MCP\uFF0C\u6309\u59D4\u6D3E\u8303\u56F4\u5DE5\u4F5C\uFF0C\u4E0D\u9012\u5F52\u59D4\u6D3E\u3002\u6BCF\u4E2A\u7236\u4F1A\u8BDD\u6700\u591A 50 \u4E2A\u5B58\u6D3B\u5B50\u4F1A\u8BDD\uFF0C\u7A7A\u95F2\u4E5F\u8BA1\u5165\u3002";
3
+ export declare const agentStartOptions: {
4
+ name: Type.TOptional<Type.TString>;
5
+ message: Type.TOptional<Type.TString>;
6
+ files: Type.TOptional<Type.TArray<Type.TString>>;
7
+ prompts: Type.TOptional<Type.TArray<Type.TString>>;
8
+ provider: Type.TOptional<Type.TString>;
9
+ model: Type.TOptional<Type.TString>;
10
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">, Type.TLiteral<"max">]>>;
11
+ cwd: Type.TOptional<Type.TString>;
12
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
13
+ noExtensions: Type.TOptional<Type.TBoolean>;
14
+ noSkills: Type.TOptional<Type.TBoolean>;
15
+ noPromptTemplates: Type.TOptional<Type.TBoolean>;
16
+ noContextFiles: Type.TOptional<Type.TBoolean>;
17
+ };
18
+ export declare const agentParametersSchema: Type.TObject<{
19
+ delivery: Type.TOptional<Type.TUnion<[Type.TLiteral<"steer">, Type.TLiteral<"followUp">]>>;
20
+ cycleId: Type.TOptional<Type.TString>;
21
+ offset: Type.TOptional<Type.TInteger>;
22
+ limit: Type.TOptional<Type.TInteger>;
23
+ name: Type.TOptional<Type.TString>;
24
+ message: Type.TOptional<Type.TString>;
25
+ files: Type.TOptional<Type.TArray<Type.TString>>;
26
+ prompts: Type.TOptional<Type.TArray<Type.TString>>;
27
+ provider: Type.TOptional<Type.TString>;
28
+ model: Type.TOptional<Type.TString>;
29
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">, Type.TLiteral<"max">]>>;
30
+ cwd: Type.TOptional<Type.TString>;
31
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
32
+ noExtensions: Type.TOptional<Type.TBoolean>;
33
+ noSkills: Type.TOptional<Type.TBoolean>;
34
+ noPromptTemplates: Type.TOptional<Type.TBoolean>;
35
+ noContextFiles: Type.TOptional<Type.TBoolean>;
36
+ action: Type.TUnion<[Type.TLiteral<"start">, Type.TLiteral<"send">, Type.TLiteral<"rename">, Type.TLiteral<"status">, Type.TLiteral<"list">, Type.TLiteral<"read">, Type.TLiteral<"stop">, Type.TLiteral<"resume">]>;
37
+ agentId: Type.TOptional<Type.TString>;
38
+ }>;
39
+ export declare const agentActionSchema: Type.TUnion<[Type.TObject<{
40
+ name: Type.TOptional<Type.TString>;
41
+ message: Type.TOptional<Type.TString>;
42
+ files: Type.TOptional<Type.TArray<Type.TString>>;
43
+ prompts: Type.TOptional<Type.TArray<Type.TString>>;
44
+ provider: Type.TOptional<Type.TString>;
45
+ model: Type.TOptional<Type.TString>;
46
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">, Type.TLiteral<"max">]>>;
47
+ cwd: Type.TOptional<Type.TString>;
48
+ tools: Type.TOptional<Type.TArray<Type.TString>>;
49
+ noExtensions: Type.TOptional<Type.TBoolean>;
50
+ noSkills: Type.TOptional<Type.TBoolean>;
51
+ noPromptTemplates: Type.TOptional<Type.TBoolean>;
52
+ noContextFiles: Type.TOptional<Type.TBoolean>;
53
+ action: Type.TLiteral<"start">;
54
+ }>, Type.TObject<{
55
+ action: Type.TLiteral<"send">;
56
+ agentId: Type.TString;
57
+ message: Type.TString;
58
+ delivery: Type.TOptional<Type.TUnion<[Type.TLiteral<"steer">, Type.TLiteral<"followUp">]>>;
59
+ }>, Type.TObject<{
60
+ action: Type.TLiteral<"rename">;
61
+ agentId: Type.TString;
62
+ name: Type.TString;
63
+ }>, Type.TObject<{
64
+ action: Type.TLiteral<"resume">;
65
+ agentId: Type.TString;
66
+ message: Type.TString;
67
+ }>, Type.TObject<{
68
+ action: Type.TLiteral<"list">;
69
+ }>, ...Type.TObject<{
70
+ action: Type.TLiteral<string>;
71
+ agentId: Type.TString;
72
+ }>[], Type.TObject<{
73
+ cycleId: Type.TOptional<Type.TString>;
74
+ offset: Type.TOptional<Type.TInteger>;
75
+ limit: Type.TOptional<Type.TInteger>;
76
+ action: Type.TLiteral<"read">;
77
+ agentId: Type.TString;
78
+ }>]>;
79
+ export declare const agentViewSchema: Type.TObject<{
80
+ agentId: Type.TString;
81
+ name: Type.TString;
82
+ cwd: Type.TString;
83
+ createdAt: Type.TNumber;
84
+ owned: Type.TBoolean;
85
+ state: Type.TUnion<[Type.TLiteral<"starting">, Type.TLiteral<"busy">, Type.TLiteral<"idle">, Type.TLiteral<"stopping">, Type.TLiteral<"stopped">, Type.TLiteral<"error">]>;
86
+ activity: Type.TString;
87
+ cycle: Type.TOptional<Type.TObject<{
88
+ cycleId: Type.TString;
89
+ startedAt: Type.TNumber;
90
+ finishedAt: Type.TOptional<Type.TNumber>;
91
+ state: Type.TUnion<[Type.TLiteral<"running">, Type.TLiteral<"completed">, Type.TLiteral<"failed">, Type.TLiteral<"cancelled">, Type.TLiteral<"interrupted">]>;
92
+ requestIds: Type.TArray<Type.TString>;
93
+ source: Type.TUnion<[Type.TLiteral<"parent">, Type.TLiteral<"interactive">, Type.TLiteral<"mixed">]>;
94
+ error: Type.TOptional<Type.TString>;
95
+ }>>;
96
+ error: Type.TOptional<Type.TString>;
97
+ requestId: Type.TOptional<Type.TString>;
98
+ messageStatus: Type.TOptional<Type.TLiteral<"queued">>;
99
+ cycles: Type.TOptional<Type.TArray<Type.TObject<{
100
+ cycleId: Type.TString;
101
+ state: Type.TString;
102
+ }>>>;
103
+ report: Type.TOptional<Type.TString>;
104
+ totalLength: Type.TOptional<Type.TInteger>;
105
+ nextOffset: Type.TOptional<Type.TUnion<[Type.TInteger, Type.TNull]>>;
106
+ }>;
107
+ export declare const agentResultSchema: Type.TUnion<[Type.TObject<{
108
+ agentId: Type.TString;
109
+ name: Type.TString;
110
+ cwd: Type.TString;
111
+ createdAt: Type.TNumber;
112
+ owned: Type.TBoolean;
113
+ state: Type.TUnion<[Type.TLiteral<"starting">, Type.TLiteral<"busy">, Type.TLiteral<"idle">, Type.TLiteral<"stopping">, Type.TLiteral<"stopped">, Type.TLiteral<"error">]>;
114
+ activity: Type.TString;
115
+ cycle: Type.TOptional<Type.TObject<{
116
+ cycleId: Type.TString;
117
+ startedAt: Type.TNumber;
118
+ finishedAt: Type.TOptional<Type.TNumber>;
119
+ state: Type.TUnion<[Type.TLiteral<"running">, Type.TLiteral<"completed">, Type.TLiteral<"failed">, Type.TLiteral<"cancelled">, Type.TLiteral<"interrupted">]>;
120
+ requestIds: Type.TArray<Type.TString>;
121
+ source: Type.TUnion<[Type.TLiteral<"parent">, Type.TLiteral<"interactive">, Type.TLiteral<"mixed">]>;
122
+ error: Type.TOptional<Type.TString>;
123
+ }>>;
124
+ error: Type.TOptional<Type.TString>;
125
+ requestId: Type.TOptional<Type.TString>;
126
+ messageStatus: Type.TOptional<Type.TLiteral<"queued">>;
127
+ cycles: Type.TOptional<Type.TArray<Type.TObject<{
128
+ cycleId: Type.TString;
129
+ state: Type.TString;
130
+ }>>>;
131
+ report: Type.TOptional<Type.TString>;
132
+ totalLength: Type.TOptional<Type.TInteger>;
133
+ nextOffset: Type.TOptional<Type.TUnion<[Type.TInteger, Type.TNull]>>;
134
+ }>, Type.TObject<{
135
+ agents: Type.TArray<Type.TObject<{
136
+ agentId: Type.TString;
137
+ name: Type.TString;
138
+ cwd: Type.TString;
139
+ createdAt: Type.TNumber;
140
+ owned: Type.TBoolean;
141
+ state: Type.TUnion<[Type.TLiteral<"starting">, Type.TLiteral<"busy">, Type.TLiteral<"idle">, Type.TLiteral<"stopping">, Type.TLiteral<"stopped">, Type.TLiteral<"error">]>;
142
+ activity: Type.TString;
143
+ cycle: Type.TOptional<Type.TObject<{
144
+ cycleId: Type.TString;
145
+ startedAt: Type.TNumber;
146
+ finishedAt: Type.TOptional<Type.TNumber>;
147
+ state: Type.TUnion<[Type.TLiteral<"running">, Type.TLiteral<"completed">, Type.TLiteral<"failed">, Type.TLiteral<"cancelled">, Type.TLiteral<"interrupted">]>;
148
+ requestIds: Type.TArray<Type.TString>;
149
+ source: Type.TUnion<[Type.TLiteral<"parent">, Type.TLiteral<"interactive">, Type.TLiteral<"mixed">]>;
150
+ error: Type.TOptional<Type.TString>;
151
+ }>>;
152
+ error: Type.TOptional<Type.TString>;
153
+ requestId: Type.TOptional<Type.TString>;
154
+ messageStatus: Type.TOptional<Type.TLiteral<"queued">>;
155
+ cycles: Type.TOptional<Type.TArray<Type.TObject<{
156
+ cycleId: Type.TString;
157
+ state: Type.TString;
158
+ }>>>;
159
+ report: Type.TOptional<Type.TString>;
160
+ totalLength: Type.TOptional<Type.TInteger>;
161
+ nextOffset: Type.TOptional<Type.TUnion<[Type.TInteger, Type.TNull]>>;
162
+ }>>;
163
+ }>]>;