@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
|
@@ -31,7 +31,7 @@ let ConversationQueue = class ConversationQueue {
|
|
|
31
31
|
runs;
|
|
32
32
|
txHost;
|
|
33
33
|
constructor(db, eventLog, conversations,
|
|
34
|
-
/** Starts the conversation's next run (
|
|
34
|
+
/** Starts the conversation's next run after a commit (a failure is logged, never thrown). */
|
|
35
35
|
runs, txHost) {
|
|
36
36
|
this.db = db;
|
|
37
37
|
this.eventLog = eventLog;
|
|
@@ -101,16 +101,16 @@ let ConversationQueue = class ConversationQueue {
|
|
|
101
101
|
}
|
|
102
102
|
if (out.created) {
|
|
103
103
|
await this.eventLog.publishChanged(conversationId, "queue");
|
|
104
|
-
await this.runs.
|
|
104
|
+
await this.runs.ensureRunAfterCommit(conversationId);
|
|
105
105
|
}
|
|
106
106
|
return { item: toItem(out.row), created: out.created };
|
|
107
107
|
}
|
|
108
108
|
// its own transaction: the caller notifies and publishes after the commit
|
|
109
109
|
async addIn(orgId, conversationId, accountId, input, files, skill, extra, internal) {
|
|
110
110
|
const t = this.db.db;
|
|
111
|
-
await t
|
|
111
|
+
const conv = await t
|
|
112
112
|
.selectFrom("conversations")
|
|
113
|
-
.select("
|
|
113
|
+
.select("last_seq")
|
|
114
114
|
.where("id", "=", conversationId)
|
|
115
115
|
.forUpdate()
|
|
116
116
|
.executeTakeFirstOrThrow();
|
|
@@ -168,6 +168,9 @@ let ConversationQueue = class ConversationQueue {
|
|
|
168
168
|
})
|
|
169
169
|
.returning(COLUMNS)
|
|
170
170
|
.executeTakeFirstOrThrow();
|
|
171
|
+
// on an idle conversation the item goes out at once: owed with it (no event of its own, so
|
|
172
|
+
// under the conversation's newest seq; transactional outbox spec §6)
|
|
173
|
+
await this.runs.oweEnsureRun(conversationId, conv.last_seq, orgId);
|
|
171
174
|
return { row, created: true };
|
|
172
175
|
}
|
|
173
176
|
/**
|
|
@@ -253,6 +256,8 @@ let ConversationQueue = class ConversationQueue {
|
|
|
253
256
|
// a task's queued message deleted by a person: its run is skipped (scheduled tasks §6)
|
|
254
257
|
await releaseQueuedTaskRunIn(t, gone.schedule);
|
|
255
258
|
await unpauseIfEmpty(t, conversationId);
|
|
259
|
+
// the wakes an unpause releases for the tree are owed with it (transactional outbox spec §6)
|
|
260
|
+
await this.runs.oweHeldTreeIn(conversationId);
|
|
256
261
|
}
|
|
257
262
|
/**
|
|
258
263
|
* Sends a queued item now: it leaves the queue and is posted as a user message in the same
|
|
@@ -263,7 +268,7 @@ let ConversationQueue = class ConversationQueue {
|
|
|
263
268
|
*/
|
|
264
269
|
async sendNow(orgId, conversationId, accountId, itemId) {
|
|
265
270
|
await this.conversations.writable(orgId, conversationId, accountId);
|
|
266
|
-
const { event, fresh, switched, unarchived, skipped, toSeq } = await this.sendNowIn(conversationId, itemId);
|
|
271
|
+
const { event, fresh, switched, unarchived, skipped, toSeq } = await this.sendNowIn(orgId, conversationId, itemId);
|
|
267
272
|
if (fresh)
|
|
268
273
|
await this.eventLog.notify(conversationId, toSeq);
|
|
269
274
|
await this.conversations.announceSkipped(skipped);
|
|
@@ -272,12 +277,12 @@ let ConversationQueue = class ConversationQueue {
|
|
|
272
277
|
if (unarchived)
|
|
273
278
|
await this.eventLog.publishChanged(conversationId, "archived");
|
|
274
279
|
await this.eventLog.publishChanged(conversationId, "queue");
|
|
275
|
-
await this.runs.
|
|
280
|
+
await this.runs.ensureRunAfterCommit(conversationId);
|
|
276
281
|
await this.runs.wakeHeldTree(conversationId);
|
|
277
282
|
return event;
|
|
278
283
|
}
|
|
279
284
|
// its own transaction: the caller notifies and publishes after the commit
|
|
280
|
-
async sendNowIn(conversationId, itemId) {
|
|
285
|
+
async sendNowIn(orgId, conversationId, itemId) {
|
|
281
286
|
const t = this.db.db;
|
|
282
287
|
await this.lockConversation(conversationId);
|
|
283
288
|
const head = await t
|
|
@@ -313,6 +318,10 @@ let ConversationQueue = class ConversationQueue {
|
|
|
313
318
|
const skips = sent
|
|
314
319
|
? { skipped: NO_REPLY_SKIPS, toSeq: null }
|
|
315
320
|
: await this.conversations.skipWaitsIn(conversationId, row.account_id, out.event.seq);
|
|
321
|
+
// the run the sent message starts is owed with it (transactional outbox spec §6), and so are
|
|
322
|
+
// the wakes the unpause releases for the tree
|
|
323
|
+
await this.runs.oweEnsureRun(conversationId, out.event.seq, orgId);
|
|
324
|
+
await this.runs.oweHeldTreeIn(conversationId);
|
|
316
325
|
return {
|
|
317
326
|
...out,
|
|
318
327
|
fresh: !sent,
|
|
@@ -323,16 +332,28 @@ let ConversationQueue = class ConversationQueue {
|
|
|
323
332
|
/** "Continue sending": clears the pause and lets `ensureRun` send the head item. */
|
|
324
333
|
async resume(orgId, conversationId, accountId) {
|
|
325
334
|
await this.conversations.writable(orgId, conversationId, accountId);
|
|
326
|
-
await this.
|
|
327
|
-
.updateTable("conversations")
|
|
328
|
-
.set({ queue_paused: false, queue_pause_reason: null })
|
|
329
|
-
.where("id", "=", conversationId)
|
|
330
|
-
.execute();
|
|
335
|
+
await this.resumeIn(orgId, conversationId);
|
|
331
336
|
await this.eventLog.publishChanged(conversationId, "queue");
|
|
332
|
-
await this.runs.
|
|
337
|
+
await this.runs.ensureRunAfterCommit(conversationId);
|
|
333
338
|
// a paused root holds the wakes of its whole tree (agent map spec §5.3)
|
|
334
339
|
await this.runs.wakeHeldTree(conversationId);
|
|
335
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Clears the pause and owes the ensure-run backstop that sends the head item (no event of its
|
|
343
|
+
* own, so under the conversation's newest seq; transactional outbox spec §6).
|
|
344
|
+
*/
|
|
345
|
+
// its own transaction: the caller publishes and starts the run after the commit
|
|
346
|
+
async resumeIn(orgId, conversationId) {
|
|
347
|
+
const conv = await this.db.db
|
|
348
|
+
.updateTable("conversations")
|
|
349
|
+
.set({ queue_paused: false, queue_pause_reason: null })
|
|
350
|
+
.where("id", "=", conversationId)
|
|
351
|
+
.returning("last_seq")
|
|
352
|
+
.executeTakeFirstOrThrow();
|
|
353
|
+
await this.runs.oweEnsureRun(conversationId, conv.last_seq, orgId);
|
|
354
|
+
// the wakes the root held for its tree (agent map spec §5.3) are owed with the unpause
|
|
355
|
+
await this.runs.oweHeldTreeIn(conversationId);
|
|
356
|
+
}
|
|
336
357
|
/** A queued item or a sent message for this client id (outside any transaction). */
|
|
337
358
|
async prior(conversationId, clientMessageId) {
|
|
338
359
|
const row = await this.db
|
|
@@ -370,6 +391,9 @@ __decorate([
|
|
|
370
391
|
__decorate([
|
|
371
392
|
Transactional({ propagation: "requires_new" })
|
|
372
393
|
], ConversationQueue.prototype, "sendNowIn", null);
|
|
394
|
+
__decorate([
|
|
395
|
+
Transactional({ propagation: "requires_new" })
|
|
396
|
+
], ConversationQueue.prototype, "resumeIn", null);
|
|
373
397
|
__decorate([
|
|
374
398
|
Transactional({ propagation: "mandatory" })
|
|
375
399
|
], ConversationQueue.prototype, "lockConversation", null);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConversationSource } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
3
|
+
/**
|
|
4
|
+
* Where a conversation comes from (memory plugin spec §6.2), stored on its row at creation
|
|
5
|
+
* (`conversations.source`, migration 0124) and never changed. A missing conversation throws
|
|
6
|
+
* rather than guessing a source (a guess could offer a group chat what only a DM may see).
|
|
7
|
+
*/
|
|
8
|
+
export declare function conversationSourceOf(db: Pick<KernelSchemaDb, "selectFrom">, conversationId: string): Promise<ConversationSource>;
|
|
9
|
+
/** The source of a conversation created for a channel chat of `chatType`. */
|
|
10
|
+
export declare const channelSource: (chatType: "dm" | "group") => ConversationSource;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a conversation comes from (memory plugin spec §6.2), stored on its row at creation
|
|
3
|
+
* (`conversations.source`, migration 0124) and never changed. A missing conversation throws
|
|
4
|
+
* rather than guessing a source (a guess could offer a group chat what only a DM may see).
|
|
5
|
+
*/
|
|
6
|
+
export async function conversationSourceOf(db, conversationId) {
|
|
7
|
+
const row = await db
|
|
8
|
+
.selectFrom("conversations")
|
|
9
|
+
.select("source")
|
|
10
|
+
.where("id", "=", conversationId)
|
|
11
|
+
.executeTakeFirst();
|
|
12
|
+
if (row === undefined)
|
|
13
|
+
throw new Error(`conversation ${conversationId} not found`);
|
|
14
|
+
return row.source;
|
|
15
|
+
}
|
|
16
|
+
/** The source of a conversation created for a channel chat of `chatType`. */
|
|
17
|
+
export const channelSource = (chatType) => chatType === "dm" ? "channel_dm" : "channel_group";
|
|
@@ -5,7 +5,7 @@ import { KernelDb } from "../infra/database/kernel-db.js";
|
|
|
5
5
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
6
6
|
import { ModelPurposesService } from "../models/purposes.js";
|
|
7
7
|
import { type AuditEntry, type HookRunner } from "../runtime/hook-calls.js";
|
|
8
|
-
import {
|
|
8
|
+
import { UsageReportJobs } from "../runtime/usage-report-jobs.js";
|
|
9
9
|
import { EventLog } from "./event-log.js";
|
|
10
10
|
import { type ConversationEvent } from "./events.js";
|
|
11
11
|
/**
|
|
@@ -56,7 +56,7 @@ export declare function titleExcerpt(firstUser: string, firstReply: string): str
|
|
|
56
56
|
export declare function cleanTitle(reply: string): string | null;
|
|
57
57
|
export interface TitleDeps {
|
|
58
58
|
db: KernelSchemaDb;
|
|
59
|
-
eventLog: Pick<EventLog, "
|
|
59
|
+
eventLog: Pick<EventLog, "appendInReport" | "readAfter" | "latestOfType" | "notify" | "publishChanged">;
|
|
60
60
|
purposes: Pick<ModelPurposesService, "chat">;
|
|
61
61
|
log: Pick<Logger, "warn">;
|
|
62
62
|
/**
|
|
@@ -64,11 +64,10 @@ export interface TitleDeps {
|
|
|
64
64
|
* title and uses up the attempt) and `model.response` with `purpose: "title"`, like compaction.
|
|
65
65
|
*/
|
|
66
66
|
hooks?: HookRunner;
|
|
67
|
-
usageReport?: Pick<UsageReporter, "enqueue">;
|
|
68
67
|
/** Aborts the call (worker shutdown). */
|
|
69
68
|
signal?: AbortSignal;
|
|
70
69
|
/** The job's transactional writes ({@link TitleGenerator}). */
|
|
71
|
-
writes: Pick<TitleGenerator, "writeResult" | "auditDenied">;
|
|
70
|
+
writes: Pick<TitleGenerator, "writeResult" | "writeUsage" | "auditDenied">;
|
|
72
71
|
}
|
|
73
72
|
/** The attempt number to enqueue for this conversation, or null when no title job is due. */
|
|
74
73
|
export declare function titleAttemptDue(db: KernelSchemaDb, conversationId: string): Promise<number | null>;
|
|
@@ -93,19 +92,22 @@ export declare class TitleGenerator {
|
|
|
93
92
|
private readonly purposes;
|
|
94
93
|
/** The title call fires the plugin hooks (`model.request`, `model.response`). */
|
|
95
94
|
private readonly host;
|
|
96
|
-
|
|
95
|
+
/** The title call's `usage.report` delivery, owed with its usage event. */
|
|
96
|
+
private readonly usage;
|
|
97
97
|
private readonly log;
|
|
98
98
|
readonly txHost: TransactionHost;
|
|
99
99
|
constructor(kdb: KernelDb, eventLog: TitleDeps["eventLog"], purposes: Pick<ModelPurposesService, "chat">,
|
|
100
100
|
/** The title call fires the plugin hooks (`model.request`, `model.response`). */
|
|
101
101
|
host: {
|
|
102
102
|
readonly hooks?: HookRunner;
|
|
103
|
-
} | undefined,
|
|
103
|
+
} | undefined,
|
|
104
|
+
/** The title call's `usage.report` delivery, owed with its usage event. */
|
|
105
|
+
usage: Pick<UsageReportJobs, "oweEvents">, log: Pick<Logger, "warn">, txHost: TransactionHost);
|
|
104
106
|
/** One attempt ({@link runTitleJob}); `signal` aborts the call (the worker stopping). */
|
|
105
107
|
run(conversationId: string, attempt: number, signal?: AbortSignal): Promise<void>;
|
|
106
108
|
/**
|
|
107
|
-
* Appends the call's `usage` event and writes the title while
|
|
108
|
-
* wins), in one transaction.
|
|
109
|
+
* Appends the call's `usage` event (owing its `usage.report` delivery) and writes the title while
|
|
110
|
+
* `title_source IS NULL` (a rename wins), in one transaction.
|
|
109
111
|
*/
|
|
110
112
|
writeResult(conversationId: string, attempt: number, out: {
|
|
111
113
|
provider: string;
|
|
@@ -115,6 +117,17 @@ export declare class TitleGenerator {
|
|
|
115
117
|
written: boolean;
|
|
116
118
|
usage: ConversationEvent | undefined;
|
|
117
119
|
}>;
|
|
120
|
+
/**
|
|
121
|
+
* Appends the usage event of a call that failed after it was sent (billed, so reported) and owes
|
|
122
|
+
* its `usage.report` delivery, in one transaction.
|
|
123
|
+
*/
|
|
124
|
+
writeUsage(conversationId: string, attempt: number, u: {
|
|
125
|
+
provider: string;
|
|
126
|
+
model: string;
|
|
127
|
+
usage: ModelUsage;
|
|
128
|
+
}): Promise<ConversationEvent | undefined>;
|
|
129
|
+
/** The usage event and its owed delivery (only when this call wrote it, not on a retry's hit). */
|
|
130
|
+
private appendUsage;
|
|
118
131
|
/** The `hook.denied` audit row of a denied title call. */
|
|
119
132
|
auditDenied(entry: AuditEntry): Promise<void>;
|
|
120
133
|
}
|
|
@@ -22,7 +22,7 @@ import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
|
22
22
|
import { ModelsModule } from "../models/models.module.js";
|
|
23
23
|
import { ModelPurposesService, PurposeAttemptError } from "../models/purposes.js";
|
|
24
24
|
import { fireObserve, hookDeniedAudit, hookDeniedEvent, hookRequestOf, } from "../runtime/hook-calls.js";
|
|
25
|
-
import {
|
|
25
|
+
import { UsageReportJobs, UsageReportJobsModule } from "../runtime/usage-report-jobs.js";
|
|
26
26
|
import { HIDDEN_FORMAT_RE } from "../text.js";
|
|
27
27
|
import { EventLog, EventLogModule } from "./event-log.js";
|
|
28
28
|
import { typedInvocation } from "./events.js";
|
|
@@ -275,10 +275,8 @@ export async function runTitleJob(d, conversationId, attempt) {
|
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
const { written, usage } = await d.writes.writeResult(conversationId, attempt, out, title);
|
|
278
|
-
if (usage)
|
|
278
|
+
if (usage)
|
|
279
279
|
await d.eventLog.notify(conversationId, usage.seq);
|
|
280
|
-
void d.usageReport?.enqueue(conversationId, usage.seq);
|
|
281
|
-
}
|
|
282
280
|
if (written)
|
|
283
281
|
await d.eventLog.publishChanged(conversationId, "title");
|
|
284
282
|
}
|
|
@@ -291,9 +289,9 @@ const usageEvent = (attempt, u) => ({
|
|
|
291
289
|
payload: { step: 0, provider: u.provider, model: u.model, ...u.usage, purpose: "title" },
|
|
292
290
|
});
|
|
293
291
|
async function logUsage(d, conversationId, attempt, u) {
|
|
294
|
-
const
|
|
292
|
+
const ev = await d.writes.writeUsage(conversationId, attempt, u);
|
|
295
293
|
if (ev)
|
|
296
|
-
|
|
294
|
+
await d.eventLog.notify(conversationId, ev.seq);
|
|
297
295
|
}
|
|
298
296
|
/** Returns a claimed attempt (shutdown before the call was sent). */
|
|
299
297
|
async function giveBack(db, conversationId, attempt) {
|
|
@@ -383,17 +381,19 @@ let TitleGenerator = class TitleGenerator {
|
|
|
383
381
|
eventLog;
|
|
384
382
|
purposes;
|
|
385
383
|
host;
|
|
386
|
-
|
|
384
|
+
usage;
|
|
387
385
|
log;
|
|
388
386
|
txHost;
|
|
389
387
|
constructor(kdb, eventLog, purposes,
|
|
390
388
|
/** The title call fires the plugin hooks (`model.request`, `model.response`). */
|
|
391
|
-
host,
|
|
389
|
+
host,
|
|
390
|
+
/** The title call's `usage.report` delivery, owed with its usage event. */
|
|
391
|
+
usage, log, txHost) {
|
|
392
392
|
this.kdb = kdb;
|
|
393
393
|
this.eventLog = eventLog;
|
|
394
394
|
this.purposes = purposes;
|
|
395
395
|
this.host = host;
|
|
396
|
-
this.
|
|
396
|
+
this.usage = usage;
|
|
397
397
|
this.log = log;
|
|
398
398
|
this.txHost = txHost;
|
|
399
399
|
}
|
|
@@ -409,21 +409,20 @@ let TitleGenerator = class TitleGenerator {
|
|
|
409
409
|
purposes: this.purposes,
|
|
410
410
|
log: this.log,
|
|
411
411
|
...(hooks !== undefined && { hooks }),
|
|
412
|
-
...(this.usageReport !== undefined && { usageReport: this.usageReport }),
|
|
413
412
|
...(signal !== undefined && { signal }),
|
|
414
413
|
writes: this,
|
|
415
414
|
}, conversationId, attempt);
|
|
416
415
|
}
|
|
417
416
|
/**
|
|
418
|
-
* Appends the call's `usage` event and writes the title while
|
|
419
|
-
* wins), in one transaction.
|
|
417
|
+
* Appends the call's `usage` event (owing its `usage.report` delivery) and writes the title while
|
|
418
|
+
* `title_source IS NULL` (a rename wins), in one transaction.
|
|
420
419
|
*/
|
|
421
420
|
async writeResult(conversationId, attempt, out, title) {
|
|
422
421
|
// Append first: it locks the conversation row FOR UPDATE before this transaction touches it.
|
|
423
422
|
// Updating the title first held the row FOR NO KEY UPDATE, which lets in another
|
|
424
423
|
// transaction's foreign key check (FOR KEY SHARE, e.g. inserting an approval); the append's
|
|
425
424
|
// FOR UPDATE then waited for that one while it waited for the title row: 40P01
|
|
426
|
-
const
|
|
425
|
+
const ev = await this.appendUsage(conversationId, attempt, out);
|
|
427
426
|
const row = title === null
|
|
428
427
|
? undefined
|
|
429
428
|
: await this.kdb.db
|
|
@@ -435,6 +434,22 @@ let TitleGenerator = class TitleGenerator {
|
|
|
435
434
|
.executeTakeFirst();
|
|
436
435
|
return { written: row !== undefined, usage: ev };
|
|
437
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Appends the usage event of a call that failed after it was sent (billed, so reported) and owes
|
|
439
|
+
* its `usage.report` delivery, in one transaction.
|
|
440
|
+
*/
|
|
441
|
+
async writeUsage(conversationId, attempt, u) {
|
|
442
|
+
return this.appendUsage(conversationId, attempt, u);
|
|
443
|
+
}
|
|
444
|
+
/** The usage event and its owed delivery (only when this call wrote it, not on a retry's hit). */
|
|
445
|
+
async appendUsage(conversationId, attempt, u) {
|
|
446
|
+
const { events, fresh } = await this.eventLog.appendInReport(conversationId, [
|
|
447
|
+
usageEvent(attempt, u),
|
|
448
|
+
]);
|
|
449
|
+
if (fresh[0])
|
|
450
|
+
await this.usage.oweEvents(conversationId, events);
|
|
451
|
+
return events[0];
|
|
452
|
+
}
|
|
438
453
|
/** The `hook.denied` audit row of a denied title call. */
|
|
439
454
|
async auditDenied(entry) {
|
|
440
455
|
await audit(this.kdb.db, entry);
|
|
@@ -443,6 +458,12 @@ let TitleGenerator = class TitleGenerator {
|
|
|
443
458
|
__decorate([
|
|
444
459
|
Transactional({ propagation: "requires_new" })
|
|
445
460
|
], TitleGenerator.prototype, "writeResult", null);
|
|
461
|
+
__decorate([
|
|
462
|
+
Transactional({ propagation: "requires_new" })
|
|
463
|
+
], TitleGenerator.prototype, "writeUsage", null);
|
|
464
|
+
__decorate([
|
|
465
|
+
Transactional({ propagation: "mandatory" })
|
|
466
|
+
], TitleGenerator.prototype, "appendUsage", null);
|
|
446
467
|
__decorate([
|
|
447
468
|
Transactional({ propagation: "requires_new" })
|
|
448
469
|
], TitleGenerator.prototype, "auditDenied", null);
|
|
@@ -452,7 +473,7 @@ TitleGenerator = __decorate([
|
|
|
452
473
|
__param(1, Inject(EventLog)),
|
|
453
474
|
__param(2, Inject(ModelPurposesService)),
|
|
454
475
|
__param(3, Inject(ExtensionHost)),
|
|
455
|
-
__param(4, Inject(
|
|
476
|
+
__param(4, Inject(UsageReportJobs)),
|
|
456
477
|
__param(5, Inject(KERNEL_LOGGER)),
|
|
457
478
|
__param(6, Inject(TransactionHost))
|
|
458
479
|
], TitleGenerator);
|
|
@@ -535,7 +556,13 @@ let TitlesModule = class TitlesModule {
|
|
|
535
556
|
};
|
|
536
557
|
TitlesModule = __decorate([
|
|
537
558
|
Module({
|
|
538
|
-
imports: [
|
|
559
|
+
imports: [
|
|
560
|
+
EventLogModule,
|
|
561
|
+
ModelsModule,
|
|
562
|
+
ExtensionsModule,
|
|
563
|
+
UsageReportJobsModule,
|
|
564
|
+
TITLE_QUEUE_MODULE,
|
|
565
|
+
],
|
|
539
566
|
providers: [TitleGenerator, TitleQueue],
|
|
540
567
|
exports: [TitleQueue, TITLE_QUEUE_MODULE],
|
|
541
568
|
})
|
|
@@ -15,3 +15,13 @@ export declare function conversationTree(db: KernelSchemaDb, conversationId: str
|
|
|
15
15
|
* `conversations.parent_conversation_id`. Empty for a root or an unknown id.
|
|
16
16
|
*/
|
|
17
17
|
export declare function conversationAncestors(db: KernelSchemaDb, conversationId: string): Promise<string[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Locks the conversations `ids` and every ancestor of theirs (`FOR NO KEY UPDATE`, in the caller's
|
|
20
|
+
* transaction) tree by tree, root first: the trees in root id order, within a tree by level below
|
|
21
|
+
* the root, then id. A reply locks its root conversation and only then the sub-agents' below it
|
|
22
|
+
* (`ConversationsService.skipWaitsIn`), and a dispatch locks a parent before its child; a locker
|
|
23
|
+
* of conversations in plain id order could take a child before its root and wait for the root
|
|
24
|
+
* while such a path holds the root and waits for the child (40P01). Returns the ids locked (the
|
|
25
|
+
* requested ones and their ancestors); an unknown id is skipped.
|
|
26
|
+
*/
|
|
27
|
+
export declare function lockConversationTrees(db: KernelSchemaDb, ids: readonly string[]): Promise<string[]>;
|
|
@@ -40,3 +40,38 @@ export async function conversationAncestors(db, conversationId) {
|
|
|
40
40
|
SELECT id FROM up WHERE level > 0 ORDER BY level`.execute(db);
|
|
41
41
|
return r.rows.map((row) => row.id);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Locks the conversations `ids` and every ancestor of theirs (`FOR NO KEY UPDATE`, in the caller's
|
|
45
|
+
* transaction) tree by tree, root first: the trees in root id order, within a tree by level below
|
|
46
|
+
* the root, then id. A reply locks its root conversation and only then the sub-agents' below it
|
|
47
|
+
* (`ConversationsService.skipWaitsIn`), and a dispatch locks a parent before its child; a locker
|
|
48
|
+
* of conversations in plain id order could take a child before its root and wait for the root
|
|
49
|
+
* while such a path holds the root and waits for the child (40P01). Returns the ids locked (the
|
|
50
|
+
* requested ones and their ancestors); an unknown id is skipped.
|
|
51
|
+
*/
|
|
52
|
+
export async function lockConversationTrees(db, ids) {
|
|
53
|
+
const wanted = [...new Set(ids)];
|
|
54
|
+
if (wanted.length === 0)
|
|
55
|
+
return [];
|
|
56
|
+
const r = await sql `
|
|
57
|
+
WITH RECURSIVE up(start, id, parent, level) AS (
|
|
58
|
+
SELECT c.id, c.id, c.parent_conversation_id, 0 FROM capybara.conversations c
|
|
59
|
+
WHERE c.id = ANY(${wanted}::text[])
|
|
60
|
+
UNION ALL
|
|
61
|
+
SELECT up.start, c.id, c.parent_conversation_id, up.level + 1
|
|
62
|
+
FROM capybara.conversations c JOIN up ON c.id = up.parent
|
|
63
|
+
WHERE up.level < ${TREE_MAX_LEVELS}
|
|
64
|
+
),
|
|
65
|
+
tops AS (
|
|
66
|
+
SELECT DISTINCT ON (start) start, id AS root, level AS height
|
|
67
|
+
FROM up ORDER BY start, level DESC
|
|
68
|
+
),
|
|
69
|
+
nodes AS (
|
|
70
|
+
SELECT DISTINCT up.id, tops.root, tops.height - up.level AS depth
|
|
71
|
+
FROM up JOIN tops ON tops.start = up.start
|
|
72
|
+
)
|
|
73
|
+
SELECT c.id FROM capybara.conversations c JOIN nodes n ON n.id = c.id
|
|
74
|
+
ORDER BY n.root, n.depth, n.id
|
|
75
|
+
FOR NO KEY UPDATE OF c`.execute(db);
|
|
76
|
+
return r.rows.map((row) => row.id);
|
|
77
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FileSystemHandle, ParsedTheme, SandboxTier, SkillInvocation } from "@capybara-hq/plugin-sdk";
|
|
1
|
+
import type { ConversationSource, FileSystemHandle, ParsedTheme, SandboxTier, SkillInvocation } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { ColumnType, Generated, Kysely } from "kysely";
|
|
3
3
|
import type { ModelRef } from "../agents/definition.js";
|
|
4
4
|
import type { ScheduleChat, ScheduleMarker, ScheduleMode, SchedulePauseReason, ScheduleStatus, ScheduleTrigger, TaskRunSkipReason, TaskRunStatus } from "../schedules/types.js";
|
|
@@ -263,6 +263,11 @@ export interface ConversationsTable {
|
|
|
263
263
|
device_id: ColumnType<string | null, string | null | undefined, string | null>;
|
|
264
264
|
/** 0113: the scheduled task that created it (`new` mode); null otherwise. */
|
|
265
265
|
scheduled_task_id: ColumnType<string | null, string | null | undefined, string | null>;
|
|
266
|
+
/**
|
|
267
|
+
* 0124: where the conversation comes from, set at creation and never changed. Required on insert
|
|
268
|
+
* (the column's `web` default is not relied on: a forgotten source must not read as web).
|
|
269
|
+
*/
|
|
270
|
+
source: ColumnType<ConversationSource, ConversationSource, never>;
|
|
266
271
|
}
|
|
267
272
|
/** 0060: an org's order of file-preview@1 previewers (UI refresh B Task 11). */
|
|
268
273
|
export interface FilePreviewersTable {
|
|
@@ -939,6 +944,8 @@ export interface DeviceMachinesTable {
|
|
|
939
944
|
features: ColumnType<string[], string[] | undefined, string[]>;
|
|
940
945
|
/** 0114: the program's local network policy summary (hello, refreshed by each `policy` op). */
|
|
941
946
|
local_policy: ColumnType<unknown | null, string | null | undefined, string | null>;
|
|
947
|
+
/** 0118: the `policy` ops sent whose answer is not recorded yet (`PendingPolicyOp[]`). */
|
|
948
|
+
pending_policy_ops: ColumnType<unknown, string | undefined, string>;
|
|
942
949
|
}
|
|
943
950
|
/** 0088_environments.sql, renamed in 0105: the device a member's new conversations use by default. */
|
|
944
951
|
export interface DeviceDefaultsTable {
|
|
@@ -1156,12 +1163,6 @@ export interface ExtensionReplicaStatusTable {
|
|
|
1156
1163
|
http_replica_id: string | null;
|
|
1157
1164
|
heartbeat_at: Ts;
|
|
1158
1165
|
}
|
|
1159
|
-
/** 0040: the usage.report sweeper's watermark (a single row, id = 1). */
|
|
1160
|
-
export interface UsageReportSweepTable {
|
|
1161
|
-
id: ColumnType<number, number | undefined, never>;
|
|
1162
|
-
watermark: Ts;
|
|
1163
|
-
updated_at: ColumnType<Date, Date | string | undefined, Date | string>;
|
|
1164
|
-
}
|
|
1165
1166
|
/** A model disabled on the platform (`org_id` null) or in one org (0089, spec B §5.3). */
|
|
1166
1167
|
export interface ModelDisabledTable {
|
|
1167
1168
|
org_id: string | null;
|
|
@@ -1181,7 +1182,7 @@ export interface ModelUsageTable {
|
|
|
1181
1182
|
input_tokens: number;
|
|
1182
1183
|
occurred_at: Ts;
|
|
1183
1184
|
reported_at: TsNullable;
|
|
1184
|
-
/** Set when the row's `usage.report` job gave up after its last attempt
|
|
1185
|
+
/** Set when the row's `usage.report` job gave up after its last attempt. */
|
|
1185
1186
|
report_failed_at: TsNullable;
|
|
1186
1187
|
}
|
|
1187
1188
|
type NullableText = ColumnType<string | null, string | null | undefined, string | null>;
|
|
@@ -1228,8 +1229,6 @@ export interface ScheduledTaskRunsTable {
|
|
|
1228
1229
|
skip_reason: ColumnType<TaskRunSkipReason | null, TaskRunSkipReason | null | undefined, TaskRunSkipReason | null>;
|
|
1229
1230
|
error: NullableText;
|
|
1230
1231
|
missing_grants: ColumnType<string[], string | undefined, string>;
|
|
1231
|
-
/** When the scanner's repair last found this started run still in flight. */
|
|
1232
|
-
rechecked_at: NullableTs;
|
|
1233
1232
|
}
|
|
1234
1233
|
/** 0113: a scheduled task's remembered grants (same shape as `conversation_tool_grants`). */
|
|
1235
1234
|
export interface ScheduledTaskGrantsTable {
|
|
@@ -1310,7 +1309,6 @@ export interface KernelDatabase {
|
|
|
1310
1309
|
extension_blobs: ExtensionBlobsTable;
|
|
1311
1310
|
extension_installs: ExtensionInstallsTable;
|
|
1312
1311
|
extension_replica_status: ExtensionReplicaStatusTable;
|
|
1313
|
-
usage_report_sweep: UsageReportSweepTable;
|
|
1314
1312
|
extension_name_owners: ExtensionNameOwnersTable;
|
|
1315
1313
|
extension_deployment_configs: ExtensionDeploymentConfigsTable;
|
|
1316
1314
|
catalog_items: CatalogItemsTable;
|
|
@@ -1338,12 +1336,34 @@ export interface KernelDatabase {
|
|
|
1338
1336
|
plugin_install_components: PluginInstallComponentsTable;
|
|
1339
1337
|
extension_catalog_sources: ExtensionCatalogSourcesTable;
|
|
1340
1338
|
bootstrap_runs: BootstrapRunsTable;
|
|
1341
|
-
platform_migration_runs: PlatformMigrationRunsTable;
|
|
1342
1339
|
org_notices: OrgNoticesTable;
|
|
1343
1340
|
platform_notices: PlatformNoticesTable;
|
|
1344
1341
|
plugin_scope_sync_failures: PluginScopeSyncFailuresTable;
|
|
1345
1342
|
extension_client_builds: ExtensionClientBuildsTable;
|
|
1346
1343
|
extension_client_reports: ExtensionClientReportsTable;
|
|
1344
|
+
outbox: OutboxTable;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* 0119: the transactional outbox (transactional outbox spec §4). A row is a BullMQ job owed by a
|
|
1348
|
+
* committed transaction; deleted on delivery, so only dead rows (`dead_at` set) stay.
|
|
1349
|
+
*/
|
|
1350
|
+
export interface OutboxTable {
|
|
1351
|
+
/** bigint identity; the pg driver reads it as a string. */
|
|
1352
|
+
id: Generated<string>;
|
|
1353
|
+
queue: string;
|
|
1354
|
+
job_name: string;
|
|
1355
|
+
/** Unique per queue: a second add of the same job before delivery is a no-op. */
|
|
1356
|
+
job_id: string;
|
|
1357
|
+
data: Json;
|
|
1358
|
+
/** The job's delay target; null runs it now. */
|
|
1359
|
+
run_at: Date | null;
|
|
1360
|
+
/** Null for platform work. */
|
|
1361
|
+
org_id: string | null;
|
|
1362
|
+
attempts: Generated<number>;
|
|
1363
|
+
next_attempt_at: Generated<Date>;
|
|
1364
|
+
last_error: string | null;
|
|
1365
|
+
dead_at: Date | null;
|
|
1366
|
+
created_at: Generated<Date>;
|
|
1347
1367
|
}
|
|
1348
1368
|
/**
|
|
1349
1369
|
* 0107: the client files of an extension package (client extensions spec §9.1), keyed by the
|
|
@@ -1379,21 +1399,14 @@ export interface ExtensionClientReportsTable {
|
|
|
1379
1399
|
last_at: Ts;
|
|
1380
1400
|
last_message: string;
|
|
1381
1401
|
}
|
|
1382
|
-
/**
|
|
1383
|
-
export
|
|
1384
|
-
id: string;
|
|
1385
|
-
started_at: Ts;
|
|
1386
|
-
finished_at: TsNullable;
|
|
1387
|
-
stats: Json<Record<string, unknown>>;
|
|
1388
|
-
}
|
|
1389
|
-
/** 0082: the kinds of {@link OrgNoticesTable}. */
|
|
1390
|
-
export type OrgNoticeKind = "skill_renamed" | "item_shared" | "shared_item_updated" | "upload_confirmed" | "upload_rejected";
|
|
1402
|
+
/** 0084 (0121 dropped `skill_renamed`): the kinds of {@link OrgNoticesTable}. */
|
|
1403
|
+
export type OrgNoticeKind = "item_shared" | "shared_item_updated" | "upload_confirmed" | "upload_rejected";
|
|
1391
1404
|
/** 0082: a notice for an org's admins (an inbox item), until one of them dismisses it. */
|
|
1392
1405
|
export interface OrgNoticesTable {
|
|
1393
1406
|
id: string;
|
|
1394
1407
|
org_id: string;
|
|
1395
1408
|
kind: OrgNoticeKind;
|
|
1396
|
-
/**
|
|
1409
|
+
/** The kind's shape (`OrgNoticeDetails` in `inbox/org-notices.ts`). */
|
|
1397
1410
|
detail: Json<Record<string, unknown>>;
|
|
1398
1411
|
created_at: Ts;
|
|
1399
1412
|
dismissed_at: TsNullable;
|
|
@@ -4,9 +4,9 @@ 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 { LockService } from "../infra/lock/lock.service.js";
|
|
7
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
7
8
|
import { DevicePolicyService } from "../local-devices/device-policy.service.js";
|
|
8
9
|
import { MachinesService } from "../local-devices/machines.js";
|
|
9
|
-
import type { KernelLogger } from "../log.js";
|
|
10
10
|
import type { DeviceSandboxLevel } from "../runtime/context/device-paths.js";
|
|
11
11
|
import { SandboxJobs } from "../sandbox/jobs.js";
|
|
12
12
|
import { SandboxProviders } from "../sandbox/providers.js";
|
|
@@ -111,7 +111,8 @@ export interface DeviceSandboxView {
|
|
|
111
111
|
export declare const RECENT_POLICY_CHANGES = 10;
|
|
112
112
|
/**
|
|
113
113
|
* One sandbox change of a device, as its owner sees it on the device page (§10.4):
|
|
114
|
-
* - `policy` (`device.policy_changed`): a local policy change sent to the machine
|
|
114
|
+
* - `policy` (`device.policy_changed`): a local policy change sent to the machine (`web`, `im`),
|
|
115
|
+
* or made on the machine by its owner (`device`, `capybara-device policy ...`);
|
|
115
116
|
* - `tier` (`device.tier_changed`): a cloud device's tier set by its owner;
|
|
116
117
|
* - `isolation` (`device.isolation_reported`): the machine reported running without a sandbox,
|
|
117
118
|
* or with one again.
|
|
@@ -122,15 +123,23 @@ export interface DeviceSandboxChangeView {
|
|
|
122
123
|
/** Hosts added to / removed from the local allowlist (`policy` only; else empty). */
|
|
123
124
|
add: string[];
|
|
124
125
|
remove: string[];
|
|
125
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* The tier set (`to: null`: follow the org's default; `from`, the tier before, only for a change
|
|
128
|
+
* made on the machine); null when the tier did not change.
|
|
129
|
+
*/
|
|
126
130
|
tier: {
|
|
131
|
+
from?: SandboxTier | null;
|
|
127
132
|
to: SandboxTier | null;
|
|
128
133
|
} | null;
|
|
129
134
|
/** The isolation set or reported; null when it did not change. */
|
|
130
135
|
isolation: "sandbox" | "none" | null;
|
|
136
|
+
/** The localhost access now (a change made on the machine only); null when it did not change. */
|
|
137
|
+
localhost: DeviceLocalPolicySummary["localhost"] | null;
|
|
138
|
+
/** Whether the machine takes the platform's changes now (made on the machine); null: unchanged. */
|
|
139
|
+
remoteGrants: DeviceLocalPolicySummary["remoteGrants"] | null;
|
|
131
140
|
/** The deciding account's display name (null when the account is gone). */
|
|
132
141
|
by: string | null;
|
|
133
|
-
/** `device`: reported
|
|
142
|
+
/** `device`: made or reported on the machine itself (a `policy` change, an `isolation`). */
|
|
134
143
|
via: "web" | "im" | "device";
|
|
135
144
|
/** The machine answered with the policy as written (false: the answer never came). */
|
|
136
145
|
confirmed: boolean;
|
|
@@ -172,8 +181,8 @@ export interface DeviceList {
|
|
|
172
181
|
* Personal devices (spec 2026-11-07-environments-design §4.2 items 7, 12, 13; §6; §9):
|
|
173
182
|
* cloud ones on the deployment's sandbox provider and `device` ones on a connected machine; a
|
|
174
183
|
* person's devices in an org, visible and usable only by their owner (anyone else gets
|
|
175
|
-
* `device.not_found`). Deleting one soft-deletes it and
|
|
176
|
-
* `sandbox-destroy-for` job
|
|
184
|
+
* `device.not_found`). Deleting one soft-deletes it and owes the destruction of its instance and
|
|
185
|
+
* files (a `sandbox-destroy-for` job) in the same transaction.
|
|
177
186
|
*/
|
|
178
187
|
export declare class DevicesService {
|
|
179
188
|
private readonly db;
|
|
@@ -182,14 +191,17 @@ export declare class DevicesService {
|
|
|
182
191
|
private readonly providers;
|
|
183
192
|
private readonly sandbox;
|
|
184
193
|
private readonly sandboxJobs;
|
|
194
|
+
/** Owes a deleted device's destruction in the delete's transaction. */
|
|
195
|
+
private readonly outbox;
|
|
185
196
|
private readonly access;
|
|
186
197
|
private readonly displayNames;
|
|
187
|
-
private readonly log;
|
|
188
198
|
/** Reads the device relay's lease (`online`). */
|
|
189
199
|
private readonly locks;
|
|
190
200
|
private readonly machines;
|
|
191
201
|
private readonly policies;
|
|
192
|
-
constructor(db: KernelDb, txHost: TransactionHost, config: Pick<KernelConfigService, "get">, providers: Pick<SandboxProviders, "cloud" | "forName">, sandbox: Pick<SandboxService, "deviceLimits" | "limitsState">, sandboxJobs: Pick<SandboxJobs, "
|
|
202
|
+
constructor(db: KernelDb, txHost: TransactionHost, config: Pick<KernelConfigService, "get">, providers: Pick<SandboxProviders, "cloud" | "forName">, sandbox: Pick<SandboxService, "deviceLimits" | "limitsState">, sandboxJobs: Pick<SandboxJobs, "resetFiles">,
|
|
203
|
+
/** Owes a deleted device's destruction in the delete's transaction. */
|
|
204
|
+
outbox: Pick<OutboxService, "add">, access: Pick<DeviceAccess, "usable">, displayNames: Pick<ExtensionDisplayNames, "many">,
|
|
193
205
|
/** Reads the device relay's lease (`online`). */
|
|
194
206
|
locks: Pick<LockService, "holderOf">, machines: Pick<MachinesService, "revoke" | "revokeActive">, policies: Pick<DevicePolicyService, "apply" | "summary">);
|
|
195
207
|
/**
|
|
@@ -275,9 +287,9 @@ export declare class DevicesService {
|
|
|
275
287
|
/** Renames the device locked by {@link lockOwn} (`before`); see {@link rename}. */
|
|
276
288
|
private renameLocked;
|
|
277
289
|
/**
|
|
278
|
-
* Deletes one of the person's live devices: soft delete, its IM default row cleared, and
|
|
279
|
-
*
|
|
280
|
-
* destroys the instance and the files). Conversations bound to it keep pointing at it; their
|
|
290
|
+
* Deletes one of the person's live devices: soft delete, its IM default row cleared, and a
|
|
291
|
+
* `sandbox-destroy-for` job owed in the same transaction (`device-destroy-<deviceId>`; the
|
|
292
|
+
* worker waits for running commands, then destroys the instance and the files). Conversations bound to it keep pointing at it; their
|
|
281
293
|
* sandbox tools then fail with `device.not_found`. A local device's machine is
|
|
282
294
|
* revoked in the same transaction; after the commit it is told `stop { reason: "deleted" }`
|
|
283
295
|
* (while connected) and its connection is closed.
|