@liy/agent-runner 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/bin/agent-runner.d.ts +8 -0
- package/dist/bin/agent-runner.js +110 -52
- 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 +98 -50
- package/dist/index.js.map +2 -2
- package/package.json +7 -3
|
@@ -1,5 +1,115 @@
|
|
|
1
|
+
import type { AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
1
2
|
import type { ResolvedAgentRunnerHarnessConfig } from "../config.js";
|
|
2
3
|
import type { HarnessSpawn, TaskAgentHarnessDriver } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Pi extension runtime error event emitted by RPC mode.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Pi 0.74.0 emits this record from RPC mode but does not include it in the
|
|
9
|
+
* exported `AgentSessionEvent` union. Keep it structural so downstream Mote UI
|
|
10
|
+
* code can still switch on the upstream `extension_error` spelling.
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export interface PiExtensionErrorEvent {
|
|
15
|
+
/**
|
|
16
|
+
* Upstream Pi event discriminator.
|
|
17
|
+
*/
|
|
18
|
+
type: "extension_error";
|
|
19
|
+
/**
|
|
20
|
+
* Extension file path that raised the error.
|
|
21
|
+
*/
|
|
22
|
+
extensionPath: string;
|
|
23
|
+
/**
|
|
24
|
+
* Extension event name being handled when the error occurred.
|
|
25
|
+
*/
|
|
26
|
+
event: string;
|
|
27
|
+
/**
|
|
28
|
+
* Human-readable extension error text.
|
|
29
|
+
*/
|
|
30
|
+
error: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Native Pi event forwarded by the Pi RPC harness driver.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export type PiEvent = AgentSessionEvent | PiExtensionErrorEvent;
|
|
38
|
+
/**
|
|
39
|
+
* Native Pi assistant-message stream event.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export type PiAssistantMessageEvent = Extract<PiEvent, {
|
|
44
|
+
type: "message_update";
|
|
45
|
+
}>["assistantMessageEvent"];
|
|
46
|
+
/**
|
|
47
|
+
* Structural copy of Pi RPC extension UI requests.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* The Pi package exports this type from an internal path in 0.74.0 but not from
|
|
51
|
+
* its public package root. Mote forwards the request opaquely and does not
|
|
52
|
+
* implement response handling in this pass.
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
56
|
+
export type PiExtensionUiRequest = {
|
|
57
|
+
type: "extension_ui_request";
|
|
58
|
+
id: string;
|
|
59
|
+
method: "select";
|
|
60
|
+
title: string;
|
|
61
|
+
options: string[];
|
|
62
|
+
timeout?: number;
|
|
63
|
+
} | {
|
|
64
|
+
type: "extension_ui_request";
|
|
65
|
+
id: string;
|
|
66
|
+
method: "confirm";
|
|
67
|
+
title: string;
|
|
68
|
+
message: string;
|
|
69
|
+
timeout?: number;
|
|
70
|
+
} | {
|
|
71
|
+
type: "extension_ui_request";
|
|
72
|
+
id: string;
|
|
73
|
+
method: "input";
|
|
74
|
+
title: string;
|
|
75
|
+
placeholder?: string;
|
|
76
|
+
timeout?: number;
|
|
77
|
+
} | {
|
|
78
|
+
type: "extension_ui_request";
|
|
79
|
+
id: string;
|
|
80
|
+
method: "editor";
|
|
81
|
+
title: string;
|
|
82
|
+
prefill?: string;
|
|
83
|
+
} | {
|
|
84
|
+
type: "extension_ui_request";
|
|
85
|
+
id: string;
|
|
86
|
+
method: "notify";
|
|
87
|
+
message: string;
|
|
88
|
+
notifyType?: "info" | "warning" | "error";
|
|
89
|
+
} | {
|
|
90
|
+
type: "extension_ui_request";
|
|
91
|
+
id: string;
|
|
92
|
+
method: "setStatus";
|
|
93
|
+
statusKey: string;
|
|
94
|
+
statusText: string | undefined;
|
|
95
|
+
} | {
|
|
96
|
+
type: "extension_ui_request";
|
|
97
|
+
id: string;
|
|
98
|
+
method: "setWidget";
|
|
99
|
+
widgetKey: string;
|
|
100
|
+
widgetLines: string[] | undefined;
|
|
101
|
+
widgetPlacement?: "aboveEditor" | "belowEditor";
|
|
102
|
+
} | {
|
|
103
|
+
type: "extension_ui_request";
|
|
104
|
+
id: string;
|
|
105
|
+
method: "setTitle";
|
|
106
|
+
title: string;
|
|
107
|
+
} | {
|
|
108
|
+
type: "extension_ui_request";
|
|
109
|
+
id: string;
|
|
110
|
+
method: "set_editor_text";
|
|
111
|
+
text: string;
|
|
112
|
+
};
|
|
3
113
|
/**
|
|
4
114
|
* Create the Pi RPC driver adapter.
|
|
5
115
|
*
|
|
@@ -63,15 +63,16 @@ export declare class JsonlByteBufferParser {
|
|
|
63
63
|
*/
|
|
64
64
|
export declare function forwardJsonlByteStream(stream: Readable, onLine: (line: string) => void): Promise<void>;
|
|
65
65
|
/**
|
|
66
|
-
* Forward one generic harness output line as
|
|
66
|
+
* Forward one generic harness output line as redacted subprocess stream text.
|
|
67
67
|
*
|
|
68
68
|
* @param channel - Connected control channel.
|
|
69
|
+
* @param taskId - Runtime task id for control-channel correlation.
|
|
70
|
+
* @param harness - Harness driver id that produced the line.
|
|
69
71
|
* @param line - Raw harness output line.
|
|
70
72
|
* @param streamName - Source stream name.
|
|
71
73
|
* @param sanitizer - Output sanitizer.
|
|
72
|
-
* @param driver - Optional driver id to include in forwarded payloads.
|
|
73
74
|
*/
|
|
74
|
-
export declare function forwardHarnessLine(channel: ControlChannel, line: string, streamName: "stdout" | "stderr", sanitizer: HarnessOutputSanitizer
|
|
75
|
+
export declare function forwardHarnessLine(channel: ControlChannel, taskId: string, harness: string, line: string, streamName: "stdout" | "stderr", sanitizer: HarnessOutputSanitizer): void;
|
|
75
76
|
/**
|
|
76
77
|
* Wait for one child process to close.
|
|
77
78
|
*
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire as ___liy_agent_runnerCreateRequire } from "node:module";var require = ___liy_agent_runnerCreateRequire(import.meta.url);
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __export = (target, all) => {
|
|
3
4
|
for (var name in all)
|
|
@@ -15511,25 +15512,17 @@ function forwardJsonlByteStream(stream, onLine) {
|
|
|
15511
15512
|
});
|
|
15512
15513
|
});
|
|
15513
15514
|
}
|
|
15514
|
-
function forwardHarnessLine(channel, line, streamName, sanitizer
|
|
15515
|
+
function forwardHarnessLine(channel, taskId, harness, line, streamName, sanitizer) {
|
|
15515
15516
|
const trimmed = sanitizer.redactText(line.trim());
|
|
15516
15517
|
if (!trimmed) {
|
|
15517
15518
|
return;
|
|
15518
15519
|
}
|
|
15519
|
-
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
}));
|
|
15526
|
-
} catch {
|
|
15527
|
-
channel.send(createExecuteTaskRpcNotification("task.log", {
|
|
15528
|
-
...driver ? { driver } : {},
|
|
15529
|
-
stream: streamName,
|
|
15530
|
-
message: trimmed
|
|
15531
|
-
}));
|
|
15532
|
-
}
|
|
15520
|
+
channel.send(createExecuteTaskRpcNotification(`harness.${streamName}`, {
|
|
15521
|
+
taskId,
|
|
15522
|
+
harness,
|
|
15523
|
+
stream: streamName,
|
|
15524
|
+
message: trimmed
|
|
15525
|
+
}));
|
|
15533
15526
|
}
|
|
15534
15527
|
function waitForChildClose(child) {
|
|
15535
15528
|
return new Promise((resolve, reject) => {
|
|
@@ -15609,10 +15602,10 @@ function startCodexJsonlHarness(input, spawnProcess) {
|
|
|
15609
15602
|
let cleanupTermination = () => void 0;
|
|
15610
15603
|
child.stdin.end(input.prompt);
|
|
15611
15604
|
const stdoutDone = forwardHarnessLines(child.stdout, (line) => {
|
|
15612
|
-
forwardHarnessLine(input.channel, line, "stdout", sanitizer);
|
|
15605
|
+
forwardHarnessLine(input.channel, input.spec.taskId, "codex-jsonl", line, "stdout", sanitizer);
|
|
15613
15606
|
});
|
|
15614
15607
|
const stderrDone = forwardHarnessLines(child.stderr, (line) => {
|
|
15615
|
-
forwardHarnessLine(input.channel, line, "stderr", sanitizer);
|
|
15608
|
+
forwardHarnessLine(input.channel, input.spec.taskId, "codex-jsonl", line, "stderr", sanitizer);
|
|
15616
15609
|
});
|
|
15617
15610
|
const result = waitForChildClose(child).then(async (closeResult) => {
|
|
15618
15611
|
cleanupTermination();
|
|
@@ -15762,11 +15755,11 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15762
15755
|
cleanupTermination();
|
|
15763
15756
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15764
15757
|
if (!agentEndReached && terminal.exitCode !== 0) {
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15758
|
+
forwardPiHarnessStreamLine(
|
|
15759
|
+
input,
|
|
15760
|
+
"stderr",
|
|
15761
|
+
`pi-rpc process closed before agent_end with ${formatHarnessExit(terminal)}`
|
|
15762
|
+
);
|
|
15770
15763
|
}
|
|
15771
15764
|
return terminal;
|
|
15772
15765
|
})();
|
|
@@ -15788,37 +15781,57 @@ function handlePiRpcStdoutLine(input) {
|
|
|
15788
15781
|
try {
|
|
15789
15782
|
parsed = JSON.parse(trimmed);
|
|
15790
15783
|
} catch {
|
|
15791
|
-
input.input
|
|
15792
|
-
driver: "pi-rpc",
|
|
15793
|
-
stream: "stdout",
|
|
15794
|
-
message: input.sanitizer.redactText(trimmed)
|
|
15795
|
-
}));
|
|
15784
|
+
forwardPiHarnessStreamLine(input.input, "stdout", input.sanitizer.redactText(trimmed));
|
|
15796
15785
|
return;
|
|
15797
15786
|
}
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15787
|
+
if (isPiRpcResponse(parsed)) {
|
|
15788
|
+
if (parsed.command === "prompt" && parsed.success === false) {
|
|
15789
|
+
input.onPromptRejected(new Error(`Pi RPC prompt was rejected: ${formatPiRpcError(parsed, input.sanitizer.redactText)}`));
|
|
15790
|
+
}
|
|
15791
|
+
return;
|
|
15792
|
+
}
|
|
15793
|
+
if (isPiExtensionUiRequest(parsed)) {
|
|
15794
|
+
forwardPiExtensionUiRequest(input.input, input.sanitizer.redactJson(parsed));
|
|
15805
15795
|
return;
|
|
15806
15796
|
}
|
|
15797
|
+
forwardPiEvent(input.input, input.sanitizer.redactJson(parsed));
|
|
15807
15798
|
if (parsed.type === "agent_end") {
|
|
15808
15799
|
input.onAgentEnd();
|
|
15809
15800
|
}
|
|
15810
15801
|
}
|
|
15811
|
-
function
|
|
15812
|
-
|
|
15802
|
+
function forwardPiEvent(input, event) {
|
|
15803
|
+
input.channel.send(createExecuteTaskRpcNotification("pi.event", {
|
|
15804
|
+
taskId: input.spec.taskId,
|
|
15805
|
+
event
|
|
15806
|
+
}));
|
|
15807
|
+
}
|
|
15808
|
+
function forwardPiExtensionUiRequest(input, request) {
|
|
15809
|
+
input.channel.send(createExecuteTaskRpcNotification("pi.extension_ui_request", {
|
|
15810
|
+
taskId: input.spec.taskId,
|
|
15811
|
+
request
|
|
15812
|
+
}));
|
|
15813
|
+
}
|
|
15814
|
+
function isPiRpcResponse(parsed) {
|
|
15815
|
+
return parsed.type === "response" && typeof parsed.command === "string";
|
|
15816
|
+
}
|
|
15817
|
+
function isPiExtensionUiRequest(parsed) {
|
|
15818
|
+
return parsed.type === "extension_ui_request" && typeof parsed.id === "string";
|
|
15819
|
+
}
|
|
15820
|
+
function forwardPiHarnessStreamLine(input, stream, message) {
|
|
15821
|
+
const trimmed = message.trim();
|
|
15813
15822
|
if (!trimmed) {
|
|
15814
15823
|
return;
|
|
15815
15824
|
}
|
|
15816
|
-
input.channel.send(createExecuteTaskRpcNotification(
|
|
15817
|
-
|
|
15818
|
-
|
|
15825
|
+
input.channel.send(createExecuteTaskRpcNotification(`harness.${stream}`, {
|
|
15826
|
+
taskId: input.spec.taskId,
|
|
15827
|
+
harness: "pi-rpc",
|
|
15828
|
+
stream,
|
|
15819
15829
|
message: trimmed
|
|
15820
15830
|
}));
|
|
15821
15831
|
}
|
|
15832
|
+
function forwardPiStderrLine(input, line, sanitizer) {
|
|
15833
|
+
forwardPiHarnessStreamLine(input, "stderr", sanitizer.redactText(line));
|
|
15834
|
+
}
|
|
15822
15835
|
function writePiRpcCommand(child, command) {
|
|
15823
15836
|
child.stdin.write(`${JSON.stringify(command)}
|
|
15824
15837
|
`);
|
|
@@ -15876,30 +15889,40 @@ async function runTaskAgentRunner(spec, options = {}) {
|
|
|
15876
15889
|
const harness = resolveAgentRunnerHarness(config2, spec.agentRunner);
|
|
15877
15890
|
const channel = await openControlChannel(spec.rpcUrl);
|
|
15878
15891
|
try {
|
|
15879
|
-
channel
|
|
15892
|
+
sendTaskStatus(channel, {
|
|
15880
15893
|
taskId: spec.taskId,
|
|
15881
|
-
|
|
15882
|
-
})
|
|
15894
|
+
status: "running"
|
|
15895
|
+
});
|
|
15883
15896
|
const completion = await runHarnessAndReadCompletion({
|
|
15884
15897
|
spec,
|
|
15885
15898
|
harness,
|
|
15886
15899
|
channel,
|
|
15887
15900
|
...options.env ? { env: options.env } : {}
|
|
15888
15901
|
});
|
|
15889
|
-
channel
|
|
15902
|
+
sendTaskStatus(channel, {
|
|
15890
15903
|
taskId: spec.taskId,
|
|
15891
15904
|
...completion
|
|
15892
|
-
})
|
|
15905
|
+
});
|
|
15893
15906
|
return completion;
|
|
15907
|
+
} catch (error48) {
|
|
15908
|
+
const completion = createFailedCompletion(error48);
|
|
15909
|
+
await writeTaskCompletion({
|
|
15910
|
+
paths,
|
|
15911
|
+
completion
|
|
15912
|
+
}).catch(() => void 0);
|
|
15913
|
+
try {
|
|
15914
|
+
sendTaskStatus(channel, {
|
|
15915
|
+
taskId: spec.taskId,
|
|
15916
|
+
...completion
|
|
15917
|
+
});
|
|
15918
|
+
} catch {
|
|
15919
|
+
}
|
|
15920
|
+
throw error48;
|
|
15894
15921
|
} finally {
|
|
15895
15922
|
channel.close();
|
|
15896
15923
|
}
|
|
15897
15924
|
} catch (error48) {
|
|
15898
|
-
const completion =
|
|
15899
|
-
status: "failed",
|
|
15900
|
-
summary: error48 instanceof Error ? error48.message : String(error48),
|
|
15901
|
-
artifactIds: []
|
|
15902
|
-
};
|
|
15925
|
+
const completion = createFailedCompletion(error48);
|
|
15903
15926
|
await writeTaskCompletion({
|
|
15904
15927
|
paths,
|
|
15905
15928
|
completion
|
|
@@ -15907,6 +15930,16 @@ async function runTaskAgentRunner(spec, options = {}) {
|
|
|
15907
15930
|
throw error48;
|
|
15908
15931
|
}
|
|
15909
15932
|
}
|
|
15933
|
+
function sendTaskStatus(channel, params) {
|
|
15934
|
+
channel.send(createExecuteTaskRpcNotification("task.status", params));
|
|
15935
|
+
}
|
|
15936
|
+
function createFailedCompletion(error48) {
|
|
15937
|
+
return {
|
|
15938
|
+
status: "failed",
|
|
15939
|
+
summary: error48 instanceof Error ? error48.message : String(error48),
|
|
15940
|
+
artifactIds: []
|
|
15941
|
+
};
|
|
15942
|
+
}
|
|
15910
15943
|
function createHarnessEnvironment(input) {
|
|
15911
15944
|
const baseEnv = input.env ?? process.env;
|
|
15912
15945
|
const harnessEnv = {};
|
|
@@ -16014,7 +16047,14 @@ async function runHarnessAndReadCompletion(input) {
|
|
|
16014
16047
|
});
|
|
16015
16048
|
return completion2;
|
|
16016
16049
|
}
|
|
16017
|
-
const completion = await readTaskCompletion(paths)
|
|
16050
|
+
const completion = await readTaskCompletion(paths).catch(async (error48) => {
|
|
16051
|
+
const fallback = createMissingCompletionFailure(error48);
|
|
16052
|
+
await writeTaskCompletion({
|
|
16053
|
+
paths,
|
|
16054
|
+
completion: fallback
|
|
16055
|
+
});
|
|
16056
|
+
return fallback;
|
|
16057
|
+
});
|
|
16018
16058
|
await validateTaskArtifactFiles({
|
|
16019
16059
|
paths,
|
|
16020
16060
|
completion
|
|
@@ -16024,6 +16064,14 @@ async function runHarnessAndReadCompletion(input) {
|
|
|
16024
16064
|
}
|
|
16025
16065
|
return completion;
|
|
16026
16066
|
}
|
|
16067
|
+
function createMissingCompletionFailure(error48) {
|
|
16068
|
+
const detail = error48 instanceof Error ? error48.message : String(error48);
|
|
16069
|
+
return {
|
|
16070
|
+
status: "failed",
|
|
16071
|
+
summary: `harness ended without writing state/completion.json: ${detail}`,
|
|
16072
|
+
artifactIds: []
|
|
16073
|
+
};
|
|
16074
|
+
}
|
|
16027
16075
|
function validateRunnerSpec(spec) {
|
|
16028
16076
|
if ("harness" in spec) {
|
|
16029
16077
|
throw new Error("task spec harness is no longer supported; use task spec agentRunner");
|