subharness 0.0.3 → 0.0.5
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/README.md +39 -9
- package/dist/adapters/approval-context.d.ts +2 -0
- package/dist/adapters/approval-context.js +9 -0
- package/dist/adapters/approval-context.js.map +1 -0
- package/dist/adapters/approval-lifetime.d.ts +8 -0
- package/dist/adapters/approval-lifetime.js +50 -0
- package/dist/adapters/approval-lifetime.js.map +1 -0
- package/dist/adapters/claude-approvals.d.ts +4 -0
- package/dist/adapters/claude-approvals.js +32 -0
- package/dist/adapters/claude-approvals.js.map +1 -0
- package/dist/adapters/claude-permissions.js +1 -1
- package/dist/adapters/claude-permissions.js.map +1 -1
- package/dist/adapters/claude-process.d.ts +3 -0
- package/dist/adapters/claude-process.js +11 -1
- package/dist/adapters/claude-process.js.map +1 -1
- package/dist/adapters/claude-result.d.ts +2 -0
- package/dist/adapters/claude-result.js +22 -0
- package/dist/adapters/claude-result.js.map +1 -0
- package/dist/adapters/claude.js +60 -12
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/codex-approvals.d.ts +6 -0
- package/dist/adapters/codex-approvals.js +111 -0
- package/dist/adapters/codex-approvals.js.map +1 -0
- package/dist/adapters/codex.js +36 -3
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/copilot-permissions.d.ts +26 -0
- package/dist/adapters/copilot-permissions.js +121 -0
- package/dist/adapters/copilot-permissions.js.map +1 -0
- package/dist/adapters/copilot-tools.d.ts +12 -0
- package/dist/adapters/copilot-tools.js +61 -0
- package/dist/adapters/copilot-tools.js.map +1 -0
- package/dist/adapters/copilot.d.ts +108 -0
- package/dist/adapters/copilot.js +819 -0
- package/dist/adapters/copilot.js.map +1 -0
- package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
- package/dist/adapters/cursor-cli-approvals.js +83 -0
- package/dist/adapters/cursor-cli-approvals.js.map +1 -0
- package/dist/adapters/cursor-cli-model.d.ts +4 -0
- package/dist/adapters/cursor-cli-model.js +64 -0
- package/dist/adapters/cursor-cli-model.js.map +1 -0
- package/dist/adapters/cursor-cli-session.d.ts +32 -0
- package/dist/adapters/cursor-cli-session.js +316 -0
- package/dist/adapters/cursor-cli-session.js.map +1 -0
- package/dist/adapters/cursor-cli-tools.d.ts +20 -0
- package/dist/adapters/cursor-cli-tools.js +181 -0
- package/dist/adapters/cursor-cli-tools.js.map +1 -0
- package/dist/adapters/cursor-cli.d.ts +2 -0
- package/dist/adapters/cursor-cli.js +306 -0
- package/dist/adapters/cursor-cli.js.map +1 -0
- package/dist/adapters/cursor-model.d.ts +7 -0
- package/dist/adapters/cursor-model.js +67 -0
- package/dist/adapters/cursor-model.js.map +1 -0
- package/dist/adapters/cursor-rpc.d.ts +42 -0
- package/dist/adapters/cursor-rpc.js +271 -0
- package/dist/adapters/cursor-rpc.js.map +1 -0
- package/dist/adapters/cursor-session.d.ts +4 -0
- package/dist/adapters/cursor-session.js +327 -0
- package/dist/adapters/cursor-session.js.map +1 -0
- package/dist/adapters/cursor-startup.d.ts +16 -0
- package/dist/adapters/cursor-startup.js +74 -0
- package/dist/adapters/cursor-startup.js.map +1 -0
- package/dist/adapters/cursor-tools.d.ts +11 -0
- package/dist/adapters/cursor-tools.js +49 -0
- package/dist/adapters/cursor-tools.js.map +1 -0
- package/dist/adapters/cursor.d.ts +6 -0
- package/dist/adapters/cursor.js +17 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/fx-approvals.d.ts +2 -0
- package/dist/adapters/fx-approvals.js +14 -0
- package/dist/adapters/fx-approvals.js.map +1 -0
- package/dist/adapters/fx-auth.d.ts +12 -2
- package/dist/adapters/fx-auth.js +51 -61
- package/dist/adapters/fx-auth.js.map +1 -1
- package/dist/adapters/fx-profile.d.ts +8 -0
- package/dist/adapters/fx-profile.js +101 -0
- package/dist/adapters/fx-profile.js.map +1 -0
- package/dist/adapters/fx-rpc.d.ts +2 -0
- package/dist/adapters/fx-rpc.js +30 -4
- package/dist/adapters/fx-rpc.js.map +1 -1
- package/dist/adapters/fx-status.d.ts +2 -0
- package/dist/adapters/fx-status.js +96 -0
- package/dist/adapters/fx-status.js.map +1 -0
- package/dist/adapters/fx.js +77 -30
- package/dist/adapters/fx.js.map +1 -1
- package/dist/adapters/opencode-access.d.ts +13 -0
- package/dist/adapters/opencode-access.js +76 -0
- package/dist/adapters/opencode-access.js.map +1 -0
- package/dist/adapters/opencode-config.d.ts +11 -0
- package/dist/adapters/opencode-config.js +238 -0
- package/dist/adapters/opencode-config.js.map +1 -0
- package/dist/adapters/opencode-http.d.ts +28 -0
- package/dist/adapters/opencode-http.js +297 -0
- package/dist/adapters/opencode-http.js.map +1 -0
- package/dist/adapters/opencode-tools.d.ts +19 -0
- package/dist/adapters/opencode-tools.js +127 -0
- package/dist/adapters/opencode-tools.js.map +1 -0
- package/dist/adapters/opencode.d.ts +2 -0
- package/dist/adapters/opencode.js +569 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/rpc.d.ts +3 -0
- package/dist/adapters/rpc.js +45 -4
- package/dist/adapters/rpc.js.map +1 -1
- package/dist/adapters/types.d.ts +7 -0
- package/dist/adapters/types.js.map +1 -1
- package/dist/approvals/schema.d.ts +4 -0
- package/dist/approvals/schema.js +70 -0
- package/dist/approvals/schema.js.map +1 -0
- package/dist/approvals/types.d.ts +47 -0
- package/dist/approvals/types.js +2 -0
- package/dist/approvals/types.js.map +1 -0
- package/dist/cli/args.d.ts +3 -2
- package/dist/cli/args.js +24 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/dashboard-client.d.ts +5 -1
- package/dist/cli/dashboard-client.js +162 -15
- package/dist/cli/dashboard-client.js.map +1 -1
- package/dist/cli/dashboard-controller.d.ts +7 -0
- package/dist/cli/dashboard-controller.js +27 -0
- package/dist/cli/dashboard-controller.js.map +1 -0
- package/dist/cli/dashboard-detail-view.d.ts +16 -0
- package/dist/cli/dashboard-detail-view.js +162 -0
- package/dist/cli/dashboard-detail-view.js.map +1 -0
- package/dist/cli/dashboard-history-view.d.ts +29 -0
- package/dist/cli/dashboard-history-view.js +211 -0
- package/dist/cli/dashboard-history-view.js.map +1 -0
- package/dist/cli/dashboard-input.d.ts +14 -0
- package/dist/cli/dashboard-input.js +128 -0
- package/dist/cli/dashboard-input.js.map +1 -0
- package/dist/cli/dashboard-layout.d.ts +12 -1
- package/dist/cli/dashboard-layout.js +32 -30
- package/dist/cli/dashboard-layout.js.map +1 -1
- package/dist/cli/dashboard-renderer.d.ts +30 -2
- package/dist/cli/dashboard-renderer.js +125 -7
- package/dist/cli/dashboard-renderer.js.map +1 -1
- package/dist/cli/dashboard-style.d.ts +9 -0
- package/dist/cli/dashboard-style.js +36 -0
- package/dist/cli/dashboard-style.js.map +1 -0
- package/dist/cli/dashboard.d.ts +5 -3
- package/dist/cli/dashboard.js +102 -12
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +37 -12
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/input.d.ts +1 -0
- package/dist/cli/input.js +23 -17
- package/dist/cli/input.js.map +1 -1
- package/dist/cli/main.js +6 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output.js +17 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/config/access-provenance.d.ts +10 -0
- package/dist/config/access-provenance.js +31 -0
- package/dist/config/access-provenance.js.map +1 -0
- package/dist/config/access.d.ts +12 -2
- package/dist/config/access.js +125 -27
- package/dist/config/access.js.map +1 -1
- package/dist/config/loader.js +1 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/oidc.js +4 -2
- package/dist/config/oidc.js.map +1 -1
- package/dist/config/project.js +2 -1
- package/dist/config/project.js.map +1 -1
- package/dist/config/resolve-access.js +24 -10
- package/dist/config/resolve-access.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/process-diagnostics.d.ts +2 -0
- package/dist/process-diagnostics.js +11 -0
- package/dist/process-diagnostics.js.map +1 -0
- package/dist/runtime/access-errors.d.ts +4 -0
- package/dist/runtime/access-errors.js +25 -0
- package/dist/runtime/access-errors.js.map +1 -0
- package/dist/runtime/approval-registry.d.ts +27 -0
- package/dist/runtime/approval-registry.js +126 -0
- package/dist/runtime/approval-registry.js.map +1 -0
- package/dist/runtime/client.js +54 -14
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/coordinator.d.ts +17 -1
- package/dist/runtime/coordinator.js +124 -6
- package/dist/runtime/coordinator.js.map +1 -1
- package/dist/runtime/dashboard-sanitize.d.ts +2 -0
- package/dist/runtime/dashboard-sanitize.js +7 -0
- package/dist/runtime/dashboard-sanitize.js.map +1 -0
- package/dist/runtime/dashboard.d.ts +43 -1
- package/dist/runtime/dashboard.js +2 -3
- package/dist/runtime/dashboard.js.map +1 -1
- package/dist/runtime/definition.js +11 -1
- package/dist/runtime/definition.js.map +1 -1
- package/dist/runtime/select-native.d.ts +2 -1
- package/dist/runtime/select-native.js +28 -10
- package/dist/runtime/select-native.js.map +1 -1
- package/dist/runtime/service.js +24 -1
- package/dist/runtime/service.js.map +1 -1
- package/dist/runtime/types.d.ts +9 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/runtime/worker-approvals.d.ts +21 -0
- package/dist/runtime/worker-approvals.js +51 -0
- package/dist/runtime/worker-approvals.js.map +1 -0
- package/dist/runtime/worker-client.js +73 -20
- package/dist/runtime/worker-client.js.map +1 -1
- package/dist/runtime/worker-server.d.ts +2 -0
- package/dist/runtime/worker-server.js +39 -10
- package/dist/runtime/worker-server.js.map +1 -1
- package/dist/sdk/definitions.d.ts +4 -1
- package/dist/sdk/definitions.js +16 -2
- package/dist/sdk/definitions.js.map +1 -1
- package/dist/sdk/permission-validation.js +10 -1
- package/dist/sdk/permission-validation.js.map +1 -1
- package/dist/sdk/types.d.ts +29 -1
- package/dist/sdk/types.js.map +1 -1
- package/package.json +4 -1
- package/sdk/access-config.md +86 -4
- package/sdk/adapter-contract.md +7 -13
- package/sdk/additional-harnesses.md +43 -0
- package/sdk/agent-skill.md +7 -4
- package/sdk/agent.md +5 -3
- package/sdk/approvals.md +120 -0
- package/sdk/authentication.md +1 -1
- package/sdk/cli/dashboard-design.md +44 -4
- package/sdk/cli/dashboard-inspection.md +25 -0
- package/sdk/cli/index.md +20 -11
- package/sdk/cli/output.md +10 -4
- package/sdk/completion-notifications.md +2 -0
- package/sdk/config.md +1 -1
- package/sdk/copilot.md +53 -0
- package/sdk/cursor.md +68 -0
- package/sdk/diagnostics.md +29 -0
- package/sdk/distribution.md +53 -1
- package/sdk/evals.md +10 -4
- package/sdk/fx.md +51 -6
- package/sdk/harnesses.md +13 -13
- package/sdk/index.md +4 -2
- package/sdk/message-delivery.md +1 -1
- package/sdk/opencode.md +57 -0
- package/sdk/permissions.md +7 -5
- package/sdk/pr-integration.md +1 -1
- package/sdk/project-team.md +2 -0
- package/sdk/sessions.md +4 -1
- package/sdk/tools.md +1 -1
- package/sdk/v1-runtime.md +6 -6
|
@@ -1,33 +1,51 @@
|
|
|
1
1
|
import { openCodex } from '../adapters/codex.js';
|
|
2
2
|
import { openClaude } from '../adapters/claude.js';
|
|
3
3
|
import { openFx } from '../adapters/fx.js';
|
|
4
|
+
import { openOpencode } from '../adapters/opencode.js';
|
|
5
|
+
import { openCopilot } from '../adapters/copilot.js';
|
|
6
|
+
import { openCursor } from '../adapters/cursor.js';
|
|
4
7
|
import { resolveAccess } from '../config/access.js';
|
|
8
|
+
import { accessAttemptContext } from '../config/access-provenance.js';
|
|
5
9
|
import { AgentError } from '../errors.js';
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
import { withAccessContext, withSessionAccessContext } from './access-errors.js';
|
|
11
|
+
const openers = {
|
|
12
|
+
codex: openCodex,
|
|
13
|
+
claudeCode: openClaude,
|
|
14
|
+
fx: openFx,
|
|
15
|
+
opencode: openOpencode,
|
|
16
|
+
copilot: openCopilot,
|
|
17
|
+
cursor: openCursor,
|
|
18
|
+
};
|
|
19
|
+
export async function selectNative(agent, cwd, env, settings, open = (options) => openers[options.harness.kind](options), selected = () => { }, onApproval) {
|
|
8
20
|
const alternatives = Array.isArray(agent.harness) ? agent.harness : [agent.harness];
|
|
9
21
|
const unavailable = [];
|
|
10
22
|
for (const harness of alternatives) {
|
|
11
23
|
const configuredConnections = settings.access?.[harness.kind];
|
|
24
|
+
const explicitAccessRequired = ['fx', 'opencode', 'copilot', 'cursor'].includes(harness.kind);
|
|
12
25
|
const connections = configuredConnections ??
|
|
13
|
-
(
|
|
26
|
+
(explicitAccessRequired ? [] : [{ type: 'subscription' }]);
|
|
14
27
|
if (configuredConnections?.length === 0) {
|
|
15
28
|
unavailable.push(`${harness.kind}: Access is disabled in the main checkout's .subharness/agents.local.json.`);
|
|
16
29
|
}
|
|
17
|
-
else if (
|
|
18
|
-
unavailable.push(
|
|
30
|
+
else if (!connections.length && explicitAccessRequired) {
|
|
31
|
+
unavailable.push(harness.kind === 'cursor'
|
|
32
|
+
? 'cursor: Enable an explicit Cursor subscription or API-key connection in personal access settings.'
|
|
33
|
+
: `${harness.kind}: Enable an explicit native login, API-key, or Gateway connection in personal access settings.`);
|
|
19
34
|
}
|
|
20
|
-
for (const connection of connections) {
|
|
35
|
+
for (const [index, connection] of connections.entries()) {
|
|
36
|
+
const context = accessAttemptContext(settings, harness.kind, connection, index, connections.length);
|
|
21
37
|
try {
|
|
22
38
|
const access = await resolveAccess(connection, harness.kind, cwd, env);
|
|
23
|
-
const native = await open({ agent, harness, cwd, env, access });
|
|
39
|
+
const native = await open({ agent, harness, cwd, env, access, ...(onApproval ? { onApproval } : {}) });
|
|
24
40
|
selected(harness.kind);
|
|
25
|
-
return native;
|
|
41
|
+
return withSessionAccessContext(native, context);
|
|
26
42
|
}
|
|
27
43
|
catch (error) {
|
|
28
|
-
if (!(error instanceof AgentError)
|
|
44
|
+
if (!(error instanceof AgentError))
|
|
29
45
|
throw error;
|
|
30
|
-
|
|
46
|
+
if (!['HARNESS_UNAVAILABLE', 'ACCESS_UNAVAILABLE'].includes(error.code))
|
|
47
|
+
throw withAccessContext(error, context);
|
|
48
|
+
unavailable.push(`${harness.kind}: ${withAccessContext(error, context).message}`);
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-native.js","sourceRoot":"","sources":["../../src/runtime/select-native.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"select-native.js","sourceRoot":"","sources":["../../src/runtime/select-native.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HarnessKind } from '../sdk/types.js';\nimport type { AdapterOptions, ExecutionDefinition, NativeSession } from '../adapters/types.js';\nimport { openCodex } from '../adapters/codex.js';\nimport { openClaude } from '../adapters/claude.js';\nimport { openFx } from '../adapters/fx.js';\nimport { openOpencode } from '../adapters/opencode.js';\nimport { openCopilot } from '../adapters/copilot.js';\nimport { openCursor } from '../adapters/cursor.js';\nimport { resolveAccess, type AccessConfig } from '../config/access.js';\nimport { accessAttemptContext } from '../config/access-provenance.js';\nimport { AgentError } from '../errors.js';\nimport type { ApprovalHandler } from '../approvals/types.js';\nimport { withAccessContext, withSessionAccessContext } from './access-errors.js';\n\nconst openers = {\n codex:openCodex,\n claudeCode:openClaude,\n fx:openFx,\n opencode:openOpencode,\n copilot:openCopilot,\n cursor:openCursor,\n} satisfies Record<HarnessKind, (options: AdapterOptions) => Promise<NativeSession>>;\n\nexport async function selectNative(\n agent: ExecutionDefinition, cwd: string, env: NodeJS.ProcessEnv, settings: AccessConfig,\n open = (options: AdapterOptions): Promise<NativeSession> => openers[options.harness.kind](options),\n selected: (kind: HarnessKind) => void = () => {},\n onApproval?: ApprovalHandler,\n): Promise<NativeSession> {\n const alternatives = Array.isArray(agent.harness) ? agent.harness : [agent.harness];\n const unavailable: string[] = [];\n for (const harness of alternatives) {\n const configuredConnections = settings.access?.[harness.kind as HarnessKind];\n const explicitAccessRequired = ['fx','opencode','copilot','cursor'].includes(harness.kind);\n const connections = configuredConnections ??\n (explicitAccessRequired ? [] : [{type:'subscription' as const}]);\n if (configuredConnections?.length === 0) {\n unavailable.push(`${harness.kind}: Access is disabled in the main checkout's .subharness/agents.local.json.`);\n } else if (!connections.length && explicitAccessRequired) {\n unavailable.push(harness.kind === 'cursor'\n ? 'cursor: Enable an explicit Cursor subscription or API-key connection in personal access settings.'\n : `${harness.kind}: Enable an explicit native login, API-key, or Gateway connection in personal access settings.`);\n }\n for (const [index, connection] of connections.entries()) {\n const context = accessAttemptContext(settings, harness.kind, connection, index, connections.length);\n try {\n const access = await resolveAccess(connection, harness.kind, cwd, env);\n const native = await open({agent,harness,cwd,env,access,...(onApproval ? {onApproval} : {})});\n selected(harness.kind);\n return withSessionAccessContext(native, context);\n } catch (error) {\n if (!(error instanceof AgentError)) throw error;\n if (!['HARNESS_UNAVAILABLE','ACCESS_UNAVAILABLE'].includes(error.code)) throw withAccessContext(error, context);\n unavailable.push(`${harness.kind}: ${withAccessContext(error, context).message}`);\n }\n }\n }\n throw new AgentError('ACCESS_UNAVAILABLE', unavailable.length ? unavailable.join('\\n') : 'No declared harness has enabled access.');\n}\n"]}
|
package/dist/runtime/service.js
CHANGED
|
@@ -30,12 +30,32 @@ export async function startService(engine, token, instanceId) {
|
|
|
30
30
|
if (Buffer.byteLength(body) > 4 * 1024 * 1024)
|
|
31
31
|
throw new AgentError('INVALID_ARGUMENT', 'Request exceeds 4 MiB.');
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
let data;
|
|
34
|
+
try {
|
|
35
|
+
data = JSON.parse(body);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new AgentError('INVALID_ARGUMENT', 'Coordinator input must be valid JSON.');
|
|
39
|
+
}
|
|
40
|
+
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
41
|
+
throw new AgentError('INVALID_ARGUMENT', 'Coordinator input must be a JSON object.');
|
|
34
42
|
let receipt;
|
|
35
43
|
switch (data.command) {
|
|
36
44
|
case 'dashboard':
|
|
37
45
|
write(await engine.dashboard());
|
|
38
46
|
break;
|
|
47
|
+
case 'dashboard-session':
|
|
48
|
+
if (typeof data.id !== 'string')
|
|
49
|
+
throw new AgentError('INVALID_ARGUMENT', 'Invalid dashboard session request fields.');
|
|
50
|
+
write(await engine.dashboardSession(data.id));
|
|
51
|
+
break;
|
|
52
|
+
case 'dashboard-detail':
|
|
53
|
+
if (typeof data.id !== 'string' ||
|
|
54
|
+
(data.includePrompt !== undefined && typeof data.includePrompt !== 'boolean') ||
|
|
55
|
+
(data.knownResponseId !== undefined && typeof data.knownResponseId !== 'string'))
|
|
56
|
+
throw new AgentError('INVALID_ARGUMENT', 'Invalid dashboard detail request fields.');
|
|
57
|
+
write(await engine.dashboardDetail(data.id, data.includePrompt ?? true, data.knownResponseId));
|
|
58
|
+
break;
|
|
39
59
|
case 'parent':
|
|
40
60
|
write(engine.parentContext(data.parentToken));
|
|
41
61
|
break;
|
|
@@ -70,6 +90,9 @@ export async function startService(engine, token, instanceId) {
|
|
|
70
90
|
case 'cancel':
|
|
71
91
|
write(await engine.cancel(data.id));
|
|
72
92
|
break;
|
|
93
|
+
case 'respond':
|
|
94
|
+
write(engine.respond(data.id, data.content, data.parentToken));
|
|
95
|
+
break;
|
|
73
96
|
default: throw new AgentError('INVALID_ARGUMENT', 'Unknown coordinator operation.');
|
|
74
97
|
}
|
|
75
98
|
if (receipt) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/runtime/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AASrD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAmB,EAAE,KAAa,EAAE,UAAkB;IACvF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QACtD,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,KAAK,UAAU,KAAK,EAAE,EAAE,CAAC;YAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QACnG,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC1D,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAC,kBAAkB,CAAC,CAAC;YACtD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,oBAAoB,EAAC,UAAU,EAAC,CAAC,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAChG,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,sBAAsB,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;QACvC,oFAAoF;QACpF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAChG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,CAAC,MAAe,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,CAAC;YACH,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAClC,IAAI,IAAI,KAAK,CAAC;gBACd,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI;oBAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,wBAAwB,CAAC,CAAC;YACnH,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;YACzC,IAAI,OAA4B,CAAC;YACjC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrB,KAAK,WAAW;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;oBAAC,MAAM;gBACzD,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAY,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACrE,KAAK,KAAK;oBAAE,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAM,CAAC,CAAC;oBAAC,MAAM;gBACrD,KAAK,MAAM;oBACT,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO;wBAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,oDAAoD,CAAC,CAAC;oBAC5I,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,MAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;oBAAC,MAAM;gBACzG,KAAK,QAAQ,EAAE,CAAC;oBACd,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,MAAM,CAAC;oBAC7C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ;wBAAE,MAAM,IAAI,UAAU,CAAC,YAAY,EAAC,4CAA4C,CAAC,CAAC;oBAC1H,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC;oBAChE,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC;oBACxC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAAC,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;oBACtG,OAAO,GAAG,SAAS,CAAC;oBAAC,MAAM;gBAC7B,CAAC;gBACD,KAAK,MAAM;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACzG,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBAAC,MAAM;gBAChE,KAAK,OAAO;oBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACnD,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;oBAAC,MAAM;gBAC3D,SAAS,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,gCAAgC,CAAC,CAAC;YACrF,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,OAAO,CAAC,CAAC;gBACf,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC/C,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;gBACvH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,KAAK,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,SAAS,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC;QAAC,CAAC;QAC3E,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,QAAQ,CAAC,GAAG,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IACH,OAAO;QACL,GAAG,EAAE,oBAAqB,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,GAAG;QAClE,KAAK,CAAC,KAAK,KAAK,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACzI,CAAC;AACJ,CAAC","sourcesContent":["import { createServer } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { AgentError, errorInfo } from '../errors.js';\nimport { Coordinator } from './coordinator.js';\nimport type { Delivery, Receipt, SessionInput } from './types.js';\n\ninterface Request {\n command: string; input?: SessionInput; id?: string; after?: string;\n prompt?: string; delivery?: Delivery; full?: boolean; detach?: boolean; parentToken?: string;\n}\n\nexport async function startService(engine: Coordinator, token: string, instanceId: string) {\n const server = createServer(async (request, response) => {\n if (request.headers.authorization !== `Bearer ${token}`) { response.writeHead(401).end(); return; }\n if (request.method === 'GET' && request.url === '/health') {\n response.setHeader('content-type','application/json');\n response.end(JSON.stringify({version:1,type:'coordinator-health',instanceId}));\n return;\n }\n if (request.method !== 'POST' || request.url !== '/') { response.writeHead(404).end(); return; }\n response.setHeader('content-type', 'application/x-ndjson');\n const observer = new AbortController();\n // Keep long, quiet observations alive without exposing progress records to callers.\n const heartbeat = setInterval(() => { if (!response.destroyed) response.write('\\n'); }, 15_000);\n response.once('close', () => { clearInterval(heartbeat); observer.abort(); });\n const write = (record: unknown) => { if (!response.destroyed) response.write(JSON.stringify(record) + '\\n'); };\n try {\n let body = '';\n for await (const chunk of request) {\n body += chunk;\n if (Buffer.byteLength(body) > 4 * 1024 * 1024) throw new AgentError('INVALID_ARGUMENT','Request exceeds 4 MiB.');\n }\n const data = JSON.parse(body) as Request;\n let receipt: Receipt | undefined;\n switch (data.command) {\n case 'dashboard': write(await engine.dashboard()); break;\n case 'parent': write(engine.parentContext(data.parentToken!)); break;\n case 'run': receipt = engine.run(data.input!); break;\n case 'send':\n if (data.detach && data.delivery === 'steer') throw new AgentError('INVALID_ARGUMENT','--detach cannot be combined with --delivery steer.');\n receipt = await engine.send(data.id!, data.prompt!, data.delivery ?? 'queue', data.parentToken); break;\n case 'resume': {\n const active = engine.queue(data.id!).active;\n if (!active || active.state !== 'failed') throw new AgentError('NOT_FAILED','This session has no failed task to resume.');\n const after = engine.status(active.taskId).response?.responseId;\n receipt = await engine.resume(data.id!);\n write(receipt); write(await engine.observe(receipt.taskId, after, data.parentToken, observer.signal));\n receipt = undefined; break;\n }\n case 'wait': write(await engine.observe(data.id!, data.after, data.parentToken, observer.signal)); break;\n case 'status': write(engine.status(data.id!, data.full)); break;\n case 'queue': write(engine.queue(data.id!)); break;\n case 'cancel': write(await engine.cancel(data.id!)); break;\n default: throw new AgentError('INVALID_ARGUMENT','Unknown coordinator operation.');\n }\n if (receipt) {\n write(receipt);\n if (receipt.type === 'started' && !data.detach) {\n write(await engine.observe(receipt.taskId, undefined, data.parentToken ?? data.input?.parentToken, observer.signal));\n }\n }\n } catch (error) { write({version:1,type:'error',error:errorInfo(error)}); }\n clearInterval(heartbeat);\n response.end();\n });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n return {\n url: `http://127.0.0.1:${(server.address() as AddressInfo).port}/`,\n async close() { await engine.close(); server.closeAllConnections(); await new Promise<void>(resolve => server.close(() => resolve())); },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/runtime/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAWrD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAmB,EAAE,KAAa,EAAE,UAAkB;IACvF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QACtD,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,KAAK,UAAU,KAAK,EAAE,EAAE,CAAC;YAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QACnG,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC1D,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAC,kBAAkB,CAAC,CAAC;YACtD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,oBAAoB,EAAC,UAAU,EAAC,CAAC,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAChG,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,sBAAsB,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;QACvC,oFAAoF;QACpF,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAChG,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,CAAC,MAAe,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,IAAI,CAAC;YACH,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAClC,IAAI,IAAI,KAAK,CAAC;gBACd,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI;oBAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,wBAAwB,CAAC,CAAC;YACnH,CAAC;YACD,IAAI,IAAa,CAAC;YAClB,IAAI,CAAC;gBAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;YAAC,CAAC;YAC3C,MAAM,CAAC;gBAAC,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,uCAAuC,CAAC,CAAC;YAAC,CAAC;YAC3F,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC1D,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,0CAA0C,CAAC,CAAC;YACtF,IAAI,OAA4B,CAAC;YACjC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;gBACrB,KAAK,WAAW;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;oBAAC,MAAM;gBACzD,KAAK,mBAAmB;oBACtB,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;wBAC7B,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,2CAA2C,CAAC,CAAC;oBACxF,KAAK,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACvD,KAAK,kBAAkB;oBACrB,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ;wBAC7B,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC;wBAC7E,CAAC,IAAI,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,eAAe,KAAK,QAAQ,CAAC;wBAChF,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,0CAA0C,CAAC,CAAC;oBACvF,KAAK,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACxG,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,WAAY,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACrE,KAAK,KAAK;oBAAE,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAM,CAAC,CAAC;oBAAC,MAAM;gBACrD,KAAK,MAAM;oBACT,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO;wBAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,oDAAoD,CAAC,CAAC;oBAC5I,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,MAAO,EAAE,IAAI,CAAC,QAAQ,IAAI,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;oBAAC,MAAM;gBACzG,KAAK,QAAQ,EAAE,CAAC;oBACd,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,MAAM,CAAC;oBAC7C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ;wBAAE,MAAM,IAAI,UAAU,CAAC,YAAY,EAAC,4CAA4C,CAAC,CAAC;oBAC1H,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC;oBAChE,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC;oBACxC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAAC,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;oBACtG,OAAO,GAAG,SAAS,CAAC;oBAAC,MAAM;gBAC7B,CAAC;gBACD,KAAK,MAAM;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACzG,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;oBAAC,MAAM;gBAChE,KAAK,OAAO;oBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACnD,KAAK,QAAQ;oBAAE,KAAK,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;oBAAC,MAAM;gBAC3D,KAAK,SAAS;oBAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAG,EAAC,IAAI,CAAC,OAAO,EAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;oBAAC,MAAM;gBACrF,SAAS,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAC,gCAAgC,CAAC,CAAC;YACrF,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,OAAO,CAAC,CAAC;gBACf,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC/C,KAAK,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;gBACvH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,KAAK,CAAC,EAAC,OAAO,EAAC,CAAC,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,SAAS,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC;QAAC,CAAC;QAC3E,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,QAAQ,CAAC,GAAG,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IACH,OAAO;QACL,GAAG,EAAE,oBAAqB,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,GAAG;QAClE,KAAK,CAAC,KAAK,KAAK,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,MAAM,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACzI,CAAC;AACJ,CAAC","sourcesContent":["import { createServer } from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { AgentError, errorInfo } from '../errors.js';\nimport { Coordinator } from './coordinator.js';\nimport type { Delivery, Receipt, SessionInput } from './types.js';\n\ninterface Request {\n command: string; input?: SessionInput; id?: string; after?: string;\n prompt?: string; delivery?: Delivery; full?: boolean; detach?: boolean; parentToken?: string;\n content?: unknown;\n includePrompt?: boolean; knownResponseId?: string;\n}\n\nexport async function startService(engine: Coordinator, token: string, instanceId: string) {\n const server = createServer(async (request, response) => {\n if (request.headers.authorization !== `Bearer ${token}`) { response.writeHead(401).end(); return; }\n if (request.method === 'GET' && request.url === '/health') {\n response.setHeader('content-type','application/json');\n response.end(JSON.stringify({version:1,type:'coordinator-health',instanceId}));\n return;\n }\n if (request.method !== 'POST' || request.url !== '/') { response.writeHead(404).end(); return; }\n response.setHeader('content-type', 'application/x-ndjson');\n const observer = new AbortController();\n // Keep long, quiet observations alive without exposing progress records to callers.\n const heartbeat = setInterval(() => { if (!response.destroyed) response.write('\\n'); }, 15_000);\n response.once('close', () => { clearInterval(heartbeat); observer.abort(); });\n const write = (record: unknown) => { if (!response.destroyed) response.write(JSON.stringify(record) + '\\n'); };\n try {\n let body = '';\n for await (const chunk of request) {\n body += chunk;\n if (Buffer.byteLength(body) > 4 * 1024 * 1024) throw new AgentError('INVALID_ARGUMENT','Request exceeds 4 MiB.');\n }\n let data: Request;\n try { data = JSON.parse(body) as Request; }\n catch { throw new AgentError('INVALID_ARGUMENT','Coordinator input must be valid JSON.'); }\n if (!data || typeof data !== 'object' || Array.isArray(data))\n throw new AgentError('INVALID_ARGUMENT','Coordinator input must be a JSON object.');\n let receipt: Receipt | undefined;\n switch (data.command) {\n case 'dashboard': write(await engine.dashboard()); break;\n case 'dashboard-session':\n if (typeof data.id !== 'string')\n throw new AgentError('INVALID_ARGUMENT', 'Invalid dashboard session request fields.');\n write(await engine.dashboardSession(data.id)); break;\n case 'dashboard-detail':\n if (typeof data.id !== 'string' ||\n (data.includePrompt !== undefined && typeof data.includePrompt !== 'boolean') ||\n (data.knownResponseId !== undefined && typeof data.knownResponseId !== 'string'))\n throw new AgentError('INVALID_ARGUMENT', 'Invalid dashboard detail request fields.');\n write(await engine.dashboardDetail(data.id, data.includePrompt ?? true, data.knownResponseId)); break;\n case 'parent': write(engine.parentContext(data.parentToken!)); break;\n case 'run': receipt = engine.run(data.input!); break;\n case 'send':\n if (data.detach && data.delivery === 'steer') throw new AgentError('INVALID_ARGUMENT','--detach cannot be combined with --delivery steer.');\n receipt = await engine.send(data.id!, data.prompt!, data.delivery ?? 'queue', data.parentToken); break;\n case 'resume': {\n const active = engine.queue(data.id!).active;\n if (!active || active.state !== 'failed') throw new AgentError('NOT_FAILED','This session has no failed task to resume.');\n const after = engine.status(active.taskId).response?.responseId;\n receipt = await engine.resume(data.id!);\n write(receipt); write(await engine.observe(receipt.taskId, after, data.parentToken, observer.signal));\n receipt = undefined; break;\n }\n case 'wait': write(await engine.observe(data.id!, data.after, data.parentToken, observer.signal)); break;\n case 'status': write(engine.status(data.id!, data.full)); break;\n case 'queue': write(engine.queue(data.id!)); break;\n case 'cancel': write(await engine.cancel(data.id!)); break;\n case 'respond': write(engine.respond(data.id!,data.content,data.parentToken)); break;\n default: throw new AgentError('INVALID_ARGUMENT','Unknown coordinator operation.');\n }\n if (receipt) {\n write(receipt);\n if (receipt.type === 'started' && !data.detach) {\n write(await engine.observe(receipt.taskId, undefined, data.parentToken ?? data.input?.parentToken, observer.signal));\n }\n }\n } catch (error) { write({version:1,type:'error',error:errorInfo(error)}); }\n clearInterval(heartbeat);\n response.end();\n });\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', resolve);\n });\n return {\n url: `http://127.0.0.1:${(server.address() as AddressInfo).port}/`,\n async close() { await engine.close(); server.closeAllConnections(); await new Promise<void>(resolve => server.close(() => resolve())); },\n };\n}\n"]}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import type { ErrorInfo } from '../errors.js';
|
|
|
2
2
|
import type { HarnessRequest, NativeSession } from '../adapters/types.js';
|
|
3
3
|
import type { HarnessKind } from '../sdk/types.js';
|
|
4
4
|
import type { DashboardHarness, DashboardWorkspace } from './dashboard.js';
|
|
5
|
-
|
|
5
|
+
import type { ApprovalHandler, NativeApprovalRequest } from '../approvals/types.js';
|
|
6
|
+
export type TaskState = 'queued' | 'running' | 'waiting' | 'awaiting_approval' | 'completed' | 'failed' | 'cancelled' | 'interrupted';
|
|
6
7
|
export type Delivery = 'queue' | 'steer' | 'interrupt';
|
|
7
8
|
export interface AgentReference {
|
|
8
9
|
file: string;
|
|
@@ -23,6 +24,7 @@ export interface SessionInput {
|
|
|
23
24
|
export interface DriverInput extends Omit<SessionInput, 'prompt' | 'parentToken'> {
|
|
24
25
|
token: string;
|
|
25
26
|
sessionId: string;
|
|
27
|
+
onApproval?: ApprovalHandler;
|
|
26
28
|
}
|
|
27
29
|
export type ManagedNativeSession = NativeSession & {
|
|
28
30
|
selectedHarness?: HarnessKind;
|
|
@@ -35,11 +37,17 @@ export interface RecordBase {
|
|
|
35
37
|
taskId: string;
|
|
36
38
|
state?: TaskState;
|
|
37
39
|
}
|
|
40
|
+
export interface ApprovalRequest extends NativeApprovalRequest {
|
|
41
|
+
requestId: string;
|
|
42
|
+
taskId: string;
|
|
43
|
+
sessionId: string;
|
|
44
|
+
}
|
|
38
45
|
export interface Observation extends RecordBase {
|
|
39
46
|
state: TaskState;
|
|
40
47
|
responseId?: string;
|
|
41
48
|
text?: string;
|
|
42
49
|
error?: ErrorInfo;
|
|
50
|
+
requests?: ApprovalRequest[];
|
|
43
51
|
}
|
|
44
52
|
export interface Receipt extends RecordBase {
|
|
45
53
|
delivery?: Delivery;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAmCA,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAgB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC","sourcesContent":["import type { ErrorInfo } from '../errors.js';\nimport type { HarnessRequest, NativeSession } from '../adapters/types.js';\nimport type { HarnessKind } from '../sdk/types.js';\nimport type { DashboardHarness, DashboardWorkspace } from './dashboard.js';\nimport type { ApprovalHandler, NativeApprovalRequest } from '../approvals/types.js';\n\nexport type TaskState = 'queued' | 'running' | 'waiting' | 'awaiting_approval' | 'completed' | 'failed' | 'cancelled' | 'interrupted';\nexport type Delivery = 'queue' | 'steer' | 'interrupt';\nexport interface AgentReference { file: string; subagents: string[] }\nexport interface HarnessReference { kind: 'harness'; harness: HarnessRequest }\nexport type ExecutionReference = AgentReference | HarnessReference;\nexport interface SessionInput { reference: ExecutionReference; cwd: string; env: NodeJS.ProcessEnv; prompt: string; parentToken?: string }\nexport interface DriverInput extends Omit<SessionInput, 'prompt' | 'parentToken'> { token: string; sessionId: string; onApproval?: ApprovalHandler }\nexport type ManagedNativeSession = NativeSession & { selectedHarness?: HarnessKind };\nexport type DriverFactory = (input: DriverInput) => Promise<ManagedNativeSession>;\nexport interface RecordBase { version: 1; type: string; sessionId: string; taskId: string; state?: TaskState }\nexport interface ApprovalRequest extends NativeApprovalRequest { requestId: string; taskId: string; sessionId: string }\nexport interface Observation extends RecordBase { state: TaskState; responseId?: string; text?: string; error?: ErrorInfo; requests?: ApprovalRequest[] }\nexport interface Receipt extends RecordBase {\n delivery?: Delivery; requestedDelivery?: Delivery; resumed?: boolean;\n paused?: true; blockedByTaskId?: string;\n}\nexport interface Response extends Observation { type: 'response'; responseId: string; text: string }\nexport interface ChildResult { taskId: string; state: TaskState; text: string }\nexport interface Task {\n id: string; sessionId: string; prompt: string; title: string; parentId?: string; state: TaskState;\n responses: Response[]; children: Set<string>; inbox: ChildResult[]; nativeActive: boolean;\n stopping: boolean; stopPromise?: Promise<void>; stopUnconfirmed?: boolean; error?: ErrorInfo;\n dispatchedAt?: number; failedAt?: number; finishedAt?: number; updatedAt: number; changed: Set<() => void>;\n}\nexport interface Session {\n id: string; token: string; input: SessionInput; driver?: Promise<ManagedNativeSession>;\n tasks: string[]; active?: string; paused: boolean; commands: Promise<unknown>; controls: number;\n harness: DashboardHarness; workspace: Promise<DashboardWorkspace>;\n}\nexport const terminal = (state: TaskState) => ['completed', 'failed', 'cancelled', 'interrupted'].includes(state);\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ErrorInfo } from '../errors.js';
|
|
2
|
+
import type { ApprovalHandler, NativeApprovalRequest } from '../approvals/types.js';
|
|
3
|
+
export type ApprovalEvent = {
|
|
4
|
+
event: 'approval.request';
|
|
5
|
+
requestId: number;
|
|
6
|
+
request: NativeApprovalRequest;
|
|
7
|
+
} | {
|
|
8
|
+
event: 'approval.withdraw';
|
|
9
|
+
requestId: number;
|
|
10
|
+
};
|
|
11
|
+
/** Independent worker controls keep the native turn promise open while the caller decides. */
|
|
12
|
+
export declare class WorkerApprovals {
|
|
13
|
+
private readonly send;
|
|
14
|
+
private nextId;
|
|
15
|
+
private pending;
|
|
16
|
+
constructor(send: (event: ApprovalEvent) => void);
|
|
17
|
+
readonly handle: ApprovalHandler;
|
|
18
|
+
respond(id: number, content?: unknown, error?: ErrorInfo): void;
|
|
19
|
+
close(): void;
|
|
20
|
+
private withdraw;
|
|
21
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { AgentError } from '../errors.js';
|
|
2
|
+
import { validateApprovalContent } from '../approvals/schema.js';
|
|
3
|
+
/** Independent worker controls keep the native turn promise open while the caller decides. */
|
|
4
|
+
export class WorkerApprovals {
|
|
5
|
+
send;
|
|
6
|
+
nextId = 1;
|
|
7
|
+
pending = new Map();
|
|
8
|
+
constructor(send) {
|
|
9
|
+
this.send = send;
|
|
10
|
+
}
|
|
11
|
+
handle = async (request, signal) => {
|
|
12
|
+
if (signal.aborted)
|
|
13
|
+
throw new AgentError('REQUEST_EXPIRED', 'The native permission request is no longer pending.');
|
|
14
|
+
const id = this.nextId++;
|
|
15
|
+
const snapshot = structuredClone(request);
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const abort = () => this.withdraw(id);
|
|
18
|
+
this.pending.set(id, { request: snapshot, resolve, reject, cleanup: () => signal.removeEventListener('abort', abort) });
|
|
19
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
20
|
+
this.send({ event: 'approval.request', requestId: id, request: snapshot });
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
respond(id, content, error) {
|
|
24
|
+
const waiting = this.pending.get(id);
|
|
25
|
+
if (!waiting)
|
|
26
|
+
throw new AgentError('REQUEST_EXPIRED', 'The native permission request is no longer pending.');
|
|
27
|
+
if (error) {
|
|
28
|
+
this.pending.delete(id);
|
|
29
|
+
waiting.cleanup();
|
|
30
|
+
waiting.reject(new AgentError(error.code, error.message));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const validated = validateApprovalContent(waiting.request.requestedSchema, content);
|
|
34
|
+
this.pending.delete(id);
|
|
35
|
+
waiting.cleanup();
|
|
36
|
+
waiting.resolve(validated);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
close() { for (const id of this.pending.keys())
|
|
40
|
+
this.withdraw(id); }
|
|
41
|
+
withdraw(id) {
|
|
42
|
+
const waiting = this.pending.get(id);
|
|
43
|
+
if (!waiting)
|
|
44
|
+
return;
|
|
45
|
+
this.pending.delete(id);
|
|
46
|
+
waiting.cleanup();
|
|
47
|
+
waiting.reject(new AgentError('REQUEST_EXPIRED', 'The native permission request is no longer pending.'));
|
|
48
|
+
this.send({ event: 'approval.withdraw', requestId: id });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=worker-approvals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-approvals.js","sourceRoot":"","sources":["../../src/runtime/worker-approvals.ts"],"names":[],"mappings":"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","sourcesContent":["import { AgentError, type ErrorInfo } from '../errors.js';\nimport { validateApprovalContent } from '../approvals/schema.js';\nimport type { ApprovalContent, ApprovalHandler, NativeApprovalRequest } from '../approvals/types.js';\n\nexport type ApprovalEvent =\n | {event:'approval.request';requestId:number;request:NativeApprovalRequest}\n | {event:'approval.withdraw';requestId:number};\ninterface Waiting {\n request: NativeApprovalRequest;\n resolve(content: ApprovalContent): void;\n reject(error: AgentError): void;\n cleanup(): void;\n}\n\n/** Independent worker controls keep the native turn promise open while the caller decides. */\nexport class WorkerApprovals {\n private nextId = 1;\n private pending = new Map<number,Waiting>();\n constructor(private readonly send: (event: ApprovalEvent) => void) {}\n\n readonly handle: ApprovalHandler = async (request,signal) => {\n if (signal.aborted) throw new AgentError('REQUEST_EXPIRED','The native permission request is no longer pending.');\n const id = this.nextId++;\n const snapshot = structuredClone(request);\n return new Promise((resolve,reject) => {\n const abort = () => this.withdraw(id);\n this.pending.set(id,{request:snapshot,resolve,reject,cleanup:() => signal.removeEventListener('abort',abort)});\n signal.addEventListener('abort',abort,{once:true});\n this.send({event:'approval.request',requestId:id,request:snapshot});\n });\n };\n\n respond(id: number, content?: unknown, error?: ErrorInfo) {\n const waiting = this.pending.get(id);\n if (!waiting) throw new AgentError('REQUEST_EXPIRED','The native permission request is no longer pending.');\n if (error) {\n this.pending.delete(id); waiting.cleanup();\n waiting.reject(new AgentError(error.code,error.message));\n } else {\n const validated = validateApprovalContent(waiting.request.requestedSchema,content);\n this.pending.delete(id); waiting.cleanup(); waiting.resolve(validated);\n }\n }\n\n close() { for (const id of this.pending.keys()) this.withdraw(id); }\n\n private withdraw(id: number) {\n const waiting = this.pending.get(id);\n if (!waiting) return;\n this.pending.delete(id); waiting.cleanup();\n waiting.reject(new AgentError('REQUEST_EXPIRED','The native permission request is no longer pending.'));\n this.send({event:'approval.withdraw',requestId:id});\n }\n}\n"]}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { fork } from 'node:child_process';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import { delimiter } from 'node:path';
|
|
4
|
-
import { AgentError } from '../errors.js';
|
|
4
|
+
import { AgentError, errorInfo } from '../errors.js';
|
|
5
5
|
import { createSessionLauncher } from './session-launcher.js';
|
|
6
|
+
import { processExitDescription } from '../process-diagnostics.js';
|
|
6
7
|
const closeResponseTimeoutMs = 15_000;
|
|
7
8
|
const shutdownTimeoutMs = 1_000;
|
|
9
|
+
const workerOperationLabels = {
|
|
10
|
+
open: 'startup',
|
|
11
|
+
turn: 'turn submission',
|
|
12
|
+
steer: 'steering',
|
|
13
|
+
interrupt: 'interruption',
|
|
14
|
+
resume: 'recovery',
|
|
15
|
+
close: 'closing',
|
|
16
|
+
'approval.respond': 'approval response',
|
|
17
|
+
};
|
|
8
18
|
function waitWithin(promise, timeout) {
|
|
9
19
|
return new Promise(resolve => {
|
|
10
20
|
const timer = setTimeout(() => resolve(false), timeout);
|
|
@@ -30,53 +40,94 @@ export async function createWorker(input, options = {}) {
|
|
|
30
40
|
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
|
|
31
41
|
});
|
|
32
42
|
}
|
|
33
|
-
catch
|
|
43
|
+
catch {
|
|
34
44
|
await launcher.close();
|
|
35
|
-
throw
|
|
45
|
+
throw new AgentError('HARNESS_FAILED', 'The session worker could not be spawned during startup.');
|
|
36
46
|
}
|
|
37
47
|
let nextId = 1;
|
|
38
48
|
const pending = new Map();
|
|
49
|
+
const approvals = new Map();
|
|
50
|
+
const withdrawApprovals = () => { for (const controller of approvals.values())
|
|
51
|
+
controller.abort(); approvals.clear(); };
|
|
39
52
|
let exited = false;
|
|
53
|
+
let closing = false;
|
|
54
|
+
let observedExit = '';
|
|
40
55
|
let markExited;
|
|
41
56
|
const processExit = new Promise(resolve => { markExited = resolve; });
|
|
42
|
-
const exit = () => {
|
|
57
|
+
const exit = (code, signal, spawnFailure = false) => {
|
|
43
58
|
if (exited)
|
|
44
59
|
return;
|
|
45
60
|
exited = true;
|
|
61
|
+
observedExit = spawnFailure || closing ? '' : processExitDescription(code, signal);
|
|
62
|
+
withdrawApprovals();
|
|
46
63
|
markExited();
|
|
47
64
|
void launcher.close().catch(() => { }).finally(() => {
|
|
48
|
-
for (const waiting of pending.values())
|
|
49
|
-
waiting.reject(new AgentError('HARNESS_FAILED',
|
|
65
|
+
for (const waiting of pending.values()) {
|
|
66
|
+
waiting.reject(new AgentError('HARNESS_FAILED', spawnFailure
|
|
67
|
+
? `The session worker process failed while ${waiting.operation} was pending.`
|
|
68
|
+
: `The session worker exited while ${waiting.operation} was pending${observedExit}.`));
|
|
69
|
+
}
|
|
50
70
|
pending.clear();
|
|
51
71
|
});
|
|
52
72
|
};
|
|
53
|
-
child.once('error', exit);
|
|
54
|
-
child.once('exit', exit);
|
|
73
|
+
child.once('error', () => exit(undefined, undefined, true));
|
|
74
|
+
child.once('exit', (code, signal) => exit(code, signal));
|
|
55
75
|
child.on('message', (message) => {
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
if ('event' in message) {
|
|
77
|
+
if (message.event === 'approval.withdraw') {
|
|
78
|
+
approvals.get(message.requestId)?.abort();
|
|
79
|
+
approvals.delete(message.requestId);
|
|
80
|
+
}
|
|
81
|
+
else if (message.event === 'approval.request') {
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
approvals.set(message.requestId, controller);
|
|
84
|
+
void Promise.resolve().then(() => {
|
|
85
|
+
if (!input.onApproval)
|
|
86
|
+
throw new AgentError('INPUT_REQUIRED', 'Native tool approval requires an observing caller.');
|
|
87
|
+
return input.onApproval(message.request, controller.signal);
|
|
88
|
+
}).then(content => { if (!controller.signal.aborted && !exited)
|
|
89
|
+
return request('approval.respond', { requestId: message.requestId, content }); }, error => { if (!controller.signal.aborted && !exited)
|
|
90
|
+
return request('approval.respond', { requestId: message.requestId, error: errorInfo(error) }); }).catch(error => {
|
|
91
|
+
// A rejected control cannot leave an already-settled caller callback parked forever.
|
|
92
|
+
if (!controller.signal.aborted && !exited)
|
|
93
|
+
return request('approval.respond', { requestId: message.requestId, error: errorInfo(error) }).catch(() => { });
|
|
94
|
+
}).finally(() => { approvals.delete(message.requestId); });
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const waiting = pending.get(message.id);
|
|
99
|
+
if (!waiting)
|
|
58
100
|
return;
|
|
59
101
|
pending.delete(message.id);
|
|
60
102
|
if (message.error)
|
|
61
|
-
|
|
103
|
+
waiting.reject(new AgentError(message.error.code, message.error.message));
|
|
62
104
|
else
|
|
63
|
-
|
|
105
|
+
waiting.resolve(message.result);
|
|
64
106
|
});
|
|
65
107
|
const request = (method, extra = {}) => new Promise((resolve, reject) => {
|
|
108
|
+
const operation = workerOperationLabels[method] ?? 'native operation';
|
|
66
109
|
if (exited) {
|
|
67
|
-
reject(new AgentError('HARNESS_FAILED',
|
|
110
|
+
reject(new AgentError('HARNESS_FAILED', `The session worker is unavailable while ${operation} was pending${observedExit}.`));
|
|
68
111
|
return;
|
|
69
112
|
}
|
|
70
113
|
const id = nextId++;
|
|
71
|
-
pending.set(id, { resolve, reject });
|
|
72
|
-
child.send({ id, method, ...extra }, error => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
114
|
+
pending.set(id, { operation, resolve, reject });
|
|
115
|
+
child.send({ id, method, ...extra }, error => {
|
|
116
|
+
if (!error)
|
|
117
|
+
return;
|
|
118
|
+
setImmediate(() => {
|
|
119
|
+
const waiting = pending.get(id);
|
|
120
|
+
if (!waiting || exited)
|
|
121
|
+
return;
|
|
122
|
+
pending.delete(id);
|
|
123
|
+
waiting.reject(new AgentError('HARNESS_FAILED', `Cannot reach the session worker while ${operation} was pending.`));
|
|
124
|
+
});
|
|
125
|
+
});
|
|
76
126
|
});
|
|
77
127
|
let selectedHarness;
|
|
128
|
+
const { onApproval, ...serializedInput } = input;
|
|
78
129
|
try {
|
|
79
|
-
selectedHarness = await request('open', { input });
|
|
130
|
+
selectedHarness = await request('open', { input: serializedInput, handlesApprovals: !!onApproval });
|
|
80
131
|
}
|
|
81
132
|
catch (error) {
|
|
82
133
|
child.kill();
|
|
@@ -106,9 +157,11 @@ export async function createWorker(input, options = {}) {
|
|
|
106
157
|
selectedHarness,
|
|
107
158
|
turn: prompt => request('turn', { prompt }),
|
|
108
159
|
steer: async (prompt) => { await request('steer', { prompt }); },
|
|
109
|
-
interrupt: async () => { await request('interrupt'); },
|
|
160
|
+
interrupt: async () => { withdrawApprovals(); await request('interrupt'); },
|
|
110
161
|
resume: () => request('resume'),
|
|
111
162
|
close: async () => {
|
|
163
|
+
closing = true;
|
|
164
|
+
withdrawApprovals();
|
|
112
165
|
let failure;
|
|
113
166
|
if (!exited) {
|
|
114
167
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-client.js","sourceRoot":"","sources":["../../src/runtime/worker-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { fork, type ChildProcess } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { delimiter } from 'node:path';\nimport { AgentError, type ErrorInfo } from '../errors.js';\nimport type { DriverInput } from './types.js';\nimport type { ManagedNativeSession } from './types.js';\nimport type { HarnessKind } from '../sdk/types.js';\nimport { createSessionLauncher } from './session-launcher.js';\n\ninterface WorkerClientOptions {\n workerModule?: URL;\n shutdownTimeoutMs?: number;\n}\n\nconst closeResponseTimeoutMs = 15_000;\nconst shutdownTimeoutMs = 1_000;\n\nfunction waitWithin(promise: Promise<unknown>, timeout: number): Promise<boolean> {\n return new Promise(resolve => {\n const timer = setTimeout(() => resolve(false),timeout);\n promise.then(\n () => { clearTimeout(timer); resolve(true); },\n () => { clearTimeout(timer); resolve(true); },\n );\n });\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeout: number): Promise<T> {\n return new Promise((resolve,reject) => {\n const timer = setTimeout(() => reject(new AgentError('HARNESS_FAILED','The session worker did not complete cleanup.')),timeout);\n promise.then(\n value => { clearTimeout(timer); resolve(value); },\n error => { clearTimeout(timer); reject(error); },\n );\n });\n}\n\nexport async function createWorker(input: DriverInput, options: WorkerClientOptions = {}): Promise<ManagedNativeSession> {\n const launcher = await createSessionLauncher(input.env.AGENT_STATE_DIR!,input.token);\n const workerModule = options.workerModule ?? new URL(`./worker.${import.meta.url.endsWith('.ts') ? 'ts' : 'js'}`, import.meta.url);\n const extension = workerModule.pathname.endsWith('.ts') ? 'ts' : 'js';\n let child: ChildProcess;\n try {\n child = fork(fileURLToPath(workerModule), [], {\n cwd: input.cwd, env: {...input.env,AGENT_PARENT_TOKEN:input.token,AGENT_CLI_PATH:launcher.path,\n PATH:launcher.directory + delimiter + (input.env.PATH ?? '')},\n execArgv: extension === 'ts' ? ['--import', import.meta.resolve('tsx')] : [],\n stdio: ['ignore','ignore','ignore','ipc'],\n });\n } catch (error) { await launcher.close(); throw error; }\n let nextId = 1;\n const pending = new Map<number, {resolve(value:unknown):void;reject(error:Error):void}>();\n let exited = false;\n let markExited!: () => void;\n const processExit = new Promise<void>(resolve => { markExited = resolve; });\n const exit = () => {\n if (exited) return;\n exited = true;\n markExited();\n void launcher.close().catch(() => {}).finally(() => {\n for (const waiting of pending.values()) waiting.reject(new AgentError('HARNESS_FAILED','The session worker exited.'));\n pending.clear();\n });\n };\n child.once('error', exit); child.once('exit', exit);\n child.on('message', (message: {id:number;result?:unknown;error?:ErrorInfo}) => {\n const request = pending.get(message.id);\n if (!request) return;\n pending.delete(message.id);\n if (message.error) request.reject(new AgentError(message.error.code, message.error.message));\n else request.resolve(message.result);\n });\n const request = (method:string, extra:Record<string,unknown> = {}) => new Promise<unknown>((resolve,reject) => {\n if (exited) { reject(new AgentError('HARNESS_FAILED','The session worker is unavailable.')); return; }\n const id = nextId++;\n pending.set(id,{resolve,reject});\n child.send({id,method,...extra}, error => { if (error) { pending.delete(id); reject(new AgentError('HARNESS_FAILED','Cannot reach the session worker.')); } });\n });\n let selectedHarness: HarnessKind;\n try { selectedHarness = await request('open',{input}) as HarnessKind; } catch (error) { child.kill(); await launcher.close(); throw error; }\n const stopWorker = async () => {\n if (exited) return;\n if (child.connected) try { child.disconnect(); } catch { /* Continue to termination escalation. */ }\n const timeout = options.shutdownTimeoutMs ?? shutdownTimeoutMs;\n if (await waitWithin(processExit,timeout)) return;\n child.kill('SIGTERM');\n if (await waitWithin(processExit,timeout)) return;\n child.kill('SIGKILL');\n if (await waitWithin(processExit,timeout)) return;\n throw new AgentError('HARNESS_FAILED','The session worker did not confirm termination.');\n };\n return {\n selectedHarness,\n turn: prompt => request('turn',{prompt}) as Promise<string>,\n steer: async prompt => { await request('steer',{prompt}); },\n interrupt: async () => { await request('interrupt'); },\n resume: () => request('resume') as Promise<string>,\n close: async () => {\n let failure: unknown;\n if (!exited) {\n try { await withTimeout(request('close'),closeResponseTimeoutMs); }\n catch (error) { failure = error; }\n }\n try { await stopWorker(); } catch (error) { failure ??= error; }\n try { await launcher.close(); } catch (error) { failure ??= error; }\n if (failure) throw failure;\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"worker-client.js","sourceRoot":"","sources":["../../src/runtime/worker-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAqB,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAC;AAIrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAOnE,MAAM,sBAAsB,GAAG,MAAM,CAAC;AACtC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC,MAAM,qBAAqB,GAA0B;IACnD,IAAI,EAAC,SAAS;IACd,IAAI,EAAC,iBAAiB;IACtB,KAAK,EAAC,UAAU;IAChB,SAAS,EAAC,cAAc;IACxB,MAAM,EAAC,UAAU;IACjB,KAAK,EAAC,SAAS;IACf,kBAAkB,EAAC,mBAAmB;CACvC,CAAC;AAEF,SAAS,UAAU,CAAC,OAAyB,EAAE,OAAe;IAC5D,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAC,OAAO,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CACV,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAC7C,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAC9C,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAI,OAAmB,EAAE,OAAe;IAC1D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAC,MAAM,EAAE,EAAE;QACpC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAC,8CAA8C,CAAC,CAAC,EAAC,OAAO,CAAC,CAAC;QAChI,OAAO,CAAC,IAAI,CACV,KAAK,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EACjD,KAAK,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACjD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAkB,EAAE,OAAO,GAAwB,EAAE;IACtF,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,eAAgB,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI,GAAG,CAAC,YAAY,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnI,MAAM,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,IAAI,KAAmB,CAAC;IACxB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE;YAC5C,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,EAAC,GAAG,KAAK,CAAC,GAAG,EAAC,kBAAkB,EAAC,KAAK,CAAC,KAAK,EAAC,cAAc,EAAC,QAAQ,CAAC,IAAI;gBAC5F,IAAI,EAAC,QAAQ,CAAC,SAAS,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAC;YAC/D,QAAQ,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;YAC5E,KAAK,EAAE,CAAC,QAAQ,EAAC,QAAQ,EAAC,QAAQ,EAAC,KAAK,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QAAC,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,yDAAyD,CAAC,CAAC;IAAC,CAAC;IACrI,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmF,CAAC;IAC3G,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0B,CAAC;IACpD,MAAM,iBAAiB,GAAG,GAAG,EAAE,GAAG,KAAK,MAAM,UAAU,IAAI,SAAS,CAAC,MAAM,EAAE;QAAE,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACxH,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,UAAuB,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,GAAG,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,MAAe,EAAE,YAAY,GAAG,KAAK,EAAE,EAAE;QACpE,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,YAAY,GAAG,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,IAAI,EAAC,MAAM,CAAC,CAAC;QAClF,iBAAiB,EAAE,CAAC;QACpB,UAAU,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YACjD,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;gBACvC,OAAO,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAE,YAAY;oBAC1D,CAAC,CAAC,2CAA2C,OAAO,CAAC,SAAS,eAAe;oBAC7E,CAAC,CAAC,mCAAmC,OAAO,CAAC,SAAS,eAAe,YAAY,GAAG,CAAC,CAAC,CAAC;YAC3F,CAAC;YACD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAC,SAAS,EAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAC,MAAM,CAAC,CAAC,CAAC;IACvD,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAqE,EAAE,EAAE;QAC5F,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,KAAK,KAAK,mBAAmB,EAAE,CAAC;gBAC1C,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;gBAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACjF,CAAC;iBAAM,IAAI,OAAO,CAAC,KAAK,KAAK,kBAAkB,EAAE,CAAC;gBAChD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAC,UAAU,CAAC,CAAC;gBAC5C,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;oBAC/B,IAAI,CAAC,KAAK,CAAC,UAAU;wBAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,oDAAoD,CAAC,CAAC;oBACnH,OAAO,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,EAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBAC7D,CAAC,CAAC,CAAC,IAAI,CACL,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM;oBAAE,OAAO,OAAO,CAAC,kBAAkB,EAAC,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS,EAAC,OAAO,EAAC,CAAC,CAAC,CAAC,CAAC,EACnI,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM;oBAAE,OAAO,OAAO,CAAC,kBAAkB,EAAC,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS,EAAC,KAAK,EAAC,SAAS,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,CACjJ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;oBACd,qFAAqF;oBACrF,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM;wBACvC,OAAO,OAAO,CAAC,kBAAkB,EAAC,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS,EAAC,KAAK,EAAC,SAAS,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAC5G,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;;YACxF,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,MAAa,EAAE,KAAK,GAA0B,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAU,CAAC,OAAO,EAAC,MAAM,EAAE,EAAE;QAC5G,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC;QACtE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAC,2CAA2C,SAAS,eAAe,YAAY,GAAG,CAAC,CAAC,CAAC;YAC5H,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,EAAE,EAAC,EAAC,SAAS,EAAC,OAAO,EAAC,MAAM,EAAC,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,EAAC,EAAE,EAAC,MAAM,EAAC,GAAG,KAAK,EAAC,EAAE,KAAK,CAAC,EAAE;YACvC,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,YAAY,CAAC,GAAG,EAAE;gBAChB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChC,IAAI,CAAC,OAAO,IAAI,MAAM;oBAAE,OAAO;gBAC/B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnB,OAAO,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAC,yCAAyC,SAAS,eAAe,CAAC,CAAC,CAAC;YACrH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,IAAI,eAA4B,CAAC;IACjC,MAAM,EAAC,UAAU,EAAC,GAAG,eAAe,EAAC,GAAG,KAAK,CAAC;IAC9C,IAAI,CAAC;QAAC,eAAe,GAAG,MAAM,OAAO,CAAC,MAAM,EAAC,EAAC,KAAK,EAAC,eAAe,EAAC,gBAAgB,EAAC,CAAC,CAAC,UAAU,EAAC,CAAgB,CAAC;IAAC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;QAAC,MAAM,KAAK,CAAC;IAAC,CAAC;IAC1L,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;QAC5B,IAAI,MAAM;YAAE,OAAO;QACnB,IAAI,KAAK,CAAC,SAAS;YAAE,IAAI,CAAC;gBAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,yCAAyC,CAAC,CAAC;QACpG,MAAM,OAAO,GAAG,OAAO,CAAC,iBAAiB,IAAI,iBAAiB,CAAC;QAC/D,IAAI,MAAM,UAAU,CAAC,WAAW,EAAC,OAAO,CAAC;YAAE,OAAO;QAClD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,IAAI,MAAM,UAAU,CAAC,WAAW,EAAC,OAAO,CAAC;YAAE,OAAO;QAClD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,IAAI,MAAM,UAAU,CAAC,WAAW,EAAC,OAAO,CAAC;YAAE,OAAO;QAClD,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,iDAAiD,CAAC,CAAC;IAC3F,CAAC,CAAC;IACF,OAAO;QACL,eAAe;QACf,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,EAAC,EAAC,MAAM,EAAC,CAAoB;QAC3D,KAAK,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,EAAC,EAAC,MAAM,EAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,SAAS,EAAE,KAAK,IAAI,EAAE,GAAG,iBAAiB,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAoB;QAClD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,OAAO,GAAG,IAAI,CAAC;YACf,iBAAiB,EAAE,CAAC;YACpB,IAAI,OAAgB,CAAC;YACrB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,IAAI,CAAC;oBAAC,MAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,EAAC,sBAAsB,CAAC,CAAC;gBAAC,CAAC;gBACnE,OAAO,KAAK,EAAE,CAAC;oBAAC,OAAO,GAAG,KAAK,CAAC;gBAAC,CAAC;YACpC,CAAC;YACD,IAAI,CAAC;gBAAC,MAAM,UAAU,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,OAAO,KAAK,KAAK,CAAC;YAAC,CAAC;YAChE,IAAI,CAAC;gBAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,OAAO,KAAK,KAAK,CAAC;YAAC,CAAC;YACpE,IAAI,OAAO;gBAAE,MAAM,OAAO,CAAC;QAC7B,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { fork, type ChildProcess } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { delimiter } from 'node:path';\nimport { AgentError, errorInfo, type ErrorInfo } from '../errors.js';\nimport type { DriverInput } from './types.js';\nimport type { ManagedNativeSession } from './types.js';\nimport type { HarnessKind } from '../sdk/types.js';\nimport { createSessionLauncher } from './session-launcher.js';\nimport type { ApprovalEvent } from './worker-approvals.js';\nimport { processExitDescription } from '../process-diagnostics.js';\n\ninterface WorkerClientOptions {\n workerModule?: URL;\n shutdownTimeoutMs?: number;\n}\n\nconst closeResponseTimeoutMs = 15_000;\nconst shutdownTimeoutMs = 1_000;\n\nconst workerOperationLabels: Record<string,string> = {\n open:'startup',\n turn:'turn submission',\n steer:'steering',\n interrupt:'interruption',\n resume:'recovery',\n close:'closing',\n 'approval.respond':'approval response',\n};\n\nfunction waitWithin(promise: Promise<unknown>, timeout: number): Promise<boolean> {\n return new Promise(resolve => {\n const timer = setTimeout(() => resolve(false),timeout);\n promise.then(\n () => { clearTimeout(timer); resolve(true); },\n () => { clearTimeout(timer); resolve(true); },\n );\n });\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeout: number): Promise<T> {\n return new Promise((resolve,reject) => {\n const timer = setTimeout(() => reject(new AgentError('HARNESS_FAILED','The session worker did not complete cleanup.')),timeout);\n promise.then(\n value => { clearTimeout(timer); resolve(value); },\n error => { clearTimeout(timer); reject(error); },\n );\n });\n}\n\nexport async function createWorker(input: DriverInput, options: WorkerClientOptions = {}): Promise<ManagedNativeSession> {\n const launcher = await createSessionLauncher(input.env.AGENT_STATE_DIR!,input.token);\n const workerModule = options.workerModule ?? new URL(`./worker.${import.meta.url.endsWith('.ts') ? 'ts' : 'js'}`, import.meta.url);\n const extension = workerModule.pathname.endsWith('.ts') ? 'ts' : 'js';\n let child: ChildProcess;\n try {\n child = fork(fileURLToPath(workerModule), [], {\n cwd: input.cwd, env: {...input.env,AGENT_PARENT_TOKEN:input.token,AGENT_CLI_PATH:launcher.path,\n PATH:launcher.directory + delimiter + (input.env.PATH ?? '')},\n execArgv: extension === 'ts' ? ['--import', import.meta.resolve('tsx')] : [],\n stdio: ['ignore','ignore','ignore','ipc'],\n });\n } catch { await launcher.close(); throw new AgentError('HARNESS_FAILED','The session worker could not be spawned during startup.'); }\n let nextId = 1;\n const pending = new Map<number, {operation:string;resolve(value:unknown):void;reject(error:Error):void}>();\n const approvals = new Map<number,AbortController>();\n const withdrawApprovals = () => { for (const controller of approvals.values()) controller.abort(); approvals.clear(); };\n let exited = false;\n let closing = false;\n let observedExit = '';\n let markExited!: () => void;\n const processExit = new Promise<void>(resolve => { markExited = resolve; });\n const exit = (code: unknown, signal: unknown, spawnFailure = false) => {\n if (exited) return;\n exited = true;\n observedExit = spawnFailure || closing ? '' : processExitDescription(code,signal);\n withdrawApprovals();\n markExited();\n void launcher.close().catch(() => {}).finally(() => {\n for (const waiting of pending.values()) {\n waiting.reject(new AgentError('HARNESS_FAILED', spawnFailure\n ? `The session worker process failed while ${waiting.operation} was pending.`\n : `The session worker exited while ${waiting.operation} was pending${observedExit}.`));\n }\n pending.clear();\n });\n };\n child.once('error', () => exit(undefined,undefined,true));\n child.once('exit', (code,signal) => exit(code,signal));\n child.on('message', (message: ApprovalEvent | {id:number;result?:unknown;error?:ErrorInfo}) => {\n if ('event' in message) {\n if (message.event === 'approval.withdraw') {\n approvals.get(message.requestId)?.abort(); approvals.delete(message.requestId);\n } else if (message.event === 'approval.request') {\n const controller = new AbortController();\n approvals.set(message.requestId,controller);\n void Promise.resolve().then(() => {\n if (!input.onApproval) throw new AgentError('INPUT_REQUIRED','Native tool approval requires an observing caller.');\n return input.onApproval(message.request,controller.signal);\n }).then(\n content => { if (!controller.signal.aborted && !exited) return request('approval.respond',{requestId:message.requestId,content}); },\n error => { if (!controller.signal.aborted && !exited) return request('approval.respond',{requestId:message.requestId,error:errorInfo(error)}); },\n ).catch(error => {\n // A rejected control cannot leave an already-settled caller callback parked forever.\n if (!controller.signal.aborted && !exited)\n return request('approval.respond',{requestId:message.requestId,error:errorInfo(error)}).catch(() => {});\n }).finally(() => { approvals.delete(message.requestId); });\n }\n return;\n }\n const waiting = pending.get(message.id);\n if (!waiting) return;\n pending.delete(message.id);\n if (message.error) waiting.reject(new AgentError(message.error.code, message.error.message));\n else waiting.resolve(message.result);\n });\n const request = (method:string, extra:Record<string,unknown> = {}) => new Promise<unknown>((resolve,reject) => {\n const operation = workerOperationLabels[method] ?? 'native operation';\n if (exited) {\n reject(new AgentError('HARNESS_FAILED',`The session worker is unavailable while ${operation} was pending${observedExit}.`));\n return;\n }\n const id = nextId++;\n pending.set(id,{operation,resolve,reject});\n child.send({id,method,...extra}, error => {\n if (!error) return;\n setImmediate(() => {\n const waiting = pending.get(id);\n if (!waiting || exited) return;\n pending.delete(id);\n waiting.reject(new AgentError('HARNESS_FAILED',`Cannot reach the session worker while ${operation} was pending.`));\n });\n });\n });\n let selectedHarness: HarnessKind;\n const {onApproval,...serializedInput} = input;\n try { selectedHarness = await request('open',{input:serializedInput,handlesApprovals:!!onApproval}) as HarnessKind; } catch (error) { child.kill(); await launcher.close(); throw error; }\n const stopWorker = async () => {\n if (exited) return;\n if (child.connected) try { child.disconnect(); } catch { /* Continue to termination escalation. */ }\n const timeout = options.shutdownTimeoutMs ?? shutdownTimeoutMs;\n if (await waitWithin(processExit,timeout)) return;\n child.kill('SIGTERM');\n if (await waitWithin(processExit,timeout)) return;\n child.kill('SIGKILL');\n if (await waitWithin(processExit,timeout)) return;\n throw new AgentError('HARNESS_FAILED','The session worker did not confirm termination.');\n };\n return {\n selectedHarness,\n turn: prompt => request('turn',{prompt}) as Promise<string>,\n steer: async prompt => { await request('steer',{prompt}); },\n interrupt: async () => { withdrawApprovals(); await request('interrupt'); },\n resume: () => request('resume') as Promise<string>,\n close: async () => {\n closing = true;\n withdrawApprovals();\n let failure: unknown;\n if (!exited) {\n try { await withTimeout(request('close'),closeResponseTimeoutMs); }\n catch (error) { failure = error; }\n }\n try { await stopWorker(); } catch (error) { failure ??= error; }\n try { await launcher.close(); } catch (error) { failure ??= error; }\n if (failure) throw failure;\n },\n };\n}\n"]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { selectNative } from './select-native.js';
|
|
1
2
|
import type { ExecutionDefinition } from '../adapters/types.js';
|
|
2
3
|
interface WorkerServerDependencies {
|
|
3
4
|
removeLauncherDirectory?(path: string): Promise<void>;
|
|
5
|
+
selectNative?: typeof selectNative;
|
|
4
6
|
}
|
|
5
7
|
export declare function delegationInstructions(definition: ExecutionDefinition, launcherPath: string): string;
|
|
6
8
|
export declare function startWorker(dependencies?: WorkerServerDependencies): void;
|