@shareai-lab/kode-sdk 1.0.0-beta.8 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -273
  3. package/README.zh-CN.md +114 -0
  4. package/dist/core/agent/breakpoint-manager.d.ts +16 -0
  5. package/dist/core/agent/breakpoint-manager.js +36 -0
  6. package/dist/core/agent/message-queue.d.ts +26 -0
  7. package/dist/core/agent/message-queue.js +57 -0
  8. package/dist/core/agent/permission-manager.d.ts +9 -0
  9. package/dist/core/agent/permission-manager.js +32 -0
  10. package/dist/core/agent/todo-manager.d.ts +26 -0
  11. package/dist/core/agent/todo-manager.js +91 -0
  12. package/dist/core/agent/tool-runner.d.ts +9 -0
  13. package/dist/core/agent/tool-runner.js +45 -0
  14. package/dist/core/agent.d.ts +228 -62
  15. package/dist/core/agent.js +1890 -615
  16. package/dist/core/config.d.ts +10 -0
  17. package/dist/core/config.js +2 -0
  18. package/dist/core/context-manager.d.ts +82 -0
  19. package/dist/core/context-manager.js +241 -0
  20. package/dist/core/errors.d.ts +22 -0
  21. package/dist/core/errors.js +49 -0
  22. package/dist/core/events.d.ts +41 -10
  23. package/dist/core/events.js +270 -68
  24. package/dist/core/file-pool.d.ts +41 -0
  25. package/dist/core/file-pool.js +102 -0
  26. package/dist/core/hooks.d.ts +3 -3
  27. package/dist/core/hooks.js +1 -1
  28. package/dist/core/permission-modes.d.ts +31 -0
  29. package/dist/core/permission-modes.js +61 -0
  30. package/dist/core/pool.d.ts +56 -13
  31. package/dist/core/pool.js +244 -34
  32. package/dist/core/room.d.ts +2 -2
  33. package/dist/core/room.js +10 -10
  34. package/dist/core/scheduler.d.ts +30 -23
  35. package/dist/core/scheduler.js +42 -168
  36. package/dist/core/skills/index.d.ts +10 -0
  37. package/dist/core/skills/index.js +20 -0
  38. package/dist/core/skills/management-manager.d.ts +130 -0
  39. package/dist/core/skills/management-manager.js +557 -0
  40. package/dist/core/skills/manager.d.ts +47 -0
  41. package/dist/core/skills/manager.js +243 -0
  42. package/dist/core/skills/operation-queue.d.ts +87 -0
  43. package/dist/core/skills/operation-queue.js +113 -0
  44. package/dist/core/skills/sandbox-file-manager.d.ts +82 -0
  45. package/dist/core/skills/sandbox-file-manager.js +183 -0
  46. package/dist/core/skills/types.d.ts +120 -0
  47. package/dist/core/skills/types.js +9 -0
  48. package/dist/core/skills/xml-generator.d.ts +13 -0
  49. package/dist/core/skills/xml-generator.js +70 -0
  50. package/dist/core/template.d.ts +57 -0
  51. package/dist/core/template.js +35 -0
  52. package/dist/core/time-bridge.d.ts +18 -0
  53. package/dist/core/time-bridge.js +100 -0
  54. package/dist/core/todo.d.ts +34 -0
  55. package/dist/core/todo.js +89 -0
  56. package/dist/core/types.d.ts +311 -114
  57. package/dist/core/types.js +1 -12
  58. package/dist/index.d.ts +47 -9
  59. package/dist/index.js +108 -15
  60. package/dist/infra/db/postgres/postgres-store.d.ts +97 -0
  61. package/dist/infra/db/postgres/postgres-store.js +1073 -0
  62. package/dist/infra/db/sqlite/sqlite-store.d.ts +84 -0
  63. package/dist/infra/db/sqlite/sqlite-store.js +800 -0
  64. package/dist/infra/e2b/e2b-fs.d.ts +29 -0
  65. package/dist/infra/e2b/e2b-fs.js +128 -0
  66. package/dist/infra/e2b/e2b-sandbox.d.ts +37 -0
  67. package/dist/infra/e2b/e2b-sandbox.js +156 -0
  68. package/dist/infra/e2b/e2b-template.d.ts +24 -0
  69. package/dist/infra/e2b/e2b-template.js +105 -0
  70. package/dist/infra/e2b/index.d.ts +4 -0
  71. package/dist/infra/e2b/index.js +9 -0
  72. package/dist/infra/e2b/types.d.ts +46 -0
  73. package/dist/infra/e2b/types.js +2 -0
  74. package/dist/infra/provider.d.ts +17 -58
  75. package/dist/infra/provider.js +65 -116
  76. package/dist/infra/providers/anthropic.d.ts +42 -0
  77. package/dist/infra/providers/anthropic.js +308 -0
  78. package/dist/infra/providers/core/errors.d.ts +230 -0
  79. package/dist/infra/providers/core/errors.js +353 -0
  80. package/dist/infra/providers/core/fork.d.ts +106 -0
  81. package/dist/infra/providers/core/fork.js +418 -0
  82. package/dist/infra/providers/core/index.d.ts +10 -0
  83. package/dist/infra/providers/core/index.js +76 -0
  84. package/dist/infra/providers/core/logger.d.ts +186 -0
  85. package/dist/infra/providers/core/logger.js +191 -0
  86. package/dist/infra/providers/core/retry.d.ts +62 -0
  87. package/dist/infra/providers/core/retry.js +189 -0
  88. package/dist/infra/providers/core/usage.d.ts +151 -0
  89. package/dist/infra/providers/core/usage.js +376 -0
  90. package/dist/infra/providers/gemini.d.ts +49 -0
  91. package/dist/infra/providers/gemini.js +493 -0
  92. package/dist/infra/providers/index.d.ts +25 -0
  93. package/dist/infra/providers/index.js +83 -0
  94. package/dist/infra/providers/openai.d.ts +123 -0
  95. package/dist/infra/providers/openai.js +662 -0
  96. package/dist/infra/providers/types.d.ts +334 -0
  97. package/dist/infra/providers/types.js +20 -0
  98. package/dist/infra/providers/utils.d.ts +53 -0
  99. package/dist/infra/providers/utils.js +400 -0
  100. package/dist/infra/sandbox-factory.d.ts +13 -0
  101. package/dist/infra/sandbox-factory.js +30 -0
  102. package/dist/infra/sandbox.d.ts +35 -6
  103. package/dist/infra/sandbox.js +174 -8
  104. package/dist/infra/store/factory.d.ts +45 -0
  105. package/dist/infra/store/factory.js +80 -0
  106. package/dist/infra/store/index.d.ts +3 -0
  107. package/dist/infra/store/index.js +26 -0
  108. package/dist/infra/store/json-store.d.ts +67 -0
  109. package/dist/infra/store/json-store.js +606 -0
  110. package/dist/infra/store/types.d.ts +342 -0
  111. package/dist/infra/store/types.js +2 -0
  112. package/dist/infra/store.d.ts +12 -32
  113. package/dist/infra/store.js +27 -130
  114. package/dist/tools/bash_kill/index.d.ts +1 -0
  115. package/dist/tools/bash_kill/index.js +35 -0
  116. package/dist/tools/bash_kill/prompt.d.ts +2 -0
  117. package/dist/tools/bash_kill/prompt.js +14 -0
  118. package/dist/tools/bash_logs/index.d.ts +1 -0
  119. package/dist/tools/bash_logs/index.js +40 -0
  120. package/dist/tools/bash_logs/prompt.d.ts +2 -0
  121. package/dist/tools/bash_logs/prompt.js +14 -0
  122. package/dist/tools/bash_run/index.d.ts +16 -0
  123. package/dist/tools/bash_run/index.js +61 -0
  124. package/dist/tools/bash_run/prompt.d.ts +2 -0
  125. package/dist/tools/bash_run/prompt.js +18 -0
  126. package/dist/tools/builtin.d.ts +7 -13
  127. package/dist/tools/builtin.js +19 -90
  128. package/dist/tools/define.d.ts +101 -0
  129. package/dist/tools/define.js +214 -0
  130. package/dist/tools/fs_edit/index.d.ts +1 -0
  131. package/dist/tools/fs_edit/index.js +62 -0
  132. package/dist/tools/fs_edit/prompt.d.ts +2 -0
  133. package/dist/tools/fs_edit/prompt.js +15 -0
  134. package/dist/tools/fs_glob/index.d.ts +1 -0
  135. package/dist/tools/fs_glob/index.js +40 -0
  136. package/dist/tools/fs_glob/prompt.d.ts +2 -0
  137. package/dist/tools/fs_glob/prompt.js +15 -0
  138. package/dist/tools/fs_grep/index.d.ts +1 -0
  139. package/dist/tools/fs_grep/index.js +66 -0
  140. package/dist/tools/fs_grep/prompt.d.ts +2 -0
  141. package/dist/tools/fs_grep/prompt.js +16 -0
  142. package/dist/tools/fs_multi_edit/index.d.ts +1 -0
  143. package/dist/tools/fs_multi_edit/index.js +106 -0
  144. package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
  145. package/dist/tools/fs_multi_edit/prompt.js +16 -0
  146. package/dist/tools/fs_read/index.d.ts +1 -0
  147. package/dist/tools/fs_read/index.js +40 -0
  148. package/dist/tools/fs_read/prompt.d.ts +2 -0
  149. package/dist/tools/fs_read/prompt.js +16 -0
  150. package/dist/tools/fs_write/index.d.ts +1 -0
  151. package/dist/tools/fs_write/index.js +40 -0
  152. package/dist/tools/fs_write/prompt.d.ts +2 -0
  153. package/dist/tools/fs_write/prompt.js +15 -0
  154. package/dist/tools/index.d.ts +11 -0
  155. package/dist/tools/index.js +61 -0
  156. package/dist/tools/mcp.d.ts +69 -0
  157. package/dist/tools/mcp.js +185 -0
  158. package/dist/tools/registry.d.ts +29 -0
  159. package/dist/tools/registry.js +26 -0
  160. package/dist/tools/scripts.d.ts +22 -0
  161. package/dist/tools/scripts.js +205 -0
  162. package/dist/tools/skills.d.ts +20 -0
  163. package/dist/tools/skills.js +115 -0
  164. package/dist/tools/task_run/index.d.ts +7 -0
  165. package/dist/tools/task_run/index.js +58 -0
  166. package/dist/tools/task_run/prompt.d.ts +5 -0
  167. package/dist/tools/task_run/prompt.js +25 -0
  168. package/dist/tools/todo_read/index.d.ts +1 -0
  169. package/dist/tools/todo_read/index.js +29 -0
  170. package/dist/tools/todo_read/prompt.d.ts +2 -0
  171. package/dist/tools/todo_read/prompt.js +18 -0
  172. package/dist/tools/todo_write/index.d.ts +1 -0
  173. package/dist/tools/todo_write/index.js +42 -0
  174. package/dist/tools/todo_write/prompt.d.ts +2 -0
  175. package/dist/tools/todo_write/prompt.js +23 -0
  176. package/dist/tools/tool.d.ts +43 -0
  177. package/dist/tools/tool.js +211 -0
  178. package/dist/tools/toolkit.d.ts +69 -0
  179. package/dist/tools/toolkit.js +98 -0
  180. package/dist/tools/type-inference.d.ts +127 -0
  181. package/dist/tools/type-inference.js +207 -0
  182. package/dist/utils/agent-id.d.ts +1 -0
  183. package/dist/utils/agent-id.js +28 -0
  184. package/dist/utils/logger.d.ts +15 -0
  185. package/dist/utils/logger.js +44 -0
  186. package/dist/utils/session-id.js +16 -16
  187. package/package.json +35 -11
  188. package/dist/tools/bash.d.ts +0 -63
  189. package/dist/tools/bash.js +0 -92
  190. package/dist/tools/fs.d.ts +0 -96
  191. package/dist/tools/fs.js +0 -100
  192. package/dist/tools/task.d.ts +0 -38
  193. package/dist/tools/task.js +0 -45
