@capybara-hq/kernel 0.1.0-rc.22 → 0.1.0-rc.24
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/bootstrap.json +25 -25
- package/dist/admin/admin.controller.d.ts +3 -3
- package/dist/admin/admin.controller.js +6 -2
- package/dist/admin/admin.module.d.ts +2 -1
- package/dist/admin/admin.module.js +7 -3
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/admin/outbox-dead.controller.d.ts +23 -0
- package/dist/admin/outbox-dead.controller.js +62 -0
- package/dist/admin/outbox-dead.schemas.d.ts +8 -0
- package/dist/admin/outbox-dead.schemas.js +18 -0
- package/dist/admin/outbox-dead.service.d.ts +66 -0
- package/dist/admin/outbox-dead.service.js +179 -0
- package/dist/admin/overview.service.d.ts +40 -5
- package/dist/admin/overview.service.js +41 -7
- package/dist/agents/from-template.js +1 -1
- package/dist/background/finish.d.ts +5 -2
- package/dist/background/finish.js +14 -3
- package/dist/background/launch.d.ts +44 -5
- package/dist/background/launch.js +92 -9
- package/dist/background/session.d.ts +14 -2
- package/dist/background/session.js +26 -4
- package/dist/background/status.d.ts +1 -1
- package/dist/background/status.js +3 -3
- package/dist/background/stop.d.ts +0 -2
- package/dist/background/stop.js +1 -21
- package/dist/background/store.d.ts +8 -0
- package/dist/background/store.js +24 -0
- package/dist/catalog/admin-catalog.controller.d.ts +21 -2
- package/dist/catalog/admin-catalog.controller.js +45 -6
- package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
- package/dist/catalog/admin-catalog.schemas.js +8 -0
- package/dist/catalog/catalog-content.d.ts +5 -0
- package/dist/catalog/catalog-content.js +1 -0
- package/dist/catalog/catalog.module.d.ts +2 -1
- package/dist/catalog/catalog.module.js +5 -1
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/platform-import-update.d.ts +50 -0
- package/dist/catalog/platform-import-update.js +116 -0
- package/dist/catalog/plugin-import.d.ts +36 -1
- package/dist/catalog/plugin-import.js +23 -1
- package/dist/catalog/plugin-upgrade.d.ts +18 -0
- package/dist/catalog/plugin-upgrade.js +19 -0
- package/dist/catalog/requests.service.js +2 -2
- package/dist/channels/channels.module.d.ts +5 -2
- package/dist/channels/channels.module.js +9 -2
- package/dist/channels/deliver-job.d.ts +25 -0
- package/dist/channels/deliver-job.js +25 -0
- package/dist/channels/inbound.d.ts +1 -1
- package/dist/channels/inbound.js +2 -15
- package/dist/channels/jobs.d.ts +28 -18
- package/dist/channels/jobs.js +63 -26
- package/dist/config/schema.d.ts +3 -6
- package/dist/config/schema.js +20 -27
- package/dist/conversations/agent-tree.d.ts +16 -0
- package/dist/conversations/agent-tree.js +36 -0
- package/dist/conversations/conversations.service.d.ts +44 -14
- package/dist/conversations/conversations.service.js +52 -38
- package/dist/conversations/event-log.d.ts +7 -10
- package/dist/conversations/event-log.js +24 -15
- package/dist/conversations/events.js +2 -1
- package/dist/conversations/queue.service.d.ts +8 -3
- package/dist/conversations/queue.service.js +37 -13
- package/dist/conversations/titles.d.ts +21 -8
- package/dist/conversations/titles.js +42 -15
- package/dist/db/kernel-schema.d.ts +26 -8
- package/dist/devices/devices.service.d.ts +12 -3
- package/dist/devices/devices.service.js +30 -9
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +15 -0
- package/dist/evals/run-replay.js +14 -8
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/lifecycle.d.ts +6 -1
- package/dist/extensions/lifecycle.js +9 -2
- package/dist/extensions/usage-subscribers.d.ts +43 -0
- package/dist/extensions/usage-subscribers.js +108 -0
- package/dist/http/api.module.js +2 -0
- package/dist/identity/settings.d.ts +53 -3
- package/dist/identity/settings.js +92 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infra/cli/kernel-cli.module.js +5 -0
- package/dist/infra/config/kernel-config.service.d.ts +7 -0
- package/dist/infra/config/kernel-config.service.js +20 -0
- package/dist/infra/events/kernel-events.d.ts +9 -35
- package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
- package/dist/infra/outbox/outbox-relay.module.js +18 -0
- package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
- package/dist/infra/outbox/outbox.dispatcher.js +310 -0
- package/dist/infra/outbox/outbox.module.d.ts +24 -0
- package/dist/infra/outbox/outbox.module.js +50 -0
- package/dist/infra/outbox/outbox.relay.d.ts +31 -0
- package/dist/infra/outbox/outbox.relay.js +76 -0
- package/dist/infra/outbox/outbox.service.d.ts +51 -0
- package/dist/infra/outbox/outbox.service.js +131 -0
- package/dist/infra/outbox/registry.d.ts +120 -0
- package/dist/infra/outbox/registry.js +108 -0
- package/dist/infra/queue/queue-names.d.ts +8 -0
- package/dist/infra/queue/queue-names.js +16 -0
- package/dist/kernel.module.js +3 -0
- package/dist/local-devices/device-policy.service.d.ts +4 -0
- package/dist/local-devices/device-policy.service.js +61 -3
- package/dist/local-devices/local-device-gateway.d.ts +4 -2
- package/dist/local-devices/local-device-gateway.js +39 -14
- package/dist/local-devices/machines.d.ts +25 -1
- package/dist/local-devices/machines.js +91 -15
- package/dist/local-devices/policy-summary.d.ts +44 -1
- package/dist/local-devices/policy-summary.js +69 -0
- package/dist/models/embeddings.d.ts +9 -9
- package/dist/models/embeddings.js +11 -18
- package/dist/models/models.module.js +3 -0
- package/dist/orgs/orgs.service.js +7 -0
- package/dist/orgs/settings.controller.js +2 -2
- package/dist/orgs/settings.service.d.ts +11 -5
- package/dist/orgs/settings.service.js +28 -14
- package/dist/overrides.d.ts +20 -3
- package/dist/overrides.js +10 -2
- package/dist/platform/exclusions.js +5 -0
- package/dist/platform/ops/admin.ops.js +50 -9
- package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
- package/dist/platform/ops/catalog-admin.ops.js +32 -4
- package/dist/platform/ops/org-settings.ops.js +3 -3
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/outbox.ops.d.ts +21 -0
- package/dist/platform/ops/outbox.ops.js +125 -0
- package/dist/platform/ops/platform.ops.js +1 -1
- package/dist/platform/ops/schedules.ops.js +40 -1
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +3 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker.module.js +9 -4
- package/dist/runtime/langgraph-loop.js +13 -5
- package/dist/runtime/limits.d.ts +15 -0
- package/dist/runtime/limits.js +25 -0
- package/dist/runtime/loop.d.ts +8 -3
- package/dist/runtime/loop.js +2 -1
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -2
- package/dist/runtime/model-call.d.ts +14 -16
- package/dist/runtime/model-call.js +14 -24
- package/dist/runtime/queue-lost-jobs.d.ts +24 -0
- package/dist/runtime/queue-lost-jobs.js +51 -0
- package/dist/runtime/run-control.d.ts +42 -5
- package/dist/runtime/run-control.js +66 -12
- package/dist/runtime/run-finish.d.ts +39 -12
- package/dist/runtime/run-finish.js +97 -14
- package/dist/runtime/run-jobs.d.ts +95 -13
- package/dist/runtime/run-jobs.js +199 -28
- package/dist/runtime/run-orphan-check.job.d.ts +142 -0
- package/dist/runtime/run-orphan-check.job.js +339 -0
- package/dist/runtime/run-processors.d.ts +16 -9
- package/dist/runtime/run-processors.js +1 -1
- package/dist/runtime/run-queue.d.ts +64 -55
- package/dist/runtime/run-queue.js +147 -284
- package/dist/runtime/run-steps.d.ts +1 -2
- package/dist/runtime/run-steps.js +8 -11
- package/dist/runtime/run-worker.d.ts +6 -17
- package/dist/runtime/run-worker.js +32 -34
- package/dist/runtime/runtime.module.d.ts +2 -3
- package/dist/runtime/runtime.module.js +5 -6
- package/dist/runtime/step-log.d.ts +16 -4
- package/dist/runtime/step-log.js +26 -6
- package/dist/runtime/stream.controller.d.ts +2 -4
- package/dist/runtime/stream.controller.js +5 -11
- package/dist/runtime/subagents/child.js +1 -1
- package/dist/runtime/subagents/definition.d.ts +2 -1
- package/dist/runtime/subagents/definition.js +4 -2
- package/dist/runtime/subagents/deliveries.d.ts +6 -3
- package/dist/runtime/subagents/deliveries.js +16 -7
- package/dist/runtime/subagents/dispatch.d.ts +12 -12
- package/dist/runtime/subagents/dispatch.js +13 -38
- package/dist/runtime/subagents/messages.d.ts +5 -1
- package/dist/runtime/subagents/messages.js +11 -3
- package/dist/runtime/subagents/skill-fork.d.ts +3 -3
- package/dist/runtime/subagents/skill-fork.js +5 -5
- package/dist/runtime/subagents/subagents.service.js +1 -1
- package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
- package/dist/runtime/subagents/tree-jobs.js +86 -0
- package/dist/runtime/usage-report-jobs.d.ts +23 -48
- package/dist/runtime/usage-report-jobs.js +67 -119
- package/dist/runtime/usage-report.d.ts +28 -77
- package/dist/runtime/usage-report.js +35 -213
- package/dist/runtime/waits.d.ts +48 -198
- package/dist/runtime/waits.js +103 -805
- package/dist/sandbox/platform-tiers.d.ts +86 -0
- package/dist/sandbox/platform-tiers.js +97 -0
- package/dist/sandbox/sandbox.service.d.ts +18 -5
- package/dist/sandbox/sandbox.service.js +75 -20
- package/dist/sandbox/tiers.d.ts +14 -2
- package/dist/sandbox/tiers.js +8 -0
- package/dist/schedules/calendar.d.ts +134 -0
- package/dist/schedules/calendar.js +410 -0
- package/dist/schedules/fire.d.ts +1 -3
- package/dist/schedules/fire.js +5 -10
- package/dist/schedules/run-tracker.d.ts +0 -5
- package/dist/schedules/run-tracker.js +0 -13
- package/dist/schedules/scan.job.js +15 -20
- package/dist/schedules/schedule-math.d.ts +42 -0
- package/dist/schedules/schedule-math.js +52 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +16 -0
- package/dist/schedules/scheduled-tasks.service.js +53 -0
- package/dist/schedules/schedules.controller.d.ts +5 -1
- package/dist/schedules/schedules.controller.js +15 -1
- package/dist/schedules/schedules.schemas.d.ts +35 -0
- package/dist/schedules/schedules.schemas.js +27 -0
- package/dist/schedules/store.d.ts +5 -0
- package/dist/schedules/store.js +20 -0
- package/dist/tools/approvals.service.d.ts +26 -7
- package/dist/tools/approvals.service.js +88 -10
- package/dist/tools/builtin-names.d.ts +5 -3
- package/dist/tools/builtin-names.js +12 -4
- package/dist/tools/builtins/builtin-tools.d.ts +1 -2
- package/dist/tools/builtins/builtin-tools.js +21 -17
- package/dist/tools/builtins/sandbox/bash.js +9 -3
- package/dist/tools/builtins/sandbox/common.d.ts +18 -1
- package/dist/tools/builtins/sandbox/common.js +14 -1
- package/dist/tools/builtins/sandbox/index.d.ts +2 -1
- package/dist/tools/builtins/sandbox/index.js +4 -1
- package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
- package/dist/tools/builtins/sandbox/task-list.js +130 -0
- package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
- package/dist/tools/builtins/sandbox/task-output.js +21 -3
- package/dist/tools/builtins/web/extract.d.ts +2 -4
- package/dist/tools/builtins/web/extract.js +2 -5
- package/dist/tools/pipeline.d.ts +1 -1
- package/dist/tools/pipeline.js +1 -1
- package/dist/tools/questions.service.d.ts +15 -6
- package/dist/tools/questions.service.js +20 -8
- package/dist/tools/registry.d.ts +4 -2
- package/dist/tools/registry.js +4 -3
- package/dist/tools/tools.module.js +4 -3
- package/package.json +3 -3
- package/src/migrations/0118_device_policy_ops.sql +6 -0
- package/src/migrations/0119_outbox.sql +22 -0
- package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { formatElapsed, lostReasonText } from "../../../background/render.js";
|
|
2
|
+
import { clip, display, sandboxBaseTimeoutMs, unavailableWhenNoSandbox, } from "./common.js";
|
|
3
|
+
import { outputFile, taskEnv } from "./task-output.js";
|
|
4
|
+
/** How many finished background tasks (and finished sub-agents) `TaskList` lists at most. */
|
|
5
|
+
export const TASK_LIST_FINISHED_LIMIT = 20;
|
|
6
|
+
const SPEC = {
|
|
7
|
+
name: "TaskList",
|
|
8
|
+
// Display only (the tool row; not in the fingerprint, never sent to the model).
|
|
9
|
+
keyArgs: ["status"],
|
|
10
|
+
description: "List this conversation's background tasks (started with Bash and run_in_background) and the " +
|
|
11
|
+
"sub-agents it dispatched. Running tasks come first, then the most recently finished ones " +
|
|
12
|
+
"(at most 20); each has its id, description, status (running, " +
|
|
13
|
+
"completed, failed, timed_out, stopped or lost), elapsed time, exit code once finished and " +
|
|
14
|
+
"output file. Sub-agents are listed with their agentId, description and status. Use it to " +
|
|
15
|
+
"find a task id you lost track of, for example after a long run; then use TaskOutput to read " +
|
|
16
|
+
"a task's output or TaskStop to stop it. Statuses are as last checked: TaskOutput checks a " +
|
|
17
|
+
"task now. It only reads, and lists nothing from other conversations.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
status: {
|
|
22
|
+
type: "string",
|
|
23
|
+
enum: ["running", "all"],
|
|
24
|
+
description: `"running" lists only what is still running; "all" (the default) also lists the ${TASK_LIST_FINISHED_LIMIT} most recently finished tasks and sub-agents.`,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
},
|
|
29
|
+
annotations: { readOnlyHint: true },
|
|
30
|
+
};
|
|
31
|
+
/** `running for 2m05s`, `failed, exit code 3, after 4m12s`, `lost (the sandbox was suspended), after 3s`. */
|
|
32
|
+
function taskState(task, now) {
|
|
33
|
+
const end = task.status === "running" ? now : (task.finishedAt ?? now);
|
|
34
|
+
const elapsed = formatElapsed(end.getTime() - task.startedAt.getTime());
|
|
35
|
+
if (task.status === "running") {
|
|
36
|
+
return task.sandboxCreatedAt === null ? "starting" : `running for ${elapsed}`;
|
|
37
|
+
}
|
|
38
|
+
let s = task.status;
|
|
39
|
+
if (task.lostReason !== null)
|
|
40
|
+
s += ` (${lostReasonText(task.lostReason)})`;
|
|
41
|
+
if (task.exitCode !== null)
|
|
42
|
+
s += `, exit code ${task.exitCode}`;
|
|
43
|
+
return `${s}, after ${elapsed}`;
|
|
44
|
+
}
|
|
45
|
+
function taskEntry(task, now) {
|
|
46
|
+
const output = task.sandboxCreatedAt === null && task.status !== "running"
|
|
47
|
+
? "none (the command never started)"
|
|
48
|
+
: outputFile(task);
|
|
49
|
+
return `- ${task.id} ${taskState(task, now)}: ${JSON.stringify(task.description)}\n Output: ${output}`;
|
|
50
|
+
}
|
|
51
|
+
const ACTIVE_AGENT = new Set(["queued", "running", "waiting"]);
|
|
52
|
+
const agentStatus = (s) => (s === "aborted" ? "stopped" : s);
|
|
53
|
+
const agentEntry = (a) => `- ${a.id} ${agentStatus(a.status)}: ${JSON.stringify(clip(a.description, 200))}`;
|
|
54
|
+
/** `1 running, 2 finished` (a zero count left out; `none` when both are). */
|
|
55
|
+
function counts(running, finished, onlyRunning) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
if (running > 0)
|
|
58
|
+
parts.push(`${running} running`);
|
|
59
|
+
if (finished > 0)
|
|
60
|
+
parts.push(`${finished} finished`);
|
|
61
|
+
if (parts.length === 0)
|
|
62
|
+
return onlyRunning ? "none running" : "none";
|
|
63
|
+
return parts.join(", ");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Built-in `TaskList`: the calling conversation's own background tasks (never its sub-agents' or
|
|
67
|
+
* another conversation's: owner `conversation_id`, as `TaskOutput` checks) and the sub-agents it
|
|
68
|
+
* dispatched itself. Running entries first (oldest first), then with `status: "all"` the
|
|
69
|
+
* {@link TASK_LIST_FINISHED_LIMIT} most recently finished. Reads PG only: it never checks a task in
|
|
70
|
+
* its sandbox, so a status is the poller's or a tool's last one.
|
|
71
|
+
*/
|
|
72
|
+
export function taskListTool(deps) {
|
|
73
|
+
return {
|
|
74
|
+
spec: SPEC,
|
|
75
|
+
defaultPolicy: "allow",
|
|
76
|
+
unavailable: unavailableWhenNoSandbox(deps),
|
|
77
|
+
timeoutMs: () => sandboxBaseTimeoutMs(deps.config.get()),
|
|
78
|
+
async run(input, ctx) {
|
|
79
|
+
const onlyRunning = input.status === "running";
|
|
80
|
+
const env = await taskEnv(deps, ctx);
|
|
81
|
+
const store = deps.background;
|
|
82
|
+
const [running, finished, agents] = await Promise.all([
|
|
83
|
+
store.runningOwnedBy(ctx.conversationId),
|
|
84
|
+
onlyRunning
|
|
85
|
+
? { rows: [], total: 0 }
|
|
86
|
+
: store.finishedOwnedBy(ctx.conversationId, TASK_LIST_FINISHED_LIMIT),
|
|
87
|
+
env.subagents?.childrenOf(ctx.orgId, ctx.conversationId) ?? [],
|
|
88
|
+
]);
|
|
89
|
+
const now = new Date();
|
|
90
|
+
const activeAgents = agents.filter((a) => ACTIVE_AGENT.has(a.status));
|
|
91
|
+
const doneAgents = onlyRunning
|
|
92
|
+
? []
|
|
93
|
+
: agents
|
|
94
|
+
.filter((a) => !ACTIVE_AGENT.has(a.status))
|
|
95
|
+
.sort((a, b) => (b.finishedAt?.getTime() ?? 0) - (a.finishedAt?.getTime() ?? 0));
|
|
96
|
+
const listedDone = doneAgents.slice(0, TASK_LIST_FINISHED_LIMIT);
|
|
97
|
+
if (running.length + finished.total + activeAgents.length + doneAgents.length === 0) {
|
|
98
|
+
return result(onlyRunning
|
|
99
|
+
? "No background tasks or sub-agents are running in this conversation."
|
|
100
|
+
: "No background tasks or sub-agents in this conversation.");
|
|
101
|
+
}
|
|
102
|
+
const lines = [
|
|
103
|
+
`Background tasks: ${counts(running.length, finished.total, onlyRunning)}.`,
|
|
104
|
+
...running.map((t) => taskEntry(t, now)),
|
|
105
|
+
...finished.rows.map((t) => taskEntry(t, now)),
|
|
106
|
+
];
|
|
107
|
+
const olderTasks = finished.total - finished.rows.length;
|
|
108
|
+
if (olderTasks > 0)
|
|
109
|
+
lines.push(`(${olderTasks} older finished tasks are not listed.)`);
|
|
110
|
+
if (agents.length > 0) {
|
|
111
|
+
lines.push("", `Sub-agents: ${counts(activeAgents.length, doneAgents.length, onlyRunning)}.`, ...activeAgents.map(agentEntry), ...listedDone.map(agentEntry));
|
|
112
|
+
const olderAgents = doneAgents.length - listedDone.length;
|
|
113
|
+
if (olderAgents > 0)
|
|
114
|
+
lines.push(`(${olderAgents} older finished sub-agents are not listed.)`);
|
|
115
|
+
}
|
|
116
|
+
lines.push("", "Statuses are as last checked. Use TaskOutput to check a task now and read its output, TaskStop to stop it." +
|
|
117
|
+
(agents.length > 0
|
|
118
|
+
? " A sub-agent's report arrives on its own; use SendMessage to give it more instructions."
|
|
119
|
+
: ""));
|
|
120
|
+
return result(lines.join("\n"));
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function result(text) {
|
|
125
|
+
return {
|
|
126
|
+
content: [{ type: "text", text }],
|
|
127
|
+
isError: false,
|
|
128
|
+
display: display("列出后台任务", "List background tasks"),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -16,6 +16,7 @@ export interface TaskEnv {
|
|
|
16
16
|
ifRunning: SandboxService["ifRunning"];
|
|
17
17
|
devices: SandboxToolDeps["devices"];
|
|
18
18
|
log: SandboxToolDeps["log"];
|
|
19
|
+
subagents?: SandboxToolDeps["subagents"];
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* The task tools' dependencies; throws the tool's error when they are missing, or when the
|
|
@@ -23,9 +24,15 @@ export interface TaskEnv {
|
|
|
23
24
|
* ruling R8).
|
|
24
25
|
*/
|
|
25
26
|
export declare function taskEnv(deps: SandboxToolDeps, ctx: BuiltinCallContext): Promise<TaskEnv>;
|
|
27
|
+
/**
|
|
28
|
+
* A sub-agent's agentId passed as a task id (as Claude Code's TaskOutput allows for background
|
|
29
|
+
* agents): its report arrives on its own, so polling or sleeping for it only wastes the run.
|
|
30
|
+
*/
|
|
31
|
+
export declare const subagentNotTaskText: (id: string) => string;
|
|
26
32
|
/**
|
|
27
33
|
* The task `id` when it belongs to the calling conversation; a task of another conversation (a
|
|
28
|
-
* sub-agent's, when called from its parent) is not found, the same as an unknown id.
|
|
34
|
+
* sub-agent's, when called from its parent) is not found, the same as an unknown id. A sub-agent's
|
|
35
|
+
* agentId gets its own text ({@link subagentNotTaskText}).
|
|
29
36
|
*/
|
|
30
37
|
export declare function ownedTask(env: TaskEnv, ctx: BuiltinCallContext, id: string): Promise<BackgroundTaskRow>;
|
|
31
38
|
/**
|
|
@@ -67,16 +67,34 @@ export async function taskEnv(deps, ctx) {
|
|
|
67
67
|
ifRunning: deps.sandbox.ifRunning.bind(deps.sandbox),
|
|
68
68
|
devices: deps.devices,
|
|
69
69
|
log: deps.log,
|
|
70
|
+
...(deps.subagents !== undefined && { subagents: deps.subagents }),
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
|
-
const notFound = (id) => new ToolError(`No background task ${clip(id, 40)} in this conversation. Pass a task id that Bash with run_in_background returned in this conversation.`);
|
|
73
|
+
const notFound = (id) => new ToolError(`No background task ${clip(id, 40)} in this conversation. Pass a task id that Bash with run_in_background returned in this conversation; call TaskList to see this conversation's tasks.`);
|
|
74
|
+
/**
|
|
75
|
+
* A sub-agent's agentId passed as a task id (as Claude Code's TaskOutput allows for background
|
|
76
|
+
* agents): its report arrives on its own, so polling or sleeping for it only wastes the run.
|
|
77
|
+
*/
|
|
78
|
+
export const subagentNotTaskText = (id) => `${clip(id, 40)} is a sub-agent, not a background task. Its report arrives in this conversation as a notification when it hands back or finishes. Don't poll or sleep for it: keep working or end your turn. Use SendMessage to give it more instructions.`;
|
|
79
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
80
|
+
/** {@link notFound}, or {@link subagentNotTaskText} when `id` is a sub-agent of the caller's tree. */
|
|
81
|
+
async function missingTask(env, ctx, id) {
|
|
82
|
+
const trimmed = id.trim();
|
|
83
|
+
if (env.subagents !== undefined &&
|
|
84
|
+
UUID_RE.test(trimmed) &&
|
|
85
|
+
(await env.subagents.inTree(sandboxConversationOf(ctx), trimmed.toLowerCase()))) {
|
|
86
|
+
return new ToolError(subagentNotTaskText(trimmed));
|
|
87
|
+
}
|
|
88
|
+
return notFound(id);
|
|
89
|
+
}
|
|
73
90
|
/**
|
|
74
91
|
* The task `id` when it belongs to the calling conversation; a task of another conversation (a
|
|
75
|
-
* sub-agent's, when called from its parent) is not found, the same as an unknown id.
|
|
92
|
+
* sub-agent's, when called from its parent) is not found, the same as an unknown id. A sub-agent's
|
|
93
|
+
* agentId gets its own text ({@link subagentNotTaskText}).
|
|
76
94
|
*/
|
|
77
95
|
export async function ownedTask(env, ctx, id) {
|
|
78
96
|
if (!TASK_ID_RE.test(id))
|
|
79
|
-
throw
|
|
97
|
+
throw await missingTask(env, ctx, id);
|
|
80
98
|
const task = await env.store.get(id);
|
|
81
99
|
if (!task || task.conversationId !== ctx.conversationId)
|
|
82
100
|
throw notFound(id);
|
|
@@ -4,7 +4,6 @@ import type { KernelConfigService } from "../../../infra/config/kernel-config.se
|
|
|
4
4
|
import { type ModelPurposesService } from "../../../models/purposes.js";
|
|
5
5
|
import { type HookRunner } from "../../../runtime/hook-calls.js";
|
|
6
6
|
import type { StepLog } from "../../../runtime/step-log.js";
|
|
7
|
-
import type { UsageReporter } from "../../../runtime/usage-report.js";
|
|
8
7
|
import type { BuiltinCallContext } from "../../registry.js";
|
|
9
8
|
/**
|
|
10
9
|
* The `WebFetch` extraction call (web tools spec §5): the fetched page and the model's prompt go to
|
|
@@ -33,13 +32,12 @@ export declare const WEB_FETCH_DENIED_TEXT = "An org policy blocked reading this
|
|
|
33
32
|
/** What {@link extractAnswer} needs. */
|
|
34
33
|
export interface WebFetchExtractDeps {
|
|
35
34
|
purposes: Pick<ModelPurposesService, "chat" | "chatLimits">;
|
|
36
|
-
eventLog: Pick<EventLog, "
|
|
37
|
-
stepLog: Pick<StepLog, "appendCounted" | "appendAudited">;
|
|
35
|
+
eventLog: Pick<EventLog, "notify" | "latestOfType">;
|
|
36
|
+
stepLog: Pick<StepLog, "appendCounted" | "appendReported" | "appendAudited">;
|
|
38
37
|
config: Pick<KernelConfigService, "get">;
|
|
39
38
|
log: Pick<Logger, "warn">;
|
|
40
39
|
/** Extension hooks (absent: none fire). */
|
|
41
40
|
hooks?: HookRunner | undefined;
|
|
42
|
-
usageReport?: Pick<UsageReporter, "enqueue"> | undefined;
|
|
43
41
|
}
|
|
44
42
|
/**
|
|
45
43
|
* The user message of the extraction call: the URL, then the page (title, markdown) between
|
|
@@ -192,7 +192,7 @@ export async function extractAnswer(deps, ctx, page, prompt) {
|
|
|
192
192
|
}
|
|
193
193
|
/**
|
|
194
194
|
* Appends the call's `usage` event (the tool call's run and step, `callId`; idempotent per call)
|
|
195
|
-
* and
|
|
195
|
+
* and owes its `usage.report` delivery in the same transaction. A sub-agent's call also counts on its parent run's
|
|
196
196
|
* `subagent_tokens_used`, in the same transaction ({@link appendCounted}).
|
|
197
197
|
*/
|
|
198
198
|
async function logUsage(deps, ctx, runId, step, u) {
|
|
@@ -209,14 +209,11 @@ async function logUsage(deps, ctx, runId, step, u) {
|
|
|
209
209
|
callId: ctx.callId,
|
|
210
210
|
},
|
|
211
211
|
};
|
|
212
|
-
|
|
212
|
+
await appendCounted(deps, {
|
|
213
213
|
conversationId: ctx.conversationId,
|
|
214
214
|
parentRunId: ctx.parentRunId,
|
|
215
215
|
budgetRunId: ctx.budgetRunId,
|
|
216
216
|
}, [event]);
|
|
217
|
-
const usage = written.find((e) => e.type === "usage");
|
|
218
|
-
if (usage)
|
|
219
|
-
void deps.usageReport?.enqueue(ctx.conversationId, usage.seq);
|
|
220
217
|
}
|
|
221
218
|
/**
|
|
222
219
|
* Records a `model.request` denial of the extraction call: the `hook_denied` event (the tool call's
|
package/dist/tools/pipeline.d.ts
CHANGED
|
@@ -310,7 +310,7 @@ export declare class ToolPipeline {
|
|
|
310
310
|
runStep(given: ToolStepContext): Promise<ToolStepOutcome>;
|
|
311
311
|
/**
|
|
312
312
|
* Writes, in the caller's transaction (`mandatory`), what a run that is being stopped (a person,
|
|
313
|
-
* its deadline, a failure,
|
|
313
|
+
* its deadline, a failure, an orphan repair) still owes its log: the report of its fork invocation
|
|
314
314
|
* (phase D, `pairStoppedForks`; a still active fork child is stopped by the caller after its
|
|
315
315
|
* commit). An `Agent` call has its result from its dispatch (agent map spec §4.1), so there is
|
|
316
316
|
* nothing to write for it. Returns the fork's call id (the caller must not write a "not executed"
|
package/dist/tools/pipeline.js
CHANGED
|
@@ -331,7 +331,7 @@ let ToolPipeline = class ToolPipeline {
|
|
|
331
331
|
}
|
|
332
332
|
/**
|
|
333
333
|
* Writes, in the caller's transaction (`mandatory`), what a run that is being stopped (a person,
|
|
334
|
-
* its deadline, a failure,
|
|
334
|
+
* its deadline, a failure, an orphan repair) still owes its log: the report of its fork invocation
|
|
335
335
|
* (phase D, `pairStoppedForks`; a still active fork child is stopped by the caller after its
|
|
336
336
|
* commit). An `Agent` call has its result from its dispatch (agent map spec §4.1), so there is
|
|
337
337
|
* nothing to write for it. Returns the fork's call id (the caller must not write a "not executed"
|
|
@@ -4,6 +4,7 @@ import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
|
4
4
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
5
5
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
6
6
|
import { KernelEvents } from "../infra/events/kernel-events.js";
|
|
7
|
+
import { RunResume } from "../runtime/run-jobs.js";
|
|
7
8
|
export type QuestionStatus = "pending" | "answered" | "skipped" | "expired" | "cancelled";
|
|
8
9
|
/** 一条输入请求(`AskUserQuestion`、插件工具的 `input_required`、MCP elicitation 共用)。 */
|
|
9
10
|
export interface QuestionRecord {
|
|
@@ -44,9 +45,11 @@ export type QuestionView = Omit<QuestionRecord, "state">;
|
|
|
44
45
|
* 状态全部在 PG:回答 / 超时 / 取消都在事务里 `SELECT … FOR UPDATE` 该行,多副本并发时恰好一个生效,
|
|
45
46
|
* 只有生效的那次写 `question_answered`。HTTP 接口见 questions.controller.ts。
|
|
46
47
|
*
|
|
47
|
-
* An answer
|
|
48
|
-
*
|
|
49
|
-
*
|
|
48
|
+
* An answer resumes its waiting run in the answer's transaction (`RunResume.resumeIn`, after the
|
|
49
|
+
* question row: lock order conversation, question, then run; transactional outbox spec §6). It is
|
|
50
|
+
* announced after the commit as the domain event `question.answered` (exactly once; no kernel
|
|
51
|
+
* subscriber: the IM card update is owed by the `question_answered` append, transactional outbox
|
|
52
|
+
* spec §8.1). Events are appended in the context's transaction (`EventLog.appendIn`).
|
|
50
53
|
*/
|
|
51
54
|
export declare class QuestionsService {
|
|
52
55
|
private readonly db;
|
|
@@ -54,7 +57,11 @@ export declare class QuestionsService {
|
|
|
54
57
|
private readonly eventLog;
|
|
55
58
|
private readonly events;
|
|
56
59
|
readonly txHost: TransactionHost;
|
|
57
|
-
|
|
60
|
+
/** An answer resumes its waiting run in the answer's transaction. */
|
|
61
|
+
private readonly resumes;
|
|
62
|
+
constructor(db: KernelDb, config: Pick<KernelConfigService, "get">, eventLog: Pick<EventLog, "appendIn" | "notify">, events: Pick<KernelEvents, "emit">, txHost: TransactionHost,
|
|
63
|
+
/** An answer resumes its waiting run in the answer's transaction. */
|
|
64
|
+
resumes: Pick<RunResume, "resumeIn">);
|
|
58
65
|
/**
|
|
59
66
|
* 新建 pending 输入请求(`expires_at` = 现在 + `tools.approvalTimeoutHours`)并写 `question_asked`,同一事务。
|
|
60
67
|
* 按 (run_id, call_id, attempt) 幂等:已存在则返回已有记录,事件按 `question_asked:<id>` 幂等。
|
|
@@ -113,8 +120,10 @@ export declare class QuestionsService {
|
|
|
113
120
|
* by a run of it that is `running` or `waiting` and was started by `accountId`. The caller holds
|
|
114
121
|
* the conversation row lock (its `appendIn`), so only questions logged before the message are
|
|
115
122
|
* seen. Each becomes `skipped` with `question_answered { outcome: "skipped", skippedBySeq }`.
|
|
116
|
-
*
|
|
117
|
-
* `
|
|
123
|
+
* The caller resumes their waiting runs in this transaction after it locked every row it skips
|
|
124
|
+
* (`ConversationsService.skipWaitsIn`: conversations, decided rows, runs). Returns the records and
|
|
125
|
+
* the highest seq written (null: none); the caller notifies and emits `question.answered` after
|
|
126
|
+
* the commit.
|
|
118
127
|
*/
|
|
119
128
|
skipPendingIn(conversationId: string, accountId: string, messageSeq: number): Promise<{
|
|
120
129
|
records: QuestionRecord[];
|
|
@@ -18,6 +18,7 @@ import { KernelDb } from "../infra/database/kernel-db.js";
|
|
|
18
18
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
19
19
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
20
20
|
import { KernelEvents } from "../infra/events/kernel-events.js";
|
|
21
|
+
import { RunResume } from "../runtime/run-jobs.js";
|
|
21
22
|
const notFound = () => new ApiError("question.not_found", "Question not found");
|
|
22
23
|
const notInitiator = () => new ApiError("forbidden", "Only the user who started the run can answer this question");
|
|
23
24
|
const toView = ({ state: _state, ...rest }) => rest;
|
|
@@ -49,9 +50,11 @@ const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArr
|
|
|
49
50
|
* 状态全部在 PG:回答 / 超时 / 取消都在事务里 `SELECT … FOR UPDATE` 该行,多副本并发时恰好一个生效,
|
|
50
51
|
* 只有生效的那次写 `question_answered`。HTTP 接口见 questions.controller.ts。
|
|
51
52
|
*
|
|
52
|
-
* An answer
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* An answer resumes its waiting run in the answer's transaction (`RunResume.resumeIn`, after the
|
|
54
|
+
* question row: lock order conversation, question, then run; transactional outbox spec §6). It is
|
|
55
|
+
* announced after the commit as the domain event `question.answered` (exactly once; no kernel
|
|
56
|
+
* subscriber: the IM card update is owed by the `question_answered` append, transactional outbox
|
|
57
|
+
* spec §8.1). Events are appended in the context's transaction (`EventLog.appendIn`).
|
|
55
58
|
*/
|
|
56
59
|
let QuestionsService = class QuestionsService {
|
|
57
60
|
db;
|
|
@@ -59,12 +62,16 @@ let QuestionsService = class QuestionsService {
|
|
|
59
62
|
eventLog;
|
|
60
63
|
events;
|
|
61
64
|
txHost;
|
|
62
|
-
|
|
65
|
+
resumes;
|
|
66
|
+
constructor(db, config, eventLog, events, txHost,
|
|
67
|
+
/** An answer resumes its waiting run in the answer's transaction. */
|
|
68
|
+
resumes) {
|
|
63
69
|
this.db = db;
|
|
64
70
|
this.config = config;
|
|
65
71
|
this.eventLog = eventLog;
|
|
66
72
|
this.events = events;
|
|
67
73
|
this.txHost = txHost;
|
|
74
|
+
this.resumes = resumes;
|
|
68
75
|
}
|
|
69
76
|
/**
|
|
70
77
|
* 新建 pending 输入请求(`expires_at` = 现在 + `tools.approvalTimeoutHours`)并写 `question_asked`,同一事务。
|
|
@@ -163,7 +170,7 @@ let QuestionsService = class QuestionsService {
|
|
|
163
170
|
async answer(questionId, accountId, answer, orgId) {
|
|
164
171
|
const { record, toSeq } = await this.answerIn(questionId, accountId, answer, orgId);
|
|
165
172
|
await this.eventLog.notify(record.conversationId, toSeq);
|
|
166
|
-
//
|
|
173
|
+
// its IM delivery is enqueued (handler failures are logged); the run resumed in the answer
|
|
167
174
|
await this.events.emit("question.answered", {
|
|
168
175
|
id: record.id,
|
|
169
176
|
orgId: record.orgId,
|
|
@@ -246,6 +253,8 @@ let QuestionsService = class QuestionsService {
|
|
|
246
253
|
.returningAll()
|
|
247
254
|
.executeTakeFirstOrThrow();
|
|
248
255
|
const toSeq = await this.answeredEvent(before, answer, accountId, "answered");
|
|
256
|
+
// the run last; a still-running run is resumed by its suspend's re-check
|
|
257
|
+
await this.resumes.resumeIn(before.runId, questionId);
|
|
249
258
|
return { record: toRecord(updated), toSeq };
|
|
250
259
|
}
|
|
251
260
|
/**
|
|
@@ -375,8 +384,10 @@ let QuestionsService = class QuestionsService {
|
|
|
375
384
|
* by a run of it that is `running` or `waiting` and was started by `accountId`. The caller holds
|
|
376
385
|
* the conversation row lock (its `appendIn`), so only questions logged before the message are
|
|
377
386
|
* seen. Each becomes `skipped` with `question_answered { outcome: "skipped", skippedBySeq }`.
|
|
378
|
-
*
|
|
379
|
-
* `
|
|
387
|
+
* The caller resumes their waiting runs in this transaction after it locked every row it skips
|
|
388
|
+
* (`ConversationsService.skipWaitsIn`: conversations, decided rows, runs). Returns the records and
|
|
389
|
+
* the highest seq written (null: none); the caller notifies and emits `question.answered` after
|
|
390
|
+
* the commit.
|
|
380
391
|
*/
|
|
381
392
|
async skipPendingIn(conversationId, accountId, messageSeq) {
|
|
382
393
|
const t = this.db.db;
|
|
@@ -451,6 +462,7 @@ QuestionsService = __decorate([
|
|
|
451
462
|
__param(1, Inject(KernelConfigService)),
|
|
452
463
|
__param(2, Inject(EventLog)),
|
|
453
464
|
__param(3, Inject(KernelEvents)),
|
|
454
|
-
__param(4, Inject(TransactionHost))
|
|
465
|
+
__param(4, Inject(TransactionHost)),
|
|
466
|
+
__param(5, Inject(RunResume))
|
|
455
467
|
], QuestionsService);
|
|
456
468
|
export { QuestionsService };
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface BuiltinCallContext extends ToolCallContext {
|
|
|
40
40
|
/**
|
|
41
41
|
* 本次运行的截止时间(epoch 毫秒,`runtime.maxRunSeconds` 起算,Ruling M20)。到点运行被中止;
|
|
42
42
|
* 沙箱命令按它收紧超时,赶在截止前自己超时、给模型可执行的说明。
|
|
43
|
+
* Absent when the run has no duration limit (`runtime.maxRunSeconds` 0): commands are then limited
|
|
44
|
+
* only by `sandbox.limits.maxCommandSeconds` and the tool timeouts.
|
|
43
45
|
*/
|
|
44
46
|
runDeadline?: number;
|
|
45
47
|
/**
|
|
@@ -236,7 +238,7 @@ export interface AgentTools {
|
|
|
236
238
|
*
|
|
237
239
|
* What is offered:
|
|
238
240
|
* - builtins: every {@link AGENT_BUILTIN_NAMES} entry registered here that can run (`unavailable`
|
|
239
|
-
* says why not), `TaskOutput` / `TaskStop` with `Bash`, `Agent` while its roster is not empty;
|
|
241
|
+
* says why not), `TaskOutput` / `TaskStop` / `TaskList` with `Bash`, `Agent` while its roster is not empty;
|
|
240
242
|
* - extension tools: every tool registered by an extension loaded on this replica and enabled in
|
|
241
243
|
* the org (`extension_org_configs.enabled`; required bootstrap plugins are enabled in every org,
|
|
242
244
|
* `enabled.ts`), whose effective config for the org is valid (layering spec A §6) and that the
|
|
@@ -380,7 +382,7 @@ export declare class ToolRegistry {
|
|
|
380
382
|
}
|
|
381
383
|
/**
|
|
382
384
|
* `tools` narrowed by a sub-agent's key filter (tools default-on spec §4): `deny` keys removed,
|
|
383
|
-
* and with `allow` only its keys kept. `TaskOutput` / `TaskStop` follow `Bash`, as they come with
|
|
385
|
+
* and with `allow` only its keys kept. `TaskOutput` / `TaskStop` / `TaskList` follow `Bash`, as they come with
|
|
384
386
|
* it. Without a filter the list is returned as it is.
|
|
385
387
|
*/
|
|
386
388
|
export declare function filterSubagentTools(tools: ResolvedTool[], filter: SubagentTools | undefined): ResolvedTool[];
|
package/dist/tools/registry.js
CHANGED
|
@@ -92,7 +92,7 @@ const builtinTool = (b, spec) => ({
|
|
|
92
92
|
*
|
|
93
93
|
* What is offered:
|
|
94
94
|
* - builtins: every {@link AGENT_BUILTIN_NAMES} entry registered here that can run (`unavailable`
|
|
95
|
-
* says why not), `TaskOutput` / `TaskStop` with `Bash`, `Agent` while its roster is not empty;
|
|
95
|
+
* says why not), `TaskOutput` / `TaskStop` / `TaskList` with `Bash`, `Agent` while its roster is not empty;
|
|
96
96
|
* - extension tools: every tool registered by an extension loaded on this replica and enabled in
|
|
97
97
|
* the org (`extension_org_configs.enabled`; required bootstrap plugins are enabled in every org,
|
|
98
98
|
* `enabled.ts`), whose effective config for the org is valid (layering spec A §6) and that the
|
|
@@ -396,7 +396,8 @@ let ToolRegistry = class ToolRegistry {
|
|
|
396
396
|
spec = agentToolSpec(roster, await this.maxConcurrentSubagents(orgId));
|
|
397
397
|
}
|
|
398
398
|
add(builtinTool(b, spec));
|
|
399
|
-
// `TaskOutput` and `
|
|
399
|
+
// `TaskOutput`, `TaskStop` and `TaskList` come with an available `Bash` (background Bash
|
|
400
|
+
// spec §2)
|
|
400
401
|
if (name === BUILTIN.Bash) {
|
|
401
402
|
for (const companion of BASH_COMPANION_TOOLS) {
|
|
402
403
|
const c = this.builtins.find((x) => x.spec.name === companion);
|
|
@@ -585,7 +586,7 @@ ToolRegistry = __decorate([
|
|
|
585
586
|
export { ToolRegistry };
|
|
586
587
|
/**
|
|
587
588
|
* `tools` narrowed by a sub-agent's key filter (tools default-on spec §4): `deny` keys removed,
|
|
588
|
-
* and with `allow` only its keys kept. `TaskOutput` / `TaskStop` follow `Bash`, as they come with
|
|
589
|
+
* and with `allow` only its keys kept. `TaskOutput` / `TaskStop` / `TaskList` follow `Bash`, as they come with
|
|
589
590
|
* it. Without a filter the list is returned as it is.
|
|
590
591
|
*/
|
|
591
592
|
export function filterSubagentTools(tools, filter) {
|
|
@@ -17,9 +17,9 @@ import { ModelsModule } from "../models/models.module.js";
|
|
|
17
17
|
import { OrgLockModule } from "../orgs/org-lock.js";
|
|
18
18
|
import { PlatformModule } from "../platform/platform.module.js";
|
|
19
19
|
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
20
|
+
import { RunJobsModule } from "../runtime/run-jobs.js";
|
|
20
21
|
import { StepLogModule } from "../runtime/step-log.js";
|
|
21
22
|
import { SubagentsModule } from "../runtime/subagents/subagents.service.js";
|
|
22
|
-
import { UsageReportModule } from "../runtime/usage-report.js";
|
|
23
23
|
import { SandboxModule } from "../sandbox/sandbox.module.js";
|
|
24
24
|
import { ScheduledTaskStoreModule } from "../schedules/store.module.js";
|
|
25
25
|
import { SkillsModule } from "../skills/skills.module.js";
|
|
@@ -72,10 +72,11 @@ ToolsModule = __decorate([
|
|
|
72
72
|
BackgroundModule,
|
|
73
73
|
// the conversation page's tool metadata reads only what the viewer may see
|
|
74
74
|
ConversationAccessModule,
|
|
75
|
-
// the WebFetch extraction call: its purpose
|
|
75
|
+
// the WebFetch extraction call: its purpose and step writes (its usage report owed with them)
|
|
76
76
|
ModelsModule,
|
|
77
|
-
UsageReportModule,
|
|
78
77
|
StepLogModule,
|
|
78
|
+
// a decision resumes its waiting run in the decision's transaction (`RunResume`)
|
|
79
|
+
RunJobsModule,
|
|
79
80
|
// the `Platform` tool's operations, actor facts and agent docs (imports no domain module)
|
|
80
81
|
PlatformModule,
|
|
81
82
|
QueueModule.registerQueue(MAINTENANCE_QUEUE_NAME),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capybara-hq/kernel",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.24",
|
|
4
4
|
"description": "Capybara kernel: config, database, plugin host and HTTP API of the Capybara agent platform",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"yaml": "^2.9.1",
|
|
66
66
|
"yauzl": "3.4.0",
|
|
67
67
|
"zod": "^4.6.7",
|
|
68
|
-
"@capybara-hq/plugin-sdk": "^0.1.0-rc.
|
|
68
|
+
"@capybara-hq/plugin-sdk": "^0.1.0-rc.18"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@langchain/langgraph-checkpoint-validation": "^1.2.0",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@types/ws": "^8.18.2",
|
|
75
75
|
"@types/yauzl": "3.4.0",
|
|
76
76
|
"ws": "^8.22.0",
|
|
77
|
-
"@capybara-hq/testing": "0.1.0-rc.
|
|
77
|
+
"@capybara-hq/testing": "0.1.0-rc.16"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"build": "tsc -b"
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-- The `policy` ops the platform sent to a machine whose answer may not be recorded yet (sandbox dev
|
|
2
|
+
-- tiers spec §10.4): a summary the machine reports by itself (a `policy` frame, the next hello)
|
|
3
|
+
-- that is such an op's change is not listed again as a change made on the machine. A JSON array of
|
|
4
|
+
-- `{ id, add, remove, tier?, isolation?, until }`; an entry leaves when its answer is recorded or,
|
|
5
|
+
-- unanswered, when `until` (epoch ms) has passed.
|
|
6
|
+
ALTER TABLE device_machines ADD COLUMN IF NOT EXISTS pending_policy_ops jsonb NOT NULL DEFAULT '[]'::jsonb;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- Transactional outbox (transactional outbox spec §4): work that must follow a commit is written
|
|
2
|
+
-- here in the same transaction as the state that owes it, and a relay delivers it to BullMQ. Rows are
|
|
3
|
+
-- deleted on delivery; only dead rows (`dead_at` set) stay.
|
|
4
|
+
|
|
5
|
+
CREATE TABLE IF NOT EXISTS outbox (
|
|
6
|
+
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
7
|
+
queue text NOT NULL,
|
|
8
|
+
job_name text NOT NULL,
|
|
9
|
+
job_id text NOT NULL,
|
|
10
|
+
data jsonb NOT NULL,
|
|
11
|
+
run_at timestamptz,
|
|
12
|
+
org_id text, -- for the overview and for org deletion; NULL for platform work
|
|
13
|
+
attempts integer NOT NULL DEFAULT 0,
|
|
14
|
+
next_attempt_at timestamptz NOT NULL DEFAULT now(),
|
|
15
|
+
last_error text,
|
|
16
|
+
dead_at timestamptz,
|
|
17
|
+
created_at timestamptz NOT NULL DEFAULT now()
|
|
18
|
+
);
|
|
19
|
+
-- one pending row per job: a second add of the same job before delivery is a no-op; a dead row
|
|
20
|
+
-- does not count, so it never blocks the same job owed again
|
|
21
|
+
CREATE UNIQUE INDEX IF NOT EXISTS outbox_job_uniq ON outbox (queue, job_id) WHERE dead_at IS NULL;
|
|
22
|
+
CREATE INDEX IF NOT EXISTS outbox_due ON outbox (next_attempt_at) WHERE dead_at IS NULL;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- 0120, transactional outbox spec §8.1 / §8.2: a `usage.report` delivery is owed in the outbox
|
|
2
|
+
-- with the usage it reports, so the usage sweeper is gone, and with it its watermark table and the
|
|
3
|
+
-- index it found unreported `model_usage` rows by. (`conversation_events_usage_idx` stays: the
|
|
4
|
+
-- admin usage aggregate reads usage events by time.)
|
|
5
|
+
-- capybara:allow-destructive the sweeper that read and wrote this single-row watermark is removed in this release (project not released, no compatibility layer)
|
|
6
|
+
DROP TABLE IF EXISTS usage_report_sweep;
|
|
7
|
+
DROP INDEX IF EXISTS model_usage_unreported;
|