@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.
- package/LICENSE +21 -0
- package/README.md +115 -273
- package/README.zh-CN.md +114 -0
- package/dist/core/agent/breakpoint-manager.d.ts +16 -0
- package/dist/core/agent/breakpoint-manager.js +36 -0
- package/dist/core/agent/message-queue.d.ts +26 -0
- package/dist/core/agent/message-queue.js +57 -0
- package/dist/core/agent/permission-manager.d.ts +9 -0
- package/dist/core/agent/permission-manager.js +32 -0
- package/dist/core/agent/todo-manager.d.ts +26 -0
- package/dist/core/agent/todo-manager.js +91 -0
- package/dist/core/agent/tool-runner.d.ts +9 -0
- package/dist/core/agent/tool-runner.js +45 -0
- package/dist/core/agent.d.ts +228 -62
- package/dist/core/agent.js +1890 -615
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.d.ts +82 -0
- package/dist/core/context-manager.js +241 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +49 -0
- package/dist/core/events.d.ts +41 -10
- package/dist/core/events.js +270 -68
- package/dist/core/file-pool.d.ts +41 -0
- package/dist/core/file-pool.js +102 -0
- package/dist/core/hooks.d.ts +3 -3
- package/dist/core/hooks.js +1 -1
- package/dist/core/permission-modes.d.ts +31 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.d.ts +56 -13
- package/dist/core/pool.js +244 -34
- package/dist/core/room.d.ts +2 -2
- package/dist/core/room.js +10 -10
- package/dist/core/scheduler.d.ts +30 -23
- package/dist/core/scheduler.js +42 -168
- package/dist/core/skills/index.d.ts +10 -0
- package/dist/core/skills/index.js +20 -0
- package/dist/core/skills/management-manager.d.ts +130 -0
- package/dist/core/skills/management-manager.js +557 -0
- package/dist/core/skills/manager.d.ts +47 -0
- package/dist/core/skills/manager.js +243 -0
- package/dist/core/skills/operation-queue.d.ts +87 -0
- package/dist/core/skills/operation-queue.js +113 -0
- package/dist/core/skills/sandbox-file-manager.d.ts +82 -0
- package/dist/core/skills/sandbox-file-manager.js +183 -0
- package/dist/core/skills/types.d.ts +120 -0
- package/dist/core/skills/types.js +9 -0
- package/dist/core/skills/xml-generator.d.ts +13 -0
- package/dist/core/skills/xml-generator.js +70 -0
- package/dist/core/template.d.ts +57 -0
- package/dist/core/template.js +35 -0
- package/dist/core/time-bridge.d.ts +18 -0
- package/dist/core/time-bridge.js +100 -0
- package/dist/core/todo.d.ts +34 -0
- package/dist/core/todo.js +89 -0
- package/dist/core/types.d.ts +311 -114
- package/dist/core/types.js +1 -12
- package/dist/index.d.ts +47 -9
- package/dist/index.js +108 -15
- package/dist/infra/db/postgres/postgres-store.d.ts +97 -0
- package/dist/infra/db/postgres/postgres-store.js +1073 -0
- package/dist/infra/db/sqlite/sqlite-store.d.ts +84 -0
- package/dist/infra/db/sqlite/sqlite-store.js +800 -0
- package/dist/infra/e2b/e2b-fs.d.ts +29 -0
- package/dist/infra/e2b/e2b-fs.js +128 -0
- package/dist/infra/e2b/e2b-sandbox.d.ts +37 -0
- package/dist/infra/e2b/e2b-sandbox.js +156 -0
- package/dist/infra/e2b/e2b-template.d.ts +24 -0
- package/dist/infra/e2b/e2b-template.js +105 -0
- package/dist/infra/e2b/index.d.ts +4 -0
- package/dist/infra/e2b/index.js +9 -0
- package/dist/infra/e2b/types.d.ts +46 -0
- package/dist/infra/e2b/types.js +2 -0
- package/dist/infra/provider.d.ts +17 -58
- package/dist/infra/provider.js +65 -116
- package/dist/infra/providers/anthropic.d.ts +42 -0
- package/dist/infra/providers/anthropic.js +308 -0
- package/dist/infra/providers/core/errors.d.ts +230 -0
- package/dist/infra/providers/core/errors.js +353 -0
- package/dist/infra/providers/core/fork.d.ts +106 -0
- package/dist/infra/providers/core/fork.js +418 -0
- package/dist/infra/providers/core/index.d.ts +10 -0
- package/dist/infra/providers/core/index.js +76 -0
- package/dist/infra/providers/core/logger.d.ts +186 -0
- package/dist/infra/providers/core/logger.js +191 -0
- package/dist/infra/providers/core/retry.d.ts +62 -0
- package/dist/infra/providers/core/retry.js +189 -0
- package/dist/infra/providers/core/usage.d.ts +151 -0
- package/dist/infra/providers/core/usage.js +376 -0
- package/dist/infra/providers/gemini.d.ts +49 -0
- package/dist/infra/providers/gemini.js +493 -0
- package/dist/infra/providers/index.d.ts +25 -0
- package/dist/infra/providers/index.js +83 -0
- package/dist/infra/providers/openai.d.ts +123 -0
- package/dist/infra/providers/openai.js +662 -0
- package/dist/infra/providers/types.d.ts +334 -0
- package/dist/infra/providers/types.js +20 -0
- package/dist/infra/providers/utils.d.ts +53 -0
- package/dist/infra/providers/utils.js +400 -0
- package/dist/infra/sandbox-factory.d.ts +13 -0
- package/dist/infra/sandbox-factory.js +30 -0
- package/dist/infra/sandbox.d.ts +35 -6
- package/dist/infra/sandbox.js +174 -8
- package/dist/infra/store/factory.d.ts +45 -0
- package/dist/infra/store/factory.js +80 -0
- package/dist/infra/store/index.d.ts +3 -0
- package/dist/infra/store/index.js +26 -0
- package/dist/infra/store/json-store.d.ts +67 -0
- package/dist/infra/store/json-store.js +606 -0
- package/dist/infra/store/types.d.ts +342 -0
- package/dist/infra/store/types.js +2 -0
- package/dist/infra/store.d.ts +12 -32
- package/dist/infra/store.js +27 -130
- package/dist/tools/bash_kill/index.d.ts +1 -0
- package/dist/tools/bash_kill/index.js +35 -0
- package/dist/tools/bash_kill/prompt.d.ts +2 -0
- package/dist/tools/bash_kill/prompt.js +14 -0
- package/dist/tools/bash_logs/index.d.ts +1 -0
- package/dist/tools/bash_logs/index.js +40 -0
- package/dist/tools/bash_logs/prompt.d.ts +2 -0
- package/dist/tools/bash_logs/prompt.js +14 -0
- package/dist/tools/bash_run/index.d.ts +16 -0
- package/dist/tools/bash_run/index.js +61 -0
- package/dist/tools/bash_run/prompt.d.ts +2 -0
- package/dist/tools/bash_run/prompt.js +18 -0
- package/dist/tools/builtin.d.ts +7 -13
- package/dist/tools/builtin.js +19 -90
- package/dist/tools/define.d.ts +101 -0
- package/dist/tools/define.js +214 -0
- package/dist/tools/fs_edit/index.d.ts +1 -0
- package/dist/tools/fs_edit/index.js +62 -0
- package/dist/tools/fs_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_edit/prompt.js +15 -0
- package/dist/tools/fs_glob/index.d.ts +1 -0
- package/dist/tools/fs_glob/index.js +40 -0
- package/dist/tools/fs_glob/prompt.d.ts +2 -0
- package/dist/tools/fs_glob/prompt.js +15 -0
- package/dist/tools/fs_grep/index.d.ts +1 -0
- package/dist/tools/fs_grep/index.js +66 -0
- package/dist/tools/fs_grep/prompt.d.ts +2 -0
- package/dist/tools/fs_grep/prompt.js +16 -0
- package/dist/tools/fs_multi_edit/index.d.ts +1 -0
- package/dist/tools/fs_multi_edit/index.js +106 -0
- package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_multi_edit/prompt.js +16 -0
- package/dist/tools/fs_read/index.d.ts +1 -0
- package/dist/tools/fs_read/index.js +40 -0
- package/dist/tools/fs_read/prompt.d.ts +2 -0
- package/dist/tools/fs_read/prompt.js +16 -0
- package/dist/tools/fs_write/index.d.ts +1 -0
- package/dist/tools/fs_write/index.js +40 -0
- package/dist/tools/fs_write/prompt.d.ts +2 -0
- package/dist/tools/fs_write/prompt.js +15 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.js +61 -0
- package/dist/tools/mcp.d.ts +69 -0
- package/dist/tools/mcp.js +185 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/scripts.d.ts +22 -0
- package/dist/tools/scripts.js +205 -0
- package/dist/tools/skills.d.ts +20 -0
- package/dist/tools/skills.js +115 -0
- package/dist/tools/task_run/index.d.ts +7 -0
- package/dist/tools/task_run/index.js +58 -0
- package/dist/tools/task_run/prompt.d.ts +5 -0
- package/dist/tools/task_run/prompt.js +25 -0
- package/dist/tools/todo_read/index.d.ts +1 -0
- package/dist/tools/todo_read/index.js +29 -0
- package/dist/tools/todo_read/prompt.d.ts +2 -0
- package/dist/tools/todo_read/prompt.js +18 -0
- package/dist/tools/todo_write/index.d.ts +1 -0
- package/dist/tools/todo_write/index.js +42 -0
- package/dist/tools/todo_write/prompt.d.ts +2 -0
- package/dist/tools/todo_write/prompt.js +23 -0
- package/dist/tools/tool.d.ts +43 -0
- package/dist/tools/tool.js +211 -0
- package/dist/tools/toolkit.d.ts +69 -0
- package/dist/tools/toolkit.js +98 -0
- package/dist/tools/type-inference.d.ts +127 -0
- package/dist/tools/type-inference.js +207 -0
- package/dist/utils/agent-id.d.ts +1 -0
- package/dist/utils/agent-id.js +28 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/session-id.js +16 -16
- package/package.json +35 -11
- package/dist/tools/bash.d.ts +0 -63
- package/dist/tools/bash.js +0 -92
- package/dist/tools/fs.d.ts +0 -96
- package/dist/tools/fs.js +0 -100
- package/dist/tools/task.d.ts +0 -38
- package/dist/tools/task.js +0 -45
package/dist/core/pool.d.ts
CHANGED
|
@@ -1,33 +1,76 @@
|
|
|
1
|
-
import { Agent,
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
|
27
|
+
private deps;
|
|
12
28
|
private maxAgents;
|
|
13
29
|
constructor(opts: AgentPoolOptions);
|
|
14
|
-
create(
|
|
15
|
-
get(
|
|
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(
|
|
20
|
-
fork(
|
|
35
|
+
status(agentId: string): Promise<AgentStatus | undefined>;
|
|
36
|
+
fork(agentId: string, snapshotSel?: SnapshotId | {
|
|
21
37
|
at?: string;
|
|
22
38
|
}): Promise<Agent>;
|
|
23
|
-
resume(
|
|
39
|
+
resume(agentId: string, config: AgentConfig, opts?: {
|
|
24
40
|
autoRun?: boolean;
|
|
25
41
|
strategy?: 'crash' | 'manual';
|
|
26
42
|
}): Promise<Agent>;
|
|
27
|
-
resumeAll(configFactory: (
|
|
43
|
+
resumeAll(configFactory: (agentId: string) => AgentConfig, opts?: {
|
|
28
44
|
autoRun?: boolean;
|
|
29
45
|
strategy?: 'crash' | 'manual';
|
|
30
46
|
}): Promise<Agent[]>;
|
|
31
|
-
delete(
|
|
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("
|
|
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.
|
|
9
|
+
this.deps = opts.dependencies;
|
|
9
10
|
this.maxAgents = opts.maxAgents || 50;
|
|
10
11
|
}
|
|
11
|
-
create(
|
|
12
|
-
if (this.agents.has(
|
|
13
|
-
throw new Error(`Agent already exists: ${
|
|
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 =
|
|
19
|
-
this.agents.set(
|
|
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(
|
|
23
|
-
return this.agents.get(
|
|
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(
|
|
30
|
-
const agent = this.agents.get(
|
|
30
|
+
async status(agentId) {
|
|
31
|
+
const agent = this.agents.get(agentId);
|
|
31
32
|
return agent ? await agent.status() : undefined;
|
|
32
33
|
}
|
|
33
|
-
async fork(
|
|
34
|
-
const agent = this.agents.get(
|
|
34
|
+
async fork(agentId, snapshotSel) {
|
|
35
|
+
const agent = this.agents.get(agentId);
|
|
35
36
|
if (!agent) {
|
|
36
|
-
throw new Error(`Agent not found: ${
|
|
37
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
37
38
|
}
|
|
38
39
|
return agent.fork(snapshotSel);
|
|
39
40
|
}
|
|
40
|
-
async resume(
|
|
41
|
+
async resume(agentId, config, opts) {
|
|
41
42
|
// 1. Check if already in pool
|
|
42
|
-
if (this.agents.has(
|
|
43
|
-
return this.agents.get(
|
|
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(
|
|
51
|
+
const exists = await this.deps.store.exists(agentId);
|
|
51
52
|
if (!exists) {
|
|
52
|
-
throw new Error(`
|
|
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(
|
|
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(
|
|
58
|
+
this.agents.set(agentId, agent);
|
|
62
59
|
return agent;
|
|
63
60
|
}
|
|
64
61
|
async resumeAll(configFactory, opts) {
|
|
65
|
-
const
|
|
62
|
+
const agentIds = await this.deps.store.list();
|
|
66
63
|
const resumed = [];
|
|
67
|
-
for (const
|
|
64
|
+
for (const agentId of agentIds) {
|
|
68
65
|
if (this.agents.size >= this.maxAgents)
|
|
69
66
|
break;
|
|
70
|
-
if (this.agents.has(
|
|
67
|
+
if (this.agents.has(agentId))
|
|
71
68
|
continue;
|
|
72
69
|
try {
|
|
73
|
-
const config = configFactory(
|
|
74
|
-
const agent = await this.resume(
|
|
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
|
-
|
|
75
|
+
logger_1.logger.error(`Failed to resume ${agentId}:`, error);
|
|
79
76
|
}
|
|
80
77
|
}
|
|
81
78
|
return resumed;
|
|
82
79
|
}
|
|
83
|
-
async delete(
|
|
84
|
-
this.agents.delete(
|
|
85
|
-
await this.store.delete(
|
|
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;
|
package/dist/core/room.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { AgentPool } from '../core/pool';
|
|
2
2
|
export interface RoomMember {
|
|
3
3
|
name: string;
|
|
4
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
24
|
-
if (
|
|
25
|
-
const agent = this.pool.get(
|
|
23
|
+
const agentId = this.members.get(mention);
|
|
24
|
+
if (agentId) {
|
|
25
|
+
const agent = this.pool.get(agentId);
|
|
26
26
|
if (agent) {
|
|
27
|
-
await agent.
|
|
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,
|
|
34
|
+
for (const [name, agentId] of this.members) {
|
|
35
35
|
if (name !== from) {
|
|
36
|
-
const agent = this.pool.get(
|
|
36
|
+
const agent = this.pool.get(agentId);
|
|
37
37
|
if (agent) {
|
|
38
|
-
await agent.
|
|
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,
|
|
45
|
+
return Array.from(this.members.entries()).map(([name, agentId]) => ({ name, agentId }));
|
|
46
46
|
}
|
|
47
47
|
extractMentions(text) {
|
|
48
48
|
const regex = /@(\w+)/g;
|
package/dist/core/scheduler.d.ts
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 {};
|