@liy/agent-runner 0.2.7 → 0.3.2
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/bin/agent-runner.js +192 -20
- package/dist/bin/agent-runner.js.map +4 -4
- package/dist/debug/pi-rpc-trace.d.ts +54 -0
- package/dist/index.js +183 -11
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One bounded Pi RPC trace record written to a task-local debug JSONL file.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export interface PiRpcTraceEvent {
|
|
7
|
+
/**
|
|
8
|
+
* Stable trace event name, such as `prompt.sent` or `stdout.event`.
|
|
9
|
+
*/
|
|
10
|
+
kind: string;
|
|
11
|
+
/**
|
|
12
|
+
* Direction or process stream that produced the event.
|
|
13
|
+
*/
|
|
14
|
+
stream?: "stdin" | "stdout" | "stderr" | "process";
|
|
15
|
+
/**
|
|
16
|
+
* Redacted trace payload. Large payloads are replaced with a preview before
|
|
17
|
+
* they are written.
|
|
18
|
+
*/
|
|
19
|
+
payload?: unknown;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Append-only task-local Pi RPC trace writer.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export interface PiRpcTrace {
|
|
27
|
+
/**
|
|
28
|
+
* Absolute path to the trace file when it was opened successfully.
|
|
29
|
+
*/
|
|
30
|
+
filePath?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Append one redacted trace record.
|
|
33
|
+
*
|
|
34
|
+
* @param event - Trace event to serialize as one JSONL record.
|
|
35
|
+
*/
|
|
36
|
+
write(event: PiRpcTraceEvent): void;
|
|
37
|
+
/**
|
|
38
|
+
* Flush and close the trace file.
|
|
39
|
+
*/
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a Pi RPC trace writer under the task workspace debug directory.
|
|
44
|
+
*
|
|
45
|
+
* @param input - Task identity and workspace location.
|
|
46
|
+
* @returns Writable trace, or a no-op trace when the debug file cannot open.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export declare function createPiRpcTrace(input: {
|
|
51
|
+
taskId: string;
|
|
52
|
+
workspaceDir: string;
|
|
53
|
+
now?: () => Date;
|
|
54
|
+
}): PiRpcTrace;
|
package/dist/index.js
CHANGED
|
@@ -15079,7 +15079,7 @@ var QuerySchema = external_exports.object({
|
|
|
15079
15079
|
limit: external_exports.number().int().positive().max(1e4).default(1e3),
|
|
15080
15080
|
accessLevel: AccessLevelSchema.default("serving")
|
|
15081
15081
|
}).superRefine((query, ctx) => {
|
|
15082
|
-
const surfaces = [query.from.surface, ...query.joins.map((
|
|
15082
|
+
const surfaces = [query.from.surface, ...query.joins.map((join3) => join3.surface)];
|
|
15083
15083
|
const knownSurfaces = /* @__PURE__ */ new Set();
|
|
15084
15084
|
for (const [index, surface] of surfaces.entries()) {
|
|
15085
15085
|
if (knownSurfaces.has(surface)) {
|
|
@@ -15114,8 +15114,8 @@ var QuerySchema = external_exports.object({
|
|
|
15114
15114
|
path: ["time", "bucket", "fn"]
|
|
15115
15115
|
});
|
|
15116
15116
|
}
|
|
15117
|
-
for (const [index,
|
|
15118
|
-
visitConditionFields(
|
|
15117
|
+
for (const [index, join3] of query.joins.entries()) {
|
|
15118
|
+
visitConditionFields(join3.on, (field) => {
|
|
15119
15119
|
validateFieldRef(field, ["joins", index, "on"]);
|
|
15120
15120
|
});
|
|
15121
15121
|
}
|
|
@@ -15632,6 +15632,92 @@ async function forwardHarnessLines(stream, handler) {
|
|
|
15632
15632
|
|
|
15633
15633
|
// src/harness-drivers/pi-rpc.ts
|
|
15634
15634
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
15635
|
+
|
|
15636
|
+
// src/debug/pi-rpc-trace.ts
|
|
15637
|
+
import { once } from "node:events";
|
|
15638
|
+
import { createWriteStream, mkdirSync } from "node:fs";
|
|
15639
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
15640
|
+
var MAX_TRACE_LINE_BYTES = 16384;
|
|
15641
|
+
var MAX_TRACE_PREVIEW_CHARS = 8e3;
|
|
15642
|
+
function createPiRpcTrace(input) {
|
|
15643
|
+
const filePath = join2(input.workspaceDir, "debug", "pi-rpc.jsonl");
|
|
15644
|
+
try {
|
|
15645
|
+
mkdirSync(dirname2(filePath), { recursive: true });
|
|
15646
|
+
const stream = createWriteStream(filePath, {
|
|
15647
|
+
flags: "a",
|
|
15648
|
+
mode: 384
|
|
15649
|
+
});
|
|
15650
|
+
return createStreamTrace({
|
|
15651
|
+
filePath,
|
|
15652
|
+
stream,
|
|
15653
|
+
taskId: input.taskId,
|
|
15654
|
+
now: input.now ?? (() => /* @__PURE__ */ new Date())
|
|
15655
|
+
});
|
|
15656
|
+
} catch {
|
|
15657
|
+
return createNoopTrace();
|
|
15658
|
+
}
|
|
15659
|
+
}
|
|
15660
|
+
function createStreamTrace(input) {
|
|
15661
|
+
let closed = false;
|
|
15662
|
+
let failed = false;
|
|
15663
|
+
input.stream.on("error", () => {
|
|
15664
|
+
failed = true;
|
|
15665
|
+
});
|
|
15666
|
+
return {
|
|
15667
|
+
filePath: input.filePath,
|
|
15668
|
+
write(event) {
|
|
15669
|
+
if (closed || failed) {
|
|
15670
|
+
return;
|
|
15671
|
+
}
|
|
15672
|
+
input.stream.write(serializeTraceRecord({
|
|
15673
|
+
ts: input.now().toISOString(),
|
|
15674
|
+
taskId: input.taskId,
|
|
15675
|
+
...event
|
|
15676
|
+
}));
|
|
15677
|
+
},
|
|
15678
|
+
async close() {
|
|
15679
|
+
if (closed) {
|
|
15680
|
+
return;
|
|
15681
|
+
}
|
|
15682
|
+
closed = true;
|
|
15683
|
+
if (failed) {
|
|
15684
|
+
return;
|
|
15685
|
+
}
|
|
15686
|
+
input.stream.end();
|
|
15687
|
+
await once(input.stream, "finish").then(() => void 0, () => void 0);
|
|
15688
|
+
}
|
|
15689
|
+
};
|
|
15690
|
+
}
|
|
15691
|
+
function createNoopTrace() {
|
|
15692
|
+
return {
|
|
15693
|
+
write() {
|
|
15694
|
+
},
|
|
15695
|
+
async close() {
|
|
15696
|
+
}
|
|
15697
|
+
};
|
|
15698
|
+
}
|
|
15699
|
+
function serializeTraceRecord(record2) {
|
|
15700
|
+
const line = `${JSON.stringify(record2)}
|
|
15701
|
+
`;
|
|
15702
|
+
if (Buffer.byteLength(line, "utf8") <= MAX_TRACE_LINE_BYTES) {
|
|
15703
|
+
return line;
|
|
15704
|
+
}
|
|
15705
|
+
return `${JSON.stringify({
|
|
15706
|
+
...record2,
|
|
15707
|
+
truncated: true,
|
|
15708
|
+
payload: previewPayload(record2.payload)
|
|
15709
|
+
})}
|
|
15710
|
+
`;
|
|
15711
|
+
}
|
|
15712
|
+
function previewPayload(payload) {
|
|
15713
|
+
const text = typeof payload === "string" ? payload : JSON.stringify(payload) ?? "undefined";
|
|
15714
|
+
if (text.length <= MAX_TRACE_PREVIEW_CHARS) {
|
|
15715
|
+
return text;
|
|
15716
|
+
}
|
|
15717
|
+
return `${text.slice(0, MAX_TRACE_PREVIEW_CHARS)}...[truncated]`;
|
|
15718
|
+
}
|
|
15719
|
+
|
|
15720
|
+
// src/harness-drivers/pi-rpc.ts
|
|
15635
15721
|
var driverOwnedPiFlags = /* @__PURE__ */ new Set([
|
|
15636
15722
|
"--mode",
|
|
15637
15723
|
"--provider",
|
|
@@ -15689,7 +15775,8 @@ function buildPiRpcArgs(harness) {
|
|
|
15689
15775
|
}
|
|
15690
15776
|
function startPiRpcHarness(input, spawnProcess) {
|
|
15691
15777
|
const harness = input.harness;
|
|
15692
|
-
const
|
|
15778
|
+
const args = buildPiRpcArgs(harness);
|
|
15779
|
+
const child = spawnProcess(harness.command, args, {
|
|
15693
15780
|
cwd: input.spec.workspaceDir,
|
|
15694
15781
|
env: input.env,
|
|
15695
15782
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -15697,6 +15784,19 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15697
15784
|
const sanitizer = createHarnessOutputSanitizer(input.env, [
|
|
15698
15785
|
...input.harness.secretEnv ?? []
|
|
15699
15786
|
]);
|
|
15787
|
+
const trace = createPiRpcTrace({
|
|
15788
|
+
taskId: input.spec.taskId,
|
|
15789
|
+
workspaceDir: input.spec.workspaceDir
|
|
15790
|
+
});
|
|
15791
|
+
trace.write({
|
|
15792
|
+
kind: "process.started",
|
|
15793
|
+
stream: "process",
|
|
15794
|
+
payload: {
|
|
15795
|
+
command: harness.command,
|
|
15796
|
+
args,
|
|
15797
|
+
cwd: input.spec.workspaceDir
|
|
15798
|
+
}
|
|
15799
|
+
});
|
|
15700
15800
|
let cleanupTermination = () => void 0;
|
|
15701
15801
|
let agentEndReached = false;
|
|
15702
15802
|
let resolveAgentEnd = () => void 0;
|
|
@@ -15713,6 +15813,7 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15713
15813
|
input,
|
|
15714
15814
|
line,
|
|
15715
15815
|
sanitizer,
|
|
15816
|
+
trace,
|
|
15716
15817
|
onAgentEnd() {
|
|
15717
15818
|
agentEndReached = true;
|
|
15718
15819
|
resolveAgentEnd("agent-end");
|
|
@@ -15723,20 +15824,36 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15723
15824
|
});
|
|
15724
15825
|
});
|
|
15725
15826
|
const stderrDone = forwardJsonlByteStream(child.stderr, (line) => {
|
|
15726
|
-
forwardPiStderrLine(input, line, sanitizer);
|
|
15827
|
+
forwardPiStderrLine(input, line, sanitizer, trace);
|
|
15727
15828
|
});
|
|
15728
|
-
|
|
15829
|
+
const promptCommand = {
|
|
15729
15830
|
id: `mote-${input.spec.taskId}`,
|
|
15730
15831
|
type: "prompt",
|
|
15731
15832
|
message: input.prompt
|
|
15833
|
+
};
|
|
15834
|
+
writePiRpcCommand(child, promptCommand);
|
|
15835
|
+
trace.write({
|
|
15836
|
+
kind: "prompt.sent",
|
|
15837
|
+
stream: "stdin",
|
|
15838
|
+
payload: {
|
|
15839
|
+
id: promptCommand.id,
|
|
15840
|
+
type: promptCommand.type,
|
|
15841
|
+
messageLength: input.prompt.length
|
|
15842
|
+
}
|
|
15732
15843
|
});
|
|
15733
15844
|
const result = (async () => {
|
|
15734
15845
|
let terminal;
|
|
15735
15846
|
try {
|
|
15736
15847
|
terminal = await Promise.race([closePromise, agentEndPromise]);
|
|
15737
15848
|
} catch (error48) {
|
|
15849
|
+
trace.write({
|
|
15850
|
+
kind: "process.error",
|
|
15851
|
+
stream: "process",
|
|
15852
|
+
payload: formatTraceError(error48)
|
|
15853
|
+
});
|
|
15738
15854
|
cleanupTermination();
|
|
15739
15855
|
cleanupTermination = terminateChildProcess(child);
|
|
15856
|
+
await trace.close();
|
|
15740
15857
|
throw error48;
|
|
15741
15858
|
}
|
|
15742
15859
|
if (terminal === "agent-end") {
|
|
@@ -15745,6 +15862,12 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15745
15862
|
const closeResult = await closePromise;
|
|
15746
15863
|
cleanupTermination();
|
|
15747
15864
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15865
|
+
trace.write({
|
|
15866
|
+
kind: "process.closed",
|
|
15867
|
+
stream: "process",
|
|
15868
|
+
payload: closeResult
|
|
15869
|
+
});
|
|
15870
|
+
await trace.close();
|
|
15748
15871
|
return {
|
|
15749
15872
|
exitCode: closeResult.exitCode,
|
|
15750
15873
|
signal: closeResult.signal,
|
|
@@ -15753,6 +15876,12 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15753
15876
|
}
|
|
15754
15877
|
cleanupTermination();
|
|
15755
15878
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15879
|
+
trace.write({
|
|
15880
|
+
kind: "process.closed",
|
|
15881
|
+
stream: "process",
|
|
15882
|
+
payload: terminal
|
|
15883
|
+
});
|
|
15884
|
+
await trace.close();
|
|
15756
15885
|
if (!agentEndReached && terminal.exitCode !== 0) {
|
|
15757
15886
|
forwardPiHarnessStreamLine(
|
|
15758
15887
|
input,
|
|
@@ -15780,20 +15909,44 @@ function handlePiRpcStdoutLine(input) {
|
|
|
15780
15909
|
try {
|
|
15781
15910
|
parsed = JSON.parse(trimmed);
|
|
15782
15911
|
} catch {
|
|
15783
|
-
|
|
15912
|
+
const message = input.sanitizer.redactText(trimmed);
|
|
15913
|
+
input.trace.write({
|
|
15914
|
+
kind: "stdout.text",
|
|
15915
|
+
stream: "stdout",
|
|
15916
|
+
payload: {
|
|
15917
|
+
message
|
|
15918
|
+
}
|
|
15919
|
+
});
|
|
15920
|
+
forwardPiHarnessStreamLine(input.input, "stdout", message);
|
|
15784
15921
|
return;
|
|
15785
15922
|
}
|
|
15923
|
+
const redacted = input.sanitizer.redactJson(parsed);
|
|
15786
15924
|
if (isPiRpcResponse(parsed)) {
|
|
15925
|
+
input.trace.write({
|
|
15926
|
+
kind: "stdout.response",
|
|
15927
|
+
stream: "stdout",
|
|
15928
|
+
payload: redacted
|
|
15929
|
+
});
|
|
15787
15930
|
if (parsed.command === "prompt" && parsed.success === false) {
|
|
15788
15931
|
input.onPromptRejected(new Error(`Pi RPC prompt was rejected: ${formatPiRpcError(parsed, input.sanitizer.redactText)}`));
|
|
15789
15932
|
}
|
|
15790
15933
|
return;
|
|
15791
15934
|
}
|
|
15792
15935
|
if (isPiExtensionUiRequest(parsed)) {
|
|
15793
|
-
|
|
15936
|
+
input.trace.write({
|
|
15937
|
+
kind: "stdout.extension_ui_request",
|
|
15938
|
+
stream: "stdout",
|
|
15939
|
+
payload: redacted
|
|
15940
|
+
});
|
|
15941
|
+
forwardPiExtensionUiRequest(input.input, redacted);
|
|
15794
15942
|
return;
|
|
15795
15943
|
}
|
|
15796
|
-
|
|
15944
|
+
input.trace.write({
|
|
15945
|
+
kind: "stdout.event",
|
|
15946
|
+
stream: "stdout",
|
|
15947
|
+
payload: redacted
|
|
15948
|
+
});
|
|
15949
|
+
forwardPiEvent(input.input, redacted);
|
|
15797
15950
|
if (parsed.type === "agent_end") {
|
|
15798
15951
|
input.onAgentEnd();
|
|
15799
15952
|
}
|
|
@@ -15828,8 +15981,16 @@ function forwardPiHarnessStreamLine(input, stream, message) {
|
|
|
15828
15981
|
message: trimmed
|
|
15829
15982
|
}));
|
|
15830
15983
|
}
|
|
15831
|
-
function forwardPiStderrLine(input, line, sanitizer) {
|
|
15832
|
-
|
|
15984
|
+
function forwardPiStderrLine(input, line, sanitizer, trace) {
|
|
15985
|
+
const message = sanitizer.redactText(line);
|
|
15986
|
+
trace.write({
|
|
15987
|
+
kind: "stderr.line",
|
|
15988
|
+
stream: "stderr",
|
|
15989
|
+
payload: {
|
|
15990
|
+
message
|
|
15991
|
+
}
|
|
15992
|
+
});
|
|
15993
|
+
forwardPiHarnessStreamLine(input, "stderr", message);
|
|
15833
15994
|
}
|
|
15834
15995
|
function writePiRpcCommand(child, command) {
|
|
15835
15996
|
child.stdin.write(`${JSON.stringify(command)}
|
|
@@ -15868,6 +16029,17 @@ function formatPiRpcError(parsed, redactText) {
|
|
|
15868
16029
|
}
|
|
15869
16030
|
return "unknown error";
|
|
15870
16031
|
}
|
|
16032
|
+
function formatTraceError(error48) {
|
|
16033
|
+
if (error48 instanceof Error) {
|
|
16034
|
+
return {
|
|
16035
|
+
name: error48.name,
|
|
16036
|
+
message: error48.message
|
|
16037
|
+
};
|
|
16038
|
+
}
|
|
16039
|
+
return {
|
|
16040
|
+
message: String(error48)
|
|
16041
|
+
};
|
|
16042
|
+
}
|
|
15871
16043
|
|
|
15872
16044
|
// src/prompt.ts
|
|
15873
16045
|
import { existsSync, readFileSync } from "node:fs";
|