@liy/agent-runner 0.1.0 → 0.2.1
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 +4 -2
- package/dist/bin/agent-runner.d.ts +8 -0
- package/dist/bin/agent-runner.js +177 -53
- package/dist/bin/agent-runner.js.map +2 -2
- package/dist/harness-drivers/pi-rpc.d.ts +110 -0
- package/dist/harness-drivers/shared.d.ts +4 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +165 -51
- package/dist/index.js.map +2 -2
- package/package.json +14 -10
package/README.md
CHANGED
|
@@ -191,8 +191,10 @@ pi --mode rpc --provider deepseek --model deepseek-v4-flash --thinking high --no
|
|
|
191
191
|
```
|
|
192
192
|
|
|
193
193
|
The driver writes one Pi RPC `prompt` command to stdin, parses Pi stdout as
|
|
194
|
-
byte-buffered JSONL, forwards Pi
|
|
195
|
-
|
|
194
|
+
byte-buffered JSONL, forwards native Pi records as `pi.event` or
|
|
195
|
+
`pi.extension_ui_request`, routes malformed stdout/stderr as
|
|
196
|
+
`harness.stdout`/`harness.stderr`, and cancels with Pi `abort`, then
|
|
197
|
+
`SIGTERM`, then `SIGKILL` after five seconds.
|
|
196
198
|
|
|
197
199
|
Direct DeepSeek token example:
|
|
198
200
|
|
|
@@ -32,3 +32,11 @@ export declare function shouldPrintHelp(argv: string[]): boolean;
|
|
|
32
32
|
* @returns Help text.
|
|
33
33
|
*/
|
|
34
34
|
export declare function formatHelp(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Check whether this module is executing as the Node entrypoint.
|
|
37
|
+
*
|
|
38
|
+
* @param moduleUrl - Current module URL.
|
|
39
|
+
* @param argvPath - Process entrypoint path, defaulting to `process.argv[1]`.
|
|
40
|
+
* @returns Whether the module should run the CLI.
|
|
41
|
+
*/
|
|
42
|
+
export declare function isEntrypoint(moduleUrl: string, argvPath?: string | undefined): boolean;
|
package/dist/bin/agent-runner.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as ___liy_agent_runnerCreateRequire } from "node:module";var require = ___liy_agent_runnerCreateRequire(import.meta.url);
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __export = (target, all) => {
|
|
4
5
|
for (var name in all)
|
|
@@ -6,6 +7,7 @@ var __export = (target, all) => {
|
|
|
6
7
|
};
|
|
7
8
|
|
|
8
9
|
// src/bin/agent-runner.ts
|
|
10
|
+
import { realpathSync } from "node:fs";
|
|
9
11
|
import { resolve } from "node:path";
|
|
10
12
|
import { fileURLToPath } from "node:url";
|
|
11
13
|
|
|
@@ -15334,25 +15336,17 @@ function forwardJsonlByteStream(stream, onLine) {
|
|
|
15334
15336
|
});
|
|
15335
15337
|
});
|
|
15336
15338
|
}
|
|
15337
|
-
function forwardHarnessLine(channel, line, streamName, sanitizer
|
|
15339
|
+
function forwardHarnessLine(channel, taskId, harness, line, streamName, sanitizer) {
|
|
15338
15340
|
const trimmed = sanitizer.redactText(line.trim());
|
|
15339
15341
|
if (!trimmed) {
|
|
15340
15342
|
return;
|
|
15341
15343
|
}
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
}));
|
|
15349
|
-
} catch {
|
|
15350
|
-
channel.send(createExecuteTaskRpcNotification("task.log", {
|
|
15351
|
-
...driver ? { driver } : {},
|
|
15352
|
-
stream: streamName,
|
|
15353
|
-
message: trimmed
|
|
15354
|
-
}));
|
|
15355
|
-
}
|
|
15344
|
+
channel.send(createExecuteTaskRpcNotification(`harness.${streamName}`, {
|
|
15345
|
+
taskId,
|
|
15346
|
+
harness,
|
|
15347
|
+
stream: streamName,
|
|
15348
|
+
message: trimmed
|
|
15349
|
+
}));
|
|
15356
15350
|
}
|
|
15357
15351
|
function waitForChildClose(child) {
|
|
15358
15352
|
return new Promise((resolve2, reject) => {
|
|
@@ -15432,10 +15426,10 @@ function startCodexJsonlHarness(input, spawnProcess) {
|
|
|
15432
15426
|
let cleanupTermination = () => void 0;
|
|
15433
15427
|
child.stdin.end(input.prompt);
|
|
15434
15428
|
const stdoutDone = forwardHarnessLines(child.stdout, (line) => {
|
|
15435
|
-
forwardHarnessLine(input.channel, line, "stdout", sanitizer);
|
|
15429
|
+
forwardHarnessLine(input.channel, input.spec.taskId, "codex-jsonl", line, "stdout", sanitizer);
|
|
15436
15430
|
});
|
|
15437
15431
|
const stderrDone = forwardHarnessLines(child.stderr, (line) => {
|
|
15438
|
-
forwardHarnessLine(input.channel, line, "stderr", sanitizer);
|
|
15432
|
+
forwardHarnessLine(input.channel, input.spec.taskId, "codex-jsonl", line, "stderr", sanitizer);
|
|
15439
15433
|
});
|
|
15440
15434
|
const result = waitForChildClose(child).then(async (closeResult) => {
|
|
15441
15435
|
cleanupTermination();
|
|
@@ -15512,6 +15506,7 @@ function buildPiRpcArgs(harness) {
|
|
|
15512
15506
|
model,
|
|
15513
15507
|
"--thinking",
|
|
15514
15508
|
thinking,
|
|
15509
|
+
"--no-session",
|
|
15515
15510
|
"--no-extensions",
|
|
15516
15511
|
"--no-prompt-templates",
|
|
15517
15512
|
"--no-themes",
|
|
@@ -15585,11 +15580,11 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15585
15580
|
cleanupTermination();
|
|
15586
15581
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15587
15582
|
if (!agentEndReached && terminal.exitCode !== 0) {
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
|
|
15583
|
+
forwardPiHarnessStreamLine(
|
|
15584
|
+
input,
|
|
15585
|
+
"stderr",
|
|
15586
|
+
`pi-rpc process closed before agent_end with ${formatHarnessExit(terminal)}`
|
|
15587
|
+
);
|
|
15593
15588
|
}
|
|
15594
15589
|
return terminal;
|
|
15595
15590
|
})();
|
|
@@ -15611,37 +15606,57 @@ function handlePiRpcStdoutLine(input) {
|
|
|
15611
15606
|
try {
|
|
15612
15607
|
parsed = JSON.parse(trimmed);
|
|
15613
15608
|
} catch {
|
|
15614
|
-
input.input
|
|
15615
|
-
driver: "pi-rpc",
|
|
15616
|
-
stream: "stdout",
|
|
15617
|
-
message: input.sanitizer.redactText(trimmed)
|
|
15618
|
-
}));
|
|
15609
|
+
forwardPiHarnessStreamLine(input.input, "stdout", input.sanitizer.redactText(trimmed));
|
|
15619
15610
|
return;
|
|
15620
15611
|
}
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15612
|
+
if (isPiRpcResponse(parsed)) {
|
|
15613
|
+
if (parsed.command === "prompt" && parsed.success === false) {
|
|
15614
|
+
input.onPromptRejected(new Error(`Pi RPC prompt was rejected: ${formatPiRpcError(parsed, input.sanitizer.redactText)}`));
|
|
15615
|
+
}
|
|
15616
|
+
return;
|
|
15617
|
+
}
|
|
15618
|
+
if (isPiExtensionUiRequest(parsed)) {
|
|
15619
|
+
forwardPiExtensionUiRequest(input.input, input.sanitizer.redactJson(parsed));
|
|
15628
15620
|
return;
|
|
15629
15621
|
}
|
|
15622
|
+
forwardPiEvent(input.input, input.sanitizer.redactJson(parsed));
|
|
15630
15623
|
if (parsed.type === "agent_end") {
|
|
15631
15624
|
input.onAgentEnd();
|
|
15632
15625
|
}
|
|
15633
15626
|
}
|
|
15634
|
-
function
|
|
15635
|
-
|
|
15627
|
+
function forwardPiEvent(input, event) {
|
|
15628
|
+
input.channel.send(createExecuteTaskRpcNotification("pi.event", {
|
|
15629
|
+
taskId: input.spec.taskId,
|
|
15630
|
+
event
|
|
15631
|
+
}));
|
|
15632
|
+
}
|
|
15633
|
+
function forwardPiExtensionUiRequest(input, request) {
|
|
15634
|
+
input.channel.send(createExecuteTaskRpcNotification("pi.extension_ui_request", {
|
|
15635
|
+
taskId: input.spec.taskId,
|
|
15636
|
+
request
|
|
15637
|
+
}));
|
|
15638
|
+
}
|
|
15639
|
+
function isPiRpcResponse(parsed) {
|
|
15640
|
+
return parsed.type === "response" && typeof parsed.command === "string";
|
|
15641
|
+
}
|
|
15642
|
+
function isPiExtensionUiRequest(parsed) {
|
|
15643
|
+
return parsed.type === "extension_ui_request" && typeof parsed.id === "string";
|
|
15644
|
+
}
|
|
15645
|
+
function forwardPiHarnessStreamLine(input, stream, message) {
|
|
15646
|
+
const trimmed = message.trim();
|
|
15636
15647
|
if (!trimmed) {
|
|
15637
15648
|
return;
|
|
15638
15649
|
}
|
|
15639
|
-
input.channel.send(createExecuteTaskRpcNotification(
|
|
15640
|
-
|
|
15641
|
-
|
|
15650
|
+
input.channel.send(createExecuteTaskRpcNotification(`harness.${stream}`, {
|
|
15651
|
+
taskId: input.spec.taskId,
|
|
15652
|
+
harness: "pi-rpc",
|
|
15653
|
+
stream,
|
|
15642
15654
|
message: trimmed
|
|
15643
15655
|
}));
|
|
15644
15656
|
}
|
|
15657
|
+
function forwardPiStderrLine(input, line, sanitizer) {
|
|
15658
|
+
forwardPiHarnessStreamLine(input, "stderr", sanitizer.redactText(line));
|
|
15659
|
+
}
|
|
15645
15660
|
function writePiRpcCommand(child, command) {
|
|
15646
15661
|
child.stdin.write(`${JSON.stringify(command)}
|
|
15647
15662
|
`);
|
|
@@ -15768,30 +15783,41 @@ async function runTaskAgentRunner(spec, options = {}) {
|
|
|
15768
15783
|
const harness = resolveAgentRunnerHarness(config2, spec.agentRunner);
|
|
15769
15784
|
const channel = await openControlChannel(spec.rpcUrl);
|
|
15770
15785
|
try {
|
|
15771
|
-
channel
|
|
15786
|
+
sendTaskStatus(channel, {
|
|
15772
15787
|
taskId: spec.taskId,
|
|
15773
|
-
|
|
15774
|
-
})
|
|
15788
|
+
status: "running"
|
|
15789
|
+
});
|
|
15775
15790
|
const completion = await runHarnessAndReadCompletion({
|
|
15776
15791
|
spec,
|
|
15777
15792
|
harness,
|
|
15778
15793
|
channel,
|
|
15794
|
+
...spec.timeouts?.taskMs !== void 0 ? { timeoutMs: spec.timeouts.taskMs } : {},
|
|
15779
15795
|
...options.env ? { env: options.env } : {}
|
|
15780
15796
|
});
|
|
15781
|
-
channel
|
|
15797
|
+
sendTaskStatus(channel, {
|
|
15782
15798
|
taskId: spec.taskId,
|
|
15783
15799
|
...completion
|
|
15784
|
-
})
|
|
15800
|
+
});
|
|
15785
15801
|
return completion;
|
|
15802
|
+
} catch (error48) {
|
|
15803
|
+
const completion = createFailedCompletion(error48);
|
|
15804
|
+
await writeTaskCompletion({
|
|
15805
|
+
paths,
|
|
15806
|
+
completion
|
|
15807
|
+
}).catch(() => void 0);
|
|
15808
|
+
try {
|
|
15809
|
+
sendTaskStatus(channel, {
|
|
15810
|
+
taskId: spec.taskId,
|
|
15811
|
+
...completion
|
|
15812
|
+
});
|
|
15813
|
+
} catch {
|
|
15814
|
+
}
|
|
15815
|
+
throw error48;
|
|
15786
15816
|
} finally {
|
|
15787
15817
|
channel.close();
|
|
15788
15818
|
}
|
|
15789
15819
|
} catch (error48) {
|
|
15790
|
-
const completion =
|
|
15791
|
-
status: "failed",
|
|
15792
|
-
summary: error48 instanceof Error ? error48.message : String(error48),
|
|
15793
|
-
artifactIds: []
|
|
15794
|
-
};
|
|
15820
|
+
const completion = createFailedCompletion(error48);
|
|
15795
15821
|
await writeTaskCompletion({
|
|
15796
15822
|
paths,
|
|
15797
15823
|
completion
|
|
@@ -15799,6 +15825,16 @@ async function runTaskAgentRunner(spec, options = {}) {
|
|
|
15799
15825
|
throw error48;
|
|
15800
15826
|
}
|
|
15801
15827
|
}
|
|
15828
|
+
function sendTaskStatus(channel, params) {
|
|
15829
|
+
channel.send(createExecuteTaskRpcNotification("task.status", params));
|
|
15830
|
+
}
|
|
15831
|
+
function createFailedCompletion(error48) {
|
|
15832
|
+
return {
|
|
15833
|
+
status: "failed",
|
|
15834
|
+
summary: error48 instanceof Error ? error48.message : String(error48),
|
|
15835
|
+
artifactIds: []
|
|
15836
|
+
};
|
|
15837
|
+
}
|
|
15802
15838
|
function createHarnessEnvironment(input) {
|
|
15803
15839
|
const baseEnv = input.env ?? process.env;
|
|
15804
15840
|
const harnessEnv = {};
|
|
@@ -15893,7 +15929,28 @@ async function runHarnessAndReadCompletion(input) {
|
|
|
15893
15929
|
...input.env ? { env: input.env } : {}
|
|
15894
15930
|
})
|
|
15895
15931
|
});
|
|
15896
|
-
const result = await
|
|
15932
|
+
const result = await waitForHarnessResult({
|
|
15933
|
+
run: activeRun,
|
|
15934
|
+
...input.timeoutMs !== void 0 ? { timeoutMs: input.timeoutMs } : {}
|
|
15935
|
+
});
|
|
15936
|
+
if (result === "timeout") {
|
|
15937
|
+
activeRun.cancel();
|
|
15938
|
+
await waitForHarnessCleanup(activeRun.result);
|
|
15939
|
+
const recovered = await readTaskCompletion(paths).catch(() => void 0);
|
|
15940
|
+
if (recovered) {
|
|
15941
|
+
await validateTaskArtifactFiles({
|
|
15942
|
+
paths,
|
|
15943
|
+
completion: recovered
|
|
15944
|
+
});
|
|
15945
|
+
return recovered;
|
|
15946
|
+
}
|
|
15947
|
+
const completion2 = createTimeoutCompletion(input.timeoutMs);
|
|
15948
|
+
await writeTaskCompletion({
|
|
15949
|
+
paths,
|
|
15950
|
+
completion: completion2
|
|
15951
|
+
});
|
|
15952
|
+
return completion2;
|
|
15953
|
+
}
|
|
15897
15954
|
if (cancelRequested) {
|
|
15898
15955
|
const completion2 = {
|
|
15899
15956
|
status: "cancelled",
|
|
@@ -15906,7 +15963,14 @@ async function runHarnessAndReadCompletion(input) {
|
|
|
15906
15963
|
});
|
|
15907
15964
|
return completion2;
|
|
15908
15965
|
}
|
|
15909
|
-
const completion = await readTaskCompletion(paths)
|
|
15966
|
+
const completion = await readTaskCompletion(paths).catch(async (error48) => {
|
|
15967
|
+
const fallback = createMissingCompletionFailure(error48);
|
|
15968
|
+
await writeTaskCompletion({
|
|
15969
|
+
paths,
|
|
15970
|
+
completion: fallback
|
|
15971
|
+
});
|
|
15972
|
+
return fallback;
|
|
15973
|
+
});
|
|
15910
15974
|
await validateTaskArtifactFiles({
|
|
15911
15975
|
paths,
|
|
15912
15976
|
completion
|
|
@@ -15916,6 +15980,46 @@ async function runHarnessAndReadCompletion(input) {
|
|
|
15916
15980
|
}
|
|
15917
15981
|
return completion;
|
|
15918
15982
|
}
|
|
15983
|
+
async function waitForHarnessResult(input) {
|
|
15984
|
+
const timeoutMs = normalizeTimeoutMs(input.timeoutMs);
|
|
15985
|
+
if (timeoutMs === void 0) {
|
|
15986
|
+
return input.run.result;
|
|
15987
|
+
}
|
|
15988
|
+
let timer;
|
|
15989
|
+
try {
|
|
15990
|
+
return await Promise.race([
|
|
15991
|
+
input.run.result,
|
|
15992
|
+
new Promise((resolve2) => {
|
|
15993
|
+
timer = setTimeout(() => resolve2("timeout"), timeoutMs);
|
|
15994
|
+
})
|
|
15995
|
+
]);
|
|
15996
|
+
} finally {
|
|
15997
|
+
if (timer) {
|
|
15998
|
+
clearTimeout(timer);
|
|
15999
|
+
}
|
|
16000
|
+
}
|
|
16001
|
+
}
|
|
16002
|
+
async function waitForHarnessCleanup(result) {
|
|
16003
|
+
await Promise.race([
|
|
16004
|
+
result.catch(() => void 0),
|
|
16005
|
+
sleep(1e4)
|
|
16006
|
+
]);
|
|
16007
|
+
}
|
|
16008
|
+
function createTimeoutCompletion(timeoutMs) {
|
|
16009
|
+
return {
|
|
16010
|
+
status: "failed",
|
|
16011
|
+
summary: timeoutMs === void 0 ? "execute_task harness timed out" : `execute_task harness timed out after ${timeoutMs}ms`,
|
|
16012
|
+
artifactIds: []
|
|
16013
|
+
};
|
|
16014
|
+
}
|
|
16015
|
+
function createMissingCompletionFailure(error48) {
|
|
16016
|
+
const detail = error48 instanceof Error ? error48.message : String(error48);
|
|
16017
|
+
return {
|
|
16018
|
+
status: "failed",
|
|
16019
|
+
summary: `harness ended without writing state/completion.json: ${detail}`,
|
|
16020
|
+
artifactIds: []
|
|
16021
|
+
};
|
|
16022
|
+
}
|
|
15919
16023
|
function validateRunnerSpec(spec) {
|
|
15920
16024
|
if ("harness" in spec) {
|
|
15921
16025
|
throw new Error("task spec harness is no longer supported; use task spec agentRunner");
|
|
@@ -15929,6 +16033,9 @@ function validateRunnerSpec(spec) {
|
|
|
15929
16033
|
if (!spec.rpcUrl?.trim()) {
|
|
15930
16034
|
throw new Error("task spec rpcUrl is required");
|
|
15931
16035
|
}
|
|
16036
|
+
if (spec.timeouts?.taskMs !== void 0 && normalizeTimeoutMs(spec.timeouts.taskMs) === void 0) {
|
|
16037
|
+
throw new Error("task spec timeouts.taskMs must be a positive finite number");
|
|
16038
|
+
}
|
|
15932
16039
|
if (spec.agentRunner?.harness !== void 0 && typeof spec.agentRunner.harness !== "string") {
|
|
15933
16040
|
throw new Error("task spec agentRunner.harness must be a string");
|
|
15934
16041
|
}
|
|
@@ -15941,6 +16048,14 @@ function validateRunnerSpec(spec) {
|
|
|
15941
16048
|
}
|
|
15942
16049
|
assertNoForbiddenSpecKeys(spec);
|
|
15943
16050
|
}
|
|
16051
|
+
function normalizeTimeoutMs(value) {
|
|
16052
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
16053
|
+
}
|
|
16054
|
+
function sleep(ms) {
|
|
16055
|
+
return new Promise((resolve2) => {
|
|
16056
|
+
setTimeout(resolve2, ms);
|
|
16057
|
+
});
|
|
16058
|
+
}
|
|
15944
16059
|
async function openControlChannel(url2) {
|
|
15945
16060
|
const WebSocketCtor = globalThis.WebSocket;
|
|
15946
16061
|
if (!WebSocketCtor) {
|
|
@@ -16063,11 +16178,20 @@ if (isEntrypoint(import.meta.url)) {
|
|
|
16063
16178
|
process.exitCode = 1;
|
|
16064
16179
|
});
|
|
16065
16180
|
}
|
|
16066
|
-
function isEntrypoint(moduleUrl) {
|
|
16067
|
-
return
|
|
16181
|
+
function isEntrypoint(moduleUrl, argvPath = process.argv[1]) {
|
|
16182
|
+
return argvPath ? realpathEntrypointPath(fileURLToPath(moduleUrl)) === realpathEntrypointPath(argvPath) : false;
|
|
16183
|
+
}
|
|
16184
|
+
function realpathEntrypointPath(path) {
|
|
16185
|
+
const resolved = resolve(path);
|
|
16186
|
+
try {
|
|
16187
|
+
return realpathSync.native(resolved);
|
|
16188
|
+
} catch {
|
|
16189
|
+
return resolved;
|
|
16190
|
+
}
|
|
16068
16191
|
}
|
|
16069
16192
|
export {
|
|
16070
16193
|
formatHelp,
|
|
16194
|
+
isEntrypoint,
|
|
16071
16195
|
main,
|
|
16072
16196
|
readConfigPathArg,
|
|
16073
16197
|
readTaskSpecArg,
|