@relayflows/sdk 2.0.54 → 2.0.56
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/dist/authored-broker.d.ts +13 -0
- package/dist/authored-broker.d.ts.map +1 -0
- package/dist/authored-broker.js +75 -0
- package/dist/authored-broker.js.map +1 -0
- package/dist/authored-budget.d.ts +1 -1
- package/dist/authored-budget.d.ts.map +1 -1
- package/dist/authored-budget.js +8 -2
- package/dist/authored-budget.js.map +1 -1
- package/dist/authored-flow-error.d.ts +6 -0
- package/dist/authored-flow-error.d.ts.map +1 -1
- package/dist/authored-flow-error.js.map +1 -1
- package/dist/authored-flow-executor.d.ts +11 -0
- package/dist/authored-flow-executor.d.ts.map +1 -1
- package/dist/authored-flow-executor.js +104 -20
- package/dist/authored-flow-executor.js.map +1 -1
- package/dist/authored-flow-loader.d.ts.map +1 -1
- package/dist/authored-flow-loader.js +42 -3
- package/dist/authored-flow-loader.js.map +1 -1
- package/dist/authored-helper-effect.d.ts.map +1 -1
- package/dist/authored-helper-effect.js +1 -1
- package/dist/authored-helper-effect.js.map +1 -1
- package/dist/authored-hooks.d.ts +2 -1
- package/dist/authored-hooks.d.ts.map +1 -1
- package/dist/authored-hooks.js +2 -2
- package/dist/authored-hooks.js.map +1 -1
- package/dist/authored-human.d.ts +18 -0
- package/dist/authored-human.d.ts.map +1 -1
- package/dist/authored-human.js +32 -4
- package/dist/authored-human.js.map +1 -1
- package/dist/authored-mcp.d.ts.map +1 -1
- package/dist/authored-mcp.js +3 -2
- package/dist/authored-mcp.js.map +1 -1
- package/dist/authored-node-entry.js +4 -0
- package/dist/authored-node-entry.js.map +1 -1
- package/dist/authored-node-runner.d.ts +8 -0
- package/dist/authored-node-runner.d.ts.map +1 -1
- package/dist/authored-node-runner.js +60 -3
- package/dist/authored-node-runner.js.map +1 -1
- package/dist/authored-plugin-effect.d.ts.map +1 -1
- package/dist/authored-plugin-effect.js +3 -2
- package/dist/authored-plugin-effect.js.map +1 -1
- package/dist/authored-preflight.d.ts.map +1 -1
- package/dist/authored-preflight.js +2 -1
- package/dist/authored-preflight.js.map +1 -1
- package/dist/authored-root.d.ts.map +1 -1
- package/dist/authored-root.js +13 -3
- package/dist/authored-root.js.map +1 -1
- package/dist/authored-serial-ordinals.d.ts +41 -0
- package/dist/authored-serial-ordinals.d.ts.map +1 -0
- package/dist/authored-serial-ordinals.js +45 -0
- package/dist/authored-serial-ordinals.js.map +1 -0
- package/dist/authored-worker-step.d.ts +5 -1
- package/dist/authored-worker-step.d.ts.map +1 -1
- package/dist/authored-worker-step.js +19 -2
- package/dist/authored-worker-step.js.map +1 -1
- package/dist/budget-preflight.d.ts.map +1 -1
- package/dist/budget-preflight.js +11 -2
- package/dist/budget-preflight.js.map +1 -1
- package/dist/bundle-transport.d.ts +2 -0
- package/dist/bundle-transport.d.ts.map +1 -1
- package/dist/bundle-transport.js +4 -0
- package/dist/bundle-transport.js.map +1 -1
- package/dist/cached-flow-runtime.d.ts +3 -0
- package/dist/cached-flow-runtime.d.ts.map +1 -0
- package/dist/cached-flow-runtime.js +37 -0
- package/dist/cached-flow-runtime.js.map +1 -0
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +13 -1
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/cloud-deploy.js +6 -5
- package/dist/cli/cloud-deploy.js.map +1 -1
- package/dist/cli/cloud-mirror-session.d.ts +8 -2
- package/dist/cli/cloud-mirror-session.d.ts.map +1 -1
- package/dist/cli/cloud-mirror-session.js +20 -27
- package/dist/cli/cloud-mirror-session.js.map +1 -1
- package/dist/cli/direct-run.d.ts.map +1 -1
- package/dist/cli/direct-run.js +2 -1
- package/dist/cli/direct-run.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +19 -4
- package/dist/cli/run.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +39 -18
- package/dist/cli.js.map +1 -1
- package/dist/cloud-deploy.d.ts +3 -3
- package/dist/cloud-deploy.d.ts.map +1 -1
- package/dist/cloud-deploy.js +15 -9
- package/dist/cloud-deploy.js.map +1 -1
- package/dist/cloud-flow-source.d.ts +13 -0
- package/dist/cloud-flow-source.d.ts.map +1 -0
- package/dist/cloud-flow-source.js +55 -0
- package/dist/cloud-flow-source.js.map +1 -0
- package/dist/cloud-mirror-transport.d.ts +2 -0
- package/dist/cloud-mirror-transport.d.ts.map +1 -1
- package/dist/cloud-mirror-transport.js +2 -0
- package/dist/cloud-mirror-transport.js.map +1 -1
- package/dist/cloud-mirror.d.ts.map +1 -1
- package/dist/cloud-mirror.js +10 -1
- package/dist/cloud-mirror.js.map +1 -1
- package/dist/communication/broker-preflight.d.ts +3 -0
- package/dist/communication/broker-preflight.d.ts.map +1 -0
- package/dist/communication/broker-preflight.js +22 -0
- package/dist/communication/broker-preflight.js.map +1 -0
- package/dist/communication/broker-spec.d.ts +20 -0
- package/dist/communication/broker-spec.d.ts.map +1 -0
- package/dist/communication/broker-spec.js +46 -0
- package/dist/communication/broker-spec.js.map +1 -0
- package/dist/communication/broker-worker.d.ts +17 -0
- package/dist/communication/broker-worker.d.ts.map +1 -0
- package/dist/communication/broker-worker.js +214 -0
- package/dist/communication/broker-worker.js.map +1 -0
- package/dist/communication/pty.d.ts +29 -0
- package/dist/communication/pty.d.ts.map +1 -0
- package/dist/communication/pty.js +40 -0
- package/dist/communication/pty.js.map +1 -0
- package/dist/communication/relay.d.ts +18 -0
- package/dist/communication/relay.d.ts.map +1 -1
- package/dist/communication/relay.js +4 -0
- package/dist/communication/relay.js.map +1 -1
- package/dist/communication/skills.d.ts +3 -0
- package/dist/communication/skills.d.ts.map +1 -0
- package/dist/communication/skills.js +17 -0
- package/dist/communication/skills.js.map +1 -0
- package/dist/communication/worker.d.ts.map +1 -1
- package/dist/communication/worker.js +9 -26
- package/dist/communication/worker.js.map +1 -1
- package/dist/failure-kinds.d.ts +1 -1
- package/dist/failure-kinds.d.ts.map +1 -1
- package/dist/failure-kinds.js +2 -0
- package/dist/failure-kinds.js.map +1 -1
- package/dist/plugin-manifest.js +1 -1
- package/dist/plugin-manifest.js.map +1 -1
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +2 -1
- package/dist/preflight.js.map +1 -1
- package/dist/worker.d.ts +1 -0
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +12 -0
- package/dist/worker.js.map +1 -1
- package/package.json +2 -2
- package/src/authored-broker.ts +73 -0
- package/src/authored-budget.ts +6 -2
- package/src/authored-flow-error.ts +6 -0
- package/src/authored-flow-executor.ts +115 -20
- package/src/authored-flow-loader.ts +43 -3
- package/src/authored-helper-effect.ts +2 -1
- package/src/authored-hooks.ts +4 -3
- package/src/authored-human.ts +35 -4
- package/src/authored-mcp.ts +7 -2
- package/src/authored-node-entry.ts +4 -1
- package/src/authored-node-runner.ts +57 -3
- package/src/authored-plugin-effect.ts +7 -2
- package/src/authored-preflight.ts +2 -1
- package/src/authored-root.ts +13 -3
- package/src/authored-serial-ordinals.ts +76 -0
- package/src/authored-worker-step.ts +17 -2
- package/src/budget-preflight.ts +9 -1
- package/src/bundle-transport.ts +4 -0
- package/src/cached-flow-runtime.ts +32 -0
- package/src/cli/check.ts +11 -1
- package/src/cli/cloud-deploy.ts +5 -5
- package/src/cli/cloud-mirror-session.ts +23 -29
- package/src/cli/direct-run.ts +2 -1
- package/src/cli/run.ts +18 -3
- package/src/cli.ts +31 -13
- package/src/cloud-deploy.ts +19 -14
- package/src/cloud-flow-source.ts +58 -0
- package/src/cloud-mirror-transport.ts +4 -0
- package/src/cloud-mirror.ts +9 -1
- package/src/communication/broker-preflight.ts +22 -0
- package/src/communication/broker-spec.ts +48 -0
- package/src/communication/broker-worker.ts +198 -0
- package/src/communication/pty.ts +47 -0
- package/src/communication/relay.ts +12 -1
- package/src/communication/skills.ts +16 -0
- package/src/communication/worker.ts +9 -26
- package/src/failure-kinds.ts +2 -0
- package/src/plugin-manifest.ts +1 -1
- package/src/preflight.ts +3 -1
- package/src/worker.ts +11 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, symlink } from 'node:fs/promises';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { agentEnvironment } from './environment.js';
|
|
4
|
+
import { resolveCliModel } from '../cli-adapter.js';
|
|
5
|
+
import type { RelayBroker } from './relay.js';
|
|
6
|
+
|
|
7
|
+
export const shellQuote = (value: string) => "'" + value.replaceAll("'", "'\"'\"'") + "'";
|
|
8
|
+
|
|
9
|
+
/** Both communication steps and retained sessions use Relay's PTY launch contract. */
|
|
10
|
+
export async function spawnFlowPty(broker: Pick<RelayBroker, 'spawnPty'>, options: {
|
|
11
|
+
name: string; cli: string; identity?: string; model?: string; task: string;
|
|
12
|
+
skipRelayPrompt?: boolean;
|
|
13
|
+
cwd: string; dataDir: string; channels: string[]; team?: string;
|
|
14
|
+
environment?: NodeJS.ProcessEnv; socket: string; token: string;
|
|
15
|
+
secrets?: string[]; scopeSecrets?: boolean;
|
|
16
|
+
metadata?: { runId: string; flow: string; step: string };
|
|
17
|
+
}) {
|
|
18
|
+
const identity = options.identity ?? options.cli;
|
|
19
|
+
const argv0 = basename(identity);
|
|
20
|
+
let command = options.cli;
|
|
21
|
+
let link: string | undefined;
|
|
22
|
+
try {
|
|
23
|
+
if (basename(command) !== argv0) {
|
|
24
|
+
const root = join(options.dataDir, 'communication');
|
|
25
|
+
await mkdir(root, { recursive: true, mode: 0o700 });
|
|
26
|
+
link = await mkdtemp(join(root, 'cli-'));
|
|
27
|
+
command = join(link, argv0);
|
|
28
|
+
await symlink(options.cli, command, 'file');
|
|
29
|
+
}
|
|
30
|
+
const handle = await broker.spawnPty({ name: options.name, cli: argv0.replace(/\.exe$/i, ''),
|
|
31
|
+
task: options.task, channels: options.channels, skipRelayPrompt: options.skipRelayPrompt ?? true,
|
|
32
|
+
...(options.team === undefined ? {} : { team: options.team }),
|
|
33
|
+
model: resolveCliModel(identity, options.model), cwd: options.cwd,
|
|
34
|
+
harnessConfig: { runtime: 'pty', command: shellQuote(command), args: [], cwd: options.cwd,
|
|
35
|
+
env: { ...agentEnvironment(identity, options.environment ?? process.env,
|
|
36
|
+
options.secrets, options.scopeSecrets ?? true),
|
|
37
|
+
RELAYFLOW_COMMUNICATION_SOCKET: options.socket, RELAYFLOW_COMMUNICATION_TOKEN: options.token,
|
|
38
|
+
...(options.metadata === undefined ? {} : {
|
|
39
|
+
RELAYFLOW_RUN_ID: options.metadata.runId, RELAYFLOW_FLOW_NAME: options.metadata.flow,
|
|
40
|
+
RELAYFLOW_STEP_NAME: options.metadata.step,
|
|
41
|
+
}) }, delivery: { mode: 'pty-injection', format: 'relay-block' } } });
|
|
42
|
+
return { handle, close: async () => { if (link) await rm(link, { recursive: true, force: true }); } };
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (link) await rm(link, { recursive: true, force: true });
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -25,7 +25,8 @@ export interface RelayMessaging {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
interface RelayModules {
|
|
28
|
-
HarnessDriverClient: { spawn(options: Record<string, unknown>): Promise<RelayBroker
|
|
28
|
+
HarnessDriverClient: { spawn(options: Record<string, unknown>): Promise<RelayBroker>;
|
|
29
|
+
connect(options: { cwd: string }): LocalBroker };
|
|
29
30
|
RelaycastMessagingClient: new (options: Record<string, unknown>) => RelayMessaging;
|
|
30
31
|
}
|
|
31
32
|
export async function loadRelayModules(): Promise<RelayModules> {
|
|
@@ -100,3 +101,13 @@ async function createRuntime(dataDir: string, runId: string): Promise<RelayRunti
|
|
|
100
101
|
throw error;
|
|
101
102
|
}
|
|
102
103
|
}
|
|
104
|
+
|
|
105
|
+
/** Connected clients disconnect on shutdown; they never terminate the user's broker. */
|
|
106
|
+
export interface LocalBroker extends RelayBroker {
|
|
107
|
+
connectEvents(): void;
|
|
108
|
+
sendMessage(input: { to: string; text: string; from: string; mode: 'wait'; data: Record<string, unknown> }): Promise<{ event_id: string; targets: string[] }>;
|
|
109
|
+
}
|
|
110
|
+
export async function connectLocalBroker(cwd: string): Promise<LocalBroker> {
|
|
111
|
+
const { HarnessDriverClient } = await loadRelayModules();
|
|
112
|
+
return HarnessDriverClient.connect({ cwd });
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { basename } from 'node:path';
|
|
4
|
+
|
|
5
|
+
const execute = promisify(execFile);
|
|
6
|
+
/** Install full skill directories (including references) using the canonical package. */
|
|
7
|
+
export async function installBrokerSkills(skills: string[], cli: string, cwd: string, signal: AbortSignal): Promise<void> {
|
|
8
|
+
if (!skills.length) return;
|
|
9
|
+
const identity = basename(cli).replace(/\.exe$/i, '');
|
|
10
|
+
const harness = ({ claude: 'claude-code', codex: 'codex', gemini: 'gemini-cli',
|
|
11
|
+
'cursor-agent': 'cursor', opencode: 'opencode' } as Record<string, string>)[identity];
|
|
12
|
+
if (!harness) throw new Error(`Skill installation is unsupported for broker CLI ${identity}`);
|
|
13
|
+
await execute('npx', ['--yes', 'skills', 'add', 'https://github.com/AgentWorkforce/skills',
|
|
14
|
+
'--skill', ...skills, '--agent', harness, '--yes', '--copy'],
|
|
15
|
+
{ cwd, signal, timeout: 120_000, maxBuffer: 1024 * 1024 });
|
|
16
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { communicationHistory } from './history.js';
|
|
2
|
-
import { mkdir, mkdtemp, rm, symlink } from 'node:fs/promises';
|
|
3
|
-
import { basename, join } from 'node:path';
|
|
4
2
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
5
3
|
import type { JournalClient } from '../journal-client.js';
|
|
6
4
|
import type { StepDispatchEvent } from '../protocol.js';
|
|
@@ -8,13 +6,12 @@ import type { ResolvedKernelAgentStep } from '../resolved-cli-identity.js';
|
|
|
8
6
|
import { isLeaseLost, withWorkerLease } from '../worker-lease.js';
|
|
9
7
|
import { isReadInterruptionError } from '../journal-read-policy.js';
|
|
10
8
|
import { workerInstruction } from '../worker-input.js';
|
|
11
|
-
import { resolveCliModel } from '../cli-adapter.js';
|
|
12
9
|
import { resolveAgentCwd } from '../agent-cwd.js';
|
|
13
10
|
import { channelName, type CommunicationInstruction } from './spec.js';
|
|
14
11
|
import { acquireRelayRuntime, type RelayHandle } from './relay.js';
|
|
15
12
|
import { CommunicationSession } from './session.js';
|
|
16
13
|
import { openCommunicationTools } from './tools.js';
|
|
17
|
-
import {
|
|
14
|
+
import { spawnFlowPty, shellQuote } from './pty.js';
|
|
18
15
|
|
|
19
16
|
export function requireCommunicationCli(cli: string | undefined): void {
|
|
20
17
|
if (!cli?.trim()) throw new Error('Agent communication requires a declared CLI executable');
|
|
@@ -62,7 +59,7 @@ async function run(client: JournalClient, dispatch: StepDispatchEvent, instructi
|
|
|
62
59
|
let pumping: Promise<void> | undefined;
|
|
63
60
|
let receipts = Promise.resolve();
|
|
64
61
|
let unsubscribe: (() => void) | undefined;
|
|
65
|
-
let
|
|
62
|
+
let pty: Awaited<ReturnType<typeof spawnFlowPty>> | undefined;
|
|
66
63
|
try {
|
|
67
64
|
let resolve!: (value: unknown) => void;
|
|
68
65
|
let reject!: (reason: unknown) => void;
|
|
@@ -74,8 +71,7 @@ async function run(client: JournalClient, dispatch: StepDispatchEvent, instructi
|
|
|
74
71
|
if (signal.aborted) abort();
|
|
75
72
|
const session = new CommunicationSession(client, dispatch, instruction, relay, summary => resolve({ summary }), reject);
|
|
76
73
|
tools = await openCommunicationTools(request => session.invoke(request));
|
|
77
|
-
const
|
|
78
|
-
const helper = `node ${quote(tools.helperPath)}`;
|
|
74
|
+
const helper = `node ${shellQuote(tools.helperPath)}`;
|
|
79
75
|
const history = await communicationHistory(client, dispatch, instruction);
|
|
80
76
|
const prompt = `${workerInstruction(instruction.instruction, dispatch)}${history}\n\nYou are flow agent ${dispatch.step_id}. Concurrent peers send messages automatically into your session through Relay. Do not poll for messages. Use your shell/terminal execution tool with ${helper} for flow communication:\n- send PEER STABLE_ID 'message text' (outgoing peers: ${instruction.outgoing.join(', ') || 'none'})\n- ack PEER DELIVERY_SEQ only after processing that message (incoming peers: ${instruction.incoming.join(', ') || 'none'})\n- complete 'summary' when your task and conversation are finished.\nUse these helpers for all peer communication; do not use Relay MCP messaging tools. Stay available for injected messages until the conversation is complete. Use stable semantic message IDs so retries deduplicate sends.`;
|
|
81
77
|
const name = `${relay.prefix}-${dispatch.step_id}`;
|
|
@@ -89,24 +85,11 @@ async function run(client: JournalClient, dispatch: StepDispatchEvent, instructi
|
|
|
89
85
|
});
|
|
90
86
|
void receipts.catch(reject);
|
|
91
87
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const linkRoot = join(dataDir, 'communication');
|
|
98
|
-
await mkdir(linkRoot, { recursive: true, mode: 0o700 });
|
|
99
|
-
cliLinkDirectory = await mkdtemp(join(linkRoot, 'cli-'));
|
|
100
|
-
command = join(cliLinkDirectory, argv0);
|
|
101
|
-
await symlink(spec.cli!, command, 'file');
|
|
102
|
-
}
|
|
103
|
-
handle = await relay.broker.spawnPty({ name, cli: basename(cliIdentity).replace(/\.exe$/i, ''), task: prompt, channels: [], skipRelayPrompt: true,
|
|
104
|
-
model: resolveCliModel(cliIdentity, spec.model), cwd: directory,
|
|
105
|
-
harnessConfig: { runtime: 'pty', command: quote(command), args: [],
|
|
106
|
-
cwd: directory, env: { ...agentEnvironment(cliIdentity, environment ?? process.env,
|
|
107
|
-
spec.secrets, client.supportsFeature?.('step_secret_scoping') ?? true),
|
|
108
|
-
RELAYFLOW_COMMUNICATION_SOCKET: tools.path, RELAYFLOW_COMMUNICATION_TOKEN: tools.token },
|
|
109
|
-
delivery: { mode: 'pty-injection', format: 'relay-block' } } });
|
|
88
|
+
pty = await spawnFlowPty(relay.broker, { name, cli: spec.cli!, identity: spec.cli_identity,
|
|
89
|
+
model: spec.model, task: prompt, channels: [], cwd: directory, dataDir,
|
|
90
|
+
environment, socket: tools.path, token: tools.token,
|
|
91
|
+
secrets: spec.secrets, scopeSecrets: client.supportsFeature?.('step_secret_scoping') ?? true });
|
|
92
|
+
handle = pty.handle;
|
|
110
93
|
const ready = await handle.waitForReady(Math.min(instruction.timeoutMs, 90_000));
|
|
111
94
|
if (ready.reason !== 'ready') throw new Error(`Communication agent did not become ready: ${ready.reason}`);
|
|
112
95
|
pumping = (async () => {
|
|
@@ -123,7 +106,7 @@ async function run(client: JournalClient, dispatch: StepDispatchEvent, instructi
|
|
|
123
106
|
finally { try { await handle?.release('Flow communication attempt ended', { deleteIdentity: true }); }
|
|
124
107
|
finally { try { await tools?.close(); } finally {
|
|
125
108
|
try { await relay.close(); }
|
|
126
|
-
finally {
|
|
109
|
+
finally { await pty?.close(); }
|
|
127
110
|
} } }
|
|
128
111
|
}
|
|
129
112
|
}
|
package/src/failure-kinds.ts
CHANGED
|
@@ -138,6 +138,8 @@ export const RUN_FAILURE_KINDS = [
|
|
|
138
138
|
'unsafe_parallel_runtime',
|
|
139
139
|
/** A predicate `.gate(fn)` judged false; the verdict is journaled as `<step>.gate`. */
|
|
140
140
|
'gate_failed',
|
|
141
|
+
/** A resumed serial body reached a journaled step id with a different call; refused, not executed. */
|
|
142
|
+
'serial_replay_order_mismatch',
|
|
141
143
|
/** `flows answer` named a wait the run is not asking: unknown, or already answered. */
|
|
142
144
|
'human_wait_unknown',
|
|
143
145
|
/** `f.memory.learn` was given a finding without non-empty string fields. */
|
package/src/plugin-manifest.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface PluginManifest {
|
|
|
39
39
|
preflight: { credentials: readonly string[]; servers: readonly string[] };
|
|
40
40
|
}
|
|
41
41
|
const identifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
42
|
-
const reserved = new Set(['run', 'llm', 'agent', 'human', 'dispatch', 'done', 'cloud', 'memory', 'mcp', 'slack', '__proto__', 'constructor', 'prototype', 'then']);
|
|
42
|
+
const reserved = new Set(['run', 'llm', 'agent', 'message', 'release', 'human', 'dispatch', 'done', 'cloud', 'memory', 'mcp', 'slack', '__proto__', 'constructor', 'prototype', 'then']);
|
|
43
43
|
const object = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
44
44
|
const strings = (v: unknown): v is string[] => Array.isArray(v) && v.every(s => typeof s === 'string' && s.trim().length > 0);
|
|
45
45
|
export function pluginPackageName(name: string): string {
|
package/src/preflight.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { brokerInstruction } from './communication/broker-spec.js';
|
|
1
2
|
import { communicationInstruction } from './communication/spec.js';
|
|
2
3
|
import { loadPlugins, type LoadedPlugin } from './plugin-loader.js';
|
|
3
4
|
import { PluginError } from './plugin-manifest.js';
|
|
@@ -340,7 +341,8 @@ function preflightSync(flow: unknown, options: PreflightOptions): PreflightResul
|
|
|
340
341
|
}
|
|
341
342
|
const resolution = resolutionByStep.get(step.id)!;
|
|
342
343
|
probeResolvedCli(resolution, options.probes, cliProbeResults, diagnostics,
|
|
343
|
-
step.type === 'agent' && communicationInstruction(step.instruction) !== undefined
|
|
344
|
+
step.type === 'agent' && (communicationInstruction(step.instruction) !== undefined || brokerInstruction(step.instruction) !== undefined),
|
|
345
|
+
step.secrets);
|
|
344
346
|
}
|
|
345
347
|
|
|
346
348
|
for (const trigger of compiled.triggers ?? []) {
|
package/src/worker.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { brokerInstruction } from './communication/broker-spec.js';
|
|
2
|
+
import { BrokerSessions } from './communication/broker-worker.js';
|
|
1
3
|
import { communicationInstruction } from './communication/spec.js';
|
|
2
4
|
import { workerSpend } from './worker-spend.js';
|
|
3
5
|
import { reportedCost } from './reported-cost.js';
|
|
@@ -60,6 +62,7 @@ export interface AgentWorkerOptions {
|
|
|
60
62
|
* shutdown.
|
|
61
63
|
*/
|
|
62
64
|
export class AgentWorker extends EventEmitter {
|
|
65
|
+
private readonly brokerSessions: BrokerSessions;
|
|
63
66
|
private attached = false;
|
|
64
67
|
private closing = false;
|
|
65
68
|
private readonly inFlight: Set<Promise<void>> = new Set();
|
|
@@ -69,6 +72,7 @@ export class AgentWorker extends EventEmitter {
|
|
|
69
72
|
private readonly options: AgentWorkerOptions,
|
|
70
73
|
) {
|
|
71
74
|
super();
|
|
75
|
+
this.brokerSessions = new BrokerSessions(options.runRoot, options.environment);
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
async attach(): Promise<void> {
|
|
@@ -107,6 +111,7 @@ export class AgentWorker extends EventEmitter {
|
|
|
107
111
|
if (pending.length > 0) {
|
|
108
112
|
await Promise.allSettled(pending);
|
|
109
113
|
}
|
|
114
|
+
await this.brokerSessions.close();
|
|
110
115
|
this.attached = false;
|
|
111
116
|
}
|
|
112
117
|
|
|
@@ -128,6 +133,12 @@ export class AgentWorker extends EventEmitter {
|
|
|
128
133
|
await completeHelperDispatch(this.client, dispatch, helper, this.options.dataDir);
|
|
129
134
|
return;
|
|
130
135
|
}
|
|
136
|
+
const broker = brokerInstruction(spec.instruction);
|
|
137
|
+
if (broker) {
|
|
138
|
+
if (!this.options.dataDir) throw new Error('Broker agents require a worker data directory');
|
|
139
|
+
await this.brokerSessions.complete(this.client, dispatch, broker, this.options.dataDir);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
131
142
|
const communication = communicationInstruction(spec.instruction);
|
|
132
143
|
if (communication) {
|
|
133
144
|
if (!this.options.dataDir) throw new Error('Agent communication requires a worker data directory');
|