@itsaplan/runner 0.3.0 → 0.4.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/dist/cli.js +35 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -620,7 +620,7 @@ function stdinText(preset, task) {
|
|
|
620
620
|
return "";
|
|
621
621
|
return presetPrompt(preset, task.systemPrompt, task.prompt);
|
|
622
622
|
}
|
|
623
|
-
async function execute(config, task,
|
|
623
|
+
async function execute(config, task, opts = {}) {
|
|
624
624
|
const preset = presetOf(config);
|
|
625
625
|
const [bin, args] = spawnArgs(config, preset, task);
|
|
626
626
|
const child = spawn(bin, args, {
|
|
@@ -628,19 +628,23 @@ async function execute(config, task, onData) {
|
|
|
628
628
|
env: childEnv(config, task),
|
|
629
629
|
detached: true
|
|
630
630
|
});
|
|
631
|
+
const kill = () => {
|
|
632
|
+
if (child.pid !== undefined)
|
|
633
|
+
killGroup(child.pid);
|
|
634
|
+
};
|
|
631
635
|
let timedOut = false;
|
|
632
636
|
const timer = setTimeout(() => {
|
|
633
637
|
timedOut = true;
|
|
634
|
-
|
|
635
|
-
killGroup(child.pid);
|
|
638
|
+
kill();
|
|
636
639
|
}, config.timeoutMs);
|
|
640
|
+
opts.signal?.addEventListener("abort", kill, { once: true });
|
|
637
641
|
let stdout = "";
|
|
638
642
|
let stderr = "";
|
|
639
643
|
child.stdout.setEncoding("utf8");
|
|
640
644
|
child.stderr.setEncoding("utf8");
|
|
641
645
|
child.stdout.on("data", (chunk) => {
|
|
642
646
|
stdout = tail2(stdout + chunk, OUTPUT_LIMIT);
|
|
643
|
-
onData?.(chunk);
|
|
647
|
+
opts.onData?.(chunk);
|
|
644
648
|
});
|
|
645
649
|
child.stderr.on("data", (chunk) => {
|
|
646
650
|
stderr = tail2(stderr + chunk, ERROR_LIMIT);
|
|
@@ -657,6 +661,7 @@ async function execute(config, task, onData) {
|
|
|
657
661
|
({ code, signal } = await exited);
|
|
658
662
|
} finally {
|
|
659
663
|
clearTimeout(timer);
|
|
664
|
+
opts.signal?.removeEventListener("abort", kill);
|
|
660
665
|
}
|
|
661
666
|
const output = stdout.trim();
|
|
662
667
|
if (code === 0)
|
|
@@ -672,13 +677,14 @@ async function execute(config, task, onData) {
|
|
|
672
677
|
|
|
673
678
|
// src/chat.ts
|
|
674
679
|
var FLUSH_MS = 500;
|
|
675
|
-
async function answer(config, client, message) {
|
|
680
|
+
async function answer(config, client, message, stop) {
|
|
676
681
|
let reported = message.sessionId !== null;
|
|
677
|
-
const stream = new AnswerStream(config.outputFormat, message.threadId, String(message.id), (events) => {
|
|
682
|
+
const stream = new AnswerStream(config.outputFormat, message.threadId, String(message.id), async (events) => {
|
|
678
683
|
const started = reported ? undefined : stream.startedSession() ?? undefined;
|
|
679
684
|
if (started)
|
|
680
685
|
reported = true;
|
|
681
|
-
|
|
686
|
+
if (await client.chatEvents(message.id, events, started))
|
|
687
|
+
stop.abort();
|
|
682
688
|
});
|
|
683
689
|
const flushing = setInterval(() => {
|
|
684
690
|
stream.flush().catch(() => {});
|
|
@@ -694,7 +700,9 @@ async function answer(config, client, message) {
|
|
|
694
700
|
ITSAPLAN_MESSAGE_ID: String(message.id),
|
|
695
701
|
ITSAPLAN_SESSION_ID: message.sessionId ?? ""
|
|
696
702
|
}
|
|
697
|
-
}, (chunk) => stream.write(chunk)).finally(() => clearInterval(flushing));
|
|
703
|
+
}, { onData: (chunk) => stream.write(chunk), signal: stop.signal }).finally(() => clearInterval(flushing));
|
|
704
|
+
if (stop.signal.aborted)
|
|
705
|
+
return;
|
|
698
706
|
if (outcome.status === "success") {
|
|
699
707
|
await stream.finish(outcome.output);
|
|
700
708
|
await client.chatResult(message.id, { status: "success" });
|
|
@@ -754,18 +762,23 @@ class Client {
|
|
|
754
762
|
return body.message;
|
|
755
763
|
}
|
|
756
764
|
async chatEvents(messageId, events, sessionId) {
|
|
757
|
-
await this.post(`/agent-chats/${messageId}/events`, {
|
|
765
|
+
const res = await this.post(`/agent-chats/${messageId}/events`, {
|
|
758
766
|
events,
|
|
759
767
|
...sessionId && { sessionId }
|
|
760
768
|
});
|
|
769
|
+
return canceled(res);
|
|
761
770
|
}
|
|
762
771
|
async chatHeartbeat(messageId) {
|
|
763
|
-
await this.post(`/agent-chats/${messageId}/heartbeat`);
|
|
772
|
+
return canceled(await this.post(`/agent-chats/${messageId}/heartbeat`));
|
|
764
773
|
}
|
|
765
774
|
async chatResult(messageId, result) {
|
|
766
775
|
await this.post(`/agent-chats/${messageId}/result`, result);
|
|
767
776
|
}
|
|
768
777
|
}
|
|
778
|
+
async function canceled(res) {
|
|
779
|
+
const body = await res.json().catch(() => ({}));
|
|
780
|
+
return body.canceled === true;
|
|
781
|
+
}
|
|
769
782
|
|
|
770
783
|
// src/cli.ts
|
|
771
784
|
var HEARTBEAT_MS = 60000;
|
|
@@ -814,14 +827,21 @@ async function handle(config, client, log2, run) {
|
|
|
814
827
|
}
|
|
815
828
|
async function handleChat(config, client, log2, message) {
|
|
816
829
|
log2(`chat ${message.id}: answering`);
|
|
830
|
+
const stop = new AbortController;
|
|
817
831
|
try {
|
|
818
|
-
await withHeartbeat(log2, () =>
|
|
819
|
-
|
|
832
|
+
await withHeartbeat(log2, async () => {
|
|
833
|
+
if (await client.chatHeartbeat(message.id))
|
|
834
|
+
stop.abort();
|
|
835
|
+
}, answer(config, client, message, stop));
|
|
820
836
|
} catch (err) {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
837
|
+
if (!stop.signal.aborted) {
|
|
838
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
839
|
+
log2(`chat ${message.id}: runner error — ${text}`);
|
|
840
|
+
await client.chatResult(message.id, { status: "failed", error: text }).catch(() => {});
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
824
843
|
}
|
|
844
|
+
log2(`chat ${message.id}: ${stop.signal.aborted ? "stopped" : "answered"}`);
|
|
825
845
|
}
|
|
826
846
|
async function drain(state, log2, concurrency, take, run, onEmpty) {
|
|
827
847
|
const active = new Set;
|