@xrkseek/harness 0.4.8 → 0.4.9
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/node_modules/@xrkseek/cordis/LICENSE +21 -0
- package/node_modules/@xrkseek/cordis/README.md +14 -0
- package/node_modules/@xrkseek/cordis/bin.js +16 -0
- package/node_modules/@xrkseek/cordis/lib/index.js +1828 -0
- package/node_modules/@xrkseek/cordis/lib/types/context.d.ts +101 -0
- package/node_modules/@xrkseek/cordis/lib/types/context.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/events.d.ts +240 -0
- package/node_modules/@xrkseek/cordis/lib/types/events.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts +202 -0
- package/node_modules/@xrkseek/cordis/lib/types/fiber.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/index.d.ts +15 -0
- package/node_modules/@xrkseek/cordis/lib/types/index.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts +105 -0
- package/node_modules/@xrkseek/cordis/lib/types/logger.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts +186 -0
- package/node_modules/@xrkseek/cordis/lib/types/reflect.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts +201 -0
- package/node_modules/@xrkseek/cordis/lib/types/registry.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/service.d.ts +55 -0
- package/node_modules/@xrkseek/cordis/lib/types/service.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts +62 -0
- package/node_modules/@xrkseek/cordis/lib/types/utils.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/package.json +49 -0
- package/node_modules/@xrkseek/cordis/src/context.d.ts +101 -0
- package/node_modules/@xrkseek/cordis/src/context.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/context.js +99 -0
- package/node_modules/@xrkseek/cordis/src/context.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/context.ts +146 -0
- package/node_modules/@xrkseek/cordis/src/events.d.ts +240 -0
- package/node_modules/@xrkseek/cordis/src/events.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/events.js +199 -0
- package/node_modules/@xrkseek/cordis/src/events.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/events.ts +352 -0
- package/node_modules/@xrkseek/cordis/src/fiber.d.ts +202 -0
- package/node_modules/@xrkseek/cordis/src/fiber.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/fiber.js +677 -0
- package/node_modules/@xrkseek/cordis/src/fiber.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/fiber.ts +754 -0
- package/node_modules/@xrkseek/cordis/src/index.d.ts +15 -0
- package/node_modules/@xrkseek/cordis/src/index.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/index.js +15 -0
- package/node_modules/@xrkseek/cordis/src/index.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/index.ts +14 -0
- package/node_modules/@xrkseek/cordis/src/logger.d.ts +105 -0
- package/node_modules/@xrkseek/cordis/src/logger.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/logger.js +193 -0
- package/node_modules/@xrkseek/cordis/src/logger.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/logger.ts +270 -0
- package/node_modules/@xrkseek/cordis/src/reflect.d.ts +186 -0
- package/node_modules/@xrkseek/cordis/src/reflect.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/reflect.js +311 -0
- package/node_modules/@xrkseek/cordis/src/reflect.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/reflect.ts +418 -0
- package/node_modules/@xrkseek/cordis/src/registry.d.ts +201 -0
- package/node_modules/@xrkseek/cordis/src/registry.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/registry.js +218 -0
- package/node_modules/@xrkseek/cordis/src/registry.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/registry.ts +337 -0
- package/node_modules/@xrkseek/cordis/src/service.d.ts +55 -0
- package/node_modules/@xrkseek/cordis/src/service.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/service.js +113 -0
- package/node_modules/@xrkseek/cordis/src/service.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/service.ts +115 -0
- package/node_modules/@xrkseek/cordis/src/utils.d.ts +62 -0
- package/node_modules/@xrkseek/cordis/src/utils.d.ts.map +1 -0
- package/node_modules/@xrkseek/cordis/src/utils.js +271 -0
- package/node_modules/@xrkseek/cordis/src/utils.js.map +1 -0
- package/node_modules/@xrkseek/cordis/src/utils.ts +287 -0
- package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/core-agent-loop/dist/index.js +39 -68
- package/node_modules/@xrkseek/core-agent-loop/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/core-session/dist/compaction.d.ts +4 -3
- package/node_modules/@xrkseek/core-session/dist/compaction.d.ts.map +1 -1
- package/node_modules/@xrkseek/core-session/dist/compaction.js.map +1 -1
- package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.d.ts.map +1 -1
- package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js +2 -1
- package/node_modules/@xrkseek/core-tools/dist/subagent-prompt.js.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/README.md +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts +16 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/catalog.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js +152 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/catalog.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts +9 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js +21 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/deepinfra-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts +16 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js +189 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/fal-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts +10 -5
- package/node_modules/@xrkseek/exec-image-gen/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/index.js +174 -18
- package/node_modules/@xrkseek/exec-image-gen/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts +16 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js +144 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/krea-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts +9 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js +21 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/meta-ai-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts +4 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js +7 -5
- package/node_modules/@xrkseek/exec-image-gen/dist/openai-http.js.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts +14 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js +117 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/openrouter-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/tools.js +43 -6
- package/node_modules/@xrkseek/exec-image-gen/dist/tools.js.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/types.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/types.js.map +1 -1
- package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts +16 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js +137 -0
- package/node_modules/@xrkseek/exec-image-gen/dist/xai-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts +52 -0
- package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js +216 -0
- package/node_modules/@xrkseek/exec-memory/dist/consolidate-pipeline.js.map +1 -0
- package/node_modules/@xrkseek/exec-memory/dist/index.d.ts +1 -0
- package/node_modules/@xrkseek/exec-memory/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-memory/dist/index.js +1 -0
- package/node_modules/@xrkseek/exec-memory/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/exec-memory/dist/tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-memory/dist/tools.js +20 -7
- package/node_modules/@xrkseek/exec-memory/dist/tools.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/README.md +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts +14 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/catalog.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js +99 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/catalog.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts +9 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js +17 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/deepinfra-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts +14 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js +342 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/fal-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts +8 -6
- package/node_modules/@xrkseek/exec-video-gen/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/index.js +122 -19
- package/node_modules/@xrkseek/exec-video-gen/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts +4 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js +21 -15
- package/node_modules/@xrkseek/exec-video-gen/dist/openai-http.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts +9 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js +18 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/openrouter-http.js.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/tools.js +26 -6
- package/node_modules/@xrkseek/exec-video-gen/dist/tools.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/types.d.ts.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/types.js.map +1 -1
- package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts +18 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.d.ts.map +1 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js +263 -0
- package/node_modules/@xrkseek/exec-video-gen/dist/xai-http.js.map +1 -0
- package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts.map +1 -1
- package/node_modules/@xrkseek/preset-harness/dist/preset.js +12 -3
- package/node_modules/@xrkseek/preset-harness/dist/preset.js.map +1 -1
- package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts +31 -0
- package/node_modules/@xrkseek/server-face/dist/agent-team-graph.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js +125 -1
- package/node_modules/@xrkseek/server-face/dist/agent-team-graph.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/context.d.ts +19 -1
- package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/index.d.ts +3 -3
- package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/index.js +1 -1
- package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/mcp-oauth.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js +25 -3
- package/node_modules/@xrkseek/server-face/dist/mcp-oauth.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts +2 -0
- package/node_modules/@xrkseek/server-face/dist/ralph-tool.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/ralph-tool.js +11 -5
- package/node_modules/@xrkseek/server-face/dist/ralph-tool.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/runtime.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/runtime.js +1 -0
- package/node_modules/@xrkseek/server-face/dist/runtime.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-status.d.ts +16 -0
- package/node_modules/@xrkseek/server-face/dist/session-status.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/session-status.js +44 -5
- package/node_modules/@xrkseek/server-face/dist/session-status.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +9 -0
- package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +50 -0
- package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-document.js +40 -0
- package/node_modules/@xrkseek/server-face/dist/settings-document.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-schemas.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/settings-schemas.js +20 -4
- package/node_modules/@xrkseek/server-face/dist/settings-schemas.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.js +191 -0
- package/node_modules/@xrkseek/server-face/dist/subagent-tools.js.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js +8 -0
- package/node_modules/@xrkseek/server-face/dist/wire/rpc-error.js.map +1 -1
- package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-host/dist/index.js +135 -24
- package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
- package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js +6 -0
- package/node_modules/@xrkseek/server-host/dist/sidebar-face-bridge.js.map +1 -1
- package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts +32 -0
- package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.d.ts.map +1 -0
- package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js +134 -0
- package/node_modules/@xrkseek/server-host/dist/workflow-engine-mount.js.map +1 -0
- package/node_modules/@xrkseek/server-host/package.json +2 -0
- package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.d.ts.map +1 -1
- package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js +20 -0
- package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-adapter.js.map +1 -1
- package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts +10 -2
- package/node_modules/@xrkseek/server-http/dist/sidebar/sidebar-face-bridge.d.ts.map +1 -1
- package/node_modules/@xrkseek/xrk-workflow/README.i18n.yaml +6 -0
- package/node_modules/@xrkseek/xrk-workflow/README.md +73 -0
- package/node_modules/@xrkseek/xrk-workflow/README.zh.md +72 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/index.d.ts +177 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/index.js +730 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.d.ts +13 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/invariant.js +118 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.d.ts +45 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/runtime-types.js +9 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/types.d.ts +118 -0
- package/node_modules/@xrkseek/xrk-workflow/lib/types/types.js +16 -0
- package/node_modules/@xrkseek/xrk-workflow/package.json +53 -0
- package/node_modules/@xrkseek/xrk-workflow/src/index.ts +947 -0
- package/package.json +5 -1
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Definition for the workflow capability seam. Service Providers execute orchestration scripts;
|
|
3
|
+
* observe-only lifecycle events never expose run control.
|
|
4
|
+
* @module @xrkseek/xrk-workflow
|
|
5
|
+
*/
|
|
6
|
+
import { Service } from '@xrkseek/cordis';
|
|
7
|
+
import { HarnessError } from '@xrkseek/xrk-llm';
|
|
8
|
+
import { SessionId } from '@xrkseek/xrk-session/types';
|
|
9
|
+
import { WorkflowRunId, } from "./types.js";
|
|
10
|
+
export { WorkflowRunId } from "./types.js";
|
|
11
|
+
/** Build the script-facing `tools` Proxy (same contract as Code Mode). */
|
|
12
|
+
export function buildWorkflowToolsProxy(bridge, signal) {
|
|
13
|
+
const listNames = () => bridge?.listNames() ?? [];
|
|
14
|
+
const callTool = (name) => async (args) => {
|
|
15
|
+
if (!bridge)
|
|
16
|
+
throw new Error('tools bridge not mounted');
|
|
17
|
+
if (!listNames().includes(name))
|
|
18
|
+
throw new Error(`unknown tool: ${name}`);
|
|
19
|
+
const out = await bridge.call(name, args ?? {}, signal);
|
|
20
|
+
if (out.isError)
|
|
21
|
+
throw new Error(`tools.${name} failed: ${out.content}`);
|
|
22
|
+
return out.content;
|
|
23
|
+
};
|
|
24
|
+
return new Proxy({}, {
|
|
25
|
+
get(_target, prop) {
|
|
26
|
+
if (typeof prop !== 'string' || prop === 'then')
|
|
27
|
+
return undefined;
|
|
28
|
+
return callTool(prop);
|
|
29
|
+
},
|
|
30
|
+
ownKeys() {
|
|
31
|
+
return [...listNames()];
|
|
32
|
+
},
|
|
33
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
34
|
+
if (typeof prop === 'string' && listNames().includes(prop)) {
|
|
35
|
+
return {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
writable: false,
|
|
39
|
+
value: callTool(prop),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Typed error for workflow-seam failures. Extends {@link HarnessError}, so the
|
|
48
|
+
* `code` is machine-routable taxonomy. `fatal` drives the combinator
|
|
49
|
+
* discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd
|
|
50
|
+
* option or a tripped cap must kill the script loudly), and reserve the
|
|
51
|
+
* per-item `null` for child-run failures and ordinary in-stage script errors.
|
|
52
|
+
* Every {@link WorkflowErrorCode} is fatal; the flag exists so the
|
|
53
|
+
* distinction is explicit at every catch site rather than implied.
|
|
54
|
+
*/
|
|
55
|
+
export class WorkflowError extends HarnessError {
|
|
56
|
+
/** Whether combinators must propagate this error instead of nulling the item. */
|
|
57
|
+
fatal;
|
|
58
|
+
constructor(message, code, options) {
|
|
59
|
+
super(message, code, options);
|
|
60
|
+
this.name = 'WorkflowError';
|
|
61
|
+
this.fatal = options?.fatal ?? true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Whether combinators must re-throw `error` instead of mapping the item to `null`.
|
|
66
|
+
* @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).
|
|
67
|
+
* @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.
|
|
68
|
+
*/
|
|
69
|
+
export function isFatalWorkflowError(error) {
|
|
70
|
+
return error instanceof WorkflowError && error.fatal;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Workflow Service Definition contract. Invalid requests throw before publication; a live
|
|
74
|
+
* run is holder-owned, its result never rejects, cancellation and disposal are
|
|
75
|
+
* bounded, and disposal waits for child cleanup within that bound. Lifecycle
|
|
76
|
+
* listener failures are contained, and `workflow/end` fires exactly once as the
|
|
77
|
+
* result settles.
|
|
78
|
+
*/
|
|
79
|
+
export class WorkflowEngine extends Service {
|
|
80
|
+
constructor(ctx) {
|
|
81
|
+
super(ctx, 'workflowEngine');
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Emit a lifecycle event while containing and logging each listener failure.
|
|
85
|
+
* @param name - the `workflow/*` event to dispatch.
|
|
86
|
+
* @param args - the event's payload, matching its declared signature.
|
|
87
|
+
*/
|
|
88
|
+
emitWorkflowEvent(name, ...args) {
|
|
89
|
+
for (const callback of this.ctx.events.dispatch('emit', [name, ...args])) {
|
|
90
|
+
try {
|
|
91
|
+
const returned = callback(...args);
|
|
92
|
+
void Promise.resolve(returned).catch((error) => {
|
|
93
|
+
this.ctx.logger.warn(`workflow: ${name} listener rejected: ${renderListenerError(error)}`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
this.ctx.logger.warn(`workflow: ${name} listener threw: ${renderListenerError(error)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Render any thrown value without violating listener containment.
|
|
104
|
+
* @param error - any thrown value.
|
|
105
|
+
* @returns `String(error)`, or a fixed label when even coercion throws.
|
|
106
|
+
*/
|
|
107
|
+
function renderListenerError(error) {
|
|
108
|
+
try {
|
|
109
|
+
return String(error);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// String coercion itself may throw.
|
|
113
|
+
return '[unrenderable thrown value]';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* In-process Provider: AsyncFunction body with `phase` / `log` / `agent`.
|
|
118
|
+
* `agent()` returns `null` unless `createAgent` is supplied (Cordis compositions
|
|
119
|
+
* that wire subagents). Product Face boot uses the Face-native `ralph` tool;
|
|
120
|
+
* this Provider fills the abstract `ctx.workflowEngine` hole for Cordis mounts.
|
|
121
|
+
*/
|
|
122
|
+
export class InProcessWorkflowEngine extends WorkflowEngine {
|
|
123
|
+
createAgent;
|
|
124
|
+
toolBridge;
|
|
125
|
+
constructor(ctx, options) {
|
|
126
|
+
super(ctx);
|
|
127
|
+
this.createAgent = options?.createAgent;
|
|
128
|
+
this.toolBridge = options?.toolBridge;
|
|
129
|
+
}
|
|
130
|
+
start(request) {
|
|
131
|
+
const meta = request.meta;
|
|
132
|
+
if (!meta || typeof meta !== 'object') {
|
|
133
|
+
throw new WorkflowError('workflow meta must be an object', 'META_INVALID');
|
|
134
|
+
}
|
|
135
|
+
if (typeof meta.name !== 'string' || !meta.name.trim()) {
|
|
136
|
+
throw new WorkflowError('workflow meta.name is required', 'META_INVALID');
|
|
137
|
+
}
|
|
138
|
+
if (typeof meta.description !== 'string' || !meta.description.trim()) {
|
|
139
|
+
throw new WorkflowError('workflow meta.description is required', 'META_INVALID');
|
|
140
|
+
}
|
|
141
|
+
if (typeof request.script !== 'string' || !request.script.trim()) {
|
|
142
|
+
throw new WorkflowError('workflow script must be a non-empty string', 'SCRIPT_PARSE');
|
|
143
|
+
}
|
|
144
|
+
const id = WorkflowRunId(`wf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`);
|
|
145
|
+
let cancelled = false;
|
|
146
|
+
let cancelReason = 'cancelled';
|
|
147
|
+
let agentsStarted = 0;
|
|
148
|
+
let currentPhase;
|
|
149
|
+
const ac = new AbortController();
|
|
150
|
+
const onAbort = () => {
|
|
151
|
+
cancelled = true;
|
|
152
|
+
cancelReason = 'parent signal aborted';
|
|
153
|
+
ac.abort();
|
|
154
|
+
};
|
|
155
|
+
if (request.signal) {
|
|
156
|
+
if (request.signal.aborted)
|
|
157
|
+
onAbort();
|
|
158
|
+
else
|
|
159
|
+
request.signal.addEventListener('abort', onAbort, { once: true });
|
|
160
|
+
}
|
|
161
|
+
const info = { id, meta: request.meta };
|
|
162
|
+
this.emitWorkflowEvent('workflow/start', info);
|
|
163
|
+
const result = (async () => {
|
|
164
|
+
try {
|
|
165
|
+
if (cancelled) {
|
|
166
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
167
|
+
}
|
|
168
|
+
const phase = (title) => {
|
|
169
|
+
currentPhase = String(title ?? '');
|
|
170
|
+
this.emitWorkflowEvent('workflow/phase', info, currentPhase);
|
|
171
|
+
};
|
|
172
|
+
const log = (message) => {
|
|
173
|
+
this.emitWorkflowEvent('workflow/log', info, String(message ?? ''));
|
|
174
|
+
};
|
|
175
|
+
const agent = async (opts = {}) => {
|
|
176
|
+
if (cancelled || ac.signal.aborted) {
|
|
177
|
+
throw new WorkflowError(cancelReason, 'CANCELLED');
|
|
178
|
+
}
|
|
179
|
+
const cap = request.maxTotalAgents;
|
|
180
|
+
if (typeof cap === 'number' && agentsStarted >= cap) {
|
|
181
|
+
throw new WorkflowError(`workflow maxTotalAgents ${cap} reached`, 'AGENT_CAP');
|
|
182
|
+
}
|
|
183
|
+
agentsStarted += 1;
|
|
184
|
+
const seq = agentsStarted;
|
|
185
|
+
const label = String(opts.label ?? opts.prompt ?? `agent-${seq}`).slice(0, 120);
|
|
186
|
+
const phaseTitle = opts.phase ?? currentPhase;
|
|
187
|
+
const childId = SessionId(`wf-child-${String(id)}-${seq}`);
|
|
188
|
+
this.emitWorkflowEvent('workflow/agent-start', info, {
|
|
189
|
+
seq,
|
|
190
|
+
label,
|
|
191
|
+
...(phaseTitle ? { phase: phaseTitle } : {}),
|
|
192
|
+
childId,
|
|
193
|
+
});
|
|
194
|
+
let outcome = 'failed';
|
|
195
|
+
let value = null;
|
|
196
|
+
try {
|
|
197
|
+
if (this.createAgent) {
|
|
198
|
+
value = await this.createAgent(request, {
|
|
199
|
+
label,
|
|
200
|
+
prompt: String(opts.prompt ?? ''),
|
|
201
|
+
...(phaseTitle ? { phase: phaseTitle } : {}),
|
|
202
|
+
});
|
|
203
|
+
outcome = cancelled ? 'cancelled' : 'completed';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
outcome = cancelled ? 'cancelled' : 'failed';
|
|
208
|
+
value = null;
|
|
209
|
+
}
|
|
210
|
+
this.emitWorkflowEvent('workflow/agent-end', info, {
|
|
211
|
+
seq,
|
|
212
|
+
label,
|
|
213
|
+
...(phaseTitle ? { phase: phaseTitle } : {}),
|
|
214
|
+
childId,
|
|
215
|
+
outcome,
|
|
216
|
+
});
|
|
217
|
+
return value;
|
|
218
|
+
};
|
|
219
|
+
const AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
|
|
220
|
+
const tools = buildWorkflowToolsProxy(this.toolBridge, ac.signal);
|
|
221
|
+
const fn = new AsyncFunction('args', 'phase', 'log', 'agent', 'tools', `"use strict";\n${request.script}`);
|
|
222
|
+
const value = await fn(request.args, phase, log, agent, tools);
|
|
223
|
+
if (cancelled || ac.signal.aborted) {
|
|
224
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
value: value === undefined ? null : value,
|
|
228
|
+
stopReason: 'completed',
|
|
229
|
+
agentsStarted,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
if (cancelled || ac.signal.aborted) {
|
|
234
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
value: null,
|
|
238
|
+
stopReason: 'error',
|
|
239
|
+
error: err instanceof Error ? err.message : String(err),
|
|
240
|
+
agentsStarted,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
})().then((settled) => {
|
|
244
|
+
this.emitWorkflowEvent('workflow/end', info, {
|
|
245
|
+
stopReason: settled.stopReason,
|
|
246
|
+
agentsStarted: settled.agentsStarted,
|
|
247
|
+
...(settled.error ? { error: settled.error } : {}),
|
|
248
|
+
});
|
|
249
|
+
return settled;
|
|
250
|
+
});
|
|
251
|
+
return {
|
|
252
|
+
id,
|
|
253
|
+
meta: request.meta,
|
|
254
|
+
result,
|
|
255
|
+
cancel(reason) {
|
|
256
|
+
cancelled = true;
|
|
257
|
+
cancelReason = reason?.trim() || 'cancelled';
|
|
258
|
+
ac.abort();
|
|
259
|
+
},
|
|
260
|
+
async dispose() {
|
|
261
|
+
cancelled = true;
|
|
262
|
+
ac.abort();
|
|
263
|
+
await result.catch(() => undefined);
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Worker-thread Provider: script body runs in an isolated `worker_threads`
|
|
270
|
+
* Worker (eval). `agent()` posts an RPC to the parent thread, which may run
|
|
271
|
+
* an optional {@link IsolatingWorkflowEngine} `createAgent` bridge (same
|
|
272
|
+
* contract as {@link InProcessWorkflowEngine}) and return a structured-cloneable
|
|
273
|
+
* value. Without `createAgent`, `agent()` still settles `null`.
|
|
274
|
+
* `await tools.name(args)` uses an optional {@link WorkflowToolBridge}
|
|
275
|
+
* (Code Mode subset — nested Host tools via parentPort RPC). Full sandboxed
|
|
276
|
+
* Node PTC process confinement is not claimed.
|
|
277
|
+
*/
|
|
278
|
+
export class IsolatingWorkflowEngine extends WorkflowEngine {
|
|
279
|
+
createAgent;
|
|
280
|
+
toolBridge;
|
|
281
|
+
constructor(ctx, options) {
|
|
282
|
+
super(ctx);
|
|
283
|
+
this.createAgent = options?.createAgent;
|
|
284
|
+
this.toolBridge = options?.toolBridge;
|
|
285
|
+
}
|
|
286
|
+
start(request) {
|
|
287
|
+
const meta = request.meta;
|
|
288
|
+
if (!meta || typeof meta !== 'object') {
|
|
289
|
+
throw new WorkflowError('workflow meta must be an object', 'META_INVALID');
|
|
290
|
+
}
|
|
291
|
+
if (typeof meta.name !== 'string' || !meta.name.trim()) {
|
|
292
|
+
throw new WorkflowError('workflow meta.name is required', 'META_INVALID');
|
|
293
|
+
}
|
|
294
|
+
if (typeof meta.description !== 'string' || !meta.description.trim()) {
|
|
295
|
+
throw new WorkflowError('workflow meta.description is required', 'META_INVALID');
|
|
296
|
+
}
|
|
297
|
+
if (typeof request.script !== 'string' || !request.script.trim()) {
|
|
298
|
+
throw new WorkflowError('workflow script must be a non-empty string', 'SCRIPT_PARSE');
|
|
299
|
+
}
|
|
300
|
+
const id = WorkflowRunId(`wf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`);
|
|
301
|
+
let cancelled = false;
|
|
302
|
+
let cancelReason = 'cancelled';
|
|
303
|
+
let agentsStarted = 0;
|
|
304
|
+
const ac = new AbortController();
|
|
305
|
+
const onAbort = () => {
|
|
306
|
+
cancelled = true;
|
|
307
|
+
cancelReason = 'parent signal aborted';
|
|
308
|
+
ac.abort();
|
|
309
|
+
};
|
|
310
|
+
if (request.signal) {
|
|
311
|
+
if (request.signal.aborted)
|
|
312
|
+
onAbort();
|
|
313
|
+
else
|
|
314
|
+
request.signal.addEventListener('abort', onAbort, { once: true });
|
|
315
|
+
}
|
|
316
|
+
const info = { id, meta: request.meta };
|
|
317
|
+
this.emitWorkflowEvent('workflow/start', info);
|
|
318
|
+
const result = (async () => {
|
|
319
|
+
if (cancelled) {
|
|
320
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
321
|
+
}
|
|
322
|
+
try {
|
|
323
|
+
const settled = await runIsolatingWorkerScript({
|
|
324
|
+
script: request.script,
|
|
325
|
+
args: request.args,
|
|
326
|
+
signal: ac.signal,
|
|
327
|
+
onPhase: (title) => {
|
|
328
|
+
this.emitWorkflowEvent('workflow/phase', info, title);
|
|
329
|
+
},
|
|
330
|
+
onLog: (message) => {
|
|
331
|
+
this.emitWorkflowEvent('workflow/log', info, message);
|
|
332
|
+
},
|
|
333
|
+
onAgentStart: (agent) => {
|
|
334
|
+
agentsStarted += 1;
|
|
335
|
+
this.emitWorkflowEvent('workflow/agent-start', info, agent);
|
|
336
|
+
},
|
|
337
|
+
onAgentEnd: (agent) => {
|
|
338
|
+
this.emitWorkflowEvent('workflow/agent-end', info, agent);
|
|
339
|
+
},
|
|
340
|
+
runId: String(id),
|
|
341
|
+
toolNames: this.toolBridge?.listNames() ?? [],
|
|
342
|
+
...(typeof request.maxTotalAgents === 'number'
|
|
343
|
+
? { maxTotalAgents: request.maxTotalAgents }
|
|
344
|
+
: {}),
|
|
345
|
+
...(this.createAgent
|
|
346
|
+
? {
|
|
347
|
+
createAgent: async (call) => {
|
|
348
|
+
if (cancelled || ac.signal.aborted) {
|
|
349
|
+
throw new WorkflowError(cancelReason, 'CANCELLED');
|
|
350
|
+
}
|
|
351
|
+
return this.createAgent(request, call);
|
|
352
|
+
},
|
|
353
|
+
}
|
|
354
|
+
: {}),
|
|
355
|
+
...(this.toolBridge ? { toolBridge: this.toolBridge } : {}),
|
|
356
|
+
});
|
|
357
|
+
if (cancelled || ac.signal.aborted) {
|
|
358
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
359
|
+
}
|
|
360
|
+
agentsStarted = Math.max(agentsStarted, settled.agentsStarted);
|
|
361
|
+
return settled;
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
if (cancelled || ac.signal.aborted) {
|
|
365
|
+
return { value: null, stopReason: 'cancelled', error: cancelReason, agentsStarted };
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
value: null,
|
|
369
|
+
stopReason: 'error',
|
|
370
|
+
error: err instanceof Error ? err.message : String(err),
|
|
371
|
+
agentsStarted,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
})().then((settled) => {
|
|
375
|
+
this.emitWorkflowEvent('workflow/end', info, {
|
|
376
|
+
stopReason: settled.stopReason,
|
|
377
|
+
agentsStarted: settled.agentsStarted,
|
|
378
|
+
...(settled.error ? { error: settled.error } : {}),
|
|
379
|
+
});
|
|
380
|
+
return settled;
|
|
381
|
+
});
|
|
382
|
+
return {
|
|
383
|
+
id,
|
|
384
|
+
meta: request.meta,
|
|
385
|
+
result,
|
|
386
|
+
cancel(reason) {
|
|
387
|
+
cancelled = true;
|
|
388
|
+
cancelReason = reason?.trim() || 'cancelled';
|
|
389
|
+
ac.abort();
|
|
390
|
+
},
|
|
391
|
+
async dispose() {
|
|
392
|
+
cancelled = true;
|
|
393
|
+
ac.abort();
|
|
394
|
+
await result.catch(() => undefined);
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
/** Best-effort clone so worker_threads can postMessage the agent result. */
|
|
400
|
+
function cloneForWorker(value) {
|
|
401
|
+
if (value === undefined)
|
|
402
|
+
return null;
|
|
403
|
+
try {
|
|
404
|
+
return structuredClone(value);
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
try {
|
|
408
|
+
return JSON.parse(JSON.stringify(value));
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
async function runIsolatingWorkerScript(input) {
|
|
416
|
+
const { Worker } = await import('node:worker_threads');
|
|
417
|
+
const workerSource = `
|
|
418
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
419
|
+
let agentsStarted = 0;
|
|
420
|
+
let callSeq = 0;
|
|
421
|
+
const pending = new Map();
|
|
422
|
+
parentPort.on('message', (msg) => {
|
|
423
|
+
if (!msg || (msg.type !== 'agent-result' && msg.type !== 'tool-result')) return;
|
|
424
|
+
const wait = pending.get(msg.callId);
|
|
425
|
+
if (!wait) return;
|
|
426
|
+
pending.delete(msg.callId);
|
|
427
|
+
if (msg.ok) wait.resolve(msg.value === undefined ? null : msg.value);
|
|
428
|
+
else wait.reject(new Error(String(msg.error || 'bridge failed')));
|
|
429
|
+
});
|
|
430
|
+
const phase = (title) => {
|
|
431
|
+
parentPort.postMessage({ type: 'phase', title: String(title ?? '') });
|
|
432
|
+
};
|
|
433
|
+
const log = (message) => {
|
|
434
|
+
parentPort.postMessage({ type: 'log', message: String(message ?? '') });
|
|
435
|
+
};
|
|
436
|
+
const agent = async (opts = {}) => {
|
|
437
|
+
const cap = workerData.maxTotalAgents;
|
|
438
|
+
if (typeof cap === 'number' && agentsStarted >= cap) {
|
|
439
|
+
throw new Error('workflow maxTotalAgents ' + cap + ' reached');
|
|
440
|
+
}
|
|
441
|
+
agentsStarted += 1;
|
|
442
|
+
const seq = agentsStarted;
|
|
443
|
+
const label = String(opts.label ?? opts.prompt ?? ('agent-' + seq)).slice(0, 120);
|
|
444
|
+
const phaseTitle = opts.phase;
|
|
445
|
+
const childId = 'wf-child-' + workerData.runId + '-' + seq;
|
|
446
|
+
const callId = 'c' + (++callSeq);
|
|
447
|
+
parentPort.postMessage({
|
|
448
|
+
type: 'agent-start',
|
|
449
|
+
seq, label, phase: phaseTitle || undefined, childId,
|
|
450
|
+
});
|
|
451
|
+
parentPort.postMessage({
|
|
452
|
+
type: 'agent-call',
|
|
453
|
+
callId, seq, label,
|
|
454
|
+
prompt: String(opts.prompt ?? ''),
|
|
455
|
+
phase: phaseTitle || undefined,
|
|
456
|
+
childId,
|
|
457
|
+
});
|
|
458
|
+
let value = null;
|
|
459
|
+
let outcome = 'completed';
|
|
460
|
+
try {
|
|
461
|
+
value = await new Promise((resolve, reject) => {
|
|
462
|
+
pending.set(callId, { resolve, reject });
|
|
463
|
+
});
|
|
464
|
+
} catch (err) {
|
|
465
|
+
outcome = 'failed';
|
|
466
|
+
parentPort.postMessage({
|
|
467
|
+
type: 'agent-end',
|
|
468
|
+
seq, label, phase: phaseTitle || undefined, childId, outcome,
|
|
469
|
+
});
|
|
470
|
+
throw err;
|
|
471
|
+
}
|
|
472
|
+
parentPort.postMessage({
|
|
473
|
+
type: 'agent-end',
|
|
474
|
+
seq, label, phase: phaseTitle || undefined, childId, outcome,
|
|
475
|
+
});
|
|
476
|
+
return value;
|
|
477
|
+
};
|
|
478
|
+
const toolNames = Array.isArray(workerData.toolNames) ? workerData.toolNames : [];
|
|
479
|
+
const callTool = (name) => async (args) => {
|
|
480
|
+
const callId = 't' + (++callSeq);
|
|
481
|
+
parentPort.postMessage({
|
|
482
|
+
type: 'tool-call',
|
|
483
|
+
callId,
|
|
484
|
+
name: String(name),
|
|
485
|
+
args: args === undefined ? {} : args,
|
|
486
|
+
});
|
|
487
|
+
const out = await new Promise((resolve, reject) => {
|
|
488
|
+
pending.set(callId, { resolve, reject });
|
|
489
|
+
});
|
|
490
|
+
if (out && out.isError) {
|
|
491
|
+
throw new Error('tools.' + name + ' failed: ' + String(out.content || ''));
|
|
492
|
+
}
|
|
493
|
+
return out && typeof out.content === 'string' ? out.content : String(out && out.content != null ? out.content : '');
|
|
494
|
+
};
|
|
495
|
+
const tools = new Proxy({}, {
|
|
496
|
+
get(_target, prop) {
|
|
497
|
+
if (typeof prop !== 'string' || prop === 'then') return undefined;
|
|
498
|
+
return callTool(prop);
|
|
499
|
+
},
|
|
500
|
+
ownKeys() { return toolNames.slice(); },
|
|
501
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
502
|
+
if (typeof prop === 'string' && toolNames.includes(prop)) {
|
|
503
|
+
return { enumerable: true, configurable: true, writable: false, value: callTool(prop) };
|
|
504
|
+
}
|
|
505
|
+
return undefined;
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
509
|
+
try {
|
|
510
|
+
const fn = new AsyncFunction('args', 'phase', 'log', 'agent', 'tools',
|
|
511
|
+
'"use strict";\\n' + workerData.script);
|
|
512
|
+
Promise.resolve(fn(workerData.args, phase, log, agent, tools)).then((value) => {
|
|
513
|
+
parentPort.postMessage({
|
|
514
|
+
type: 'done',
|
|
515
|
+
ok: true,
|
|
516
|
+
value: value === undefined ? null : value,
|
|
517
|
+
agentsStarted,
|
|
518
|
+
});
|
|
519
|
+
}).catch((err) => {
|
|
520
|
+
parentPort.postMessage({
|
|
521
|
+
type: 'done',
|
|
522
|
+
ok: false,
|
|
523
|
+
error: String(err && err.message ? err.message : err),
|
|
524
|
+
agentsStarted,
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
} catch (err) {
|
|
528
|
+
parentPort.postMessage({
|
|
529
|
+
type: 'done',
|
|
530
|
+
ok: false,
|
|
531
|
+
error: String(err && err.message ? err.message : err),
|
|
532
|
+
agentsStarted: 0,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
`;
|
|
536
|
+
return new Promise((resolve, reject) => {
|
|
537
|
+
const worker = new Worker(workerSource, {
|
|
538
|
+
eval: true,
|
|
539
|
+
workerData: {
|
|
540
|
+
script: input.script,
|
|
541
|
+
args: input.args ?? null,
|
|
542
|
+
runId: input.runId,
|
|
543
|
+
toolNames: [...(input.toolNames ?? [])],
|
|
544
|
+
...(typeof input.maxTotalAgents === 'number'
|
|
545
|
+
? { maxTotalAgents: input.maxTotalAgents }
|
|
546
|
+
: {}),
|
|
547
|
+
},
|
|
548
|
+
resourceLimits: { maxOldGenerationSizeMb: 128 },
|
|
549
|
+
});
|
|
550
|
+
let settled = false;
|
|
551
|
+
let agentsStartedSeen = 0;
|
|
552
|
+
const finish = (result) => {
|
|
553
|
+
if (settled)
|
|
554
|
+
return;
|
|
555
|
+
settled = true;
|
|
556
|
+
input.signal?.removeEventListener('abort', onAbort);
|
|
557
|
+
void worker.terminate().catch(() => undefined);
|
|
558
|
+
resolve(result);
|
|
559
|
+
};
|
|
560
|
+
const onAbort = () => {
|
|
561
|
+
void worker.terminate().catch(() => undefined);
|
|
562
|
+
finish({
|
|
563
|
+
value: null,
|
|
564
|
+
stopReason: 'cancelled',
|
|
565
|
+
error: 'parent signal aborted',
|
|
566
|
+
agentsStarted: agentsStartedSeen,
|
|
567
|
+
});
|
|
568
|
+
};
|
|
569
|
+
if (input.signal) {
|
|
570
|
+
if (input.signal.aborted) {
|
|
571
|
+
onAbort();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
input.signal.addEventListener('abort', onAbort, { once: true });
|
|
575
|
+
}
|
|
576
|
+
worker.on('message', (msg) => {
|
|
577
|
+
if (!msg || typeof msg !== 'object')
|
|
578
|
+
return;
|
|
579
|
+
if (msg.type === 'phase' && typeof msg.title === 'string') {
|
|
580
|
+
input.onPhase(msg.title);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
if (msg.type === 'log' && typeof msg.message === 'string') {
|
|
584
|
+
input.onLog(msg.message);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (msg.type === 'agent-start' && typeof msg.seq === 'number') {
|
|
588
|
+
agentsStartedSeen = Math.max(agentsStartedSeen, msg.seq);
|
|
589
|
+
input.onAgentStart({
|
|
590
|
+
seq: msg.seq,
|
|
591
|
+
label: String(msg.label ?? ''),
|
|
592
|
+
...(msg.phase ? { phase: msg.phase } : {}),
|
|
593
|
+
childId: SessionId(String(msg.childId ?? `wf-child-${msg.seq}`)),
|
|
594
|
+
});
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (msg.type === 'agent-call' && typeof msg.callId === 'string') {
|
|
598
|
+
const callId = msg.callId;
|
|
599
|
+
const label = String(msg.label ?? '');
|
|
600
|
+
const prompt = String(msg.prompt ?? '');
|
|
601
|
+
const phaseTitle = msg.phase;
|
|
602
|
+
void (async () => {
|
|
603
|
+
try {
|
|
604
|
+
let value = null;
|
|
605
|
+
if (input.createAgent) {
|
|
606
|
+
value = await input.createAgent({
|
|
607
|
+
label,
|
|
608
|
+
prompt,
|
|
609
|
+
...(phaseTitle ? { phase: String(phaseTitle) } : {}),
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
worker.postMessage({
|
|
613
|
+
type: 'agent-result',
|
|
614
|
+
callId,
|
|
615
|
+
ok: true,
|
|
616
|
+
value: cloneForWorker(value),
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
catch (err) {
|
|
620
|
+
worker.postMessage({
|
|
621
|
+
type: 'agent-result',
|
|
622
|
+
callId,
|
|
623
|
+
ok: false,
|
|
624
|
+
error: err instanceof Error ? err.message : String(err),
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
})();
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (msg.type === 'tool-call' && typeof msg.callId === 'string' && typeof msg.name === 'string') {
|
|
631
|
+
const callId = msg.callId;
|
|
632
|
+
const name = msg.name;
|
|
633
|
+
void (async () => {
|
|
634
|
+
try {
|
|
635
|
+
if (!input.toolBridge) {
|
|
636
|
+
worker.postMessage({
|
|
637
|
+
type: 'tool-result',
|
|
638
|
+
callId,
|
|
639
|
+
ok: false,
|
|
640
|
+
error: 'tools bridge not mounted',
|
|
641
|
+
});
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const names = input.toolBridge.listNames();
|
|
645
|
+
if (!names.includes(name)) {
|
|
646
|
+
worker.postMessage({
|
|
647
|
+
type: 'tool-result',
|
|
648
|
+
callId,
|
|
649
|
+
ok: false,
|
|
650
|
+
error: `unknown tool: ${name}`,
|
|
651
|
+
});
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const out = await input.toolBridge.call(name, msg.args ?? {}, input.signal);
|
|
655
|
+
worker.postMessage({
|
|
656
|
+
type: 'tool-result',
|
|
657
|
+
callId,
|
|
658
|
+
ok: true,
|
|
659
|
+
value: cloneForWorker({
|
|
660
|
+
content: out.content,
|
|
661
|
+
...(out.isError ? { isError: true } : {}),
|
|
662
|
+
}),
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
worker.postMessage({
|
|
667
|
+
type: 'tool-result',
|
|
668
|
+
callId,
|
|
669
|
+
ok: false,
|
|
670
|
+
error: err instanceof Error ? err.message : String(err),
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
})();
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
if (msg.type === 'agent-end' && typeof msg.seq === 'number') {
|
|
677
|
+
input.onAgentEnd({
|
|
678
|
+
seq: msg.seq,
|
|
679
|
+
label: String(msg.label ?? ''),
|
|
680
|
+
...(msg.phase ? { phase: msg.phase } : {}),
|
|
681
|
+
childId: SessionId(String(msg.childId ?? `wf-child-${msg.seq}`)),
|
|
682
|
+
outcome: msg.outcome ?? 'completed',
|
|
683
|
+
});
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
if (msg.type === 'done') {
|
|
687
|
+
const agentsStarted = typeof msg.agentsStarted === 'number' ? msg.agentsStarted : agentsStartedSeen;
|
|
688
|
+
if (msg.ok) {
|
|
689
|
+
finish({
|
|
690
|
+
value: msg.value ?? null,
|
|
691
|
+
stopReason: 'completed',
|
|
692
|
+
agentsStarted,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
finish({
|
|
697
|
+
value: null,
|
|
698
|
+
stopReason: 'error',
|
|
699
|
+
error: msg.error || 'worker failed',
|
|
700
|
+
agentsStarted,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
worker.on('error', (err) => {
|
|
706
|
+
finish({
|
|
707
|
+
value: null,
|
|
708
|
+
stopReason: 'error',
|
|
709
|
+
error: err instanceof Error ? err.message : String(err),
|
|
710
|
+
agentsStarted: agentsStartedSeen,
|
|
711
|
+
});
|
|
712
|
+
});
|
|
713
|
+
worker.on('exit', (code) => {
|
|
714
|
+
if (settled)
|
|
715
|
+
return;
|
|
716
|
+
if (code === 0) {
|
|
717
|
+
finish({
|
|
718
|
+
value: null,
|
|
719
|
+
stopReason: 'completed',
|
|
720
|
+
agentsStarted: agentsStartedSeen,
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
reject(new WorkflowError(`isolating worker exited ${code}`, 'WORKER_EXIT'));
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
export default WorkflowEngine;
|
|
730
|
+
//# sourceMappingURL=index.js.map
|