@code-yeongyu/senpi-agent-core 2026.9.29 → 2026.10.1-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/README.md +49 -20
- package/dist/agent-loop.d.ts +27 -3
- package/dist/agent-loop.js +192 -56
- package/dist/agent.d.ts +21 -7
- package/dist/agent.js +38 -18
- package/dist/harness/execution/tools.d.ts +1 -1
- package/dist/harness/execution/tools.js +0 -2
- package/dist/harness/messages.js +1 -0
- package/dist/harness/pico3/bash.d.ts +10 -0
- package/dist/harness/pico3/bash.js +25 -0
- package/dist/harness/pico3/bounded.d.ts +21 -0
- package/dist/harness/pico3/bounded.js +95 -0
- package/dist/harness/pico3/chord.d.ts +41 -0
- package/dist/harness/pico3/chord.js +147 -0
- package/dist/harness/pico3/context.d.ts +16 -0
- package/dist/harness/pico3/context.js +88 -0
- package/dist/harness/pico3/harness.d.ts +198 -0
- package/dist/harness/pico3/harness.js +645 -0
- package/dist/harness/pico3/hooks.d.ts +10 -0
- package/dist/harness/pico3/hooks.js +33 -0
- package/dist/harness/pico3/index.d.ts +19 -0
- package/dist/harness/pico3/index.js +15 -0
- package/dist/harness/pico3/jsonl.d.ts +58 -0
- package/dist/harness/pico3/jsonl.js +322 -0
- package/dist/harness/pico3/kinds/collapse.d.ts +49 -0
- package/dist/harness/pico3/kinds/collapse.js +191 -0
- package/dist/harness/pico3/kinds/entries.d.ts +78 -0
- package/dist/harness/pico3/kinds/entries.js +13 -0
- package/dist/harness/pico3/kinds/frames.d.ts +9 -0
- package/dist/harness/pico3/kinds/frames.js +75 -0
- package/dist/harness/pico3/kinds/generation.d.ts +94 -0
- package/dist/harness/pico3/kinds/generation.js +504 -0
- package/dist/harness/pico3/kinds/job.d.ts +44 -0
- package/dist/harness/pico3/kinds/job.js +143 -0
- package/dist/harness/pico3/kinds/plugin.d.ts +15 -0
- package/dist/harness/pico3/kinds/plugin.js +35 -0
- package/dist/harness/pico3/kinds/post-tools.d.ts +22 -0
- package/dist/harness/pico3/kinds/post-tools.js +145 -0
- package/dist/harness/pico3/kinds/task-api.d.ts +3 -0
- package/dist/harness/pico3/kinds/task-api.js +45 -0
- package/dist/harness/pico3/kinds/tool.d.ts +43 -0
- package/dist/harness/pico3/kinds/tool.js +373 -0
- package/dist/harness/pico3/legacy-tracker.d.ts +11 -0
- package/dist/harness/pico3/legacy-tracker.js +39 -0
- package/dist/harness/pico3/membrane.d.ts +23 -0
- package/dist/harness/pico3/membrane.js +140 -0
- package/dist/harness/pico3/memory.d.ts +53 -0
- package/dist/harness/pico3/memory.js +265 -0
- package/dist/harness/pico3/scheduler.d.ts +49 -0
- package/dist/harness/pico3/scheduler.js +437 -0
- package/dist/harness/pico3/session.d.ts +264 -0
- package/dist/harness/pico3/session.js +1328 -0
- package/dist/harness/pico3/system.d.ts +126 -0
- package/dist/harness/pico3/system.js +244 -0
- package/dist/harness/pico3/types.d.ts +973 -0
- package/dist/harness/pico3/types.js +94 -0
- package/dist/harness/pico3/view.d.ts +34 -0
- package/dist/harness/pico3/view.js +404 -0
- package/dist/harness/runtime/drive/tool-placement.js +2 -27
- package/dist/harness/telemetry.d.ts +36 -36
- package/dist/harness/tools/image.js +1 -1
- package/dist/harness/utils/read-folders/index.d.ts +2 -2
- package/dist/harness/utils/read-folders/index.js +2 -2
- package/dist/harness/utils/read-folders/tree-sitter/grammar-assets.js +1 -1
- package/dist/proxy.d.ts +2 -2
- package/dist/types.d.ts +111 -34
- package/package.json +10 -5
- package/dist/agent-loop.d.ts.map +0 -1
- package/dist/agent-loop.js.map +0 -1
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js.map +0 -1
- package/dist/assistant-terminal-state.d.ts.map +0 -1
- package/dist/assistant-terminal-state.js.map +0 -1
- package/dist/empty-assistant-recovery.d.ts.map +0 -1
- package/dist/empty-assistant-recovery.js.map +0 -1
- package/dist/harness/agent-harness.d.ts.map +0 -1
- package/dist/harness/agent-harness.js.map +0 -1
- package/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
- package/dist/harness/compaction/branch-summarization.js.map +0 -1
- package/dist/harness/compaction/compaction.d.ts.map +0 -1
- package/dist/harness/compaction/compaction.js.map +0 -1
- package/dist/harness/compaction/utils.d.ts.map +0 -1
- package/dist/harness/compaction/utils.js.map +0 -1
- package/dist/harness/config.d.ts.map +0 -1
- package/dist/harness/config.js.map +0 -1
- package/dist/harness/context.d.ts.map +0 -1
- package/dist/harness/context.js.map +0 -1
- package/dist/harness/env/nodejs.d.ts.map +0 -1
- package/dist/harness/env/nodejs.js.map +0 -1
- package/dist/harness/events.d.ts.map +0 -1
- package/dist/harness/events.js.map +0 -1
- package/dist/harness/execution/assistant.d.ts.map +0 -1
- package/dist/harness/execution/assistant.js.map +0 -1
- package/dist/harness/execution/effect-gate.d.ts.map +0 -1
- package/dist/harness/execution/effect-gate.js.map +0 -1
- package/dist/harness/execution/tools.d.ts.map +0 -1
- package/dist/harness/execution/tools.js.map +0 -1
- package/dist/harness/hooks.d.ts.map +0 -1
- package/dist/harness/hooks.js.map +0 -1
- package/dist/harness/messages.d.ts.map +0 -1
- package/dist/harness/messages.js.map +0 -1
- package/dist/harness/prompt-templates.d.ts.map +0 -1
- package/dist/harness/prompt-templates.js.map +0 -1
- package/dist/harness/result.d.ts.map +0 -1
- package/dist/harness/result.js.map +0 -1
- package/dist/harness/runtime/drive/boundary.d.ts.map +0 -1
- package/dist/harness/runtime/drive/boundary.js.map +0 -1
- package/dist/harness/runtime/drive/checkpoint.d.ts.map +0 -1
- package/dist/harness/runtime/drive/checkpoint.js.map +0 -1
- package/dist/harness/runtime/drive/deferred.d.ts.map +0 -1
- package/dist/harness/runtime/drive/deferred.js.map +0 -1
- package/dist/harness/runtime/drive/generation.d.ts.map +0 -1
- package/dist/harness/runtime/drive/generation.js.map +0 -1
- package/dist/harness/runtime/drive/reconcile.d.ts.map +0 -1
- package/dist/harness/runtime/drive/reconcile.js.map +0 -1
- package/dist/harness/runtime/drive/recovery.d.ts.map +0 -1
- package/dist/harness/runtime/drive/recovery.js.map +0 -1
- package/dist/harness/runtime/drive/response.d.ts.map +0 -1
- package/dist/harness/runtime/drive/response.js.map +0 -1
- package/dist/harness/runtime/drive/retry.d.ts.map +0 -1
- package/dist/harness/runtime/drive/retry.js.map +0 -1
- package/dist/harness/runtime/drive/structural.d.ts.map +0 -1
- package/dist/harness/runtime/drive/structural.js.map +0 -1
- package/dist/harness/runtime/drive/terminal.d.ts.map +0 -1
- package/dist/harness/runtime/drive/terminal.js.map +0 -1
- package/dist/harness/runtime/drive/tool-placement.d.ts.map +0 -1
- package/dist/harness/runtime/drive/tool-placement.js.map +0 -1
- package/dist/harness/runtime/drive/tools.d.ts.map +0 -1
- package/dist/harness/runtime/drive/tools.js.map +0 -1
- package/dist/harness/runtime/drive.d.ts.map +0 -1
- package/dist/harness/runtime/drive.js.map +0 -1
- package/dist/harness/runtime/harness.d.ts.map +0 -1
- package/dist/harness/runtime/harness.js.map +0 -1
- package/dist/harness/runtime/index.d.ts.map +0 -1
- package/dist/harness/runtime/index.js.map +0 -1
- package/dist/harness/runtime/lane.d.ts.map +0 -1
- package/dist/harness/runtime/lane.js.map +0 -1
- package/dist/harness/runtime/progress.d.ts.map +0 -1
- package/dist/harness/runtime/progress.js.map +0 -1
- package/dist/harness/runtime/reducer.d.ts.map +0 -1
- package/dist/harness/runtime/reducer.js.map +0 -1
- package/dist/harness/runtime/restore.d.ts.map +0 -1
- package/dist/harness/runtime/restore.js.map +0 -1
- package/dist/harness/runtime/transcript.d.ts.map +0 -1
- package/dist/harness/runtime/transcript.js.map +0 -1
- package/dist/harness/runtime/types.d.ts.map +0 -1
- package/dist/harness/runtime/types.js.map +0 -1
- package/dist/harness/session/commit.d.ts.map +0 -1
- package/dist/harness/session/commit.js.map +0 -1
- package/dist/harness/session/context.d.ts.map +0 -1
- package/dist/harness/session/context.js.map +0 -1
- package/dist/harness/session/fork-policy.d.ts.map +0 -1
- package/dist/harness/session/fork-policy.js.map +0 -1
- package/dist/harness/session/fork.d.ts.map +0 -1
- package/dist/harness/session/fork.js.map +0 -1
- package/dist/harness/session/in-memory-storage-state.d.ts.map +0 -1
- package/dist/harness/session/in-memory-storage-state.js.map +0 -1
- package/dist/harness/session/index.d.ts.map +0 -1
- package/dist/harness/session/index.js.map +0 -1
- package/dist/harness/session/jsonl/codec.d.ts.map +0 -1
- package/dist/harness/session/jsonl/codec.js.map +0 -1
- package/dist/harness/session/jsonl/fork.d.ts.map +0 -1
- package/dist/harness/session/jsonl/fork.js.map +0 -1
- package/dist/harness/session/jsonl/index.d.ts.map +0 -1
- package/dist/harness/session/jsonl/index.js.map +0 -1
- package/dist/harness/session/jsonl/io.d.ts.map +0 -1
- package/dist/harness/session/jsonl/io.js.map +0 -1
- package/dist/harness/session/jsonl/legacy-v3.d.ts.map +0 -1
- package/dist/harness/session/jsonl/legacy-v3.js.map +0 -1
- package/dist/harness/session/jsonl/repo.d.ts.map +0 -1
- package/dist/harness/session/jsonl/repo.js.map +0 -1
- package/dist/harness/session/jsonl/storage.d.ts.map +0 -1
- package/dist/harness/session/jsonl/storage.js.map +0 -1
- package/dist/harness/session/jsonl/types.d.ts.map +0 -1
- package/dist/harness/session/jsonl/types.js.map +0 -1
- package/dist/harness/session/memory.d.ts.map +0 -1
- package/dist/harness/session/memory.js.map +0 -1
- package/dist/harness/session/mutation-line.d.ts.map +0 -1
- package/dist/harness/session/mutation-line.js.map +0 -1
- package/dist/harness/session/session.d.ts.map +0 -1
- package/dist/harness/session/session.js.map +0 -1
- package/dist/harness/session/testing/benchmark/datasets.d.ts.map +0 -1
- package/dist/harness/session/testing/benchmark/datasets.js.map +0 -1
- package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +0 -1
- package/dist/harness/session/testing/benchmark/session-repo.js.map +0 -1
- package/dist/harness/session/testing/benchmark/storage.d.ts.map +0 -1
- package/dist/harness/session/testing/benchmark/storage.js.map +0 -1
- package/dist/harness/session/testing/conformance/session-repo.d.ts.map +0 -1
- package/dist/harness/session/testing/conformance/session-repo.js.map +0 -1
- package/dist/harness/session/testing/conformance/storage.d.ts.map +0 -1
- package/dist/harness/session/testing/conformance/storage.js.map +0 -1
- package/dist/harness/session/testing/gating-storage.d.ts.map +0 -1
- package/dist/harness/session/testing/gating-storage.js.map +0 -1
- package/dist/harness/session/testing/index.d.ts.map +0 -1
- package/dist/harness/session/testing/index.js.map +0 -1
- package/dist/harness/session/testing/instrumented-storage.d.ts.map +0 -1
- package/dist/harness/session/testing/instrumented-storage.js.map +0 -1
- package/dist/harness/session/testing/storage-decorator.d.ts.map +0 -1
- package/dist/harness/session/testing/storage-decorator.js.map +0 -1
- package/dist/harness/session/testing/types.d.ts.map +0 -1
- package/dist/harness/session/testing/types.js.map +0 -1
- package/dist/harness/session/types.d.ts.map +0 -1
- package/dist/harness/session/types.js.map +0 -1
- package/dist/harness/session/values.d.ts.map +0 -1
- package/dist/harness/session/values.js.map +0 -1
- package/dist/harness/skills.d.ts.map +0 -1
- package/dist/harness/skills.js.map +0 -1
- package/dist/harness/system-prompt.d.ts.map +0 -1
- package/dist/harness/system-prompt.js.map +0 -1
- package/dist/harness/telemetry.d.ts.map +0 -1
- package/dist/harness/telemetry.js.map +0 -1
- package/dist/harness/tools/bash.d.ts.map +0 -1
- package/dist/harness/tools/bash.js.map +0 -1
- package/dist/harness/tools/edit-diff.d.ts.map +0 -1
- package/dist/harness/tools/edit-diff.js.map +0 -1
- package/dist/harness/tools/edit.d.ts.map +0 -1
- package/dist/harness/tools/edit.js.map +0 -1
- package/dist/harness/tools/file-mutation-queue.d.ts.map +0 -1
- package/dist/harness/tools/file-mutation-queue.js.map +0 -1
- package/dist/harness/tools/image.d.ts.map +0 -1
- package/dist/harness/tools/image.js.map +0 -1
- package/dist/harness/tools/index.d.ts.map +0 -1
- package/dist/harness/tools/index.js.map +0 -1
- package/dist/harness/tools/path-utils.d.ts.map +0 -1
- package/dist/harness/tools/path-utils.js.map +0 -1
- package/dist/harness/tools/post-mutate.d.ts.map +0 -1
- package/dist/harness/tools/post-mutate.js.map +0 -1
- package/dist/harness/tools/read.d.ts.map +0 -1
- package/dist/harness/tools/read.js.map +0 -1
- package/dist/harness/tools/tool-context.d.ts.map +0 -1
- package/dist/harness/tools/tool-context.js.map +0 -1
- package/dist/harness/tools/write.d.ts.map +0 -1
- package/dist/harness/tools/write.js.map +0 -1
- package/dist/harness/types.d.ts.map +0 -1
- package/dist/harness/types.js.map +0 -1
- package/dist/harness/utils/adaptive-publisher.d.ts.map +0 -1
- package/dist/harness/utils/adaptive-publisher.js.map +0 -1
- package/dist/harness/utils/output-capture.d.ts.map +0 -1
- package/dist/harness/utils/output-capture.js.map +0 -1
- package/dist/harness/utils/read-folders/brace-scanner.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/brace-scanner.js.map +0 -1
- package/dist/harness/utils/read-folders/compose.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/compose.js.map +0 -1
- package/dist/harness/utils/read-folders/header-protection.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/header-protection.js.map +0 -1
- package/dist/harness/utils/read-folders/index.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/index.js.map +0 -1
- package/dist/harness/utils/read-folders/lexical-context.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/lexical-context.js.map +0 -1
- package/dist/harness/utils/read-folders/lexical-spans.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/lexical-spans.js.map +0 -1
- package/dist/harness/utils/read-folders/prepare.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/prepare.js.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/engine.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/engine.js.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/grammar-assets.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/grammar-assets.js.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/syntax.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/tree-sitter/syntax.js.map +0 -1
- package/dist/harness/utils/read-folders/types.d.ts.map +0 -1
- package/dist/harness/utils/read-folders/types.js.map +0 -1
- package/dist/harness/utils/segmented-read-view.d.ts.map +0 -1
- package/dist/harness/utils/segmented-read-view.js.map +0 -1
- package/dist/harness/utils/shell-output.d.ts.map +0 -1
- package/dist/harness/utils/shell-output.js.map +0 -1
- package/dist/harness/utils/truncate.d.ts.map +0 -1
- package/dist/harness/utils/truncate.js.map +0 -1
- package/dist/harness/utils/usage.d.ts.map +0 -1
- package/dist/harness/utils/usage.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/node.d.ts.map +0 -1
- package/dist/node.js.map +0 -1
- package/dist/proxy.d.ts.map +0 -1
- package/dist/proxy.js.map +0 -1
- package/dist/search/index.d.ts.map +0 -1
- package/dist/search/index.js.map +0 -1
- package/dist/stream-fn.d.ts.map +0 -1
- package/dist/stream-fn.js.map +0 -1
- package/dist/tool-arguments.d.ts.map +0 -1
- package/dist/tool-arguments.js.map +0 -1
- package/dist/tool-name-alias.d.ts.map +0 -1
- package/dist/tool-name-alias.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const failed = (reason, detail) => ({
|
|
2
|
+
status: "failed",
|
|
3
|
+
failure: { reason, detail },
|
|
4
|
+
});
|
|
5
|
+
const notice = (text, now) => ({
|
|
6
|
+
kind: "pi.notice",
|
|
7
|
+
model: [{ role: "user", content: text, timestamp: now }],
|
|
8
|
+
});
|
|
9
|
+
const jobKind = {
|
|
10
|
+
name: "pi.job",
|
|
11
|
+
slot: () => ({}),
|
|
12
|
+
describe: (task) => ({
|
|
13
|
+
stage: task.checkpoint?.phase ?? "starting",
|
|
14
|
+
...(task.slot ?? {}),
|
|
15
|
+
}),
|
|
16
|
+
inflight: ["spawning", "running"],
|
|
17
|
+
phases: {
|
|
18
|
+
async waiting(task, runtime, ctx) {
|
|
19
|
+
await runtime.sleep(task.checkpoint.untilMs, ctx);
|
|
20
|
+
return spawn(task, task.checkpoint.occurrence, runtime, ctx);
|
|
21
|
+
},
|
|
22
|
+
async spawning(task, runtime, ctx) {
|
|
23
|
+
return reconcile(task, task.checkpoint, runtime, ctx);
|
|
24
|
+
},
|
|
25
|
+
async running(task, runtime, ctx) {
|
|
26
|
+
return reconcile(task, task.checkpoint, runtime, ctx);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
async initial(task, runtime, ctx) {
|
|
30
|
+
if (runtime.processHost === undefined)
|
|
31
|
+
return { done: () => failed("spawn", "no process host") };
|
|
32
|
+
const now = runtime.now();
|
|
33
|
+
const untilMs = task.input.notBefore ?? now;
|
|
34
|
+
if (untilMs > now)
|
|
35
|
+
return { next: { phase: "waiting", untilMs, occurrence: 1 } };
|
|
36
|
+
return spawn(task, 1, runtime, ctx);
|
|
37
|
+
},
|
|
38
|
+
async abort(task, runtime, ctx) {
|
|
39
|
+
const checkpoint = task.checkpoint;
|
|
40
|
+
if (checkpoint === undefined || checkpoint.phase === "waiting" || runtime.processHost === undefined)
|
|
41
|
+
return async () => ({ killed: false });
|
|
42
|
+
await runtime.processHost.kill(checkpoint.key, "SIGTERM", ctx);
|
|
43
|
+
await runtime.sleep(runtime.now() + 5000, ctx);
|
|
44
|
+
await runtime.processHost.kill(checkpoint.key, "SIGKILL", ctx);
|
|
45
|
+
return async () => ({ killed: true });
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
export const job = Object.freeze(jobKind);
|
|
49
|
+
async function spawn(task, occurrence, runtime, ctx) {
|
|
50
|
+
const key = `${task.id}:${occurrence}`;
|
|
51
|
+
await runtime.commit((tx) => tx.checkpoint({ phase: "spawning", key, occurrence }), ctx);
|
|
52
|
+
try {
|
|
53
|
+
await runtime.processHost.start(key, task.input, ctx);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (ctx.abortSignal?.aborted)
|
|
57
|
+
throw error;
|
|
58
|
+
return {
|
|
59
|
+
done: async (tx, current) => {
|
|
60
|
+
if (task.input.notify)
|
|
61
|
+
await tx.write(current.conversationId, notice(`job ${task.id} failed to start: ${String(error)}`, runtime.now()));
|
|
62
|
+
return failed("spawn", String(error));
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
await runtime.commit((tx) => tx.checkpoint({ phase: "running", key, occurrence }), ctx);
|
|
67
|
+
return poll(task, key, occurrence, runtime, ctx);
|
|
68
|
+
}
|
|
69
|
+
async function reconcile(task, checkpoint, runtime, ctx) {
|
|
70
|
+
if (runtime.processHost === undefined)
|
|
71
|
+
return { done: () => failed("interrupted", "no process host after restart") };
|
|
72
|
+
let status;
|
|
73
|
+
try {
|
|
74
|
+
status = await runtime.processHost.status(checkpoint.key, ctx);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
return { done: () => failed("interrupted", `host status failed: ${String(error)}`) };
|
|
78
|
+
}
|
|
79
|
+
if (status.status === "unknown") {
|
|
80
|
+
if (!task.input.rerun)
|
|
81
|
+
return { done: () => failed("interrupted", "process outcome unknown") };
|
|
82
|
+
return spawn(task, checkpoint.occurrence, runtime, ctx);
|
|
83
|
+
}
|
|
84
|
+
if (checkpoint.phase === "spawning") {
|
|
85
|
+
await runtime.commit((tx) => tx.checkpoint({ phase: "running", key: checkpoint.key, occurrence: checkpoint.occurrence }), ctx);
|
|
86
|
+
}
|
|
87
|
+
return poll(task, checkpoint.key, checkpoint.occurrence, runtime, ctx);
|
|
88
|
+
}
|
|
89
|
+
async function poll(task, key, occurrence, runtime, ctx) {
|
|
90
|
+
for (let attempt = 0;; attempt++) {
|
|
91
|
+
let status;
|
|
92
|
+
try {
|
|
93
|
+
status = await runtime.processHost.status(key, ctx);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return { done: () => failed("interrupted", `host status failed: ${String(error)}`) };
|
|
97
|
+
}
|
|
98
|
+
if (status.status === "unknown") {
|
|
99
|
+
if (!task.input.rerun)
|
|
100
|
+
return { done: () => failed("interrupted", "process outcome unknown") };
|
|
101
|
+
return spawn(task, occurrence, runtime, ctx);
|
|
102
|
+
}
|
|
103
|
+
const snapshot = status;
|
|
104
|
+
await runtime.commit((tx, current) => {
|
|
105
|
+
const output = tx.slot({ id: current.id, kind: jobKind });
|
|
106
|
+
output.stdout = snapshot.stdout;
|
|
107
|
+
output.stderr = snapshot.stderr;
|
|
108
|
+
output.droppedStdout = snapshot.droppedStdout;
|
|
109
|
+
output.droppedStderr = snapshot.droppedStderr;
|
|
110
|
+
if (snapshot.status === "exited")
|
|
111
|
+
output.exitCode = snapshot.exitCode;
|
|
112
|
+
}, ctx);
|
|
113
|
+
if (snapshot.status === "exited") {
|
|
114
|
+
const { exitCode, stdout, stderr } = snapshot;
|
|
115
|
+
if (task.input.every === undefined) {
|
|
116
|
+
return {
|
|
117
|
+
done: async (tx, current) => {
|
|
118
|
+
if (task.input.notify)
|
|
119
|
+
await tx.write(current.conversationId, notice(`job ${task.id} exited with code ${exitCode}`, runtime.now()));
|
|
120
|
+
return { status: "completed", result: { exitCode, occurrences: occurrence, stdout, stderr } };
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const untilMs = runtime.now() + task.input.every;
|
|
125
|
+
return {
|
|
126
|
+
next: async (tx, current) => {
|
|
127
|
+
if (task.input.notify)
|
|
128
|
+
await tx.write(current.conversationId, notice(`job ${task.id} occurrence ${occurrence} exited with code ${exitCode}`, runtime.now()));
|
|
129
|
+
const output = tx.slot({ id: current.id, kind: jobKind });
|
|
130
|
+
output.stdout = "";
|
|
131
|
+
output.stderr = "";
|
|
132
|
+
output.droppedStdout = 0;
|
|
133
|
+
output.droppedStderr = 0;
|
|
134
|
+
delete output.exitCode;
|
|
135
|
+
output.occurrence = occurrence + 1;
|
|
136
|
+
return { phase: "waiting", untilMs, occurrence: occurrence + 1 };
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
await runtime.sleep(runtime.now() + Math.min(1000, 100 * 2 ** Math.min(attempt, 4)), ctx);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=job.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type JsonValue, type Kind } from "../types.ts";
|
|
2
|
+
export type PluginInput = {
|
|
3
|
+
handler: string;
|
|
4
|
+
input: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
type PluginCheckpoint = {
|
|
7
|
+
phase: "started";
|
|
8
|
+
};
|
|
9
|
+
type PluginFailure = {
|
|
10
|
+
reason: "missing_handler" | "threw";
|
|
11
|
+
detail: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const plugin: Readonly<Kind<PluginInput, PluginCheckpoint, import("@earendil-works/chord").JsonValue, PluginFailure, null, object, import("../types.ts").KindConfig<import("../types.ts").ConfigShape, import("../types.ts").ConfigShape>, import("../types.ts").JsonObject, import("../types.ts").TaskTx>>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { toStored } from "../types.js";
|
|
2
|
+
import { taskApi } from "./task-api.js";
|
|
3
|
+
const pluginKind = {
|
|
4
|
+
name: "pi.plugin",
|
|
5
|
+
inflight: ["started"],
|
|
6
|
+
phases: {
|
|
7
|
+
async started(task, runtime, ctx) {
|
|
8
|
+
return run(task, runtime, ctx);
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
async initial(task, runtime, ctx) {
|
|
12
|
+
await runtime.commit((tx) => tx.checkpoint({ phase: "started" }), ctx);
|
|
13
|
+
return run(task, runtime, ctx);
|
|
14
|
+
},
|
|
15
|
+
async abort() {
|
|
16
|
+
return async () => null;
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export const plugin = Object.freeze(pluginKind);
|
|
20
|
+
async function run(task, runtime, ctx) {
|
|
21
|
+
const handler = runtime.plugins.get(task.input.handler);
|
|
22
|
+
if (handler === undefined) {
|
|
23
|
+
return { done: () => ({ status: "failed", failure: { reason: "missing_handler", detail: task.input.handler } }) };
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const result = toStored(await handler(task.input.input, taskApi(task, runtime), ctx));
|
|
27
|
+
return { done: () => ({ status: "completed", result }) };
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (ctx.abortSignal?.aborted)
|
|
31
|
+
throw error;
|
|
32
|
+
return { done: () => ({ status: "failed", failure: { reason: "threw", detail: String(error) } }) };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Context } from "@earendil-works/chord";
|
|
2
|
+
import { type CoreKind, type HookInfo, type Id } from "../types.ts";
|
|
3
|
+
export type PostToolsInput = {
|
|
4
|
+
inputs: Id[];
|
|
5
|
+
assistant: Id;
|
|
6
|
+
tools: Id[];
|
|
7
|
+
};
|
|
8
|
+
export type PostToolsResult = {
|
|
9
|
+
successor?: Id;
|
|
10
|
+
ended?: "terminate" | "handoff";
|
|
11
|
+
};
|
|
12
|
+
export interface PostToolsHooks {
|
|
13
|
+
afterTools(assistant: Id, results: Id[], info: HookInfo, ctx: Context): void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare const postToolsConfig: {
|
|
16
|
+
readonly sticky: {
|
|
17
|
+
readonly steeringMode: "all" | "one-at-a-time";
|
|
18
|
+
readonly followUpMode: "all" | "one-at-a-time";
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare const postTools: CoreKind<PostToolsInput, never, PostToolsResult, never, null, PostToolsHooks, typeof postToolsConfig>;
|
|
22
|
+
//# sourceMappingURL=post-tools.d.ts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { toStored } from "../types.js";
|
|
2
|
+
export const postToolsConfig = {
|
|
3
|
+
sticky: {
|
|
4
|
+
steeringMode: "one-at-a-time",
|
|
5
|
+
followUpMode: "one-at-a-time",
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
|
+
export const postTools = {
|
|
9
|
+
name: "pi.post_tools",
|
|
10
|
+
turn: true,
|
|
11
|
+
config: postToolsConfig,
|
|
12
|
+
phases: {},
|
|
13
|
+
async initial(task, rt, ctx) {
|
|
14
|
+
const rows = await rt.commit(async (tx) => {
|
|
15
|
+
const assistant = await tx.entry(task.input.assistant);
|
|
16
|
+
const calls = (assistant?.model?.[0]?.content ?? []).filter((content) => content.type === "toolCall");
|
|
17
|
+
return Promise.all(task.input.tools.map(async (id, index) => {
|
|
18
|
+
const toolTask = (await tx.task(id));
|
|
19
|
+
const call = calls[index];
|
|
20
|
+
if (toolTask.outcome?.status === "completed") {
|
|
21
|
+
const result = toolTask.outcome.result;
|
|
22
|
+
return {
|
|
23
|
+
call,
|
|
24
|
+
entry: result.entry,
|
|
25
|
+
control: result.control,
|
|
26
|
+
missing: undefined,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (toolTask.outcome?.status === "aborted") {
|
|
30
|
+
const aborted = toolTask.outcome.result;
|
|
31
|
+
return {
|
|
32
|
+
call,
|
|
33
|
+
entry: aborted.entry,
|
|
34
|
+
control: undefined,
|
|
35
|
+
missing: aborted.entry === undefined ? "aborted" : undefined,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { call, entry: undefined, control: undefined, missing: "orphaned" };
|
|
39
|
+
}));
|
|
40
|
+
}, ctx);
|
|
41
|
+
const results = rows.map((row) => row.entry).filter((entry) => entry !== undefined);
|
|
42
|
+
await rt.hooks.each(ctx, (hook, api) => hook.afterTools?.(task.input.assistant, results, api, ctx));
|
|
43
|
+
return {
|
|
44
|
+
done: async (tx, current) => {
|
|
45
|
+
const conversationId = current.conversationId;
|
|
46
|
+
const head = await tx.newestEntry(conversationId, { withHead: true });
|
|
47
|
+
const state = tx.rewindable(conversationId);
|
|
48
|
+
const selectedTools = [...state.selectedTools];
|
|
49
|
+
let terminate = false;
|
|
50
|
+
let handoff;
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
for (const name of row.control?.addTools ?? [])
|
|
53
|
+
if (!selectedTools.includes(name))
|
|
54
|
+
selectedTools.push(name);
|
|
55
|
+
if (row.control?.terminate)
|
|
56
|
+
terminate = true;
|
|
57
|
+
if (row.control?.handoff !== undefined)
|
|
58
|
+
handoff = row.control.handoff;
|
|
59
|
+
}
|
|
60
|
+
if (selectedTools.length !== state.selectedTools.length) {
|
|
61
|
+
state.selectedTools = selectedTools;
|
|
62
|
+
tx.emit({ type: "config.changed", keys: ["selectedTools"] });
|
|
63
|
+
}
|
|
64
|
+
for (const row of rows) {
|
|
65
|
+
if (row.missing === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
tx.appendEntry(conversationId, {
|
|
68
|
+
kind: "pi.tool_result",
|
|
69
|
+
model: [
|
|
70
|
+
toStored({
|
|
71
|
+
role: "toolResult",
|
|
72
|
+
toolCallId: row.call.id,
|
|
73
|
+
toolName: row.call.name,
|
|
74
|
+
content: [{ type: "text", text: `Tool result unavailable: task ${row.missing}.` }],
|
|
75
|
+
isError: true,
|
|
76
|
+
timestamp: rt.now(),
|
|
77
|
+
}),
|
|
78
|
+
],
|
|
79
|
+
data: { diagnostics: [{ severity: "error", message: row.missing, code: row.missing }] },
|
|
80
|
+
});
|
|
81
|
+
tx.emit({
|
|
82
|
+
type: "warning",
|
|
83
|
+
source: "post_tools",
|
|
84
|
+
message: `synthesized ${row.missing} tool result for ${row.call.id}`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
let headBoundary = head?.id;
|
|
88
|
+
if (handoff !== undefined) {
|
|
89
|
+
headBoundary = tx.appendEntry(conversationId, {
|
|
90
|
+
kind: "pi.handoff",
|
|
91
|
+
head: "self",
|
|
92
|
+
model: [{ role: "user", content: handoff, timestamp: rt.now() }],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (handoff !== undefined || terminate) {
|
|
96
|
+
tx.sticky(conversationId).turn = { tools: [] };
|
|
97
|
+
await tx.resolveInputs(task.input.inputs, { status: "done", answer: task.input.assistant });
|
|
98
|
+
tx.emit({ type: "turn.ended", inputs: task.input.inputs, status: "done", answer: task.input.assistant });
|
|
99
|
+
const { triggers } = await tx.boundary(conversationId, "final", headBoundary);
|
|
100
|
+
if (triggers.length > 0)
|
|
101
|
+
tx.emit({ type: "turn.started", inputs: triggers });
|
|
102
|
+
const ended = handoff !== undefined ? "handoff" : "terminate";
|
|
103
|
+
return {
|
|
104
|
+
status: "completed",
|
|
105
|
+
result: triggers.length > 0
|
|
106
|
+
? { ended, successor: tx.createTask({ kind: "pi.generation", input: { inputs: triggers } }) }
|
|
107
|
+
: { ended },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const { triggers, terminated } = await tx.boundary(conversationId, "postTools", headBoundary);
|
|
111
|
+
if (terminated) {
|
|
112
|
+
tx.sticky(conversationId).turn = { tools: [] };
|
|
113
|
+
await tx.resolveInputs(task.input.inputs, { status: "unanswered", reason: "terminated" });
|
|
114
|
+
tx.emit({ type: "turn.ended", inputs: task.input.inputs, status: "unanswered", reason: "terminated" });
|
|
115
|
+
if (triggers.length > 0)
|
|
116
|
+
tx.emit({ type: "turn.started", inputs: triggers });
|
|
117
|
+
return {
|
|
118
|
+
status: "completed",
|
|
119
|
+
result: triggers.length > 0
|
|
120
|
+
? { successor: tx.createTask({ kind: "pi.generation", input: { inputs: triggers } }) }
|
|
121
|
+
: {},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
status: "completed",
|
|
126
|
+
result: {
|
|
127
|
+
successor: tx.createTask({
|
|
128
|
+
kind: "pi.generation",
|
|
129
|
+
input: { inputs: [...task.input.inputs, ...triggers] },
|
|
130
|
+
}),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
async abort(task) {
|
|
137
|
+
return async (tx, current) => {
|
|
138
|
+
tx.sticky(current.conversationId).turn = { tools: [] };
|
|
139
|
+
await tx.resolveInputs(task.input.inputs, { status: "unanswered", reason: "aborted" });
|
|
140
|
+
tx.emit({ type: "turn.ended", inputs: task.input.inputs, status: "unanswered", reason: "aborted" });
|
|
141
|
+
return null;
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=post-tools.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function taskApi(task, runtime) {
|
|
2
|
+
const isKind = (value) => typeof value === "object" && value !== null && "name" in value && "initial" in value;
|
|
3
|
+
return {
|
|
4
|
+
taskId: task.id,
|
|
5
|
+
conversationId: task.conversationId,
|
|
6
|
+
callId: "",
|
|
7
|
+
stream: () => {
|
|
8
|
+
throw new Error("stream is only available to tools");
|
|
9
|
+
},
|
|
10
|
+
progress: () => {
|
|
11
|
+
throw new Error("progress is only available to tools");
|
|
12
|
+
},
|
|
13
|
+
memo: (() => Promise.reject(new Error("memo is only available to tools"))),
|
|
14
|
+
async conversation(spec, ctx) {
|
|
15
|
+
const id = await runtime.createOwnedConversation(spec, ctx);
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
send: async (input, childContext) => {
|
|
19
|
+
const inputId = await runtime.sendOwned(id, input, childContext);
|
|
20
|
+
return {
|
|
21
|
+
id: inputId,
|
|
22
|
+
wait: (waitContext) => runtime.waitForInput(inputId, waitContext),
|
|
23
|
+
result: (resultContext) => runtime.commit((tx) => tx.input(inputId), resultContext),
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
abort: (childContext) => runtime.abortConversation(id, childContext),
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
task: ((kind, input, opts, ctx) => {
|
|
30
|
+
if (!isKind(kind))
|
|
31
|
+
throw new Error("task(): pass a kind token");
|
|
32
|
+
return runtime.commit((tx) => tx.createTask(kind, input, opts), ctx);
|
|
33
|
+
}),
|
|
34
|
+
getTask: async (ref, ctx) => (await runtime.commit((tx) => tx.task(ref.id), ctx)),
|
|
35
|
+
waitForTask: (ref, ctx) => runtime.waitForTask(ref.id, ctx),
|
|
36
|
+
slot: (ref, ctx) => runtime.commit(async (tx) => {
|
|
37
|
+
const storedTask = await tx.task(ref.id);
|
|
38
|
+
if (storedTask === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
return (tx.snapshot({ doc: "sticky", conversationId: storedTask.conversationId }).tasks[ref.id] ??
|
|
41
|
+
undefined);
|
|
42
|
+
}, ctx),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=task-api.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Context } from "@earendil-works/chord";
|
|
2
|
+
import type { ToolCall } from "@earendil-works/pi-ai";
|
|
3
|
+
import { type AnyToolDeclaration, type BeforeToolApi, type CoreKind, type HookInfo, type HookResult, type Id, type Step, type Stored, type ToolControl, type ToolResult } from "../types.ts";
|
|
4
|
+
export type StoredToolCall = Stored<ToolCall>;
|
|
5
|
+
export type ToolInput = {
|
|
6
|
+
assistant: Id;
|
|
7
|
+
call: StoredToolCall;
|
|
8
|
+
offered: string[];
|
|
9
|
+
index: number;
|
|
10
|
+
};
|
|
11
|
+
export type ToolCheckpoint = {
|
|
12
|
+
phase: "started";
|
|
13
|
+
replay: "safe" | "unsafe";
|
|
14
|
+
call: StoredToolCall;
|
|
15
|
+
};
|
|
16
|
+
export type ToolTaskResult = {
|
|
17
|
+
entry: Id;
|
|
18
|
+
control?: ToolControl;
|
|
19
|
+
};
|
|
20
|
+
/** Hook points this kind calls. Register with `h.hooks(namespace, kinds.tool, { … })`. */
|
|
21
|
+
export interface ToolHooks {
|
|
22
|
+
/** Before invocation, before `started`. Chain on `call`; `{ block }` stops it. A throw blocks. */
|
|
23
|
+
beforeTool(call: StoredToolCall, api: BeforeToolApi, ctx: Context): HookResult<{
|
|
24
|
+
call?: StoredToolCall;
|
|
25
|
+
block?: string;
|
|
26
|
+
}>;
|
|
27
|
+
/** After the tool returns; may replace the result. Chain. */
|
|
28
|
+
afterTool(call: StoredToolCall, result: ToolResult, api: HookInfo & {
|
|
29
|
+
readonly callId: string;
|
|
30
|
+
}, ctx: Context): HookResult<ToolResult>;
|
|
31
|
+
}
|
|
32
|
+
/** Validate arguments with the tool's real schema (TypeBox 1.x). */
|
|
33
|
+
export declare function invalid(declaration: AnyToolDeclaration, call: StoredToolCall): string | undefined;
|
|
34
|
+
export declare const tool: CoreKind<ToolInput, ToolCheckpoint, ToolTaskResult, never, {
|
|
35
|
+
entry: Id;
|
|
36
|
+
}, ToolHooks>;
|
|
37
|
+
export declare const DEFAULT_BOUNDS: {
|
|
38
|
+
maxBytes: number;
|
|
39
|
+
maxLines: number;
|
|
40
|
+
retain: "head";
|
|
41
|
+
};
|
|
42
|
+
export type { Step };
|
|
43
|
+
//# sourceMappingURL=tool.d.ts.map
|