fix(agent-pod): stop double-encoding events in agent-run.js
JSON.stringify({id, event: line}) treated the already-JSON `line` as a
plain string, so every event landed in the hub double-encoded (a JSON
string containing escaped JSON, not an object) -- agent-console's
json.Unmarshal into a struct silently failed on every single event.
Now the raw JSON line is spliced directly into the request body.
Also await all in-flight event posts before posting /agent/end, since
those POSTs were fire-and-forget and could reorder past it on the wire.
This commit is contained in:
@@ -21,10 +21,17 @@ data:
|
|||||||
await fetch(`${HUB}${path}`, {
|
await fetch(`${HUB}${path}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(body),
|
body,
|
||||||
}).catch((err) => console.error(`hub post ${path} failed:`, err.message));
|
}).catch((err) => console.error(`hub post ${path} failed:`, err.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `rawLine` is already a full JSON object (one per pi --mode json stdout
|
||||||
|
// line) -- embed it as-is rather than JSON.stringify-ing it into a nested
|
||||||
|
// string, or the hub ends up storing an escaped string instead of an event.
|
||||||
|
function postEvent(id, rawLine) {
|
||||||
|
return post("/agent/event", `{"id":${JSON.stringify(id)},"event":${rawLine}}`);
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const agent = args.shift();
|
const agent = args.shift();
|
||||||
@@ -34,18 +41,22 @@ data:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
await post("/agent/start", { id, agent });
|
await post("/agent/start", JSON.stringify({ id, agent }));
|
||||||
|
|
||||||
const child = spawn("pi", ["-p", "--mode", "json", ...args], {
|
const child = spawn("pi", ["-p", "--mode", "json", ...args], {
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Track in-flight event posts so /agent/end can't race ahead of them --
|
||||||
|
// fetch() isn't awaited per-line (would serialize on network latency), but
|
||||||
|
// 'close' must wait for all of them before reporting done.
|
||||||
|
const pending = [];
|
||||||
const rl = readline.createInterface({ input: child.stdout });
|
const rl = readline.createInterface({ input: child.stdout });
|
||||||
rl.on("line", (line) => {
|
rl.on("line", (line) => {
|
||||||
if (!line.trim()) return;
|
if (!line.trim()) return;
|
||||||
try {
|
try {
|
||||||
JSON.parse(line); // pi emits one JSON object per line; validate before relay
|
JSON.parse(line); // pi emits one JSON object per line; validate before relay
|
||||||
post("/agent/event", { id, event: line });
|
pending.push(postEvent(id, line));
|
||||||
} catch {
|
} catch {
|
||||||
// non-JSON stdout noise, ignore
|
// non-JSON stdout noise, ignore
|
||||||
}
|
}
|
||||||
@@ -54,7 +65,8 @@ data:
|
|||||||
child.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
child.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
||||||
|
|
||||||
child.on("close", async (code) => {
|
child.on("close", async (code) => {
|
||||||
await post("/agent/end", { id, status: code === 0 ? "done" : "error" });
|
await Promise.all(pending);
|
||||||
|
await post("/agent/end", JSON.stringify({ id, status: code === 0 ? "done" : "error" }));
|
||||||
process.exit(code ?? 1);
|
process.exit(code ?? 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user