@capybara-hq/kernel 0.1.0-rc.23 → 0.1.0-rc.25
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.module.d.ts +2 -1
- package/dist/admin/admin.module.js +9 -3
- package/dist/admin/health.service.d.ts +2 -2
- package/dist/admin/health.service.js +6 -2
- 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/agents.module.js +3 -0
- package/dist/agents/agents.service.d.ts +6 -1
- package/dist/agents/agents.service.js +11 -2
- 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 +2 -1
- package/dist/background/launch.js +5 -2
- 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-import.module.js +0 -4
- package/dist/catalog/catalog-scope.service.d.ts +63 -26
- package/dist/catalog/catalog-scope.service.js +146 -71
- package/dist/catalog/catalog.module.d.ts +2 -1
- package/dist/catalog/catalog.module.js +9 -4
- package/dist/catalog/catalog.service.d.ts +11 -4
- package/dist/catalog/catalog.service.js +21 -5
- package/dist/catalog/cli.d.ts +4 -3
- package/dist/catalog/cli.js +8 -13
- package/dist/catalog/job-ids.d.ts +8 -20
- package/dist/catalog/job-ids.js +11 -16
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-plugin-uploads.d.ts +11 -4
- package/dist/catalog/org-plugin-uploads.js +21 -6
- package/dist/catalog/owned-items.d.ts +6 -13
- package/dist/catalog/owned-items.js +11 -29
- package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
- package/dist/catalog/owned-plugin-cleanup.js +12 -66
- package/dist/catalog/platform-components.d.ts +56 -34
- package/dist/catalog/platform-components.js +68 -78
- 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 +64 -26
- package/dist/catalog/plugin-import.js +113 -77
- package/dist/catalog/plugin-upgrade.d.ts +22 -4
- package/dist/catalog/plugin-upgrade.js +26 -19
- package/dist/catalog/scope-jobs.d.ts +59 -0
- package/dist/catalog/scope-jobs.js +65 -0
- package/dist/catalog/scope-sync-workers.d.ts +22 -0
- package/dist/catalog/scope-sync-workers.js +58 -2
- package/dist/catalog/scope-sync.d.ts +40 -65
- package/dist/catalog/scope-sync.js +114 -122
- 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 +4 -17
- package/dist/channels/jobs.d.ts +28 -18
- package/dist/channels/jobs.js +63 -26
- package/dist/channels/threads.d.ts +4 -3
- package/dist/channels/threads.js +4 -3
- package/dist/config/schema.d.ts +0 -3
- package/dist/config/schema.js +11 -20
- package/dist/conversations/agent-tree.d.ts +16 -0
- package/dist/conversations/agent-tree.js +36 -0
- package/dist/conversations/conversations.controller.js +4 -2
- package/dist/conversations/conversations.service.d.ts +61 -19
- package/dist/conversations/conversations.service.js +69 -43
- package/dist/conversations/event-log.d.ts +7 -10
- package/dist/conversations/event-log.js +24 -15
- package/dist/conversations/events.d.ts +21 -0
- package/dist/conversations/events.js +26 -2
- package/dist/conversations/queue.service.d.ts +8 -3
- package/dist/conversations/queue.service.js +37 -13
- package/dist/conversations/source.d.ts +10 -0
- package/dist/conversations/source.js +17 -0
- package/dist/conversations/titles.d.ts +21 -8
- package/dist/conversations/titles.js +42 -15
- package/dist/conversations/tree.d.ts +10 -0
- package/dist/conversations/tree.js +35 -0
- package/dist/db/kernel-schema.d.ts +35 -22
- package/dist/devices/devices.service.d.ts +23 -11
- package/dist/devices/devices.service.js +34 -26
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +11 -0
- package/dist/evals/run-replay.d.ts +13 -2
- package/dist/evals/run-replay.js +42 -9
- package/dist/evals/snapshot.d.ts +7 -1
- package/dist/evals/snapshot.js +2 -1
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/hooks.d.ts +22 -3
- package/dist/extensions/hooks.js +15 -1
- package/dist/extensions/lifecycle-hooks.d.ts +99 -0
- package/dist/extensions/lifecycle-hooks.js +273 -0
- package/dist/extensions/lifecycle.d.ts +6 -1
- package/dist/extensions/lifecycle.js +9 -2
- package/dist/extensions/org-config.d.ts +13 -1
- package/dist/extensions/org-config.js +19 -2
- package/dist/extensions/permission-view.d.ts +9 -5
- package/dist/extensions/permission-view.js +9 -4
- package/dist/extensions/point-defaults.d.ts +28 -1
- package/dist/extensions/point-defaults.js +44 -13
- 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/inbox/inbox.service.d.ts +6 -20
- package/dist/inbox/inbox.service.js +0 -3
- package/dist/inbox/org-notices.d.ts +1 -1
- package/dist/inbox/platform-inbox.service.d.ts +3 -32
- package/dist/inbox/platform-inbox.service.js +5 -54
- 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/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 +244 -0
- package/dist/infra/outbox/registry.js +234 -0
- package/dist/infra/queue/queue-names.d.ts +8 -0
- package/dist/infra/queue/queue-names.js +17 -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/machines.d.ts +13 -5
- package/dist/local-devices/machines.js +45 -7
- 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/directory-sync.js +1 -1
- package/dist/orgs/members.service.js +1 -1
- package/dist/orgs/offboarding.d.ts +50 -57
- package/dist/orgs/offboarding.js +117 -162
- package/dist/orgs/orgs.module.js +3 -0
- package/dist/orgs/orgs.service.d.ts +11 -5
- package/dist/orgs/orgs.service.js +22 -6
- package/dist/overrides.d.ts +23 -3
- package/dist/overrides.js +12 -2
- package/dist/platform/exclusions.js +5 -0
- package/dist/platform/ops/admin.ops.js +18 -2
- 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/inbox.ops.js +4 -20
- 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.d.ts +1 -0
- package/dist/platform/ops/platform.ops.js +6 -3
- 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-role.d.ts +10 -5
- package/dist/roles/worker-role.js +19 -9
- package/dist/roles/worker.module.js +11 -8
- package/dist/runtime/context/build.d.ts +3 -0
- package/dist/runtime/context/build.js +15 -0
- package/dist/runtime/context/plugin-context.d.ts +20 -0
- package/dist/runtime/context/plugin-context.js +30 -0
- package/dist/runtime/langgraph-loop.js +17 -5
- package/dist/runtime/limits.d.ts +15 -0
- package/dist/runtime/limits.js +25 -0
- package/dist/runtime/loop.d.ts +16 -3
- package/dist/runtime/loop.js +2 -1
- package/dist/runtime/maintenance.d.ts +7 -3
- package/dist/runtime/maintenance.js +52 -12
- package/dist/runtime/model-call.d.ts +20 -17
- package/dist/runtime/model-call.js +15 -24
- package/dist/runtime/plugin-context.service.d.ts +69 -0
- package/dist/runtime/plugin-context.service.js +208 -0
- 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 +47 -5
- package/dist/runtime/run-control.js +79 -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 +75 -53
- package/dist/runtime/run-queue.js +189 -263
- package/dist/runtime/run-steps.d.ts +1 -2
- package/dist/runtime/run-steps.js +8 -11
- package/dist/runtime/run-worker.d.ts +26 -16
- package/dist/runtime/run-worker.js +132 -37
- package/dist/runtime/runtime.module.d.ts +2 -3
- package/dist/runtime/runtime.module.js +7 -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 +14 -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 +8 -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/jobs.d.ts +20 -10
- package/dist/sandbox/jobs.js +23 -17
- package/dist/sandbox/sandbox.service.d.ts +17 -4
- package/dist/sandbox/sandbox.service.js +55 -14
- package/dist/schedules/calendar.d.ts +134 -0
- package/dist/schedules/calendar.js +410 -0
- package/dist/schedules/fire.d.ts +26 -7
- package/dist/schedules/fire.js +91 -22
- package/dist/schedules/job-ids.d.ts +66 -17
- package/dist/schedules/job-ids.js +81 -13
- package/dist/schedules/run-tracker.d.ts +0 -5
- package/dist/schedules/run-tracker.js +2 -14
- package/dist/schedules/scan.job.d.ts +13 -32
- package/dist/schedules/scan.job.js +50 -164
- 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 +22 -6
- package/dist/schedules/scheduled-tasks.service.js +70 -14
- package/dist/schedules/schedules.controller.d.ts +5 -1
- package/dist/schedules/schedules.controller.js +15 -1
- package/dist/schedules/schedules.module.js +0 -4
- 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/skills/changes.controller.d.ts +1 -1
- package/dist/skills/changes.controller.js +1 -1
- package/dist/tools/approvals.service.d.ts +41 -11
- package/dist/tools/approvals.service.js +108 -14
- 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 +12 -3
- package/dist/tools/pipeline.js +6 -1
- package/dist/tools/questions.service.d.ts +30 -10
- package/dist/tools/questions.service.js +41 -27
- package/dist/tools/registry.d.ts +12 -3
- package/dist/tools/registry.js +13 -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
- package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
- package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
- package/src/migrations/0123_pgvector.sql +27 -0
- package/src/migrations/0124_conversation_source.sql +36 -0
- package/dist/catalog/platform-migration.d.ts +0 -115
- package/dist/catalog/platform-migration.js +0 -583
- package/dist/infra/queue/add-job-once.d.ts +0 -14
- package/dist/infra/queue/add-job-once.js +0 -16
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { isDeepStrictEqual } from "node:util";
|
|
11
|
+
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
12
|
+
import { afterCommit } from "../database/after-commit.js";
|
|
13
|
+
import { KernelDb } from "../database/kernel-db.js";
|
|
14
|
+
import { currentStore, TransactionHost } from "../database/transaction-host.js";
|
|
15
|
+
import { Transactional } from "../database/transactional.decorator.js";
|
|
16
|
+
import { KERNEL_LOGGER } from "../tokens.js";
|
|
17
|
+
/** The fast path `add` hands each committed transaction's rows to (`OutboxModule` provides it). */
|
|
18
|
+
export const OUTBOX_FAST_PATH = Symbol("OUTBOX_FAST_PATH");
|
|
19
|
+
/**
|
|
20
|
+
* Test seam (`KernelOverride`): `true` makes a reused job id with different data throw instead of
|
|
21
|
+
* logging an error (spec §4, designer's call: "throws in tests, logs in production").
|
|
22
|
+
*/
|
|
23
|
+
export const OUTBOX_STRICT_CONFLICTS = Symbol("OUTBOX_STRICT_CONFLICTS");
|
|
24
|
+
/**
|
|
25
|
+
* The ids each open transaction inserted, keyed by its transaction store: lives only as long as
|
|
26
|
+
* that transaction (a WeakMap entry, no state shared across requests).
|
|
27
|
+
*/
|
|
28
|
+
const pendingIds = new WeakMap();
|
|
29
|
+
/**
|
|
30
|
+
* Writes owed work as a row in the caller's transaction (spec §3.2): the row commits or rolls back
|
|
31
|
+
* with the business write, and after the commit the fast path delivers it when it is due now (a
|
|
32
|
+
* row with a future `runAt` waits for the relay, spec §3.3).
|
|
33
|
+
*/
|
|
34
|
+
let OutboxService = class OutboxService {
|
|
35
|
+
txHost;
|
|
36
|
+
db;
|
|
37
|
+
log;
|
|
38
|
+
fastPath;
|
|
39
|
+
strictConflicts;
|
|
40
|
+
constructor(txHost, db, log, fastPath, strictConflicts = false) {
|
|
41
|
+
this.txHost = txHost;
|
|
42
|
+
this.db = db;
|
|
43
|
+
this.log = log;
|
|
44
|
+
this.fastPath = fastPath;
|
|
45
|
+
this.strictConflicts = strictConflicts;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Adds the job to the outbox in the transaction in context (throws outside one). Returns true when
|
|
49
|
+
* it inserted a row, false when the same (queue, jobId) is already owed (a no-op; a dead row is
|
|
50
|
+
* not owed). A conflict whose stored data differs is a bug in the job id: it throws under strict
|
|
51
|
+
* conflicts, else logs an error. Undefined data is stored as JSON null.
|
|
52
|
+
*/
|
|
53
|
+
async add(job) {
|
|
54
|
+
if (job.jobId.includes(":")) {
|
|
55
|
+
throw new Error(`outbox job id "${job.jobId}" must not contain ":" (BullMQ uses it as its key separator); ` +
|
|
56
|
+
'join the id\'s parts with "-" instead');
|
|
57
|
+
}
|
|
58
|
+
const json = JSON.stringify(job.data ?? null);
|
|
59
|
+
const row = await this.db
|
|
60
|
+
.insertInto("outbox")
|
|
61
|
+
.values({
|
|
62
|
+
queue: job.queue,
|
|
63
|
+
job_name: job.name,
|
|
64
|
+
job_id: job.jobId,
|
|
65
|
+
data: json,
|
|
66
|
+
run_at: job.runAt ?? null,
|
|
67
|
+
org_id: job.orgId ?? null,
|
|
68
|
+
})
|
|
69
|
+
.onConflict((oc) => oc.columns(["queue", "job_id"]).where("dead_at", "is", null).doNothing())
|
|
70
|
+
.returning("id")
|
|
71
|
+
.executeTakeFirst();
|
|
72
|
+
if (row) {
|
|
73
|
+
// only a job due now goes through the fast path (ruling R20): a delayed one (a backstop, a
|
|
74
|
+
// timeout) is claimed by the relay within its next tick and added with its remaining delay,
|
|
75
|
+
// so the commit's caller spends no claim transaction on work due in seconds or hours
|
|
76
|
+
if (job.runAt === undefined || job.runAt.getTime() <= Date.now()) {
|
|
77
|
+
this.deliverAfterCommit(row.id);
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const stored = await this.db
|
|
82
|
+
.selectFrom("outbox")
|
|
83
|
+
.select(["job_name", "data"])
|
|
84
|
+
.where("queue", "=", job.queue)
|
|
85
|
+
.where("job_id", "=", job.jobId)
|
|
86
|
+
.where("dead_at", "is", null)
|
|
87
|
+
.executeTakeFirst();
|
|
88
|
+
// no row: the owed one was delivered (and deleted) since the conflict; BullMQ dedupes the id
|
|
89
|
+
if (stored && !isDeepStrictEqual(stored.data, JSON.parse(json))) {
|
|
90
|
+
const msg = "outbox job id reused with different data";
|
|
91
|
+
const fields = {
|
|
92
|
+
queue: job.queue,
|
|
93
|
+
jobId: job.jobId,
|
|
94
|
+
job: job.name,
|
|
95
|
+
owedJob: stored.job_name,
|
|
96
|
+
};
|
|
97
|
+
if (this.strictConflicts)
|
|
98
|
+
throw new Error(`${msg}: ${JSON.stringify(fields)}`);
|
|
99
|
+
this.log.error(msg, fields);
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
/** Collects `id` for its transaction; the first id registers the transaction's one hint. */
|
|
104
|
+
deliverAfterCommit(id) {
|
|
105
|
+
// `mandatory` guarantees a live store here
|
|
106
|
+
const store = currentStore();
|
|
107
|
+
if (!store)
|
|
108
|
+
throw new Error("outbox: no transaction in context");
|
|
109
|
+
const ids = pendingIds.get(store);
|
|
110
|
+
if (ids) {
|
|
111
|
+
ids.push(id);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const first = [id];
|
|
115
|
+
pendingIds.set(store, first);
|
|
116
|
+
afterCommit(() => this.fastPath(first));
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
__decorate([
|
|
120
|
+
Transactional({ propagation: "mandatory" })
|
|
121
|
+
], OutboxService.prototype, "add", null);
|
|
122
|
+
OutboxService = __decorate([
|
|
123
|
+
Injectable(),
|
|
124
|
+
__param(0, Inject(TransactionHost)),
|
|
125
|
+
__param(1, Inject(KernelDb)),
|
|
126
|
+
__param(2, Inject(KERNEL_LOGGER)),
|
|
127
|
+
__param(3, Inject(OUTBOX_FAST_PATH)),
|
|
128
|
+
__param(4, Optional()),
|
|
129
|
+
__param(4, Inject(OUTBOX_STRICT_CONFLICTS))
|
|
130
|
+
], OutboxService);
|
|
131
|
+
export { OutboxService };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type { JobsOptions } from "bullmq";
|
|
2
|
+
import type { KernelQueueName } from "../queue/queue-names.js";
|
|
3
|
+
/** What the registry says about one job name added through the outbox (spec §3.5, §5). */
|
|
4
|
+
export interface OutboxJobSpec {
|
|
5
|
+
/** The kernel queue the job is added to, or the queues when one job name serves several. */
|
|
6
|
+
queue: KernelQueueName | readonly KernelQueueName[];
|
|
7
|
+
/** One sentence: why a duplicate delivery of this job is harmless (state check, key, id). */
|
|
8
|
+
idempotent: string;
|
|
9
|
+
/** Repo-relative path of the file whose `@Processor` handles the job. */
|
|
10
|
+
processedIn: string;
|
|
11
|
+
/**
|
|
12
|
+
* BullMQ options the dispatcher adds the job with over the queue defaults
|
|
13
|
+
* (`QUEUE_JOB_DEFAULTS`); the job id and the delay always come from the row.
|
|
14
|
+
*/
|
|
15
|
+
opts?: Pick<JobsOptions, "attempts" | "backoff" | "priority" | "removeOnComplete" | "removeOnFail">;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Every job name added through the outbox. The task that introduces a job name adds its entry; a
|
|
19
|
+
* name without one does not type-check as an `OutboxJobName` (`add` does not check it at runtime).
|
|
20
|
+
*/
|
|
21
|
+
export declare const OUTBOX_JOBS: {
|
|
22
|
+
readonly run: {
|
|
23
|
+
readonly queue: readonly ["cap-kernel-runs", "cap-kernel-subagent-runs"];
|
|
24
|
+
readonly idempotent: "the run worker starts only a run in `queued` state for this job's runId; a finished run's job only repeats the idempotent post-run ensureRun, a waiting run's does nothing";
|
|
25
|
+
readonly processedIn: "packages/kernel/src/runtime/run-processors.ts";
|
|
26
|
+
readonly opts: {
|
|
27
|
+
readonly attempts: 1;
|
|
28
|
+
readonly removeOnComplete: true;
|
|
29
|
+
readonly removeOnFail: true;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
readonly "ensure-run": {
|
|
33
|
+
readonly queue: "cap-kernel-maintenance";
|
|
34
|
+
readonly idempotent: "ensureRun decides from the conversation's state; with nothing unconsumed it is a no-op";
|
|
35
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
36
|
+
readonly opts: {
|
|
37
|
+
readonly removeOnComplete: true;
|
|
38
|
+
readonly removeOnFail: true;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
readonly "wait-timeout": {
|
|
42
|
+
readonly queue: "cap-kernel-maintenance";
|
|
43
|
+
readonly idempotent: "a timeout acts only on a still-pending wait (a row lock and status check) and a resume starts only a waiting run with nothing else pending";
|
|
44
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
45
|
+
readonly opts: {
|
|
46
|
+
readonly attempts: 5;
|
|
47
|
+
readonly backoff: {
|
|
48
|
+
readonly type: "exponential";
|
|
49
|
+
readonly delay: 5000;
|
|
50
|
+
};
|
|
51
|
+
readonly removeOnComplete: true;
|
|
52
|
+
readonly removeOnFail: true;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
readonly "stop-tree": {
|
|
56
|
+
readonly queue: "cap-kernel-maintenance";
|
|
57
|
+
readonly idempotent: "stopping a stopped run is a no-op";
|
|
58
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
59
|
+
readonly opts: {
|
|
60
|
+
readonly attempts: 5;
|
|
61
|
+
readonly backoff: {
|
|
62
|
+
readonly type: "exponential";
|
|
63
|
+
readonly delay: 5000;
|
|
64
|
+
};
|
|
65
|
+
readonly removeOnComplete: true;
|
|
66
|
+
readonly removeOnFail: true;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
readonly "run-stop": {
|
|
70
|
+
readonly queue: "cap-kernel-maintenance";
|
|
71
|
+
readonly idempotent: "stopping a finished run is a no-op";
|
|
72
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
73
|
+
readonly opts: {
|
|
74
|
+
readonly attempts: 5;
|
|
75
|
+
readonly backoff: {
|
|
76
|
+
readonly type: "exponential";
|
|
77
|
+
readonly delay: 5000;
|
|
78
|
+
};
|
|
79
|
+
readonly removeOnComplete: true;
|
|
80
|
+
readonly removeOnFail: {
|
|
81
|
+
readonly age: number;
|
|
82
|
+
readonly count: 1000;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
readonly "sandbox-destroy-for": {
|
|
87
|
+
readonly queue: "cap-kernel-maintenance";
|
|
88
|
+
readonly idempotent: "destroying a destroyed device is a no-op";
|
|
89
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
90
|
+
readonly opts: {
|
|
91
|
+
readonly attempts: 5;
|
|
92
|
+
readonly backoff: {
|
|
93
|
+
readonly type: "exponential";
|
|
94
|
+
readonly delay: 30000;
|
|
95
|
+
};
|
|
96
|
+
readonly removeOnComplete: true;
|
|
97
|
+
readonly removeOnFail: 100;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
readonly "deliver-to-parent": {
|
|
101
|
+
readonly queue: "cap-kernel-maintenance";
|
|
102
|
+
readonly idempotent: "the delivery's idempotency key is the child run id";
|
|
103
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
104
|
+
readonly opts: {
|
|
105
|
+
readonly attempts: 5;
|
|
106
|
+
readonly backoff: {
|
|
107
|
+
readonly type: "exponential";
|
|
108
|
+
readonly delay: 5000;
|
|
109
|
+
};
|
|
110
|
+
readonly removeOnComplete: true;
|
|
111
|
+
readonly removeOnFail: true;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
readonly "usage-report": {
|
|
115
|
+
readonly queue: "cap-kernel-usage-report";
|
|
116
|
+
readonly idempotent: "handlers are idempotent by eventId (the event's `<conversationId>/<seq>` or the model_usage row id), and the job's `pending` list keeps a retry from reaching plugins already served";
|
|
117
|
+
readonly processedIn: "packages/kernel/src/runtime/run-processors.ts";
|
|
118
|
+
readonly opts: {
|
|
119
|
+
readonly attempts: 6;
|
|
120
|
+
readonly backoff: {
|
|
121
|
+
readonly type: "exponential";
|
|
122
|
+
readonly delay: 2000;
|
|
123
|
+
};
|
|
124
|
+
readonly removeOnComplete: {
|
|
125
|
+
readonly age: number;
|
|
126
|
+
readonly count: 100000;
|
|
127
|
+
};
|
|
128
|
+
readonly removeOnFail: {
|
|
129
|
+
readonly age: number;
|
|
130
|
+
readonly count: 100000;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
readonly deliver: {
|
|
135
|
+
readonly queue: "cap-kernel-channels";
|
|
136
|
+
readonly idempotent: "a delivery resumes from the conversation's delivered seq under a per-conversation lock and sends with idempotency keys, so a second job sends nothing twice";
|
|
137
|
+
readonly processedIn: "packages/kernel/src/channels/channels.module.ts";
|
|
138
|
+
readonly opts: {
|
|
139
|
+
readonly attempts: 8;
|
|
140
|
+
readonly backoff: {
|
|
141
|
+
readonly type: "deliver";
|
|
142
|
+
};
|
|
143
|
+
readonly priority: 10;
|
|
144
|
+
readonly removeOnComplete: true;
|
|
145
|
+
readonly removeOnFail: true;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
readonly "scope-item": {
|
|
149
|
+
readonly queue: "cap-kernel-plugin-scope";
|
|
150
|
+
readonly idempotent: "the sync converges each (item, org) from the scope, switches and installs it reads under the org's lock, and the installer re-checks under the org row lock, so a second run changes nothing";
|
|
151
|
+
readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
|
|
152
|
+
readonly opts: {
|
|
153
|
+
readonly attempts: 1;
|
|
154
|
+
readonly removeOnComplete: true;
|
|
155
|
+
readonly removeOnFail: true;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
readonly "scope-item-backstop": {
|
|
159
|
+
readonly queue: "cap-kernel-plugin-scope";
|
|
160
|
+
readonly idempotent: "the sync converges each (item, org) from what it reads, as a scope-item job does, so a run after the immediate job changes nothing";
|
|
161
|
+
readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
|
|
162
|
+
readonly opts: {
|
|
163
|
+
readonly attempts: 5;
|
|
164
|
+
readonly backoff: {
|
|
165
|
+
readonly type: "exponential";
|
|
166
|
+
readonly delay: 60000;
|
|
167
|
+
};
|
|
168
|
+
readonly removeOnComplete: true;
|
|
169
|
+
readonly removeOnFail: true;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
readonly "scope-org": {
|
|
173
|
+
readonly queue: "cap-kernel-plugin-scope";
|
|
174
|
+
readonly idempotent: "the sync converges each (item, org) of the org from what it reads, so a second run changes nothing";
|
|
175
|
+
readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
|
|
176
|
+
readonly opts: {
|
|
177
|
+
readonly attempts: 1;
|
|
178
|
+
readonly removeOnComplete: true;
|
|
179
|
+
readonly removeOnFail: true;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
readonly "owned-plugin-cleanup": {
|
|
183
|
+
readonly queue: "cap-kernel-maintenance";
|
|
184
|
+
readonly idempotent: "the cleanup takes the extension out only while no live item uses it, and a missing install or a released claim changes nothing";
|
|
185
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
186
|
+
readonly opts: {
|
|
187
|
+
readonly attempts: 3;
|
|
188
|
+
readonly backoff: {
|
|
189
|
+
readonly type: "exponential";
|
|
190
|
+
readonly delay: 5000;
|
|
191
|
+
};
|
|
192
|
+
readonly removeOnComplete: true;
|
|
193
|
+
readonly removeOnFail: true;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
readonly "sched-fire": {
|
|
197
|
+
readonly queue: "cap-kernel-maintenance";
|
|
198
|
+
readonly idempotent: "a fire acts only on a pending task run, under its row lock; a retried start reuses what the first one made";
|
|
199
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
200
|
+
readonly opts: {
|
|
201
|
+
readonly attempts: 3;
|
|
202
|
+
readonly backoff: {
|
|
203
|
+
readonly type: "exponential";
|
|
204
|
+
readonly delay: 2000;
|
|
205
|
+
};
|
|
206
|
+
readonly removeOnComplete: true;
|
|
207
|
+
readonly removeOnFail: true;
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
readonly "sched-settle": {
|
|
211
|
+
readonly queue: "cap-kernel-maintenance";
|
|
212
|
+
readonly idempotent: "a check acts only on a task run still pending (claimed for the claimed check, unclaimed for the unfired one), under the task and run row locks, so a run claimed, started, ended or skipped since is left as it is";
|
|
213
|
+
readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
|
|
214
|
+
readonly opts: {
|
|
215
|
+
readonly attempts: 5;
|
|
216
|
+
readonly backoff: {
|
|
217
|
+
readonly type: "exponential";
|
|
218
|
+
readonly delay: 5000;
|
|
219
|
+
};
|
|
220
|
+
readonly removeOnComplete: true;
|
|
221
|
+
readonly removeOnFail: true;
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
readonly lifecycle: {
|
|
225
|
+
readonly queue: "cap-kernel-lifecycle";
|
|
226
|
+
readonly idempotent: "lifecycle handlers must be idempotent (the SDK contract): they delete what the plugin holds for the removed member, agent or org, and deleting it again is a no-op";
|
|
227
|
+
readonly processedIn: "packages/kernel/src/extensions/lifecycle-hooks.ts";
|
|
228
|
+
readonly opts: {
|
|
229
|
+
readonly attempts: 15;
|
|
230
|
+
readonly backoff: {
|
|
231
|
+
readonly type: "exponential";
|
|
232
|
+
readonly delay: 2000;
|
|
233
|
+
};
|
|
234
|
+
readonly removeOnComplete: true;
|
|
235
|
+
readonly removeOnFail: {
|
|
236
|
+
readonly age: number;
|
|
237
|
+
readonly count: 1000;
|
|
238
|
+
};
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
export type OutboxJobName = keyof typeof OUTBOX_JOBS;
|
|
243
|
+
/** The registry's BullMQ options of a job name (none for a name it does not list). */
|
|
244
|
+
export declare function outboxJobOptions(name: string): OutboxJobSpec["opts"];
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every job name added through the outbox. The task that introduces a job name adds its entry; a
|
|
3
|
+
* name without one does not type-check as an `OutboxJobName` (`add` does not check it at runtime).
|
|
4
|
+
*/
|
|
5
|
+
export const OUTBOX_JOBS = {
|
|
6
|
+
// `runtime/run-jobs.ts` RUN_JOB: one name on both run queues (a sub-agent's runs go to the
|
|
7
|
+
// sub-agent queue), under the job ids `runJobId` builds and, for a waiting run's resume
|
|
8
|
+
// (`RunResume.resumeIn`), `resumeJobId`
|
|
9
|
+
run: {
|
|
10
|
+
queue: ["cap-kernel-runs", "cap-kernel-subagent-runs"],
|
|
11
|
+
idempotent: "the run worker starts only a run in `queued` state for this job's runId; a finished run's job only repeats the idempotent post-run ensureRun, a waiting run's does nothing",
|
|
12
|
+
processedIn: "packages/kernel/src/runtime/run-processors.ts",
|
|
13
|
+
// one attempt (the run's own paths handle failures); removed once done, so the next run of the
|
|
14
|
+
// same trigger can take the id again (the post-run ensureRun, R34)
|
|
15
|
+
opts: { attempts: 1, removeOnComplete: true, removeOnFail: true },
|
|
16
|
+
},
|
|
17
|
+
// `runtime/run-jobs.ts` ENSURE_RUN_JOB: the ensure-run backstop owed with every message, queue
|
|
18
|
+
// change, background task finish, sub-agent delivery and run end (spec §6), under the job ids
|
|
19
|
+
// `ensureRunJobId` builds
|
|
20
|
+
"ensure-run": {
|
|
21
|
+
queue: "cap-kernel-maintenance",
|
|
22
|
+
idempotent: "ensureRun decides from the conversation's state; with nothing unconsumed it is a no-op",
|
|
23
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
24
|
+
// removed once done (the queue defaults keep finished jobs), so a later write under the same
|
|
25
|
+
// seq (a queue change writes no event of its own) owes a job that is not deduped away
|
|
26
|
+
opts: { removeOnComplete: true, removeOnFail: true },
|
|
27
|
+
},
|
|
28
|
+
// `runtime/waits.ts` WAIT_TIMEOUT_JOB: owed with the suspend that sets a run `waiting`, under
|
|
29
|
+
// `waitTimeoutJobId`, with `runAt` = the wait's deadline (spec §6 "Resumes and timeouts")
|
|
30
|
+
"wait-timeout": {
|
|
31
|
+
queue: "cap-kernel-maintenance",
|
|
32
|
+
idempotent: "a timeout acts only on a still-pending wait (a row lock and status check) and a resume starts only a waiting run with nothing else pending",
|
|
33
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
34
|
+
// retried while PG is briefly unavailable; removed once done
|
|
35
|
+
opts: {
|
|
36
|
+
attempts: 5,
|
|
37
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
38
|
+
removeOnComplete: true,
|
|
39
|
+
removeOnFail: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
// `runtime/subagents/tree-jobs.ts` STOP_TREE_JOB: owed by a run's terminal transaction that
|
|
43
|
+
// leaves an active fork child (or a person-stopped sub-agent's descendants), under
|
|
44
|
+
// `stopChildrenJobId`, and by a root's delete, under `stopDeletedTreeJobId` (spec §6)
|
|
45
|
+
"stop-tree": {
|
|
46
|
+
queue: "cap-kernel-maintenance",
|
|
47
|
+
idempotent: "stopping a stopped run is a no-op",
|
|
48
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
49
|
+
// retried while PG is briefly unavailable; removed once done
|
|
50
|
+
opts: {
|
|
51
|
+
attempts: 5,
|
|
52
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
53
|
+
removeOnComplete: true,
|
|
54
|
+
removeOnFail: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// `orgs/offboarding.ts` RUN_STOP_JOB: owed by the offboard transaction for each of the departed
|
|
58
|
+
// member's active runs in the org, under `runStopJobId` (spec §8.1)
|
|
59
|
+
"run-stop": {
|
|
60
|
+
queue: "cap-kernel-maintenance",
|
|
61
|
+
idempotent: "stopping a finished run is a no-op",
|
|
62
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
63
|
+
// retried while PG or Redis is briefly unavailable; removed once done; a job that failed every
|
|
64
|
+
// attempt is kept a week (no sweep stops the run after it: the failure must stay visible)
|
|
65
|
+
opts: {
|
|
66
|
+
attempts: 5,
|
|
67
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
68
|
+
removeOnComplete: true,
|
|
69
|
+
removeOnFail: { age: 7 * 86_400, count: 1_000 },
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
// `sandbox/jobs.ts` SANDBOX_DESTROY_FOR_JOB: owed by the transaction that soft-deletes a device
|
|
73
|
+
// (its deletion, offboarding), under `deviceDestroyJobId` (spec §8.1)
|
|
74
|
+
"sandbox-destroy-for": {
|
|
75
|
+
queue: "cap-kernel-maintenance",
|
|
76
|
+
idempotent: "destroying a destroyed device is a no-op",
|
|
77
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
78
|
+
// the options the direct enqueue had: retried while the provider is down
|
|
79
|
+
opts: {
|
|
80
|
+
attempts: 5,
|
|
81
|
+
backoff: { type: "exponential", delay: 30_000 },
|
|
82
|
+
removeOnComplete: true,
|
|
83
|
+
removeOnFail: 100,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
// `runtime/subagents/tree-jobs.ts` DELIVER_TO_PARENT_JOB: owed by a sub-agent run's terminal
|
|
87
|
+
// transaction, under `deliverToParentJobId` (spec §6)
|
|
88
|
+
"deliver-to-parent": {
|
|
89
|
+
queue: "cap-kernel-maintenance",
|
|
90
|
+
idempotent: "the delivery's idempotency key is the child run id",
|
|
91
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
92
|
+
opts: {
|
|
93
|
+
attempts: 5,
|
|
94
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
95
|
+
removeOnComplete: true,
|
|
96
|
+
removeOnFail: true,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
// `runtime/usage-report-jobs.ts` USAGE_REPORT_JOB: owed with the usage it reports (a `usage`
|
|
100
|
+
// event or a `model_usage` row) while some plugin subscribes, under `usageReportJobId` /
|
|
101
|
+
// `modelUsageJobId` (spec §8.1)
|
|
102
|
+
"usage-report": {
|
|
103
|
+
queue: "cap-kernel-usage-report",
|
|
104
|
+
idempotent: "handlers are idempotent by eventId (the event's `<conversationId>/<seq>` or the model_usage row id), and the job's `pending` list keeps a retry from reaching plugins already served",
|
|
105
|
+
processedIn: "packages/kernel/src/runtime/run-processors.ts",
|
|
106
|
+
// first attempt plus 5 retries, 2 s doubling (F11); finished jobs kept a day so a re-add of the
|
|
107
|
+
// same id (a crash between the add and the row's delete) dedupes; failed ones a week; both
|
|
108
|
+
// capped by count (I-2: a long outage of a billing endpoint cannot grow Redis)
|
|
109
|
+
opts: {
|
|
110
|
+
attempts: 6,
|
|
111
|
+
backoff: { type: "exponential", delay: 2_000 },
|
|
112
|
+
removeOnComplete: { age: 24 * 3600, count: 100_000 },
|
|
113
|
+
removeOnFail: { age: 7 * 86_400, count: 100_000 },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
// `channels/deliver-job.ts` DELIVER_JOB: owed by every event append of a conversation with a
|
|
117
|
+
// channel target (a reply, an approval decision, a question answer, a wait stop) and by binding
|
|
118
|
+
// a conversation to its target, under `deliverJobId` (spec §8.1)
|
|
119
|
+
deliver: {
|
|
120
|
+
queue: "cap-kernel-channels",
|
|
121
|
+
idempotent: "a delivery resumes from the conversation's delivered seq under a per-conversation lock and sends with idempotency keys, so a second job sends nothing twice",
|
|
122
|
+
processedIn: "packages/kernel/src/channels/channels.module.ts",
|
|
123
|
+
// the platform's retry-after, else exponential (the processor's `deliver` backoff strategy);
|
|
124
|
+
// behind inbound jobs; removed once done, so a later append's id is never deduped away
|
|
125
|
+
opts: {
|
|
126
|
+
attempts: 8,
|
|
127
|
+
backoff: { type: "deliver" },
|
|
128
|
+
priority: 10,
|
|
129
|
+
removeOnComplete: true,
|
|
130
|
+
removeOnFail: true,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
// `catalog/scope-sync.ts` SCOPE_ITEM_JOB: owed by every transaction that changes an item's
|
|
134
|
+
// scope, disabled flag, list, owner or platform version, under `scopeItemJobId` (one per scope
|
|
135
|
+
// version), and by a sync deferred on a replica that had not loaded the extension yet, under
|
|
136
|
+
// `scopeRetryJobId` with `runAt` (spec §8.1)
|
|
137
|
+
"scope-item": {
|
|
138
|
+
queue: "cap-kernel-plugin-scope",
|
|
139
|
+
idempotent: "the sync converges each (item, org) from the scope, switches and installs it reads under the org's lock, and the installer re-checks under the org row lock, so a second run changes nothing",
|
|
140
|
+
processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts",
|
|
141
|
+
// one attempt (a pair's failure is recorded, not retried); removed once done, so the next
|
|
142
|
+
// add of the same id is not swallowed
|
|
143
|
+
opts: { attempts: 1, removeOnComplete: true, removeOnFail: true },
|
|
144
|
+
},
|
|
145
|
+
// `catalog/scope-jobs.ts` SCOPE_BACKSTOP_JOB: owed by a confirmation's commit (an import, a
|
|
146
|
+
// permissions confirm, an org upload's first version) with `runAt` 5 min on, under
|
|
147
|
+
// `scopeBackstopJobId`, so a crash before the post-deploy add still converges (ruling R24)
|
|
148
|
+
"scope-item-backstop": {
|
|
149
|
+
queue: "cap-kernel-plugin-scope",
|
|
150
|
+
idempotent: "the sync converges each (item, org) from what it reads, as a scope-item job does, so a run after the immediate job changes nothing",
|
|
151
|
+
processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts",
|
|
152
|
+
// retried while the item's extension is not enabled on the deployment yet (the job throws):
|
|
153
|
+
// 1, 2, 4, 8 min; removed once done
|
|
154
|
+
opts: {
|
|
155
|
+
attempts: 5,
|
|
156
|
+
backoff: { type: "exponential", delay: 60_000 },
|
|
157
|
+
removeOnComplete: true,
|
|
158
|
+
removeOnFail: true,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
// `catalog/scope-sync.ts` SCOPE_ORG_JOB: owed by an org's creation, under `scopeOrgJobId`
|
|
162
|
+
"scope-org": {
|
|
163
|
+
queue: "cap-kernel-plugin-scope",
|
|
164
|
+
idempotent: "the sync converges each (item, org) of the org from what it reads, so a second run changes nothing",
|
|
165
|
+
processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts",
|
|
166
|
+
opts: { attempts: 1, removeOnComplete: true, removeOnFail: true },
|
|
167
|
+
},
|
|
168
|
+
// `catalog/job-ids.ts` OWNED_PLUGIN_CLEANUP_JOB: owed by the removal of an org-owned plugin
|
|
169
|
+
// (and by a confirmation that took out the extension of an item removed meanwhile), under
|
|
170
|
+
// `ownedPluginCleanupJobId` (spec §8.1)
|
|
171
|
+
"owned-plugin-cleanup": {
|
|
172
|
+
queue: "cap-kernel-maintenance",
|
|
173
|
+
idempotent: "the cleanup takes the extension out only while no live item uses it, and a missing install or a released claim changes nothing",
|
|
174
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
175
|
+
// a few retries while PG is briefly unavailable; removed once done
|
|
176
|
+
opts: {
|
|
177
|
+
attempts: 3,
|
|
178
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
179
|
+
removeOnComplete: true,
|
|
180
|
+
removeOnFail: true,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
// `schedules/job-ids.ts` SCHED_FIRE_JOB: owed by the transaction that writes a pending task run
|
|
184
|
+
// (the scan's tick, a person's "run now"), under `schedFireJobId` (spec §8.1)
|
|
185
|
+
"sched-fire": {
|
|
186
|
+
queue: "cap-kernel-maintenance",
|
|
187
|
+
idempotent: "a fire acts only on a pending task run, under its row lock; a retried start reuses what the first one made",
|
|
188
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
189
|
+
// a few retries while PG is briefly unavailable; removed once done
|
|
190
|
+
opts: {
|
|
191
|
+
attempts: 3,
|
|
192
|
+
backoff: { type: "exponential", delay: 2_000 },
|
|
193
|
+
removeOnComplete: true,
|
|
194
|
+
removeOnFail: true,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
// `schedules/job-ids.ts` SCHED_SETTLE_JOB: the claimed check, owed by the fire job's claim (the
|
|
198
|
+
// transaction that writes `fired_at`) with `runAt` 10 min on, under `schedSettleJobId` (a run
|
|
199
|
+
// still in flight owes the next check an hour on); the unfired check, owed with the task run
|
|
200
|
+
// (scan tick, "run now") under `schedSettleUnfiredJobId` (ruling R26)
|
|
201
|
+
"sched-settle": {
|
|
202
|
+
queue: "cap-kernel-maintenance",
|
|
203
|
+
idempotent: "a check acts only on a task run still pending (claimed for the claimed check, unclaimed for the unfired one), under the task and run row locks, so a run claimed, started, ended or skipped since is left as it is",
|
|
204
|
+
processedIn: "packages/kernel/src/runtime/maintenance.ts",
|
|
205
|
+
// retried while PG is briefly unavailable; removed once done
|
|
206
|
+
opts: {
|
|
207
|
+
attempts: 5,
|
|
208
|
+
backoff: { type: "exponential", delay: 5_000 },
|
|
209
|
+
removeOnComplete: true,
|
|
210
|
+
removeOnFail: true,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
// `extensions/lifecycle-hooks.ts` LIFECYCLE_JOB: owed by the transaction that removes a member,
|
|
214
|
+
// deletes an agent or deletes an org, once per subscribing plugin, under `lifecycleJobId`
|
|
215
|
+
// (memory plugin spec §6.3)
|
|
216
|
+
lifecycle: {
|
|
217
|
+
queue: "cap-kernel-lifecycle",
|
|
218
|
+
idempotent: "lifecycle handlers must be idempotent (the SDK contract): they delete what the plugin holds for the removed member, agent or org, and deleting it again is a no-op",
|
|
219
|
+
processedIn: "packages/kernel/src/extensions/lifecycle-hooks.ts",
|
|
220
|
+
// retried while the plugin is not loaded on the replica that took the job (a rolling deploy)
|
|
221
|
+
// or its handler fails: 15 attempts from 2 s, doubling (about 18 h in all); removed once done;
|
|
222
|
+
// a job that failed every attempt is kept a week (the failure must stay visible)
|
|
223
|
+
opts: {
|
|
224
|
+
attempts: 15,
|
|
225
|
+
backoff: { type: "exponential", delay: 2_000 },
|
|
226
|
+
removeOnComplete: true,
|
|
227
|
+
removeOnFail: { age: 7 * 86_400, count: 1_000 },
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
/** The registry's BullMQ options of a job name (none for a name it does not list). */
|
|
232
|
+
export function outboxJobOptions(name) {
|
|
233
|
+
return OUTBOX_JOBS[name]?.opts;
|
|
234
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kernel's own BullMQ queues, spelled as literals so infra code (the outbox registry and
|
|
3
|
+
* dispatcher) names a queue without importing feature modules. `KERNEL_QUEUE_NAMES`
|
|
4
|
+
* (admin/health.service.ts) lists the same names from the feature constants;
|
|
5
|
+
* test/infra/queue-names.test.ts keeps the two equal.
|
|
6
|
+
*/
|
|
7
|
+
export declare const KERNEL_QUEUES: readonly ["cap-kernel-runs", "cap-kernel-subagent-runs", "cap-kernel-channels", "cap-kernel-maintenance", "cap-kernel-plugin-scope", "cap-kernel-titles", "cap-kernel-usage-report", "cap-kernel-evals", "cap-kernel-lifecycle"];
|
|
8
|
+
export type KernelQueueName = (typeof KERNEL_QUEUES)[number];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The kernel's own BullMQ queues, spelled as literals so infra code (the outbox registry and
|
|
3
|
+
* dispatcher) names a queue without importing feature modules. `KERNEL_QUEUE_NAMES`
|
|
4
|
+
* (admin/health.service.ts) lists the same names from the feature constants;
|
|
5
|
+
* test/infra/queue-names.test.ts keeps the two equal.
|
|
6
|
+
*/
|
|
7
|
+
export const KERNEL_QUEUES = [
|
|
8
|
+
"cap-kernel-runs",
|
|
9
|
+
"cap-kernel-subagent-runs",
|
|
10
|
+
"cap-kernel-channels",
|
|
11
|
+
"cap-kernel-maintenance",
|
|
12
|
+
"cap-kernel-plugin-scope",
|
|
13
|
+
"cap-kernel-titles",
|
|
14
|
+
"cap-kernel-usage-report",
|
|
15
|
+
"cap-kernel-evals",
|
|
16
|
+
"cap-kernel-lifecycle",
|
|
17
|
+
];
|
package/dist/kernel.module.js
CHANGED
|
@@ -25,6 +25,7 @@ import { databaseCheck, HEALTH_CHECKS, redisCheck } from "./infra/health/health.
|
|
|
25
25
|
import { GracefulShutdownModule } from "./infra/lifecycle/graceful-shutdown.module.js";
|
|
26
26
|
import { LockModule } from "./infra/lock/lock.module.js";
|
|
27
27
|
import { LoggingModule } from "./infra/logging/logging.module.js";
|
|
28
|
+
import { OutboxModule } from "./infra/outbox/outbox.module.js";
|
|
28
29
|
import { PresenceModule } from "./infra/presence/presence.module.js";
|
|
29
30
|
import { QueueModule } from "./infra/queue/queue.module.js";
|
|
30
31
|
import { RedisModule } from "./infra/redis/redis.module.js";
|
|
@@ -95,6 +96,8 @@ let KernelModule = KernelModule_1 = class KernelModule {
|
|
|
95
96
|
ConfigModule.forRoot(config, options.env !== undefined ? { env: options.env } : {}),
|
|
96
97
|
GracefulShutdownModule,
|
|
97
98
|
DatabaseModule.forRoot(),
|
|
99
|
+
// owed jobs written in the caller's transaction (transactional outbox spec §3.2)
|
|
100
|
+
OutboxModule,
|
|
98
101
|
RedisModule,
|
|
99
102
|
LockModule,
|
|
100
103
|
CacheModule,
|
|
@@ -53,6 +53,10 @@ export declare class DevicePolicyService {
|
|
|
53
53
|
features: DeviceFeature[];
|
|
54
54
|
policy: DeviceLocalPolicySummary | null;
|
|
55
55
|
} | null>;
|
|
56
|
+
/** Adds `op` to the machine's pending ops, dropping the expired ones. */
|
|
57
|
+
private notePending;
|
|
58
|
+
/** Removes the pending op `opId` from the machine's row. */
|
|
59
|
+
private dropPending;
|
|
56
60
|
/**
|
|
57
61
|
* Keeps the policy the machine wrote on its row and audits the change (`confirmed`); with no
|
|
58
62
|
* policy (the answer never came) only audits the attempt, unconfirmed. The detail's `isolation`
|