skyloom 1.4.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/.github/workflows/ci.yml +36 -0
- package/CONVERSION_PLAN.md +191 -0
- package/README.md +67 -0
- package/dist/agents/dew.d.ts +15 -0
- package/dist/agents/dew.d.ts.map +1 -0
- package/dist/agents/dew.js +74 -0
- package/dist/agents/dew.js.map +1 -0
- package/dist/agents/fair.d.ts +15 -0
- package/dist/agents/fair.d.ts.map +1 -0
- package/dist/agents/fair.js +106 -0
- package/dist/agents/fair.js.map +1 -0
- package/dist/agents/fog.d.ts +15 -0
- package/dist/agents/fog.d.ts.map +1 -0
- package/dist/agents/fog.js +52 -0
- package/dist/agents/fog.js.map +1 -0
- package/dist/agents/frost.d.ts +15 -0
- package/dist/agents/frost.d.ts.map +1 -0
- package/dist/agents/frost.js +54 -0
- package/dist/agents/frost.js.map +1 -0
- package/dist/agents/rain.d.ts +15 -0
- package/dist/agents/rain.d.ts.map +1 -0
- package/dist/agents/rain.js +54 -0
- package/dist/agents/rain.js.map +1 -0
- package/dist/agents/snow.d.ts +27 -0
- package/dist/agents/snow.d.ts.map +1 -0
- package/dist/agents/snow.js +226 -0
- package/dist/agents/snow.js.map +1 -0
- package/dist/cli/main.d.ts +7 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +402 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/mode.d.ts +17 -0
- package/dist/cli/mode.d.ts.map +1 -0
- package/dist/cli/mode.js +56 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/core/agent.d.ts +174 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1332 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agent_helpers.d.ts +51 -0
- package/dist/core/agent_helpers.d.ts.map +1 -0
- package/dist/core/agent_helpers.js +477 -0
- package/dist/core/agent_helpers.js.map +1 -0
- package/dist/core/bus.d.ts +99 -0
- package/dist/core/bus.d.ts.map +1 -0
- package/dist/core/bus.js +191 -0
- package/dist/core/bus.js.map +1 -0
- package/dist/core/cache.d.ts +63 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +121 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/checkpoint.d.ts +19 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +120 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/circuit_breaker.d.ts +46 -0
- package/dist/core/circuit_breaker.d.ts.map +1 -0
- package/dist/core/circuit_breaker.js +99 -0
- package/dist/core/circuit_breaker.js.map +1 -0
- package/dist/core/config.d.ts +97 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +281 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +78 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +84 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/factory.d.ts +63 -0
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +537 -0
- package/dist/core/factory.js.map +1 -0
- package/dist/core/icons.d.ts +28 -0
- package/dist/core/icons.d.ts.map +1 -0
- package/dist/core/icons.js +86 -0
- package/dist/core/icons.js.map +1 -0
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +54 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/llm.d.ts +121 -0
- package/dist/core/llm.d.ts.map +1 -0
- package/dist/core/llm.js +532 -0
- package/dist/core/llm.js.map +1 -0
- package/dist/core/logger.d.ts +57 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +122 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp.d.ts +190 -0
- package/dist/core/mcp.d.ts.map +1 -0
- package/dist/core/mcp.js +822 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/mcp_server.d.ts +26 -0
- package/dist/core/mcp_server.d.ts.map +1 -0
- package/dist/core/mcp_server.js +211 -0
- package/dist/core/mcp_server.js.map +1 -0
- package/dist/core/memory.d.ts +190 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +988 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/middleware.d.ts +114 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +248 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/pipelines.d.ts +87 -0
- package/dist/core/pipelines.d.ts.map +1 -0
- package/dist/core/pipelines.js +301 -0
- package/dist/core/pipelines.js.map +1 -0
- package/dist/core/profile.d.ts +23 -0
- package/dist/core/profile.d.ts.map +1 -0
- package/dist/core/profile.js +289 -0
- package/dist/core/profile.js.map +1 -0
- package/dist/core/router.d.ts +24 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +111 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/schemas.d.ts +82 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +200 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/semantic.d.ts +92 -0
- package/dist/core/semantic.d.ts.map +1 -0
- package/dist/core/semantic.js +175 -0
- package/dist/core/semantic.js.map +1 -0
- package/dist/core/skill.d.ts +68 -0
- package/dist/core/skill.d.ts.map +1 -0
- package/dist/core/skill.js +350 -0
- package/dist/core/skill.js.map +1 -0
- package/dist/core/tool.d.ts +99 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +341 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/tool_router.d.ts +29 -0
- package/dist/core/tool_router.d.ts.map +1 -0
- package/dist/core/tool_router.js +172 -0
- package/dist/core/tool_router.js.map +1 -0
- package/dist/core/workspace.d.ts +48 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +179 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/plugins/loader.d.ts +17 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +96 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/skills/loader.d.ts +9 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +78 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/tools/builtin.d.ts +10 -0
- package/dist/tools/builtin.d.ts.map +1 -0
- package/dist/tools/builtin.js +414 -0
- package/dist/tools/builtin.js.map +1 -0
- package/dist/tools/computer.d.ts +12 -0
- package/dist/tools/computer.d.ts.map +1 -0
- package/dist/tools/computer.js +326 -0
- package/dist/tools/computer.js.map +1 -0
- package/dist/tools/delegate.d.ts +10 -0
- package/dist/tools/delegate.d.ts.map +1 -0
- package/dist/tools/delegate.js +45 -0
- package/dist/tools/delegate.js.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +647 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/tts.d.ts +33 -0
- package/dist/web/tts.d.ts.map +1 -0
- package/dist/web/tts.js +69 -0
- package/dist/web/tts.js.map +1 -0
- package/package.json +60 -0
- package/scripts/install.js +48 -0
- package/scripts/link.js +10 -0
- package/setup.bat +79 -0
- package/skill-test-ty2fOA/test.md +10 -0
- package/src/agents/dew.ts +70 -0
- package/src/agents/fair.ts +102 -0
- package/src/agents/fog.ts +48 -0
- package/src/agents/frost.ts +50 -0
- package/src/agents/rain.ts +50 -0
- package/src/agents/snow.ts +239 -0
- package/src/cli/main.ts +405 -0
- package/src/cli/mode.ts +58 -0
- package/src/core/agent.ts +1506 -0
- package/src/core/agent_helpers.ts +461 -0
- package/src/core/bus.ts +221 -0
- package/src/core/cache.ts +153 -0
- package/src/core/checkpoint.ts +94 -0
- package/src/core/circuit_breaker.ts +119 -0
- package/src/core/config.ts +341 -0
- package/src/core/constants.ts +95 -0
- package/src/core/factory.ts +627 -0
- package/src/core/icons.ts +53 -0
- package/src/core/index.ts +31 -0
- package/src/core/llm.ts +724 -0
- package/src/core/logger.ts +144 -0
- package/src/core/mcp.ts +953 -0
- package/src/core/mcp_server.ts +176 -0
- package/src/core/memory.ts +1169 -0
- package/src/core/middleware.ts +350 -0
- package/src/core/pipelines.ts +424 -0
- package/src/core/profile.ts +255 -0
- package/src/core/router.ts +124 -0
- package/src/core/schemas.ts +282 -0
- package/src/core/semantic.ts +211 -0
- package/src/core/skill.ts +342 -0
- package/src/core/tool.ts +427 -0
- package/src/core/tool_router.ts +193 -0
- package/src/core/workspace.ts +150 -0
- package/src/plugins/loader.ts +66 -0
- package/src/skills/loader.ts +46 -0
- package/src/sql.js.d.ts +29 -0
- package/src/tools/builtin.ts +382 -0
- package/src/tools/computer.ts +269 -0
- package/src/tools/delegate.ts +49 -0
- package/src/web/server.ts +634 -0
- package/src/web/tts.ts +93 -0
- package/tests/bus.test.ts +121 -0
- package/tests/icons.test.ts +45 -0
- package/tests/router.test.ts +86 -0
- package/tests/schemas.test.ts +51 -0
- package/tests/semantic.test.ts +83 -0
- package/tests/setup.ts +10 -0
- package/tests/skill.test.ts +172 -0
- package/tests/tool.test.ts +108 -0
- package/tests/tool_router.test.ts +71 -0
- package/tsconfig.json +37 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared constants across the Skyloom framework.
|
|
4
|
+
* Central home for values that cross module boundaries — keeps
|
|
5
|
+
* circular imports in check and avoids duplication.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ROUTING_MODES = exports.MAX_CONTEXT_TOKENS = exports.LOG_LEVELS = exports.RESPONSE_TYPES = exports.MEMORY_LAYERS = exports.MAX_TOOL_RETRIES = exports.DEFAULT_TOOL_TIMEOUT = exports.AGENT_DESCRIPTIONS = exports.VALID_AGENTS = exports.TASK_DONE_SENTINEL = void 0;
|
|
9
|
+
/**
|
|
10
|
+
* Sentinel returned by the task_done tool. When the LLM calls
|
|
11
|
+
* task_done, the chat-stream loop detects this value in the tool
|
|
12
|
+
* result and terminates the turn cleanly (no truncation warning).
|
|
13
|
+
*/
|
|
14
|
+
exports.TASK_DONE_SENTINEL = "__TASK_DONE__";
|
|
15
|
+
/**
|
|
16
|
+
* Valid agent names in the system
|
|
17
|
+
*/
|
|
18
|
+
exports.VALID_AGENTS = Object.freeze({
|
|
19
|
+
fog: "fog",
|
|
20
|
+
rain: "rain",
|
|
21
|
+
frost: "frost",
|
|
22
|
+
snow: "snow",
|
|
23
|
+
dew: "dew",
|
|
24
|
+
fair: "fair",
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Agent roles and descriptions
|
|
28
|
+
*/
|
|
29
|
+
exports.AGENT_DESCRIPTIONS = {
|
|
30
|
+
fog: "Research & Analysis — explore, investigate, analyze",
|
|
31
|
+
rain: "Code Generation — create, implement, generate",
|
|
32
|
+
frost: "Review & Optimization — critique, optimize, verify",
|
|
33
|
+
snow: "Planning & Orchestration — plan, decompose, coordinate",
|
|
34
|
+
dew: "DevOps & Execution — operate, deploy, execute",
|
|
35
|
+
fair: "Emotional Companion — comfort, encourage, advise",
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Default tool timeout in milliseconds
|
|
39
|
+
*/
|
|
40
|
+
exports.DEFAULT_TOOL_TIMEOUT = 30000; // 30 seconds
|
|
41
|
+
/**
|
|
42
|
+
* Maximum retries for tool execution
|
|
43
|
+
*/
|
|
44
|
+
exports.MAX_TOOL_RETRIES = 3;
|
|
45
|
+
/**
|
|
46
|
+
* Memory layer configuration
|
|
47
|
+
*/
|
|
48
|
+
exports.MEMORY_LAYERS = Object.freeze({
|
|
49
|
+
SHORT_TERM: "short_term",
|
|
50
|
+
WORKING: "working",
|
|
51
|
+
LONG_TERM: "long_term",
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Response types
|
|
55
|
+
*/
|
|
56
|
+
exports.RESPONSE_TYPES = Object.freeze({
|
|
57
|
+
TEXT: "text",
|
|
58
|
+
TOOL_CALL: "tool_call",
|
|
59
|
+
TOOL_RESULT: "tool_result",
|
|
60
|
+
ERROR: "error",
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Log levels
|
|
64
|
+
*/
|
|
65
|
+
exports.LOG_LEVELS = Object.freeze({
|
|
66
|
+
DEBUG: 0,
|
|
67
|
+
INFO: 1,
|
|
68
|
+
WARN: 2,
|
|
69
|
+
ERROR: 3,
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Maximum context window (tokens)
|
|
73
|
+
*/
|
|
74
|
+
exports.MAX_CONTEXT_TOKENS = 100000;
|
|
75
|
+
/**
|
|
76
|
+
* Routing modes for CLI
|
|
77
|
+
*/
|
|
78
|
+
exports.ROUTING_MODES = Object.freeze({
|
|
79
|
+
DIRECT: "direct",
|
|
80
|
+
SINGLE: "single",
|
|
81
|
+
ORCHESTRATE: "orchestrate",
|
|
82
|
+
AUTO: "auto",
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AACU,QAAA,kBAAkB,GAAG,eAAe,CAAC;AAElD;;GAEG;AACU,QAAA,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;IACxC,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;CACJ,CAAC,CAAC;AAOZ;;GAEG;AACU,QAAA,kBAAkB,GAA8B;IAC3D,GAAG,EAAE,qDAAqD;IAC1D,IAAI,EAAE,+CAA+C;IACrD,KAAK,EAAE,oDAAoD;IAC3D,IAAI,EAAE,wDAAwD;IAC9D,GAAG,EAAE,+CAA+C;IACpD,IAAI,EAAE,kDAAkD;CACzD,CAAC;AAEF;;GAEG;AACU,QAAA,oBAAoB,GAAG,KAAK,CAAC,CAAC,aAAa;AAExD;;GAEG;AACU,QAAA,gBAAgB,GAAG,CAAC,CAAC;AAElC;;GAEG;AACU,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,YAAY;IACxB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;CACd,CAAC,CAAC;AAEZ;;GAEG;AACU,QAAA,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,aAAa;IAC1B,KAAK,EAAE,OAAO;CACN,CAAC,CAAC;AAEZ;;GAEG;AACU,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACA,CAAC,CAAC;AAEZ;;GAEG;AACU,QAAA,kBAAkB,GAAG,MAAM,CAAC;AAEzC;;GAEG;AACU,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,aAAa;IAC1B,IAAI,EAAE,MAAM;CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System factory — unified Agent creation and task orchestration.
|
|
3
|
+
*
|
|
4
|
+
* Avoids duplication between CLI and web entry points.
|
|
5
|
+
*/
|
|
6
|
+
import { BaseAgent } from './agent';
|
|
7
|
+
import { MessageBus } from './bus';
|
|
8
|
+
import { loadConfig } from './config';
|
|
9
|
+
import { LLMClient } from './llm';
|
|
10
|
+
import { ToolRegistry } from './tool';
|
|
11
|
+
export declare class SystemContext {
|
|
12
|
+
config: ReturnType<typeof loadConfig>;
|
|
13
|
+
bus: MessageBus;
|
|
14
|
+
llm: LLMClient;
|
|
15
|
+
agentMap: Map<string, BaseAgent>;
|
|
16
|
+
toolRegistry: ToolRegistry;
|
|
17
|
+
workspacePath: string;
|
|
18
|
+
mcp: any;
|
|
19
|
+
mcpStatus: string[];
|
|
20
|
+
constructor(opts: {
|
|
21
|
+
config: ReturnType<typeof loadConfig>;
|
|
22
|
+
bus: MessageBus;
|
|
23
|
+
llm: LLMClient;
|
|
24
|
+
agentMap: Map<string, BaseAgent>;
|
|
25
|
+
toolRegistry: ToolRegistry;
|
|
26
|
+
workspacePath?: string;
|
|
27
|
+
mcp?: any;
|
|
28
|
+
mcpStatus?: string[];
|
|
29
|
+
});
|
|
30
|
+
initAll(): Promise<void>;
|
|
31
|
+
closeAll(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Bootstrap the full system: config, bus, LLM, tools, skills, plugins, agents.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createSystemContext(): SystemContext;
|
|
37
|
+
export declare class TaskExecutionResult {
|
|
38
|
+
id: string;
|
|
39
|
+
agent: string;
|
|
40
|
+
description: string;
|
|
41
|
+
success: boolean;
|
|
42
|
+
content: string;
|
|
43
|
+
constructor(opts: {
|
|
44
|
+
id: string;
|
|
45
|
+
agent: string;
|
|
46
|
+
description: string;
|
|
47
|
+
success: boolean;
|
|
48
|
+
content: string;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export declare function orchestrateTask(goal: string, agentMap: Map<string, BaseAgent>, snow?: BaseAgent | null, options?: {
|
|
52
|
+
onTaskStart?: ((task: any) => Promise<void>) | null;
|
|
53
|
+
onTaskDone?: ((task: any, result: TaskExecutionResult) => Promise<void>) | null;
|
|
54
|
+
onPlanned?: ((tasks: any[]) => Promise<boolean | null>) | null;
|
|
55
|
+
onToolStatus?: ((status: string) => void) | null;
|
|
56
|
+
resultTruncate?: number | null;
|
|
57
|
+
summaryPromptTemplate?: string;
|
|
58
|
+
maxTaskRetries?: number;
|
|
59
|
+
maxReplanRounds?: number;
|
|
60
|
+
maxTotalTasks?: number;
|
|
61
|
+
resume?: boolean;
|
|
62
|
+
}): Promise<[any[], TaskExecutionResult[], string]>;
|
|
63
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* System factory — unified Agent creation and task orchestration.
|
|
4
|
+
*
|
|
5
|
+
* Avoids duplication between CLI and web entry points.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.TaskExecutionResult = exports.SystemContext = void 0;
|
|
9
|
+
exports.createSystemContext = createSystemContext;
|
|
10
|
+
exports.orchestrateTask = orchestrateTask;
|
|
11
|
+
const agent_1 = require("./agent");
|
|
12
|
+
const bus_1 = require("./bus");
|
|
13
|
+
const config_1 = require("./config");
|
|
14
|
+
const llm_1 = require("./llm");
|
|
15
|
+
const logger_1 = require("./logger");
|
|
16
|
+
const skill_1 = require("./skill");
|
|
17
|
+
const tool_1 = require("./tool");
|
|
18
|
+
const log = (0, logger_1.getLogger)('factory');
|
|
19
|
+
class SystemContext {
|
|
20
|
+
constructor(opts) {
|
|
21
|
+
this.workspacePath = '';
|
|
22
|
+
this.mcp = null;
|
|
23
|
+
this.mcpStatus = [];
|
|
24
|
+
this.config = opts.config;
|
|
25
|
+
this.bus = opts.bus;
|
|
26
|
+
this.llm = opts.llm;
|
|
27
|
+
this.agentMap = opts.agentMap;
|
|
28
|
+
this.toolRegistry = opts.toolRegistry;
|
|
29
|
+
this.workspacePath = opts.workspacePath || '';
|
|
30
|
+
this.mcp = opts.mcp || null;
|
|
31
|
+
this.mcpStatus = opts.mcpStatus || [];
|
|
32
|
+
}
|
|
33
|
+
async initAll() {
|
|
34
|
+
if (this.mcp) {
|
|
35
|
+
try {
|
|
36
|
+
this.mcpStatus = await this.mcp.connectAll();
|
|
37
|
+
if (this.mcpStatus.length > 0) {
|
|
38
|
+
log.info('mcp_connected', { servers: this.mcpStatus.join(', ') });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
log.warn('mcp_connect_all_failed', { error: String(e) });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const agent of this.agentMap.values()) {
|
|
46
|
+
await agent.init();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async closeAll() {
|
|
50
|
+
for (const agent of this.agentMap.values()) {
|
|
51
|
+
await agent.close();
|
|
52
|
+
}
|
|
53
|
+
if (this.mcp) {
|
|
54
|
+
try {
|
|
55
|
+
await this.mcp.closeAll();
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
log.warn('mcp_close_failed', { error: String(e) });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.SystemContext = SystemContext;
|
|
64
|
+
/**
|
|
65
|
+
* Bootstrap the full system: config, bus, LLM, tools, skills, plugins, agents.
|
|
66
|
+
*/
|
|
67
|
+
function createSystemContext() {
|
|
68
|
+
const config = (0, config_1.loadConfig)();
|
|
69
|
+
let workspacePath = '';
|
|
70
|
+
try {
|
|
71
|
+
const { resolveWorkspacePath, initWorkspace } = require('./workspace');
|
|
72
|
+
const wsRoot = resolveWorkspacePath(config.workspace?.path || 'auto');
|
|
73
|
+
initWorkspace(wsRoot);
|
|
74
|
+
workspacePath = wsRoot;
|
|
75
|
+
log.info('workspace', { path: workspacePath });
|
|
76
|
+
}
|
|
77
|
+
catch { /* ignore */ }
|
|
78
|
+
const bus = new bus_1.MessageBus();
|
|
79
|
+
// Shared registries
|
|
80
|
+
const baseToolRegistry = new tool_1.ToolRegistry();
|
|
81
|
+
const baseSkillRegistry = new skill_1.SkillRegistry();
|
|
82
|
+
// Register builtin tools
|
|
83
|
+
try {
|
|
84
|
+
const { registerBuiltinTools } = require('../tools/builtin');
|
|
85
|
+
registerBuiltinTools(baseToolRegistry);
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
log.warn('builtin_tools_not_available', { error: String(e) });
|
|
89
|
+
}
|
|
90
|
+
// Register all skills
|
|
91
|
+
try {
|
|
92
|
+
const { registerAllSkills } = require('../skills/loader');
|
|
93
|
+
registerAllSkills(baseSkillRegistry);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
log.warn('skills_not_available', { error: String(e) });
|
|
97
|
+
}
|
|
98
|
+
// Load plugins
|
|
99
|
+
try {
|
|
100
|
+
const { PluginLoader } = require('../plugins/loader');
|
|
101
|
+
const pluginLoader = new PluginLoader(baseToolRegistry);
|
|
102
|
+
const pluginConfig = config.plugins;
|
|
103
|
+
const pluginDirs = pluginConfig?.enabled ? (pluginConfig.directories || []) : [];
|
|
104
|
+
pluginLoader.loadFromDirectories(pluginDirs);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
log.warn('plugins_not_available', { error: String(e) });
|
|
108
|
+
}
|
|
109
|
+
// Configure MCP manager
|
|
110
|
+
let mcpManager = null;
|
|
111
|
+
try {
|
|
112
|
+
const { MCPManager, loadPersistedServers } = require('./mcp');
|
|
113
|
+
mcpManager = new MCPManager(baseToolRegistry);
|
|
114
|
+
const persisted = loadPersistedServers();
|
|
115
|
+
const mcpServers = config.mcp?.servers || [];
|
|
116
|
+
const allServers = [...mcpServers, ...persisted];
|
|
117
|
+
if (allServers.length > 0) {
|
|
118
|
+
mcpManager.configure(allServers);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
log.warn('mcp_not_available', { error: String(e) });
|
|
123
|
+
}
|
|
124
|
+
// Shared LLM client
|
|
125
|
+
const llm = new llm_1.LLMClient(config, baseToolRegistry);
|
|
126
|
+
// Per-agent registries
|
|
127
|
+
const agents = new Map();
|
|
128
|
+
// Try to dynamically load agent classes
|
|
129
|
+
const agentNames = ['fog', 'rain', 'frost', 'snow', 'dew', 'fair'];
|
|
130
|
+
for (const name of agentNames) {
|
|
131
|
+
const agentRegistry = new tool_1.ToolRegistry();
|
|
132
|
+
agentRegistry.merge(baseToolRegistry);
|
|
133
|
+
const agentSkills = new skill_1.SkillRegistry();
|
|
134
|
+
agentSkills.merge(baseSkillRegistry);
|
|
135
|
+
try {
|
|
136
|
+
// Try dynamic import
|
|
137
|
+
const clsName = name.charAt(0).toUpperCase() + name.slice(1) + 'Agent';
|
|
138
|
+
// Use require for now since dynamic imports are async
|
|
139
|
+
let AgentClass = null;
|
|
140
|
+
try {
|
|
141
|
+
const mod = require(`../agents/${name}`);
|
|
142
|
+
AgentClass = mod[clsName];
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
log.warn('agent_class_missing', { agent: name });
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (!AgentClass) {
|
|
149
|
+
log.warn('agent_class_not_found', { agent: name, class: clsName });
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const agent = new AgentClass(config, llm, bus, agentRegistry, agentSkills);
|
|
153
|
+
// Register delegate_to tool
|
|
154
|
+
try {
|
|
155
|
+
const { createDelegateTool } = require('../tools/delegate');
|
|
156
|
+
agentRegistry.register(createDelegateTool(agents, agent));
|
|
157
|
+
}
|
|
158
|
+
catch (e) {
|
|
159
|
+
log.warn('delegate_tool_not_available', { agent: name, error: String(e) });
|
|
160
|
+
}
|
|
161
|
+
agents.set(name, agent);
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
log.warn('agent_creation_failed', { agent: name, error: String(e) });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Bind agents to MCP
|
|
168
|
+
if (mcpManager) {
|
|
169
|
+
try {
|
|
170
|
+
mcpManager.bindAgents(agents);
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
log.warn('mcp_bind_failed', { error: String(e) });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return new SystemContext({
|
|
177
|
+
config,
|
|
178
|
+
bus,
|
|
179
|
+
llm,
|
|
180
|
+
agentMap: agents,
|
|
181
|
+
toolRegistry: baseToolRegistry,
|
|
182
|
+
workspacePath,
|
|
183
|
+
mcp: mcpManager,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
// ── Task orchestration ──
|
|
187
|
+
class TaskExecutionResult {
|
|
188
|
+
constructor(opts) {
|
|
189
|
+
this.id = opts.id;
|
|
190
|
+
this.agent = opts.agent;
|
|
191
|
+
this.description = opts.description;
|
|
192
|
+
this.success = opts.success;
|
|
193
|
+
this.content = opts.content;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
exports.TaskExecutionResult = TaskExecutionResult;
|
|
197
|
+
// Placeholder phrases that mean the LLM gave up
|
|
198
|
+
const PLACEHOLDER_PATTERNS = [
|
|
199
|
+
'done', 'ok', 'completed', 'task completed', 'task done', 'task finished',
|
|
200
|
+
'finished', '已完成', '完成了', '好的', '好了', 'ok!',
|
|
201
|
+
];
|
|
202
|
+
const STATUS_REPORT_KEYWORDS = [
|
|
203
|
+
'已完成', '完成了', '已成功', '已经完成', '工作已', '任务已',
|
|
204
|
+
'task complete', 'task is complete', 'i have completed', "i've completed",
|
|
205
|
+
'successfully completed', 'finished the', 'i finished',
|
|
206
|
+
'已经写好', '已经写完', '已经做好', '写完了', '做完了',
|
|
207
|
+
];
|
|
208
|
+
const DELIVERABLE_MARKERS = [
|
|
209
|
+
'```', 'http://', 'https://', '|', '## ', '###', '- [ ]', '1.', '/', '\\',
|
|
210
|
+
];
|
|
211
|
+
function isThinContent(content) {
|
|
212
|
+
if (!content)
|
|
213
|
+
return true;
|
|
214
|
+
const stripped = content.trim();
|
|
215
|
+
if (!stripped)
|
|
216
|
+
return true;
|
|
217
|
+
const lowered = stripped.toLowerCase();
|
|
218
|
+
if (lowered.startsWith('[truncated]') || lowered.startsWith('[error:'))
|
|
219
|
+
return true;
|
|
220
|
+
const bare = lowered.replace(/[.!?。!?\s]+$/, '').trim();
|
|
221
|
+
if (PLACEHOLDER_PATTERNS.includes(bare))
|
|
222
|
+
return true;
|
|
223
|
+
return (stripped.length <= 200 &&
|
|
224
|
+
STATUS_REPORT_KEYWORDS.some(k => lowered.includes(k)) &&
|
|
225
|
+
!DELIVERABLE_MARKERS.some(m => stripped.includes(m)));
|
|
226
|
+
}
|
|
227
|
+
const RESULT_FAILURE_MARKERS = [
|
|
228
|
+
'[truncated]', '[stuck]', '[Error', 'Error:',
|
|
229
|
+
'未能完成', '无法完成', '[cycle detected]', '[CircuitBreakerOpen]',
|
|
230
|
+
];
|
|
231
|
+
function looksObviouslyComplete(results) {
|
|
232
|
+
if (!results.length)
|
|
233
|
+
return false;
|
|
234
|
+
return results.every(r => {
|
|
235
|
+
if (!r.success)
|
|
236
|
+
return false;
|
|
237
|
+
const body = (r.content || '').trim();
|
|
238
|
+
if (body.length < 400)
|
|
239
|
+
return false;
|
|
240
|
+
return !RESULT_FAILURE_MARKERS.some(m => body.includes(m));
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
async function executeWithRetry(agent, aTask, maxAttempts, onStatus) {
|
|
244
|
+
let lastResult = null;
|
|
245
|
+
const originalDescription = aTask.description;
|
|
246
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
247
|
+
try {
|
|
248
|
+
const result = await agent.executeTask(aTask, onStatus);
|
|
249
|
+
const content = (result.content || '').trim();
|
|
250
|
+
const truncated = result.truncated === true;
|
|
251
|
+
const ok = result.success && !isThinContent(content);
|
|
252
|
+
if (ok && !truncated)
|
|
253
|
+
return result;
|
|
254
|
+
lastResult = result;
|
|
255
|
+
if (attempt < maxAttempts) {
|
|
256
|
+
const reason = truncated
|
|
257
|
+
? 'previous attempt was truncated'
|
|
258
|
+
: 'previous attempt was empty or a placeholder ack';
|
|
259
|
+
aTask.description = `${originalDescription}\n\n[retry ${attempt + 1}/${maxAttempts}] ${reason}. You MUST produce the actual deliverable.`;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch (e) {
|
|
263
|
+
lastResult = { success: false, content: `Attempt ${attempt} threw: ${e}` };
|
|
264
|
+
}
|
|
265
|
+
if (attempt < maxAttempts) {
|
|
266
|
+
await new Promise(r => setTimeout(r, Math.min(500 * Math.pow(2, attempt - 1), 2000)));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
aTask.description = originalDescription;
|
|
270
|
+
return lastResult || { success: false, content: `All ${maxAttempts} attempts failed` };
|
|
271
|
+
}
|
|
272
|
+
async function executePending(pending, agentMap, results, resultsById, fullContentsById, completed, options) {
|
|
273
|
+
while (pending.length > 0) {
|
|
274
|
+
const ready = pending.filter(t => t.allDeps.every((dep) => completed.has(dep)));
|
|
275
|
+
if (ready.length === 0) {
|
|
276
|
+
for (const t of pending) {
|
|
277
|
+
const missing = t.allDeps.filter((d) => !completed.has(d));
|
|
278
|
+
t.transitionTo(agent_1.TaskState.FAILED);
|
|
279
|
+
const r = new TaskExecutionResult({
|
|
280
|
+
id: t.id, agent: t.assignedTo || '',
|
|
281
|
+
description: t.description, success: false,
|
|
282
|
+
content: `[dependency missing] task ${t.id} requires ${missing.join(', ')} which never completed`,
|
|
283
|
+
});
|
|
284
|
+
results.push(r);
|
|
285
|
+
resultsById.set(r.id, r);
|
|
286
|
+
completed.add(r.id);
|
|
287
|
+
if (options.onTaskDone)
|
|
288
|
+
await options.onTaskDone(t, r);
|
|
289
|
+
}
|
|
290
|
+
pending.length = 0;
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
for (const t of ready)
|
|
294
|
+
t.transitionTo(agent_1.TaskState.RUNNING);
|
|
295
|
+
const batchResults = await Promise.all(ready.map(async (t) => {
|
|
296
|
+
const agent = agentMap.get(t.assignedTo);
|
|
297
|
+
if (!agent) {
|
|
298
|
+
return new TaskExecutionResult({
|
|
299
|
+
id: t.id, agent: t.assignedTo || '',
|
|
300
|
+
description: t.description, success: false,
|
|
301
|
+
content: `Agent '${t.assignedTo}' not found`,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (options.onTaskStart)
|
|
305
|
+
await options.onTaskStart(t);
|
|
306
|
+
let description = t.description;
|
|
307
|
+
const upstreamSections = [];
|
|
308
|
+
const thinUpstreamIds = [];
|
|
309
|
+
for (const depId of t.allDeps) {
|
|
310
|
+
if (resultsById.has(depId)) {
|
|
311
|
+
const parent = resultsById.get(depId);
|
|
312
|
+
const fullContent = fullContentsById.get(depId) || parent.content || '';
|
|
313
|
+
if (isThinContent(fullContent)) {
|
|
314
|
+
thinUpstreamIds.push(parent.id);
|
|
315
|
+
upstreamSections.push(`## 上游产出缺失 (task ${parent.id} · ${parent.agent})\n` +
|
|
316
|
+
`⚠ 上游任务声称完成但未产出实际内容。\n` +
|
|
317
|
+
`原始回复:\n${fullContent}`);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
upstreamSections.push(`## 上游产出 (task ${parent.id} · ${parent.agent})\n${fullContent}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (upstreamSections.length > 0) {
|
|
325
|
+
description = `${t.description}\n\n${upstreamSections.join('\n\n')}`;
|
|
326
|
+
}
|
|
327
|
+
if (thinUpstreamIds.length > 0) {
|
|
328
|
+
log.warn('thin_upstream', { task: t.id, thin_upstream: thinUpstreamIds });
|
|
329
|
+
}
|
|
330
|
+
const aTask = new agent_1.Task({
|
|
331
|
+
id: t.id,
|
|
332
|
+
description,
|
|
333
|
+
assignedTo: t.assignedTo,
|
|
334
|
+
parentId: t.parentId,
|
|
335
|
+
metadata: t.metadata,
|
|
336
|
+
});
|
|
337
|
+
const result = await executeWithRetry(agent, aTask, options.maxTaskRetries, options.onToolStatus);
|
|
338
|
+
if (result.success)
|
|
339
|
+
t.transitionTo(agent_1.TaskState.COMPLETED);
|
|
340
|
+
else
|
|
341
|
+
t.transitionTo(agent_1.TaskState.FAILED);
|
|
342
|
+
const full = result.content || '';
|
|
343
|
+
fullContentsById.set(t.id, full);
|
|
344
|
+
const tr = options.resultTruncate != null && full.length > options.resultTruncate
|
|
345
|
+
? full.slice(0, options.resultTruncate) : full;
|
|
346
|
+
const r = new TaskExecutionResult({
|
|
347
|
+
id: t.id, agent: t.assignedTo || '',
|
|
348
|
+
description: t.description, success: result.success,
|
|
349
|
+
content: tr,
|
|
350
|
+
});
|
|
351
|
+
if (options.onTaskDone)
|
|
352
|
+
await options.onTaskDone(t, r);
|
|
353
|
+
return r;
|
|
354
|
+
}));
|
|
355
|
+
for (const r of batchResults) {
|
|
356
|
+
results.push(r);
|
|
357
|
+
resultsById.set(r.id, r);
|
|
358
|
+
completed.add(r.id);
|
|
359
|
+
}
|
|
360
|
+
for (const t of ready) {
|
|
361
|
+
const idx = pending.indexOf(t);
|
|
362
|
+
if (idx >= 0)
|
|
363
|
+
pending.splice(idx, 1);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function judgeGoalAchievement(snow, goal, results) {
|
|
368
|
+
const bullets = results.map(r => {
|
|
369
|
+
const status = r.success ? '成功' : '失败';
|
|
370
|
+
const excerpt = (r.content || '').slice(0, 800);
|
|
371
|
+
return `- [task ${r.id} · agent=${r.agent} · status=${status}] len=${(r.content || '').length}chars\n ${excerpt}`;
|
|
372
|
+
}).join('\n');
|
|
373
|
+
const prompt = `你是一名极严格的项目验收员。验证 sub-task 真的产出了可验证的交付物。
|
|
374
|
+
|
|
375
|
+
## 验收规则(严格执行)
|
|
376
|
+
|
|
377
|
+
1. **「调研/搜集/查询」类**:必须列出具体对象名称和数据/特性/链接。
|
|
378
|
+
2. **「撰写/生成/写作」类**:必须包含实际的文本/代码/markdown。
|
|
379
|
+
3. **「审查/审计/对比」类**:必须列出具体问题点。
|
|
380
|
+
4. **核心交付物缺失绝不容忍**。
|
|
381
|
+
|
|
382
|
+
## 用户原目标
|
|
383
|
+
${goal}
|
|
384
|
+
|
|
385
|
+
## 子任务执行结果
|
|
386
|
+
${bullets}
|
|
387
|
+
|
|
388
|
+
严格按下列 JSON 格式输出(除 JSON 之外不要任何其他字符):
|
|
389
|
+
{"achieved": true/false, "missing": "若未达成,逐项列出缺什么"}`;
|
|
390
|
+
try {
|
|
391
|
+
const raw = await snow.chatOneshot(prompt);
|
|
392
|
+
let text = raw.trim();
|
|
393
|
+
if (text.startsWith('```')) {
|
|
394
|
+
text = text.replace(/```/g, '').replace(/^json/i, '').trim();
|
|
395
|
+
}
|
|
396
|
+
const start = text.indexOf('{');
|
|
397
|
+
const end = text.lastIndexOf('}');
|
|
398
|
+
if (start < 0 || end <= start)
|
|
399
|
+
return [true, ''];
|
|
400
|
+
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
401
|
+
return [!!parsed.achieved, (parsed.missing || '').trim()];
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return [true, ''];
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async function orchestrateTask(goal, agentMap, snow = null, options) {
|
|
408
|
+
const snowAgent = snow || agentMap.get('snow') || null;
|
|
409
|
+
if (!snowAgent) {
|
|
410
|
+
return [[], [], 'Snow agent not available'];
|
|
411
|
+
}
|
|
412
|
+
const maxTaskRetries = options?.maxTaskRetries ?? 3;
|
|
413
|
+
const maxReplanRounds = options?.maxReplanRounds ?? 1;
|
|
414
|
+
const maxTotalTasks = options?.maxTotalTasks ?? 6;
|
|
415
|
+
const resultTruncate = options?.resultTruncate ?? 500;
|
|
416
|
+
// Try pipeline match first
|
|
417
|
+
let tasks;
|
|
418
|
+
try {
|
|
419
|
+
const { matchPipeline, buildTasksFromPipeline } = require('./pipelines');
|
|
420
|
+
const matched = matchPipeline(goal);
|
|
421
|
+
if (matched) {
|
|
422
|
+
tasks = buildTasksFromPipeline(matched, goal);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
tasks = await snowAgent.orchestrate(goal);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
tasks = await snowAgent.orchestrate(goal);
|
|
430
|
+
}
|
|
431
|
+
if (!tasks || tasks.length === 0) {
|
|
432
|
+
return [[], [], 'No tasks were planned'];
|
|
433
|
+
}
|
|
434
|
+
// Notify caller of the plan
|
|
435
|
+
if (options?.onPlanned) {
|
|
436
|
+
const proceed = await options.onPlanned(tasks);
|
|
437
|
+
if (proceed === false) {
|
|
438
|
+
return [tasks, [], '[CANCELLED] plan rejected before execution'];
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const completed = new Set();
|
|
442
|
+
const results = [];
|
|
443
|
+
const resultsById = new Map();
|
|
444
|
+
const fullContentsById = new Map();
|
|
445
|
+
let pending = tasks.filter((t) => t.assignedTo && t.assignedTo !== 'snow');
|
|
446
|
+
let replanRound = 0;
|
|
447
|
+
// Cycle detection
|
|
448
|
+
function hasCycle(t, path) {
|
|
449
|
+
if (path.has(t.id))
|
|
450
|
+
return true;
|
|
451
|
+
path.add(t.id);
|
|
452
|
+
for (const depId of t.allDeps || []) {
|
|
453
|
+
const dep = tasks.find((x) => x.id === depId);
|
|
454
|
+
if (dep && hasCycle(dep, new Set(path)))
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
pending = pending.filter((t) => {
|
|
460
|
+
if (hasCycle(t, new Set())) {
|
|
461
|
+
results.push(new TaskExecutionResult({
|
|
462
|
+
id: t.id, agent: t.assignedTo || '',
|
|
463
|
+
description: t.description, success: false,
|
|
464
|
+
content: `[cycle detected] task ${t.id} has circular dependency`,
|
|
465
|
+
}));
|
|
466
|
+
completed.add(t.id);
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
return true;
|
|
470
|
+
});
|
|
471
|
+
while (true) {
|
|
472
|
+
await executePending(pending, agentMap, results, resultsById, fullContentsById, completed, {
|
|
473
|
+
onTaskStart: options?.onTaskStart || null,
|
|
474
|
+
onTaskDone: options?.onTaskDone || null,
|
|
475
|
+
onToolStatus: options?.onToolStatus || null,
|
|
476
|
+
resultTruncate,
|
|
477
|
+
maxTaskRetries,
|
|
478
|
+
});
|
|
479
|
+
pending = [];
|
|
480
|
+
if (!results.length || replanRound >= maxReplanRounds)
|
|
481
|
+
break;
|
|
482
|
+
if (results.length === 1 && results[0].success)
|
|
483
|
+
break;
|
|
484
|
+
if (looksObviouslyComplete(results))
|
|
485
|
+
break;
|
|
486
|
+
const [achieved, missing] = await judgeGoalAchievement(snowAgent, goal, results);
|
|
487
|
+
if (achieved)
|
|
488
|
+
break;
|
|
489
|
+
replanRound++;
|
|
490
|
+
try {
|
|
491
|
+
const extraTasks = await snowAgent.replanForMissing(goal, results, missing, new Set(tasks.map((t) => t.id)));
|
|
492
|
+
if (!extraTasks || extraTasks.length === 0)
|
|
493
|
+
break;
|
|
494
|
+
if (tasks.length + extraTasks.length > maxTotalTasks)
|
|
495
|
+
break;
|
|
496
|
+
tasks.push(...extraTasks);
|
|
497
|
+
if (options?.onPlanned) {
|
|
498
|
+
const proceed = await options.onPlanned(tasks);
|
|
499
|
+
if (proceed === false)
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
pending = extraTasks.filter((t) => t.assignedTo && t.assignedTo !== 'snow');
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
// Generate summary
|
|
509
|
+
let summary;
|
|
510
|
+
if (!results.length) {
|
|
511
|
+
summary = '没有需要执行的任务。';
|
|
512
|
+
}
|
|
513
|
+
else if (results.length === 1) {
|
|
514
|
+
summary = results[0].content;
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
const tpl = options?.summaryPromptTemplate || '请汇总以下所有子任务的执行结果:\n\n';
|
|
518
|
+
let summaryPrompt = tpl;
|
|
519
|
+
for (const r of results) {
|
|
520
|
+
const status = r.success ? '成功' : '失败';
|
|
521
|
+
summaryPrompt += `### 任务 ${r.id} (${r.agent}) - ${status}\n${(r.content || '').slice(0, 300)}\n\n`;
|
|
522
|
+
}
|
|
523
|
+
summary = await snowAgent.chatOneshot(summaryPrompt);
|
|
524
|
+
}
|
|
525
|
+
// Check if we hit the replan budget without full completion
|
|
526
|
+
if (replanRound >= maxReplanRounds && results.length > 1) {
|
|
527
|
+
try {
|
|
528
|
+
const [achieved, missing] = await judgeGoalAchievement(snowAgent, goal, results);
|
|
529
|
+
if (!achieved && missing) {
|
|
530
|
+
summary = `[INCOMPLETE] 经过 ${maxReplanRounds + 1} 轮规划仍未完全达成目标。\n剩余缺口:${missing}\n\n${summary}`;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
catch { /* ignore */ }
|
|
534
|
+
}
|
|
535
|
+
return [tasks, results, summary];
|
|
536
|
+
}
|
|
537
|
+
//# sourceMappingURL=factory.js.map
|