@@ -1,33 +1,76 @@
1
- import { Agent, AgentOptions } from '../core/agent';
2
- import { Store } from '../infra/store';
3
- import { AgentTemplate } from '../tools/task';
4
- import { AgentStatus, SnapshotId } from '../core/types';
1
+ import { Agent, AgentConfig, AgentDependencies } from './agent';
2
+ import { AgentStatus, SnapshotId } from './types';
5
3
  export interface AgentPoolOptions {
6
- store: Store;
4
+ dependencies: AgentDependencies;
7
5
  maxAgents?: number;
8
6
  }
7
+ export interface GracefulShutdownOptions {
8
+ /** Maximum time to wait for agents to complete current step (ms), default 30000 */
9
+ timeout?: number;
10
+ /** Save running agents list for resumeFromShutdown(), default true */
11
+ saveRunningList?: boolean;
12
+ /** Force interrupt agents that don't complete within timeout, default true */
13
+ forceInterrupt?: boolean;
14
+ }
15
+ export interface ShutdownResult {
16
+ /** Agents that completed gracefully */
17
+ completed: string[];
18
+ /** Agents that were interrupted due to timeout */
19
+ interrupted: string[];
20
+ /** Agents that failed to save state */
21
+ failed: string[];
22
+ /** Total shutdown time in ms */
23
+ durationMs: number;
24
+ }
9
25
  export declare class AgentPool {
10
26
  private agents;
11
- private store;
27
+ private deps;
12
28
  private maxAgents;
13
29
  constructor(opts: AgentPoolOptions);
14
- create(sessionId: string, templateOrOpts: AgentTemplate | AgentOptions, overrides?: Partial<AgentOptions>): Agent;
15
- get(sessionId: string): Agent | undefined;
30
+ create(agentId: string, config: AgentConfig): Promise<Agent>;
31
+ get(agentId: string): Agent | undefined;
16
32
  list(opts?: {
17
33
  prefix?: string;
18
34
  }): string[];
19
- status(sessionId: string): Promise<AgentStatus | undefined>;
20
- fork(sessionId: string, snapshotSel?: SnapshotId | {
35
+ status(agentId: string): Promise<AgentStatus | undefined>;
36
+ fork(agentId: string, snapshotSel?: SnapshotId | {
21
37
  at?: string;
22
38
  }): Promise<Agent>;
23
- resume(sessionId: string, opts: Omit<AgentOptions, 'sessionId' | 'store'> & {
39
+ resume(agentId: string, config: AgentConfig, opts?: {
24
40
  autoRun?: boolean;
25
41
  strategy?: 'crash' | 'manual';
26
42
  }): Promise<Agent>;
27
- resumeAll(configFactory: (sessionId: string) => Omit<AgentOptions, 'sessionId' | 'store'>, opts?: {
43
+ resumeAll(configFactory: (agentId: string) => AgentConfig, opts?: {
28
44
  autoRun?: boolean;
29
45
  strategy?: 'crash' | 'manual';
30
46
  }): Promise<Agent[]>;
31
- delete(sessionId: string): Promise<void>;
47
+ delete(agentId: string): Promise<void>;
32
48
  size(): number;
49
+ /**
50
+ * Gracefully shutdown all agents in the pool
51
+ * 1. Stop accepting new operations
52
+ * 2. Wait for running agents to complete current step
53
+ * 3. Persist all agent states
54
+ * 4. Optionally save running agents list for recovery
55
+ */
56
+ gracefulShutdown(opts?: GracefulShutdownOptions): Promise<ShutdownResult>;
57
+ /**
58
+ * Resume agents from a previous graceful shutdown
59
+ * Reads the running agents list and resumes each agent
60
+ */
61
+ resumeFromShutdown(configFactory: (agentId: string) => AgentConfig, opts?: {
62
+ autoRun?: boolean;
63
+ strategy?: 'crash' | 'manual';
64
+ }): Promise<Agent[]>;
65
+ /**
66
+ * Register signal handlers for graceful shutdown
67
+ * Call this in your server setup code
68
+ */
69
+ registerShutdownHandlers(configFactory?: (agentId: string) => AgentConfig, opts?: GracefulShutdownOptions): void;
70
+ private waitForAgentReady;
71
+ private persistAgentState;
72
+ private saveRunningAgentsList;
73
+ private loadRunningAgentsList;
74
+ private clearRunningAgentsList;
75
+ private sleep;
33
76
  }
package/dist/core/pool.js CHANGED
@@ -1,91 +1,301 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AgentPool = void 0;
4
- const agent_1 = require("../core/agent");
4
+ const agent_1 = require("./agent");
5
+ const logger_1 = require("../utils/logger");
5
6
  class AgentPool {
6
7
  constructor(opts) {
7
8
  this.agents = new Map();
8
- this.store = opts.store;
9
+ this.deps = opts.dependencies;
9
10
  this.maxAgents = opts.maxAgents || 50;
10
11
  }
11
- create(sessionId, templateOrOpts, overrides) {
12
- if (this.agents.has(sessionId)) {
13
- throw new Error(`Agent already exists: ${sessionId}`);
12
+ async create(agentId, config) {
13
+ if (this.agents.has(agentId)) {
14
+ throw new Error(`Agent already exists: ${agentId}`);
14
15
  }
15
16
  if (this.agents.size >= this.maxAgents) {
16
17
  throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
17
18
  }
18
- const agent = new agent_1.Agent(templateOrOpts, overrides);
19
- this.agents.set(sessionId, agent);
19
+ const agent = await agent_1.Agent.create({ ...config, agentId }, this.deps);
20
+ this.agents.set(agentId, agent);
20
21
  return agent;
21
22
  }
22
- get(sessionId) {
23
- return this.agents.get(sessionId);
23
+ get(agentId) {
24
+ return this.agents.get(agentId);
24
25
  }
25
26
  list(opts) {
26
27
  const ids = Array.from(this.agents.keys());
27
28
  return opts?.prefix ? ids.filter((id) => id.startsWith(opts.prefix)) : ids;
28
29
  }
29
- async status(sessionId) {
30
- const agent = this.agents.get(sessionId);
30
+ async status(agentId) {
31
+ const agent = this.agents.get(agentId);
31
32
  return agent ? await agent.status() : undefined;
32
33
  }
33
- async fork(sessionId, snapshotSel) {
34
- const agent = this.agents.get(sessionId);
34
+ async fork(agentId, snapshotSel) {
35
+ const agent = this.agents.get(agentId);
35
36
  if (!agent) {
36
- throw new Error(`Agent not found: ${sessionId}`);
37
+ throw new Error(`Agent not found: ${agentId}`);
37
38
  }
38
39
  return agent.fork(snapshotSel);
39
40
  }
40
- async resume(sessionId, opts) {
41
+ async resume(agentId, config, opts) {
41
42
  // 1. Check if already in pool
42
- if (this.agents.has(sessionId)) {
43
- return this.agents.get(sessionId);
43
+ if (this.agents.has(agentId)) {
44
+ return this.agents.get(agentId);
44
45
  }
45
46
  // 2. Check pool capacity
46
47
  if (this.agents.size >= this.maxAgents) {
47
48
  throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
48
49
  }
49
50
  // 3. Verify session exists
50
- const exists = await this.store.exists(sessionId);
51
+ const exists = await this.deps.store.exists(agentId);
51
52
  if (!exists) {
52
- throw new Error(`Session not found in store: ${sessionId}`);
53
+ throw new Error(`Agent not found in store: ${agentId}`);
53
54
  }
54
55
  // 4. Use Agent.resume() to restore
55
- const agent = await agent_1.Agent.resume(sessionId, {
56
- ...opts,
57
- sessionId,
58
- store: this.store,
59
- });
56
+ const agent = await agent_1.Agent.resume(agentId, { ...config, agentId }, this.deps, opts);
60
57
  // 5. Add to pool
61
- this.agents.set(sessionId, agent);
58
+ this.agents.set(agentId, agent);
62
59
  return agent;
63
60
  }
64
61
  async resumeAll(configFactory, opts) {
65
- const sessionIds = await this.store.list();
62
+ const agentIds = await this.deps.store.list();
66
63
  const resumed = [];
67
- for (const sessionId of sessionIds) {
64
+ for (const agentId of agentIds) {
68
65
  if (this.agents.size >= this.maxAgents)
69
66
  break;
70
- if (this.agents.has(sessionId))
67
+ if (this.agents.has(agentId))
71
68
  continue;
72
69
  try {
73
- const config = configFactory(sessionId);
74
- const agent = await this.resume(sessionId, { ...config, ...opts });
70
+ const config = configFactory(agentId);
71
+ const agent = await this.resume(agentId, config, opts);
75
72
  resumed.push(agent);
76
73
  }
77
74
  catch (error) {
78
- console.error(`Failed to resume ${sessionId}:`, error);
75
+ logger_1.logger.error(`Failed to resume ${agentId}:`, error);
79
76
  }
80
77
  }
81
78
  return resumed;
82
79
  }
83
- async delete(sessionId) {
84
- this.agents.delete(sessionId);
85
- await this.store.delete(sessionId);
80
+ async delete(agentId) {
81
+ this.agents.delete(agentId);
82
+ await this.deps.store.delete(agentId);
86
83
  }
87
84
  size() {
88
85
  return this.agents.size;
89
86
  }
87
+ /**
88
+ * Gracefully shutdown all agents in the pool
89
+ * 1. Stop accepting new operations
90
+ * 2. Wait for running agents to complete current step
91
+ * 3. Persist all agent states
92
+ * 4. Optionally save running agents list for recovery
93
+ */
94
+ async gracefulShutdown(opts) {
95
+ const startTime = Date.now();
96
+ const timeout = opts?.timeout ?? 30000;
97
+ const saveRunningList = opts?.saveRunningList ?? true;
98
+ const forceInterrupt = opts?.forceInterrupt ?? true;
99
+ const result = {
100
+ completed: [],
101
+ interrupted: [],
102
+ failed: [],
103
+ durationMs: 0,
104
+ };
105
+ const agentIds = Array.from(this.agents.keys());
106
+ logger_1.logger.info(`[AgentPool] Starting graceful shutdown for ${agentIds.length} agents`);
107
+ // Group agents by state
108
+ const workingAgents = [];
109
+ const readyAgents = [];
110
+ for (const [id, agent] of this.agents) {
111
+ const status = await agent.status();
112
+ if (status.state === 'WORKING') {
113
+ workingAgents.push({ id, agent });
114
+ }
115
+ else {
116
+ readyAgents.push({ id, agent });
117
+ }
118
+ }
119
+ // 1. Persist ready agents immediately
120
+ for (const { id, agent } of readyAgents) {
121
+ try {
122
+ await this.persistAgentState(agent);
123
+ result.completed.push(id);
124
+ }
125
+ catch (error) {
126
+ logger_1.logger.error(`[AgentPool] Failed to persist agent ${id}:`, error);
127
+ result.failed.push(id);
128
+ }
129
+ }
130
+ // 2. Wait for working agents with timeout
131
+ if (workingAgents.length > 0) {
132
+ logger_1.logger.info(`[AgentPool] Waiting for ${workingAgents.length} working agents...`);
133
+ const waitPromises = workingAgents.map(async ({ id, agent }) => {
134
+ try {
135
+ const completed = await this.waitForAgentReady(agent, timeout);
136
+ if (completed) {
137
+ await this.persistAgentState(agent);
138
+ return { id, status: 'completed' };
139
+ }
140
+ else if (forceInterrupt) {
141
+ await agent.interrupt({ note: 'Graceful shutdown timeout' });
142
+ await this.persistAgentState(agent);
143
+ return { id, status: 'interrupted' };
144
+ }
145
+ else {
146
+ return { id, status: 'interrupted' };
147
+ }
148
+ }
149
+ catch (error) {
150
+ logger_1.logger.error(`[AgentPool] Error during shutdown for agent ${id}:`, error);
151
+ return { id, status: 'failed' };
152
+ }
153
+ });
154
+ const results = await Promise.all(waitPromises);
155
+ for (const { id, status } of results) {
156
+ if (status === 'completed') {
157
+ result.completed.push(id);
158
+ }
159
+ else if (status === 'interrupted') {
160
+ result.interrupted.push(id);
161
+ }
162
+ else {
163
+ result.failed.push(id);
164
+ }
165
+ }
166
+ }
167
+ // 3. Save running agents list for recovery
168
+ if (saveRunningList) {
169
+ try {
170
+ await this.saveRunningAgentsList(agentIds);
171
+ logger_1.logger.info(`[AgentPool] Saved running agents list: ${agentIds.length} agents`);
172
+ }
173
+ catch (error) {
174
+ logger_1.logger.error(`[AgentPool] Failed to save running agents list:`, error);
175
+ }
176
+ }
177
+ result.durationMs = Date.now() - startTime;
178
+ logger_1.logger.info(`[AgentPool] Graceful shutdown completed in ${result.durationMs}ms`, {
179
+ completed: result.completed.length,
180
+ interrupted: result.interrupted.length,
181
+ failed: result.failed.length,
182
+ });
183
+ return result;
184
+ }
185
+ /**
186
+ * Resume agents from a previous graceful shutdown
187
+ * Reads the running agents list and resumes each agent
188
+ */
189
+ async resumeFromShutdown(configFactory, opts) {
190
+ const runningList = await this.loadRunningAgentsList();
191
+ if (!runningList || runningList.length === 0) {
192
+ logger_1.logger.info('[AgentPool] No running agents list found, nothing to resume');
193
+ return [];
194
+ }
195
+ logger_1.logger.info(`[AgentPool] Resuming ${runningList.length} agents from shutdown`);
196
+ const resumed = [];
197
+ for (const agentId of runningList) {
198
+ if (this.agents.size >= this.maxAgents) {
199
+ logger_1.logger.warn(`[AgentPool] Pool is full, cannot resume more agents`);
200
+ break;
201
+ }
202
+ try {
203
+ const config = configFactory(agentId);
204
+ const agent = await this.resume(agentId, config, {
205
+ autoRun: opts?.autoRun ?? false,
206
+ strategy: opts?.strategy ?? 'crash',
207
+ });
208
+ resumed.push(agent);
209
+ }
210
+ catch (error) {
211
+ logger_1.logger.error(`[AgentPool] Failed to resume agent ${agentId}:`, error);
212
+ }
213
+ }
214
+ // Clear the running agents list after successful resume
215
+ await this.clearRunningAgentsList();
216
+ logger_1.logger.info(`[AgentPool] Resumed ${resumed.length}/${runningList.length} agents`);
217
+ return resumed;
218
+ }
219
+ /**
220
+ * Register signal handlers for graceful shutdown
221
+ * Call this in your server setup code
222
+ */
223
+ registerShutdownHandlers(configFactory, opts) {
224
+ const handler = async (signal) => {
225
+ logger_1.logger.info(`[AgentPool] Received ${signal}, initiating graceful shutdown...`);
226
+ try {
227
+ const result = await this.gracefulShutdown(opts);
228
+ logger_1.logger.info(`[AgentPool] Shutdown complete:`, result);
229
+ process.exit(0);
230
+ }
231
+ catch (error) {
232
+ logger_1.logger.error(`[AgentPool] Shutdown failed:`, error);
233
+ process.exit(1);
234
+ }
235
+ };
236
+ process.on('SIGTERM', () => handler('SIGTERM'));
237
+ process.on('SIGINT', () => handler('SIGINT'));
238
+ logger_1.logger.info('[AgentPool] Shutdown handlers registered for SIGTERM and SIGINT');
239
+ }
240
+ // ========== Private Helper Methods ==========
241
+ async waitForAgentReady(agent, timeout) {
242
+ const startTime = Date.now();
243
+ const pollInterval = 100; // ms
244
+ while (Date.now() - startTime < timeout) {
245
+ const status = await agent.status();
246
+ if (status.state !== 'WORKING') {
247
+ return true;
248
+ }
249
+ await this.sleep(pollInterval);
250
+ }
251
+ return false;
252
+ }
253
+ async persistAgentState(agent) {
254
+ // Agent's internal persist methods are private, so we rely on the fact that
255
+ // state is automatically persisted during normal operation.
256
+ // This is a no-op placeholder for potential future explicit persist calls.
257
+ // The agent's state is already persisted via WAL mechanism.
258
+ }
259
+ async saveRunningAgentsList(agentIds) {
260
+ const meta = {
261
+ agentIds,
262
+ shutdownAt: new Date().toISOString(),
263
+ version: '1.0.0',
264
+ };
265
+ // Use the store's saveInfo to persist to a special key
266
+ // We use a well-known agent ID prefix for pool metadata
267
+ const poolMetaId = '__pool_meta__';
268
+ await this.deps.store.saveInfo(poolMetaId, {
269
+ agentId: poolMetaId,
270
+ templateId: '__pool_meta__',
271
+ createdAt: new Date().toISOString(),
272
+ runningAgents: meta,
273
+ });
274
+ }
275
+ async loadRunningAgentsList() {
276
+ const poolMetaId = '__pool_meta__';
277
+ try {
278
+ const info = await this.deps.store.loadInfo(poolMetaId);
279
+ if (info && info.runningAgents) {
280
+ return info.runningAgents.agentIds;
281
+ }
282
+ }
283
+ catch {
284
+ // Ignore errors, return null
285
+ }
286
+ return null;
287
+ }
288
+ async clearRunningAgentsList() {
289
+ const poolMetaId = '__pool_meta__';
290
+ try {
291
+ await this.deps.store.delete(poolMetaId);
292
+ }
293
+ catch {
294
+ // Ignore errors
295
+ }
296
+ }
297
+ sleep(ms) {
298
+ return new Promise((resolve) => setTimeout(resolve, ms));
299
+ }
90
300
  }
91
301
  exports.AgentPool = AgentPool;
@@ -1,13 +1,13 @@
1
1
  import { AgentPool } from '../core/pool';
2
2
  export interface RoomMember {
3
3
  name: string;
4
- sessionId: string;
4
+ agentId: string;
5
5
  }
6
6
  export declare class Room {
7
7
  private pool;
8
8
  private members;
9
9
  constructor(pool: AgentPool);
10
- join(name: string, sessionId: string): void;
10
+ join(name: string, agentId: string): void;
11
11
  leave(name: string): void;
12
12
  say(from: string, text: string): Promise<void>;
13
13
  getMembers(): RoomMember[];
package/dist/core/room.js CHANGED
@@ -6,11 +6,11 @@ class Room {
6
6
  this.pool = pool;
7
7
  this.members = new Map();
8
8
  }
9
- join(name, sessionId) {
9
+ join(name, agentId) {
10
10
  if (this.members.has(name)) {
11
11
  throw new Error(`Member already exists: ${name}`);
12
12
  }
13
- this.members.set(name, sessionId);
13
+ this.members.set(name, agentId);
14
14
  }
15
15
  leave(name) {
16
16
  this.members.delete(name);
@@ -20,29 +20,29 @@ class Room {
20
20
  if (mentions.length > 0) {
21
21
  // Directed message
22
22
  for (const mention of mentions) {
23
- const sessionId = this.members.get(mention);
24
- if (sessionId) {
25
- const agent = this.pool.get(sessionId);
23
+ const agentId = this.members.get(mention);
24
+ if (agentId) {
25
+ const agent = this.pool.get(agentId);
26
26
  if (agent) {
27
- await agent.send(`[from:${from}] ${text}`);
27
+ await agent.complete(`[from:${from}] ${text}`);
28
28
  }
29
29
  }
30
30
  }
31
31
  }
32
32
  else {
33
33
  // Broadcast to all except sender
34
- for (const [name, sessionId] of this.members) {
34
+ for (const [name, agentId] of this.members) {
35
35
  if (name !== from) {
36
- const agent = this.pool.get(sessionId);
36
+ const agent = this.pool.get(agentId);
37
37
  if (agent) {
38
- await agent.send(`[from:${from}] ${text}`);
38
+ await agent.complete(`[from:${from}] ${text}`);
39
39
  }
40
40
  }
41
41
  }
42
42
  }
43
43
  }
44
44
  getMembers() {
45
- return Array.from(this.members.entries()).map(([name, sessionId]) => ({ name, sessionId }));
45
+ return Array.from(this.members.entries()).map(([name, agentId]) => ({ name, agentId }));
46
46
  }
47
47
  extractMentions(text) {
48
48
  const regex = /@(\w+)/g;
@@ -1,26 +1,33 @@
1
- type TimeInterval = string;
2
- type ScheduleCallback = (ctx?: any) => void | Promise<void>;
3
- export declare class Scheduler {
4
- private tasks;
5
- private stepCounters;
6
- private timers;
7
- every(interval: TimeInterval, callback: ScheduleCallback): this;
8
- everySteps(steps: number, callback: ScheduleCallback, targetId?: string): this;
9
- daily(time: string, callback: ScheduleCallback): this;
10
- weekly(dayTime: string, callback: ScheduleCallback): this;
11
- notifyStep(targetId?: string): void;
12
- stop(): void;
13
- private parseInterval;
14
- private scheduleDailyTask;
15
- private scheduleWeeklyTask;
1
+ type StepCallback = (ctx: {
2
+ stepCount: number;
3
+ }) => void | Promise<void>;
4
+ type TaskCallback = () => void | Promise<void>;
5
+ export type AgentSchedulerHandle = string;
6
+ type TriggerKind = 'steps' | 'time' | 'cron';
7
+ interface SchedulerOptions {
8
+ onTrigger?: (info: {
9
+ taskId: string;
10
+ spec: string;
11
+ kind: TriggerKind;
12
+ }) => void;
16
13
  }
17
- export declare class AgentSchedulerHandle {
18
- private scheduler;
19
- private agentId?;
20
- constructor(scheduler: Scheduler, agentId?: string | undefined);
21
- every(interval: TimeInterval, callback: ScheduleCallback): this;
22
- everySteps(steps: number, callback: ScheduleCallback): this;
23
- daily(time: string, callback: ScheduleCallback): this;
24
- weekly(dayTime: string, callback: ScheduleCallback): this;
14
+ export declare class Scheduler {
15
+ private readonly stepTasks;
16
+ private readonly listeners;
17
+ private queued;
18
+ private readonly onTrigger?;
19
+ constructor(opts?: SchedulerOptions);
20
+ everySteps(every: number, callback: StepCallback): AgentSchedulerHandle;
21
+ onStep(callback: StepCallback): () => void;
22
+ enqueue(callback: TaskCallback): void;
23
+ notifyStep(stepCount: number): void;
24
+ cancel(taskId: AgentSchedulerHandle): void;
25
+ clear(): void;
26
+ notifyExternalTrigger(info: {
27
+ taskId: string;
28
+ spec: string;
29
+ kind: 'time' | 'cron';
30
+ }): void;
31
+ private generateId;
25
32
  }
26
33
  export {};