@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
package/dist/bin/agent-runner.js
CHANGED
|
@@ -14964,7 +14964,7 @@ var QuerySchema = external_exports.object({
|
|
|
14964
14964
|
limit: external_exports.number().int().positive().max(1e4).default(1e3),
|
|
14965
14965
|
accessLevel: AccessLevelSchema.default("serving")
|
|
14966
14966
|
}).superRefine((query, ctx) => {
|
|
14967
|
-
const surfaces = [query.from.surface, ...query.joins.map((
|
|
14967
|
+
const surfaces = [query.from.surface, ...query.joins.map((join3) => join3.surface)];
|
|
14968
14968
|
const knownSurfaces = /* @__PURE__ */ new Set();
|
|
14969
14969
|
for (const [index, surface] of surfaces.entries()) {
|
|
14970
14970
|
if (knownSurfaces.has(surface)) {
|
|
@@ -14999,8 +14999,8 @@ var QuerySchema = external_exports.object({
|
|
|
14999
14999
|
path: ["time", "bucket", "fn"]
|
|
15000
15000
|
});
|
|
15001
15001
|
}
|
|
15002
|
-
for (const [index,
|
|
15003
|
-
visitConditionFields(
|
|
15002
|
+
for (const [index, join3] of query.joins.entries()) {
|
|
15003
|
+
visitConditionFields(join3.on, (field) => {
|
|
15004
15004
|
validateFieldRef(field, ["joins", index, "on"]);
|
|
15005
15005
|
});
|
|
15006
15006
|
}
|
|
@@ -15456,6 +15456,92 @@ async function forwardHarnessLines(stream, handler) {
|
|
|
15456
15456
|
|
|
15457
15457
|
// src/harness-drivers/pi-rpc.ts
|
|
15458
15458
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
15459
|
+
|
|
15460
|
+
// src/debug/pi-rpc-trace.ts
|
|
15461
|
+
import { once } from "node:events";
|
|
15462
|
+
import { createWriteStream, mkdirSync } from "node:fs";
|
|
15463
|
+
import { dirname, join } from "node:path";
|
|
15464
|
+
var MAX_TRACE_LINE_BYTES = 16384;
|
|
15465
|
+
var MAX_TRACE_PREVIEW_CHARS = 8e3;
|
|
15466
|
+
function createPiRpcTrace(input) {
|
|
15467
|
+
const filePath = join(input.workspaceDir, "debug", "pi-rpc.jsonl");
|
|
15468
|
+
try {
|
|
15469
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
15470
|
+
const stream = createWriteStream(filePath, {
|
|
15471
|
+
flags: "a",
|
|
15472
|
+
mode: 384
|
|
15473
|
+
});
|
|
15474
|
+
return createStreamTrace({
|
|
15475
|
+
filePath,
|
|
15476
|
+
stream,
|
|
15477
|
+
taskId: input.taskId,
|
|
15478
|
+
now: input.now ?? (() => /* @__PURE__ */ new Date())
|
|
15479
|
+
});
|
|
15480
|
+
} catch {
|
|
15481
|
+
return createNoopTrace();
|
|
15482
|
+
}
|
|
15483
|
+
}
|
|
15484
|
+
function createStreamTrace(input) {
|
|
15485
|
+
let closed = false;
|
|
15486
|
+
let failed = false;
|
|
15487
|
+
input.stream.on("error", () => {
|
|
15488
|
+
failed = true;
|
|
15489
|
+
});
|
|
15490
|
+
return {
|
|
15491
|
+
filePath: input.filePath,
|
|
15492
|
+
write(event) {
|
|
15493
|
+
if (closed || failed) {
|
|
15494
|
+
return;
|
|
15495
|
+
}
|
|
15496
|
+
input.stream.write(serializeTraceRecord({
|
|
15497
|
+
ts: input.now().toISOString(),
|
|
15498
|
+
taskId: input.taskId,
|
|
15499
|
+
...event
|
|
15500
|
+
}));
|
|
15501
|
+
},
|
|
15502
|
+
async close() {
|
|
15503
|
+
if (closed) {
|
|
15504
|
+
return;
|
|
15505
|
+
}
|
|
15506
|
+
closed = true;
|
|
15507
|
+
if (failed) {
|
|
15508
|
+
return;
|
|
15509
|
+
}
|
|
15510
|
+
input.stream.end();
|
|
15511
|
+
await once(input.stream, "finish").then(() => void 0, () => void 0);
|
|
15512
|
+
}
|
|
15513
|
+
};
|
|
15514
|
+
}
|
|
15515
|
+
function createNoopTrace() {
|
|
15516
|
+
return {
|
|
15517
|
+
write() {
|
|
15518
|
+
},
|
|
15519
|
+
async close() {
|
|
15520
|
+
}
|
|
15521
|
+
};
|
|
15522
|
+
}
|
|
15523
|
+
function serializeTraceRecord(record2) {
|
|
15524
|
+
const line = `${JSON.stringify(record2)}
|
|
15525
|
+
`;
|
|
15526
|
+
if (Buffer.byteLength(line, "utf8") <= MAX_TRACE_LINE_BYTES) {
|
|
15527
|
+
return line;
|
|
15528
|
+
}
|
|
15529
|
+
return `${JSON.stringify({
|
|
15530
|
+
...record2,
|
|
15531
|
+
truncated: true,
|
|
15532
|
+
payload: previewPayload(record2.payload)
|
|
15533
|
+
})}
|
|
15534
|
+
`;
|
|
15535
|
+
}
|
|
15536
|
+
function previewPayload(payload) {
|
|
15537
|
+
const text = typeof payload === "string" ? payload : JSON.stringify(payload) ?? "undefined";
|
|
15538
|
+
if (text.length <= MAX_TRACE_PREVIEW_CHARS) {
|
|
15539
|
+
return text;
|
|
15540
|
+
}
|
|
15541
|
+
return `${text.slice(0, MAX_TRACE_PREVIEW_CHARS)}...[truncated]`;
|
|
15542
|
+
}
|
|
15543
|
+
|
|
15544
|
+
// src/harness-drivers/pi-rpc.ts
|
|
15459
15545
|
var driverOwnedPiFlags = /* @__PURE__ */ new Set([
|
|
15460
15546
|
"--mode",
|
|
15461
15547
|
"--provider",
|
|
@@ -15513,7 +15599,8 @@ function buildPiRpcArgs(harness) {
|
|
|
15513
15599
|
}
|
|
15514
15600
|
function startPiRpcHarness(input, spawnProcess) {
|
|
15515
15601
|
const harness = input.harness;
|
|
15516
|
-
const
|
|
15602
|
+
const args = buildPiRpcArgs(harness);
|
|
15603
|
+
const child = spawnProcess(harness.command, args, {
|
|
15517
15604
|
cwd: input.spec.workspaceDir,
|
|
15518
15605
|
env: input.env,
|
|
15519
15606
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -15521,6 +15608,19 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15521
15608
|
const sanitizer = createHarnessOutputSanitizer(input.env, [
|
|
15522
15609
|
...input.harness.secretEnv ?? []
|
|
15523
15610
|
]);
|
|
15611
|
+
const trace = createPiRpcTrace({
|
|
15612
|
+
taskId: input.spec.taskId,
|
|
15613
|
+
workspaceDir: input.spec.workspaceDir
|
|
15614
|
+
});
|
|
15615
|
+
trace.write({
|
|
15616
|
+
kind: "process.started",
|
|
15617
|
+
stream: "process",
|
|
15618
|
+
payload: {
|
|
15619
|
+
command: harness.command,
|
|
15620
|
+
args,
|
|
15621
|
+
cwd: input.spec.workspaceDir
|
|
15622
|
+
}
|
|
15623
|
+
});
|
|
15524
15624
|
let cleanupTermination = () => void 0;
|
|
15525
15625
|
let agentEndReached = false;
|
|
15526
15626
|
let resolveAgentEnd = () => void 0;
|
|
@@ -15537,6 +15637,7 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15537
15637
|
input,
|
|
15538
15638
|
line,
|
|
15539
15639
|
sanitizer,
|
|
15640
|
+
trace,
|
|
15540
15641
|
onAgentEnd() {
|
|
15541
15642
|
agentEndReached = true;
|
|
15542
15643
|
resolveAgentEnd("agent-end");
|
|
@@ -15547,20 +15648,36 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15547
15648
|
});
|
|
15548
15649
|
});
|
|
15549
15650
|
const stderrDone = forwardJsonlByteStream(child.stderr, (line) => {
|
|
15550
|
-
forwardPiStderrLine(input, line, sanitizer);
|
|
15651
|
+
forwardPiStderrLine(input, line, sanitizer, trace);
|
|
15551
15652
|
});
|
|
15552
|
-
|
|
15653
|
+
const promptCommand = {
|
|
15553
15654
|
id: `mote-${input.spec.taskId}`,
|
|
15554
15655
|
type: "prompt",
|
|
15555
15656
|
message: input.prompt
|
|
15657
|
+
};
|
|
15658
|
+
writePiRpcCommand(child, promptCommand);
|
|
15659
|
+
trace.write({
|
|
15660
|
+
kind: "prompt.sent",
|
|
15661
|
+
stream: "stdin",
|
|
15662
|
+
payload: {
|
|
15663
|
+
id: promptCommand.id,
|
|
15664
|
+
type: promptCommand.type,
|
|
15665
|
+
messageLength: input.prompt.length
|
|
15666
|
+
}
|
|
15556
15667
|
});
|
|
15557
15668
|
const result = (async () => {
|
|
15558
15669
|
let terminal;
|
|
15559
15670
|
try {
|
|
15560
15671
|
terminal = await Promise.race([closePromise, agentEndPromise]);
|
|
15561
15672
|
} catch (error48) {
|
|
15673
|
+
trace.write({
|
|
15674
|
+
kind: "process.error",
|
|
15675
|
+
stream: "process",
|
|
15676
|
+
payload: formatTraceError(error48)
|
|
15677
|
+
});
|
|
15562
15678
|
cleanupTermination();
|
|
15563
15679
|
cleanupTermination = terminateChildProcess(child);
|
|
15680
|
+
await trace.close();
|
|
15564
15681
|
throw error48;
|
|
15565
15682
|
}
|
|
15566
15683
|
if (terminal === "agent-end") {
|
|
@@ -15569,6 +15686,12 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15569
15686
|
const closeResult = await closePromise;
|
|
15570
15687
|
cleanupTermination();
|
|
15571
15688
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15689
|
+
trace.write({
|
|
15690
|
+
kind: "process.closed",
|
|
15691
|
+
stream: "process",
|
|
15692
|
+
payload: closeResult
|
|
15693
|
+
});
|
|
15694
|
+
await trace.close();
|
|
15572
15695
|
return {
|
|
15573
15696
|
exitCode: closeResult.exitCode,
|
|
15574
15697
|
signal: closeResult.signal,
|
|
@@ -15577,6 +15700,12 @@ function startPiRpcHarness(input, spawnProcess) {
|
|
|
15577
15700
|
}
|
|
15578
15701
|
cleanupTermination();
|
|
15579
15702
|
await Promise.all([stdoutDone, stderrDone]);
|
|
15703
|
+
trace.write({
|
|
15704
|
+
kind: "process.closed",
|
|
15705
|
+
stream: "process",
|
|
15706
|
+
payload: terminal
|
|
15707
|
+
});
|
|
15708
|
+
await trace.close();
|
|
15580
15709
|
if (!agentEndReached && terminal.exitCode !== 0) {
|
|
15581
15710
|
forwardPiHarnessStreamLine(
|
|
15582
15711
|
input,
|
|
@@ -15604,20 +15733,44 @@ function handlePiRpcStdoutLine(input) {
|
|
|
15604
15733
|
try {
|
|
15605
15734
|
parsed = JSON.parse(trimmed);
|
|
15606
15735
|
} catch {
|
|
15607
|
-
|
|
15736
|
+
const message = input.sanitizer.redactText(trimmed);
|
|
15737
|
+
input.trace.write({
|
|
15738
|
+
kind: "stdout.text",
|
|
15739
|
+
stream: "stdout",
|
|
15740
|
+
payload: {
|
|
15741
|
+
message
|
|
15742
|
+
}
|
|
15743
|
+
});
|
|
15744
|
+
forwardPiHarnessStreamLine(input.input, "stdout", message);
|
|
15608
15745
|
return;
|
|
15609
15746
|
}
|
|
15747
|
+
const redacted = input.sanitizer.redactJson(parsed);
|
|
15610
15748
|
if (isPiRpcResponse(parsed)) {
|
|
15749
|
+
input.trace.write({
|
|
15750
|
+
kind: "stdout.response",
|
|
15751
|
+
stream: "stdout",
|
|
15752
|
+
payload: redacted
|
|
15753
|
+
});
|
|
15611
15754
|
if (parsed.command === "prompt" && parsed.success === false) {
|
|
15612
15755
|
input.onPromptRejected(new Error(`Pi RPC prompt was rejected: ${formatPiRpcError(parsed, input.sanitizer.redactText)}`));
|
|
15613
15756
|
}
|
|
15614
15757
|
return;
|
|
15615
15758
|
}
|
|
15616
15759
|
if (isPiExtensionUiRequest(parsed)) {
|
|
15617
|
-
|
|
15760
|
+
input.trace.write({
|
|
15761
|
+
kind: "stdout.extension_ui_request",
|
|
15762
|
+
stream: "stdout",
|
|
15763
|
+
payload: redacted
|
|
15764
|
+
});
|
|
15765
|
+
forwardPiExtensionUiRequest(input.input, redacted);
|
|
15618
15766
|
return;
|
|
15619
15767
|
}
|
|
15620
|
-
|
|
15768
|
+
input.trace.write({
|
|
15769
|
+
kind: "stdout.event",
|
|
15770
|
+
stream: "stdout",
|
|
15771
|
+
payload: redacted
|
|
15772
|
+
});
|
|
15773
|
+
forwardPiEvent(input.input, redacted);
|
|
15621
15774
|
if (parsed.type === "agent_end") {
|
|
15622
15775
|
input.onAgentEnd();
|
|
15623
15776
|
}
|
|
@@ -15652,8 +15805,16 @@ function forwardPiHarnessStreamLine(input, stream, message) {
|
|
|
15652
15805
|
message: trimmed
|
|
15653
15806
|
}));
|
|
15654
15807
|
}
|
|
15655
|
-
function forwardPiStderrLine(input, line, sanitizer) {
|
|
15656
|
-
|
|
15808
|
+
function forwardPiStderrLine(input, line, sanitizer, trace) {
|
|
15809
|
+
const message = sanitizer.redactText(line);
|
|
15810
|
+
trace.write({
|
|
15811
|
+
kind: "stderr.line",
|
|
15812
|
+
stream: "stderr",
|
|
15813
|
+
payload: {
|
|
15814
|
+
message
|
|
15815
|
+
}
|
|
15816
|
+
});
|
|
15817
|
+
forwardPiHarnessStreamLine(input, "stderr", message);
|
|
15657
15818
|
}
|
|
15658
15819
|
function writePiRpcCommand(child, command) {
|
|
15659
15820
|
child.stdin.write(`${JSON.stringify(command)}
|
|
@@ -15692,6 +15853,17 @@ function formatPiRpcError(parsed, redactText) {
|
|
|
15692
15853
|
}
|
|
15693
15854
|
return "unknown error";
|
|
15694
15855
|
}
|
|
15856
|
+
function formatTraceError(error48) {
|
|
15857
|
+
if (error48 instanceof Error) {
|
|
15858
|
+
return {
|
|
15859
|
+
name: error48.name,
|
|
15860
|
+
message: error48.message
|
|
15861
|
+
};
|
|
15862
|
+
}
|
|
15863
|
+
return {
|
|
15864
|
+
message: String(error48)
|
|
15865
|
+
};
|
|
15866
|
+
}
|
|
15695
15867
|
|
|
15696
15868
|
// src/prompt.ts
|
|
15697
15869
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -15741,14 +15913,14 @@ function renderHarnessPromptTemplate(input) {
|
|
|
15741
15913
|
|
|
15742
15914
|
// src/runtime.ts
|
|
15743
15915
|
import { mkdir, readFile as readFile2, stat, writeFile } from "node:fs/promises";
|
|
15744
|
-
import { dirname, join } from "node:path";
|
|
15916
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
15745
15917
|
var uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
15746
15918
|
function createTaskAgentWorkspacePaths(workspaceDir) {
|
|
15747
15919
|
const normalized = workspaceDir.replace(/\/+$/g, "");
|
|
15748
15920
|
return {
|
|
15749
15921
|
workspaceDir: normalized,
|
|
15750
|
-
stateDir:
|
|
15751
|
-
artifactsDir:
|
|
15922
|
+
stateDir: join2(normalized, "state"),
|
|
15923
|
+
artifactsDir: join2(normalized, "artifacts")
|
|
15752
15924
|
};
|
|
15753
15925
|
}
|
|
15754
15926
|
async function ensureTaskAgentWorkspace(paths) {
|
|
@@ -15758,10 +15930,10 @@ async function ensureTaskAgentWorkspace(paths) {
|
|
|
15758
15930
|
]);
|
|
15759
15931
|
}
|
|
15760
15932
|
async function writeTaskCompletion(input) {
|
|
15761
|
-
await writeJsonFile(
|
|
15933
|
+
await writeJsonFile(join2(input.paths.stateDir, "completion.json"), input.completion);
|
|
15762
15934
|
}
|
|
15763
15935
|
async function readTaskCompletion(paths) {
|
|
15764
|
-
const raw = await readFile2(
|
|
15936
|
+
const raw = await readFile2(join2(paths.stateDir, "completion.json"), "utf8");
|
|
15765
15937
|
const parsed = JSON.parse(raw);
|
|
15766
15938
|
if (parsed.status !== "completed" && parsed.status !== "partial" && parsed.status !== "failed" && parsed.status !== "cancelled") {
|
|
15767
15939
|
throw new Error("completion status must be completed, partial, failed, or cancelled");
|
|
@@ -15779,13 +15951,13 @@ async function readTaskCompletion(paths) {
|
|
|
15779
15951
|
}
|
|
15780
15952
|
async function validateTaskArtifactFiles(input) {
|
|
15781
15953
|
for (const artifactId of input.completion.artifactIds) {
|
|
15782
|
-
const artifactPath =
|
|
15954
|
+
const artifactPath = join2(createArtifactDir(input.paths, artifactId), "artifact.json");
|
|
15783
15955
|
const artifact = taskArtifactDraftSchema.parse(JSON.parse(await readFile2(artifactPath, "utf8")));
|
|
15784
15956
|
if (artifact.artifactId !== artifactId) {
|
|
15785
15957
|
throw new Error(`artifact id mismatch for ${artifactId}`);
|
|
15786
15958
|
}
|
|
15787
15959
|
if ("dataset" in artifact) {
|
|
15788
|
-
const dataPath =
|
|
15960
|
+
const dataPath = join2(createArtifactDir(input.paths, artifactId), "data.csv");
|
|
15789
15961
|
const dataStat = await stat(dataPath);
|
|
15790
15962
|
if (dataStat.size <= 0) {
|
|
15791
15963
|
throw new Error(`dataset artifact ${artifactId} data.csv must be non-empty`);
|
|
@@ -15800,10 +15972,10 @@ function assertTaskArtifactId(artifactId) {
|
|
|
15800
15972
|
}
|
|
15801
15973
|
function createArtifactDir(paths, artifactId) {
|
|
15802
15974
|
assertTaskArtifactId(artifactId);
|
|
15803
|
-
return
|
|
15975
|
+
return join2(paths.artifactsDir, artifactId);
|
|
15804
15976
|
}
|
|
15805
15977
|
async function writeJsonFile(path, value) {
|
|
15806
|
-
await mkdir(
|
|
15978
|
+
await mkdir(dirname2(path), { recursive: true });
|
|
15807
15979
|
await writeFile(path, `${JSON.stringify(value, null, 2)}
|
|
15808
15980
|
`);
|
|
15809
15981
|
}
|