kode-sdk 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 +201 -0
- package/README.md +74 -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 +47 -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 +271 -0
- package/dist/core/agent.js +2334 -0
- package/dist/core/checkpointer.d.ts +96 -0
- package/dist/core/checkpointer.js +57 -0
- package/dist/core/checkpointers/file.d.ts +20 -0
- package/dist/core/checkpointers/file.js +153 -0
- package/dist/core/checkpointers/index.d.ts +3 -0
- package/dist/core/checkpointers/index.js +9 -0
- package/dist/core/checkpointers/redis.d.ts +35 -0
- package/dist/core/checkpointers/redis.js +113 -0
- package/dist/core/compression/ai-strategy.d.ts +53 -0
- package/dist/core/compression/ai-strategy.js +298 -0
- package/dist/core/compression/index.d.ts +12 -0
- package/dist/core/compression/index.js +27 -0
- package/dist/core/compression/prompts.d.ts +35 -0
- package/dist/core/compression/prompts.js +114 -0
- package/dist/core/compression/simple-strategy.d.ts +44 -0
- package/dist/core/compression/simple-strategy.js +240 -0
- package/dist/core/compression/token-estimator.d.ts +42 -0
- package/dist/core/compression/token-estimator.js +121 -0
- package/dist/core/compression/types.d.ts +140 -0
- package/dist/core/compression/types.js +9 -0
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.d.ts +115 -0
- package/dist/core/context-manager.js +107 -0
- package/dist/core/errors.d.ts +6 -0
- package/dist/core/errors.js +17 -0
- package/dist/core/events.d.ts +49 -0
- package/dist/core/events.js +312 -0
- package/dist/core/file-pool.d.ts +43 -0
- package/dist/core/file-pool.js +120 -0
- package/dist/core/hooks.d.ts +23 -0
- package/dist/core/hooks.js +71 -0
- package/dist/core/permission-modes.d.ts +31 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.d.ts +31 -0
- package/dist/core/pool.js +87 -0
- package/dist/core/room.d.ts +15 -0
- package/dist/core/room.js +57 -0
- package/dist/core/scheduler.d.ts +33 -0
- package/dist/core/scheduler.js +58 -0
- package/dist/core/template.d.ts +69 -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 +380 -0
- package/dist/core/types.js +3 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +147 -0
- package/dist/infra/provider.d.ts +144 -0
- package/dist/infra/provider.js +294 -0
- package/dist/infra/sandbox-factory.d.ts +10 -0
- package/dist/infra/sandbox-factory.js +21 -0
- package/dist/infra/sandbox.d.ts +87 -0
- package/dist/infra/sandbox.js +255 -0
- package/dist/infra/store.d.ts +154 -0
- package/dist/infra/store.js +584 -0
- package/dist/skills/index.d.ts +12 -0
- package/dist/skills/index.js +36 -0
- package/dist/skills/injector.d.ts +29 -0
- package/dist/skills/injector.js +96 -0
- package/dist/skills/loader.d.ts +59 -0
- package/dist/skills/loader.js +215 -0
- package/dist/skills/manager.d.ts +85 -0
- package/dist/skills/manager.js +221 -0
- package/dist/skills/parser.d.ts +40 -0
- package/dist/skills/parser.js +107 -0
- package/dist/skills/types.d.ts +107 -0
- package/dist/skills/types.js +7 -0
- package/dist/skills/validator.d.ts +30 -0
- package/dist/skills/validator.js +121 -0
- package/dist/store.d.ts +1 -0
- package/dist/store.js +5 -0
- 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 +9 -0
- package/dist/tools/builtin.js +27 -0
- 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 +60 -0
- package/dist/tools/fs_glob/prompt.d.ts +2 -0
- package/dist/tools/fs_glob/prompt.js +18 -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_rm/index.d.ts +1 -0
- package/dist/tools/fs_rm/index.js +41 -0
- package/dist/tools/fs_rm/prompt.d.ts +2 -0
- package/dist/tools/fs_rm/prompt.js +14 -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 +9 -0
- package/dist/tools/index.js +56 -0
- package/dist/tools/mcp.d.ts +73 -0
- package/dist/tools/mcp.js +198 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/skill_activate/index.d.ts +5 -0
- package/dist/tools/skill_activate/index.js +63 -0
- package/dist/tools/skill_list/index.d.ts +5 -0
- package/dist/tools/skill_list/index.js +48 -0
- package/dist/tools/skill_resource/index.d.ts +5 -0
- package/dist/tools/skill_resource/index.js +82 -0
- package/dist/tools/task_run/index.d.ts +7 -0
- package/dist/tools/task_run/index.js +60 -0
- package/dist/tools/task_run/prompt.d.ts +5 -0
- package/dist/tools/task_run/prompt.js +29 -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 +104 -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/session-id.d.ts +21 -0
- package/dist/utils/session-id.js +64 -0
- package/dist/utils/unicode.d.ts +17 -0
- package/dist/utils/unicode.js +62 -0
- package/package.json +117 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HookManager = void 0;
|
|
4
|
+
class HookManager {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.hooks = [];
|
|
7
|
+
}
|
|
8
|
+
register(hooks, origin = 'agent') {
|
|
9
|
+
this.hooks.push({ hooks, origin });
|
|
10
|
+
}
|
|
11
|
+
getRegistered() {
|
|
12
|
+
return this.hooks.map(({ hooks, origin }) => ({
|
|
13
|
+
origin,
|
|
14
|
+
names: [
|
|
15
|
+
hooks.preToolUse && 'preToolUse',
|
|
16
|
+
hooks.postToolUse && 'postToolUse',
|
|
17
|
+
hooks.preModel && 'preModel',
|
|
18
|
+
hooks.postModel && 'postModel',
|
|
19
|
+
].filter(Boolean),
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
async runPreToolUse(call, ctx) {
|
|
23
|
+
for (const { hooks } of this.hooks) {
|
|
24
|
+
if (hooks.preToolUse) {
|
|
25
|
+
const result = await hooks.preToolUse(call, ctx);
|
|
26
|
+
if (result)
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
async runPostToolUse(outcome, ctx) {
|
|
33
|
+
let current = outcome;
|
|
34
|
+
for (const { hooks } of this.hooks) {
|
|
35
|
+
if (hooks.postToolUse) {
|
|
36
|
+
const result = await hooks.postToolUse(current, ctx);
|
|
37
|
+
if (result && typeof result === 'object') {
|
|
38
|
+
if ('replace' in result) {
|
|
39
|
+
current = result.replace;
|
|
40
|
+
}
|
|
41
|
+
else if ('update' in result) {
|
|
42
|
+
current = { ...current, ...result.update };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
async runPreModel(request) {
|
|
50
|
+
for (const { hooks } of this.hooks) {
|
|
51
|
+
if (hooks.preModel) {
|
|
52
|
+
await hooks.preModel(request);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async runPostModel(response) {
|
|
57
|
+
for (const { hooks } of this.hooks) {
|
|
58
|
+
if (hooks.postModel) {
|
|
59
|
+
await hooks.postModel(response);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async runMessagesChanged(snapshot) {
|
|
64
|
+
for (const { hooks } of this.hooks) {
|
|
65
|
+
if (hooks.messagesChanged) {
|
|
66
|
+
await hooks.messagesChanged(snapshot);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.HookManager = HookManager;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PermissionConfig } from './template';
|
|
2
|
+
import { ToolDescriptor } from '../tools/registry';
|
|
3
|
+
export type PermissionDecision = 'allow' | 'deny' | 'ask';
|
|
4
|
+
export interface PermissionEvaluationContext {
|
|
5
|
+
toolName: string;
|
|
6
|
+
descriptor?: ToolDescriptor;
|
|
7
|
+
config: PermissionConfig;
|
|
8
|
+
}
|
|
9
|
+
export type PermissionModeHandler = (ctx: PermissionEvaluationContext) => PermissionDecision;
|
|
10
|
+
export interface SerializedPermissionMode {
|
|
11
|
+
name: string;
|
|
12
|
+
builtIn: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare class PermissionModeRegistry {
|
|
15
|
+
private handlers;
|
|
16
|
+
private customModes;
|
|
17
|
+
register(mode: string, handler: PermissionModeHandler, isBuiltIn?: boolean): void;
|
|
18
|
+
get(mode: string): PermissionModeHandler | undefined;
|
|
19
|
+
list(): string[];
|
|
20
|
+
/**
|
|
21
|
+
* 序列化权限模式配置
|
|
22
|
+
* 仅序列化自定义模式的名称,内置模式在 Resume 时自动恢复
|
|
23
|
+
*/
|
|
24
|
+
serialize(): SerializedPermissionMode[];
|
|
25
|
+
/**
|
|
26
|
+
* 验证序列化的权限模式是否可恢复
|
|
27
|
+
* 返回缺失的自定义模式列表
|
|
28
|
+
*/
|
|
29
|
+
validateRestore(serialized: SerializedPermissionMode[]): string[];
|
|
30
|
+
}
|
|
31
|
+
export declare const permissionModes: PermissionModeRegistry;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.permissionModes = exports.PermissionModeRegistry = void 0;
|
|
4
|
+
class PermissionModeRegistry {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.handlers = new Map();
|
|
7
|
+
this.customModes = new Set();
|
|
8
|
+
}
|
|
9
|
+
register(mode, handler, isBuiltIn = false) {
|
|
10
|
+
this.handlers.set(mode, handler);
|
|
11
|
+
if (!isBuiltIn) {
|
|
12
|
+
this.customModes.add(mode);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
get(mode) {
|
|
16
|
+
return this.handlers.get(mode);
|
|
17
|
+
}
|
|
18
|
+
list() {
|
|
19
|
+
return Array.from(this.handlers.keys());
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 序列化权限模式配置
|
|
23
|
+
* 仅序列化自定义模式的名称,内置模式在 Resume 时自动恢复
|
|
24
|
+
*/
|
|
25
|
+
serialize() {
|
|
26
|
+
return Array.from(this.handlers.keys()).map(name => ({
|
|
27
|
+
name,
|
|
28
|
+
builtIn: !this.customModes.has(name)
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 验证序列化的权限模式是否可恢复
|
|
33
|
+
* 返回缺失的自定义模式列表
|
|
34
|
+
*/
|
|
35
|
+
validateRestore(serialized) {
|
|
36
|
+
const missing = [];
|
|
37
|
+
for (const mode of serialized) {
|
|
38
|
+
if (!mode.builtIn && !this.handlers.has(mode.name)) {
|
|
39
|
+
missing.push(mode.name);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return missing;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.PermissionModeRegistry = PermissionModeRegistry;
|
|
46
|
+
exports.permissionModes = new PermissionModeRegistry();
|
|
47
|
+
const MUTATING_ACCESS = new Set(['write', 'execute', 'manage', 'mutate']);
|
|
48
|
+
// 内置模式
|
|
49
|
+
exports.permissionModes.register('auto', () => 'allow', true);
|
|
50
|
+
exports.permissionModes.register('approval', () => 'ask', true);
|
|
51
|
+
exports.permissionModes.register('readonly', (ctx) => {
|
|
52
|
+
const metadata = ctx.descriptor?.metadata || {};
|
|
53
|
+
if (metadata.mutates === true)
|
|
54
|
+
return 'deny';
|
|
55
|
+
if (metadata.mutates === false)
|
|
56
|
+
return 'allow';
|
|
57
|
+
const access = typeof metadata.access === 'string' ? metadata.access.toLowerCase() : undefined;
|
|
58
|
+
if (access && MUTATING_ACCESS.has(access))
|
|
59
|
+
return 'deny';
|
|
60
|
+
return 'ask';
|
|
61
|
+
}, true);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Agent, AgentConfig, AgentDependencies } from './agent';
|
|
2
|
+
import { AgentStatus, SnapshotId } from './types';
|
|
3
|
+
export interface AgentPoolOptions {
|
|
4
|
+
dependencies: AgentDependencies;
|
|
5
|
+
maxAgents?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class AgentPool {
|
|
8
|
+
private agents;
|
|
9
|
+
private deps;
|
|
10
|
+
private maxAgents;
|
|
11
|
+
constructor(opts: AgentPoolOptions);
|
|
12
|
+
create(agentId: string, config: AgentConfig): Promise<Agent>;
|
|
13
|
+
get(agentId: string): Agent | undefined;
|
|
14
|
+
list(opts?: {
|
|
15
|
+
prefix?: string;
|
|
16
|
+
}): string[];
|
|
17
|
+
status(agentId: string): Promise<AgentStatus | undefined>;
|
|
18
|
+
fork(agentId: string, snapshotSel?: SnapshotId | {
|
|
19
|
+
at?: string;
|
|
20
|
+
}): Promise<Agent>;
|
|
21
|
+
resume(agentId: string, config: AgentConfig, opts?: {
|
|
22
|
+
autoRun?: boolean;
|
|
23
|
+
strategy?: 'crash' | 'manual';
|
|
24
|
+
}): Promise<Agent>;
|
|
25
|
+
resumeAll(configFactory: (agentId: string) => AgentConfig, opts?: {
|
|
26
|
+
autoRun?: boolean;
|
|
27
|
+
strategy?: 'crash' | 'manual';
|
|
28
|
+
}): Promise<Agent[]>;
|
|
29
|
+
delete(agentId: string): Promise<void>;
|
|
30
|
+
size(): number;
|
|
31
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentPool = void 0;
|
|
4
|
+
const agent_1 = require("./agent");
|
|
5
|
+
class AgentPool {
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
this.agents = new Map();
|
|
8
|
+
this.deps = opts.dependencies;
|
|
9
|
+
this.maxAgents = opts.maxAgents || 50;
|
|
10
|
+
}
|
|
11
|
+
async create(agentId, config) {
|
|
12
|
+
if (this.agents.has(agentId)) {
|
|
13
|
+
throw new Error(`Agent already exists: ${agentId}`);
|
|
14
|
+
}
|
|
15
|
+
if (this.agents.size >= this.maxAgents) {
|
|
16
|
+
throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
|
|
17
|
+
}
|
|
18
|
+
const agent = await agent_1.Agent.create({ ...config, agentId }, this.deps);
|
|
19
|
+
this.agents.set(agentId, agent);
|
|
20
|
+
return agent;
|
|
21
|
+
}
|
|
22
|
+
get(agentId) {
|
|
23
|
+
return this.agents.get(agentId);
|
|
24
|
+
}
|
|
25
|
+
list(opts) {
|
|
26
|
+
const ids = Array.from(this.agents.keys());
|
|
27
|
+
return opts?.prefix ? ids.filter((id) => id.startsWith(opts.prefix)) : ids;
|
|
28
|
+
}
|
|
29
|
+
async status(agentId) {
|
|
30
|
+
const agent = this.agents.get(agentId);
|
|
31
|
+
return agent ? await agent.status() : undefined;
|
|
32
|
+
}
|
|
33
|
+
async fork(agentId, snapshotSel) {
|
|
34
|
+
const agent = this.agents.get(agentId);
|
|
35
|
+
if (!agent) {
|
|
36
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
37
|
+
}
|
|
38
|
+
return agent.fork(snapshotSel);
|
|
39
|
+
}
|
|
40
|
+
async resume(agentId, config, opts) {
|
|
41
|
+
// 1. Check if already in pool
|
|
42
|
+
if (this.agents.has(agentId)) {
|
|
43
|
+
return this.agents.get(agentId);
|
|
44
|
+
}
|
|
45
|
+
// 2. Check pool capacity
|
|
46
|
+
if (this.agents.size >= this.maxAgents) {
|
|
47
|
+
throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
|
|
48
|
+
}
|
|
49
|
+
// 3. Verify session exists
|
|
50
|
+
const exists = await this.deps.store.exists(agentId);
|
|
51
|
+
if (!exists) {
|
|
52
|
+
throw new Error(`Agent not found in store: ${agentId}`);
|
|
53
|
+
}
|
|
54
|
+
// 4. Use Agent.resume() to restore
|
|
55
|
+
const agent = await agent_1.Agent.resume(agentId, { ...config, agentId }, this.deps, opts);
|
|
56
|
+
// 5. Add to pool
|
|
57
|
+
this.agents.set(agentId, agent);
|
|
58
|
+
return agent;
|
|
59
|
+
}
|
|
60
|
+
async resumeAll(configFactory, opts) {
|
|
61
|
+
const agentIds = await this.deps.store.list();
|
|
62
|
+
const resumed = [];
|
|
63
|
+
for (const agentId of agentIds) {
|
|
64
|
+
if (this.agents.size >= this.maxAgents)
|
|
65
|
+
break;
|
|
66
|
+
if (this.agents.has(agentId))
|
|
67
|
+
continue;
|
|
68
|
+
try {
|
|
69
|
+
const config = configFactory(agentId);
|
|
70
|
+
const agent = await this.resume(agentId, config, opts);
|
|
71
|
+
resumed.push(agent);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error(`Failed to resume ${agentId}:`, error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return resumed;
|
|
78
|
+
}
|
|
79
|
+
async delete(agentId) {
|
|
80
|
+
this.agents.delete(agentId);
|
|
81
|
+
await this.deps.store.delete(agentId);
|
|
82
|
+
}
|
|
83
|
+
size() {
|
|
84
|
+
return this.agents.size;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.AgentPool = AgentPool;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AgentPool } from '../core/pool';
|
|
2
|
+
export interface RoomMember {
|
|
3
|
+
name: string;
|
|
4
|
+
agentId: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class Room {
|
|
7
|
+
private pool;
|
|
8
|
+
private members;
|
|
9
|
+
constructor(pool: AgentPool);
|
|
10
|
+
join(name: string, agentId: string): void;
|
|
11
|
+
leave(name: string): void;
|
|
12
|
+
say(from: string, text: string): Promise<void>;
|
|
13
|
+
getMembers(): RoomMember[];
|
|
14
|
+
private extractMentions;
|
|
15
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Room = void 0;
|
|
4
|
+
class Room {
|
|
5
|
+
constructor(pool) {
|
|
6
|
+
this.pool = pool;
|
|
7
|
+
this.members = new Map();
|
|
8
|
+
}
|
|
9
|
+
join(name, agentId) {
|
|
10
|
+
if (this.members.has(name)) {
|
|
11
|
+
throw new Error(`Member already exists: ${name}`);
|
|
12
|
+
}
|
|
13
|
+
this.members.set(name, agentId);
|
|
14
|
+
}
|
|
15
|
+
leave(name) {
|
|
16
|
+
this.members.delete(name);
|
|
17
|
+
}
|
|
18
|
+
async say(from, text) {
|
|
19
|
+
const mentions = this.extractMentions(text);
|
|
20
|
+
if (mentions.length > 0) {
|
|
21
|
+
// Directed message
|
|
22
|
+
for (const mention of mentions) {
|
|
23
|
+
const agentId = this.members.get(mention);
|
|
24
|
+
if (agentId) {
|
|
25
|
+
const agent = this.pool.get(agentId);
|
|
26
|
+
if (agent) {
|
|
27
|
+
await agent.complete(`[from:${from}] ${text}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Broadcast to all except sender
|
|
34
|
+
for (const [name, agentId] of this.members) {
|
|
35
|
+
if (name !== from) {
|
|
36
|
+
const agent = this.pool.get(agentId);
|
|
37
|
+
if (agent) {
|
|
38
|
+
await agent.complete(`[from:${from}] ${text}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
getMembers() {
|
|
45
|
+
return Array.from(this.members.entries()).map(([name, agentId]) => ({ name, agentId }));
|
|
46
|
+
}
|
|
47
|
+
extractMentions(text) {
|
|
48
|
+
const regex = /@(\w+)/g;
|
|
49
|
+
const mentions = [];
|
|
50
|
+
let match;
|
|
51
|
+
while ((match = regex.exec(text)) !== null) {
|
|
52
|
+
mentions.push(match[1]);
|
|
53
|
+
}
|
|
54
|
+
return mentions;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.Room = Room;
|
|
@@ -0,0 +1,33 @@
|
|
|
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;
|
|
13
|
+
}
|
|
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;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Scheduler = void 0;
|
|
4
|
+
class Scheduler {
|
|
5
|
+
constructor(opts) {
|
|
6
|
+
this.stepTasks = new Map();
|
|
7
|
+
this.listeners = new Set();
|
|
8
|
+
this.queued = Promise.resolve();
|
|
9
|
+
this.onTrigger = opts?.onTrigger;
|
|
10
|
+
}
|
|
11
|
+
everySteps(every, callback) {
|
|
12
|
+
if (!Number.isFinite(every) || every <= 0) {
|
|
13
|
+
throw new Error('everySteps: interval must be positive');
|
|
14
|
+
}
|
|
15
|
+
const id = this.generateId('steps');
|
|
16
|
+
this.stepTasks.set(id, {
|
|
17
|
+
id,
|
|
18
|
+
every,
|
|
19
|
+
callback,
|
|
20
|
+
lastTriggered: 0,
|
|
21
|
+
});
|
|
22
|
+
return id;
|
|
23
|
+
}
|
|
24
|
+
onStep(callback) {
|
|
25
|
+
this.listeners.add(callback);
|
|
26
|
+
return () => this.listeners.delete(callback);
|
|
27
|
+
}
|
|
28
|
+
enqueue(callback) {
|
|
29
|
+
this.queued = this.queued.then(() => Promise.resolve(callback())).catch(() => undefined);
|
|
30
|
+
}
|
|
31
|
+
notifyStep(stepCount) {
|
|
32
|
+
for (const listener of this.listeners) {
|
|
33
|
+
void Promise.resolve(listener({ stepCount }));
|
|
34
|
+
}
|
|
35
|
+
for (const task of this.stepTasks.values()) {
|
|
36
|
+
const shouldTrigger = stepCount - task.lastTriggered >= task.every;
|
|
37
|
+
if (!shouldTrigger)
|
|
38
|
+
continue;
|
|
39
|
+
task.lastTriggered = stepCount;
|
|
40
|
+
void Promise.resolve(task.callback({ stepCount }));
|
|
41
|
+
this.onTrigger?.({ taskId: task.id, spec: `steps:${task.every}`, kind: 'steps' });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
cancel(taskId) {
|
|
45
|
+
this.stepTasks.delete(taskId);
|
|
46
|
+
}
|
|
47
|
+
clear() {
|
|
48
|
+
this.stepTasks.clear();
|
|
49
|
+
this.listeners.clear();
|
|
50
|
+
}
|
|
51
|
+
notifyExternalTrigger(info) {
|
|
52
|
+
this.onTrigger?.(info);
|
|
53
|
+
}
|
|
54
|
+
generateId(prefix) {
|
|
55
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.Scheduler = Scheduler;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Hooks } from './hooks';
|
|
2
|
+
export type PermissionDecisionMode = 'auto' | 'approval' | 'readonly' | (string & {});
|
|
3
|
+
export interface PermissionConfig {
|
|
4
|
+
mode: PermissionDecisionMode;
|
|
5
|
+
requireApprovalTools?: string[];
|
|
6
|
+
allowTools?: string[];
|
|
7
|
+
denyTools?: string[];
|
|
8
|
+
metadata?: Record<string, any>;
|
|
9
|
+
}
|
|
10
|
+
export interface SubAgentConfig {
|
|
11
|
+
templates?: string[];
|
|
12
|
+
depth: number;
|
|
13
|
+
inheritConfig?: boolean;
|
|
14
|
+
overrides?: {
|
|
15
|
+
permission?: PermissionConfig;
|
|
16
|
+
todo?: TodoConfig;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface TodoConfig {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
remindIntervalSteps?: number;
|
|
22
|
+
storagePath?: string;
|
|
23
|
+
reminderOnStart?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface AgentTemplateDefinition {
|
|
26
|
+
id: string;
|
|
27
|
+
name?: string;
|
|
28
|
+
desc?: string;
|
|
29
|
+
version?: string;
|
|
30
|
+
systemPrompt: string;
|
|
31
|
+
model?: string;
|
|
32
|
+
sandbox?: Record<string, any>;
|
|
33
|
+
tools?: '*' | string[];
|
|
34
|
+
permission?: PermissionConfig;
|
|
35
|
+
runtime?: TemplateRuntimeConfig;
|
|
36
|
+
hooks?: Hooks;
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Skills 自动激活配置
|
|
41
|
+
*/
|
|
42
|
+
export interface TemplateSkillsConfig {
|
|
43
|
+
/** 启动时自动激活的 Skills(核心 Skills) */
|
|
44
|
+
autoActivate?: string[];
|
|
45
|
+
/** 推荐激活的 Skills(在系统提示中显示推荐) */
|
|
46
|
+
recommend?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* 强制启用的 Skills(不可被用户关闭)。
|
|
49
|
+
*
|
|
50
|
+
* 若未指定,默认等同于 autoActivate(即:自动激活的核心技能默认视为必需)。
|
|
51
|
+
*/
|
|
52
|
+
locked?: string[];
|
|
53
|
+
}
|
|
54
|
+
export interface TemplateRuntimeConfig {
|
|
55
|
+
exposeThinking?: boolean;
|
|
56
|
+
todo?: TodoConfig;
|
|
57
|
+
subagents?: SubAgentConfig;
|
|
58
|
+
/** Skills 自动激活配置 */
|
|
59
|
+
skills?: TemplateSkillsConfig;
|
|
60
|
+
metadata?: Record<string, any>;
|
|
61
|
+
}
|
|
62
|
+
export declare class AgentTemplateRegistry {
|
|
63
|
+
private templates;
|
|
64
|
+
register(template: AgentTemplateDefinition): void;
|
|
65
|
+
bulkRegister(templates: AgentTemplateDefinition[]): void;
|
|
66
|
+
has(id: string): boolean;
|
|
67
|
+
get(id: string): AgentTemplateDefinition;
|
|
68
|
+
list(): AgentTemplateDefinition[];
|
|
69
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentTemplateRegistry = void 0;
|
|
4
|
+
class AgentTemplateRegistry {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.templates = new Map();
|
|
7
|
+
}
|
|
8
|
+
register(template) {
|
|
9
|
+
if (!template.id)
|
|
10
|
+
throw new Error('Template id is required');
|
|
11
|
+
if (!template.systemPrompt || !template.systemPrompt.trim()) {
|
|
12
|
+
throw new Error(`Template ${template.id} must provide a non-empty systemPrompt`);
|
|
13
|
+
}
|
|
14
|
+
this.templates.set(template.id, template);
|
|
15
|
+
}
|
|
16
|
+
bulkRegister(templates) {
|
|
17
|
+
for (const tpl of templates) {
|
|
18
|
+
this.register(tpl);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
has(id) {
|
|
22
|
+
return this.templates.has(id);
|
|
23
|
+
}
|
|
24
|
+
get(id) {
|
|
25
|
+
const tpl = this.templates.get(id);
|
|
26
|
+
if (!tpl) {
|
|
27
|
+
throw new Error(`Template not found: ${id}`);
|
|
28
|
+
}
|
|
29
|
+
return tpl;
|
|
30
|
+
}
|
|
31
|
+
list() {
|
|
32
|
+
return Array.from(this.templates.values());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.AgentTemplateRegistry = AgentTemplateRegistry;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Scheduler } from './scheduler';
|
|
2
|
+
export interface TimeBridgeOptions {
|
|
3
|
+
scheduler: Scheduler;
|
|
4
|
+
driftToleranceMs?: number;
|
|
5
|
+
logger?: (msg: string, meta?: Record<string, any>) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare class TimeBridge {
|
|
8
|
+
private readonly scheduler;
|
|
9
|
+
private readonly driftTolerance;
|
|
10
|
+
private readonly logger?;
|
|
11
|
+
private readonly timers;
|
|
12
|
+
constructor(opts: TimeBridgeOptions);
|
|
13
|
+
everyMinutes(minutes: number, callback: () => void | Promise<void>): string;
|
|
14
|
+
cron(expr: string, callback: () => void | Promise<void>): string;
|
|
15
|
+
stop(timerId: string): void;
|
|
16
|
+
dispose(): void;
|
|
17
|
+
private generateId;
|
|
18
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeBridge = void 0;
|
|
4
|
+
class TimeBridge {
|
|
5
|
+
constructor(opts) {
|
|
6
|
+
this.timers = new Map();
|
|
7
|
+
this.scheduler = opts.scheduler;
|
|
8
|
+
this.driftTolerance = opts.driftToleranceMs ?? 5000;
|
|
9
|
+
this.logger = opts.logger;
|
|
10
|
+
}
|
|
11
|
+
everyMinutes(minutes, callback) {
|
|
12
|
+
if (!Number.isFinite(minutes) || minutes <= 0) {
|
|
13
|
+
throw new Error('everyMinutes: interval must be positive');
|
|
14
|
+
}
|
|
15
|
+
const interval = minutes * 60 * 1000;
|
|
16
|
+
const id = this.generateId('minutes');
|
|
17
|
+
const scheduleNext = () => {
|
|
18
|
+
const due = Date.now() + interval;
|
|
19
|
+
const handle = setTimeout(() => tick(due), interval);
|
|
20
|
+
entry.cancel = () => clearTimeout(handle);
|
|
21
|
+
};
|
|
22
|
+
const spec = `every:${minutes}m`;
|
|
23
|
+
const tick = (due) => {
|
|
24
|
+
this.scheduler.enqueue(async () => {
|
|
25
|
+
const drift = Math.abs(Date.now() - due);
|
|
26
|
+
if (drift > this.driftTolerance) {
|
|
27
|
+
this.logger?.('timebridge:drift', { id, drift, expectedInterval: interval });
|
|
28
|
+
}
|
|
29
|
+
await callback();
|
|
30
|
+
this.scheduler.notifyExternalTrigger({ taskId: id, spec, kind: 'time' });
|
|
31
|
+
});
|
|
32
|
+
scheduleNext();
|
|
33
|
+
};
|
|
34
|
+
const entry = {
|
|
35
|
+
id,
|
|
36
|
+
cancel: () => undefined,
|
|
37
|
+
};
|
|
38
|
+
this.timers.set(id, entry);
|
|
39
|
+
scheduleNext();
|
|
40
|
+
return id;
|
|
41
|
+
}
|
|
42
|
+
cron(expr, callback) {
|
|
43
|
+
const parts = expr.trim().split(/\s+/);
|
|
44
|
+
if (parts.length !== 5) {
|
|
45
|
+
throw new Error(`Unsupported cron expression: ${expr}`);
|
|
46
|
+
}
|
|
47
|
+
const minute = Number(parts[0]);
|
|
48
|
+
const hour = Number(parts[1]);
|
|
49
|
+
if (!Number.isInteger(minute) || !Number.isInteger(hour)) {
|
|
50
|
+
throw new Error(`Cron expression must be numeric minutes/hours: ${expr}`);
|
|
51
|
+
}
|
|
52
|
+
const id = this.generateId('cron');
|
|
53
|
+
const scheduleNext = () => {
|
|
54
|
+
const now = new Date();
|
|
55
|
+
const next = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute, 0, 0);
|
|
56
|
+
if (next <= now) {
|
|
57
|
+
next.setDate(next.getDate() + 1);
|
|
58
|
+
}
|
|
59
|
+
const due = next.getTime();
|
|
60
|
+
const delay = Math.max(0, due - Date.now());
|
|
61
|
+
const handle = setTimeout(() => tick(due), delay);
|
|
62
|
+
entry.cancel = () => clearTimeout(handle);
|
|
63
|
+
};
|
|
64
|
+
const tick = (due) => {
|
|
65
|
+
this.scheduler.enqueue(async () => {
|
|
66
|
+
const drift = Math.abs(Date.now() - due);
|
|
67
|
+
if (drift > this.driftTolerance) {
|
|
68
|
+
this.logger?.('timebridge:drift', { id, drift, spec: expr });
|
|
69
|
+
}
|
|
70
|
+
await callback();
|
|
71
|
+
this.scheduler.notifyExternalTrigger({ taskId: id, spec: expr, kind: 'cron' });
|
|
72
|
+
});
|
|
73
|
+
scheduleNext();
|
|
74
|
+
};
|
|
75
|
+
const entry = {
|
|
76
|
+
id,
|
|
77
|
+
cancel: () => undefined,
|
|
78
|
+
};
|
|
79
|
+
this.timers.set(id, entry);
|
|
80
|
+
scheduleNext();
|
|
81
|
+
return id;
|
|
82
|
+
}
|
|
83
|
+
stop(timerId) {
|
|
84
|
+
const entry = this.timers.get(timerId);
|
|
85
|
+
if (!entry)
|
|
86
|
+
return;
|
|
87
|
+
entry.cancel();
|
|
88
|
+
this.timers.delete(timerId);
|
|
89
|
+
}
|
|
90
|
+
dispose() {
|
|
91
|
+
for (const entry of this.timers.values()) {
|
|
92
|
+
entry.cancel();
|
|
93
|
+
}
|
|
94
|
+
this.timers.clear();
|
|
95
|
+
}
|
|
96
|
+
generateId(prefix) {
|
|
97
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.TimeBridge = TimeBridge;
|