@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
package/dist/runtime/step-log.js
CHANGED
|
@@ -17,28 +17,43 @@ import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
|
17
17
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
18
18
|
import { recordToolSpecs } from "../tools/specs.js";
|
|
19
19
|
import { budgetRunOf } from "./subagents/limits.js";
|
|
20
|
+
import { UsageReportJobs, UsageReportJobsModule } from "./usage-report-jobs.js";
|
|
20
21
|
/**
|
|
21
22
|
* The writes of a run step that go to the event log together with another row, each in a
|
|
22
23
|
* transaction of its own (the caller notifies the log after the commit): a model call with the
|
|
23
|
-
* tool definitions it sent, a denial with its audit row,
|
|
24
|
-
*
|
|
24
|
+
* tool definitions it sent, a denial with its audit row, usage events with their owed
|
|
25
|
+
* `usage.report` deliveries (transactional outbox spec §8.1), and a sub-agent's usage counted on
|
|
26
|
+
* its parent run. The step functions (`model-call.ts`, `hook-calls.ts`) reach it through their deps.
|
|
25
27
|
*/
|
|
26
28
|
let StepLog = class StepLog {
|
|
27
29
|
kdb;
|
|
28
30
|
eventLog;
|
|
31
|
+
usage;
|
|
29
32
|
txHost;
|
|
30
|
-
constructor(kdb, eventLog, txHost) {
|
|
33
|
+
constructor(kdb, eventLog, usage, txHost) {
|
|
31
34
|
this.kdb = kdb;
|
|
32
35
|
this.eventLog = eventLog;
|
|
36
|
+
this.usage = usage;
|
|
33
37
|
this.txHost = txHost;
|
|
34
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Appends events and owes the `usage.report` delivery of the `usage` events it newly wrote, in
|
|
41
|
+
* one transaction. Returns what was written (hits included) and the highest new seq (null:
|
|
42
|
+
* nothing new).
|
|
43
|
+
*/
|
|
44
|
+
async appendReported(conversationId, events) {
|
|
45
|
+
const { events: written, fresh } = await this.eventLog.appendInReport(conversationId, events);
|
|
46
|
+
const added = written.filter((_, i) => fresh[i]);
|
|
47
|
+
await this.usage.oweEvents(conversationId, added);
|
|
48
|
+
return { written, toSeq: added.length > 0 ? Math.max(...added.map((e) => e.seq)) : null };
|
|
49
|
+
}
|
|
35
50
|
/**
|
|
36
51
|
* Appends events of a sub-agent's run and adds the tokens of the usage events it newly wrote to
|
|
37
52
|
* the `subagent_tokens_used` of the tree's budget run (sub-agents spec §8.3, agent map spec §6:
|
|
38
53
|
* the whole tree counts on one run): `counter.budgetRunId`, the run's own window
|
|
39
54
|
* (`SubagentParent.budgetRunId`), else the parent run's ({@link budgetRunOf}). A usage event
|
|
40
55
|
* already in the log (an idempotent hit after a crash) adds nothing, so each call counts exactly
|
|
41
|
-
* once. Returns what was written (hits included) and the highest new seq (null: nothing new).
|
|
56
|
+
* once; the new usage events' `usage.report` deliveries are owed in the same transaction. Returns what was written (hits included) and the highest new seq (null: nothing new).
|
|
42
57
|
*/
|
|
43
58
|
async appendCounted(conversationId, counter, events) {
|
|
44
59
|
const t = this.kdb.db;
|
|
@@ -51,6 +66,7 @@ let StepLog = class StepLog {
|
|
|
51
66
|
.executeTakeFirstOrThrow();
|
|
52
67
|
const written = await this.eventLog.appendIn(conversationId, events);
|
|
53
68
|
const fresh = written.filter((e) => e.seq > Number(before.last_seq));
|
|
69
|
+
await this.usage.oweEvents(conversationId, fresh);
|
|
54
70
|
let tokens = 0;
|
|
55
71
|
for (const e of fresh)
|
|
56
72
|
if (e.type === "usage")
|
|
@@ -79,6 +95,9 @@ let StepLog = class StepLog {
|
|
|
79
95
|
return this.eventLog.appendIn(conversationId, events);
|
|
80
96
|
}
|
|
81
97
|
};
|
|
98
|
+
__decorate([
|
|
99
|
+
Transactional({ propagation: "requires_new" })
|
|
100
|
+
], StepLog.prototype, "appendReported", null);
|
|
82
101
|
__decorate([
|
|
83
102
|
Transactional({ propagation: "requires_new" })
|
|
84
103
|
], StepLog.prototype, "appendCounted", null);
|
|
@@ -92,7 +111,8 @@ StepLog = __decorate([
|
|
|
92
111
|
Injectable(),
|
|
93
112
|
__param(0, Inject(KernelDb)),
|
|
94
113
|
__param(1, Inject(EventLog)),
|
|
95
|
-
__param(2, Inject(
|
|
114
|
+
__param(2, Inject(UsageReportJobs)),
|
|
115
|
+
__param(3, Inject(TransactionHost))
|
|
96
116
|
], StepLog);
|
|
97
117
|
export { StepLog };
|
|
98
118
|
/**
|
|
@@ -103,7 +123,7 @@ let StepLogModule = class StepLogModule {
|
|
|
103
123
|
};
|
|
104
124
|
StepLogModule = __decorate([
|
|
105
125
|
Module({
|
|
106
|
-
imports: [EventLogModule],
|
|
126
|
+
imports: [EventLogModule, UsageReportJobsModule],
|
|
107
127
|
providers: [StepLog],
|
|
108
128
|
exports: [StepLog],
|
|
109
129
|
})
|
|
@@ -2,7 +2,6 @@ import type { Logger } from "@capybara-hq/plugin-sdk";
|
|
|
2
2
|
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { ConversationAccess } from "../conversations/access.js";
|
|
5
|
-
import { ConversationsService } from "../conversations/conversations.service.js";
|
|
6
5
|
import { ApiTokenService } from "../identity/api-tokens.js";
|
|
7
6
|
import { type Principal } from "../identity/principal.js";
|
|
8
7
|
import { SessionService } from "../identity/sessions.js";
|
|
@@ -18,7 +17,7 @@ declare const DraftParams: z.ZodObject<{
|
|
|
18
17
|
}, z.core.$strip>;
|
|
19
18
|
/**
|
|
20
19
|
* 会话事件流(SSE):`GET /api/v1/orgs/:orgId/conversations/:id/stream?after=<seq>`,`agents.use`,只有会话所有者可用。
|
|
21
|
-
* -
|
|
20
|
+
* - opening it never changes run state (a read; transactional outbox spec §6);
|
|
22
21
|
* - 先订阅会话频道、再回放 `after`(或优先的 `Last-Event-ID`)之后的事件:`id: <seq>` / `event: event`;
|
|
23
22
|
* - after that catch-up, one `event: draft` (`data: {"runId","step","text","thinking"}`) per step of
|
|
24
23
|
* the running run whose `assistant_message` is not logged (live drafts, spec 2026-11-07 §3.2);
|
|
@@ -33,11 +32,10 @@ export declare class ConversationStreamController {
|
|
|
33
32
|
private readonly streams;
|
|
34
33
|
private readonly sessions;
|
|
35
34
|
private readonly tokens;
|
|
36
|
-
private readonly conversations;
|
|
37
35
|
private readonly access;
|
|
38
36
|
private readonly drafts;
|
|
39
37
|
private readonly log;
|
|
40
|
-
constructor(streams: ConversationStreams, sessions: SessionService, tokens: ApiTokenService,
|
|
38
|
+
constructor(streams: ConversationStreams, sessions: SessionService, tokens: ApiTokenService, access: ConversationAccess, drafts: RunDrafts, log: Pick<Logger, "warn">);
|
|
41
39
|
/**
|
|
42
40
|
* The live drafts of one run (spec 2026-11-07 §3.2): `{ drafts: { step, text, thinking }[] }`,
|
|
43
41
|
* the steps still streaming whose `assistant_message` is not logged (none once the run is no
|
|
@@ -10,7 +10,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { Controller, Get, Headers, Inject, Param, Req, Res } from "@nestjs/common";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
import { ConversationAccess } from "../conversations/access.js";
|
|
13
|
-
import { ConversationsService } from "../conversations/conversations.service.js";
|
|
14
13
|
import { ApiError } from "../errors.js";
|
|
15
14
|
import { ApiTokenService } from "../identity/api-tokens.js";
|
|
16
15
|
import { credentialCheck } from "../identity/credential-check.js";
|
|
@@ -45,7 +44,7 @@ class RunDraftParamsDto extends createZodDto(DraftParams, "RunDraftParams") {
|
|
|
45
44
|
}
|
|
46
45
|
/**
|
|
47
46
|
* 会话事件流(SSE):`GET /api/v1/orgs/:orgId/conversations/:id/stream?after=<seq>`,`agents.use`,只有会话所有者可用。
|
|
48
|
-
* -
|
|
47
|
+
* - opening it never changes run state (a read; transactional outbox spec §6);
|
|
49
48
|
* - 先订阅会话频道、再回放 `after`(或优先的 `Last-Event-ID`)之后的事件:`id: <seq>` / `event: event`;
|
|
50
49
|
* - after that catch-up, one `event: draft` (`data: {"runId","step","text","thinking"}`) per step of
|
|
51
50
|
* the running run whose `assistant_message` is not logged (live drafts, spec 2026-11-07 §3.2);
|
|
@@ -60,15 +59,13 @@ let ConversationStreamController = class ConversationStreamController {
|
|
|
60
59
|
streams;
|
|
61
60
|
sessions;
|
|
62
61
|
tokens;
|
|
63
|
-
conversations;
|
|
64
62
|
access;
|
|
65
63
|
drafts;
|
|
66
64
|
log;
|
|
67
|
-
constructor(streams, sessions, tokens,
|
|
65
|
+
constructor(streams, sessions, tokens, access, drafts, log) {
|
|
68
66
|
this.streams = streams;
|
|
69
67
|
this.sessions = sessions;
|
|
70
68
|
this.tokens = tokens;
|
|
71
|
-
this.conversations = conversations;
|
|
72
69
|
this.access = access;
|
|
73
70
|
this.drafts = drafts;
|
|
74
71
|
this.log = log;
|
|
@@ -131,8 +128,6 @@ let ConversationStreamController = class ConversationStreamController {
|
|
|
131
128
|
},
|
|
132
129
|
});
|
|
133
130
|
reply.hijack();
|
|
134
|
-
// 可见性已通过:不阻塞地 ensureRun(清理孤儿运行、投递等待中的消息),见 ConversationsService.kickRun。
|
|
135
|
-
this.conversations.kickRun(id);
|
|
136
131
|
res.on("close", () => handle.close());
|
|
137
132
|
// 订阅期间客户端已断开:close 事件可能已经错过
|
|
138
133
|
if (res.destroyed || !res.socket || res.socket.destroyed) {
|
|
@@ -173,9 +168,8 @@ ConversationStreamController = __decorate([
|
|
|
173
168
|
__param(0, Inject(ConversationStreams)),
|
|
174
169
|
__param(1, Inject(SessionService)),
|
|
175
170
|
__param(2, Inject(ApiTokenService)),
|
|
176
|
-
__param(3, Inject(
|
|
177
|
-
__param(4, Inject(
|
|
178
|
-
__param(5, Inject(
|
|
179
|
-
__param(6, Inject(KERNEL_LOGGER))
|
|
171
|
+
__param(3, Inject(ConversationAccess)),
|
|
172
|
+
__param(4, Inject(RunDrafts)),
|
|
173
|
+
__param(5, Inject(KERNEL_LOGGER))
|
|
180
174
|
], ConversationStreamController);
|
|
181
175
|
export { ConversationStreamController };
|
|
@@ -179,7 +179,7 @@ export async function childResult(eventLog, row, opts = {}) {
|
|
|
179
179
|
else {
|
|
180
180
|
status = "aborted";
|
|
181
181
|
// §4.4: a person's stop names its account; a stop by nobody (null) is the kernel stopping the
|
|
182
|
-
// child on its parent's behalf (stopChildren with no account: the parent's end,
|
|
182
|
+
// child on its parent's behalf (stopChildren with no account: the parent's end, its `stop-tree` job)
|
|
183
183
|
abortedBy =
|
|
184
184
|
terminal.payload.reason === "user" && terminal.payload.byAccountId === null
|
|
185
185
|
? "parent"
|
|
@@ -20,6 +20,7 @@ export declare class SubagentTypeGoneError extends Error {
|
|
|
20
20
|
export interface EffectiveDefinition {
|
|
21
21
|
definition: AgentDefinition;
|
|
22
22
|
template: EventPayload<"subagent_started">["template"];
|
|
23
|
+
/** The child's step limit; 0 = no limit. */
|
|
23
24
|
maxSteps: number;
|
|
24
25
|
/**
|
|
25
26
|
* The child's preamble, frozen into `subagent_started.preamble` (model-visible):
|
|
@@ -72,7 +73,7 @@ export interface ChildDepth {
|
|
|
72
73
|
* - `general` / `inline` / `plugin`: the parent's definition narrowed by the template (tools by
|
|
73
74
|
* resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins; skills
|
|
74
75
|
* by its `disallowedSkills`), the template's instructions, its `skills` the child has named in
|
|
75
|
-
* the preamble to load first (general gets no line), `maxSteps =
|
|
76
|
+
* the preamble to load first (general gets no line), `maxSteps` = the tighter of the template's and `runtime.maxSteps` (0 = no limit), and the model tier
|
|
76
77
|
* `tier` (the call's) → the template's → `inherit`; an unmapped tier runs on the parent's model
|
|
77
78
|
* (`tierFallback`); a template `effort` is set when the resolved model declares it;
|
|
78
79
|
* - `agent`: the org agent's version that passed the gates (`orgAgent`, from {@link checkOrgAgent}),
|
|
@@ -6,6 +6,7 @@ import { ApiError } from "../../errors.js";
|
|
|
6
6
|
import { invocationOf, resolveSkills } from "../../skills/catalog.js";
|
|
7
7
|
import { agentSkills, usableSkills } from "../../skills/usable.js";
|
|
8
8
|
import { AGENT_TOOL, CHILD_REMOVED_TOOLS } from "../../tools/builtin-names.js";
|
|
9
|
+
import { tightestLimit } from "../limits.js";
|
|
9
10
|
import { SUBAGENT_PREAMBLE } from "./preamble.js";
|
|
10
11
|
export { CHILD_REMOVED_TOOLS } from "../../tools/builtin-names.js";
|
|
11
12
|
/**
|
|
@@ -222,7 +223,7 @@ function orgAgentDefinition(d, a) {
|
|
|
222
223
|
* - `general` / `inline` / `plugin`: the parent's definition narrowed by the template (tools by
|
|
223
224
|
* resolved key, `disallowedTools`, {@link CHILD_REMOVED_TOOLS}; policies stricter-wins; skills
|
|
224
225
|
* by its `disallowedSkills`), the template's instructions, its `skills` the child has named in
|
|
225
|
-
* the preamble to load first (general gets no line), `maxSteps =
|
|
226
|
+
* the preamble to load first (general gets no line), `maxSteps` = the tighter of the template's and `runtime.maxSteps` (0 = no limit), and the model tier
|
|
226
227
|
* `tier` (the call's) → the template's → `inherit`; an unmapped tier runs on the parent's model
|
|
227
228
|
* (`tierFallback`); a template `effort` is set when the resolved model declares it;
|
|
228
229
|
* - `agent`: the org agent's version that passed the gates (`orgAgent`, from {@link checkOrgAgent}),
|
|
@@ -293,7 +294,8 @@ export async function effectiveDefinition(d, a) {
|
|
|
293
294
|
return {
|
|
294
295
|
definition,
|
|
295
296
|
template: ref,
|
|
296
|
-
|
|
297
|
+
// the tighter of the template's and the deployment's, 0 = no limit (`runtime.maxSteps` 0)
|
|
298
|
+
maxSteps: tightestLimit(template?.maxSteps, runtimeMax) ?? 0,
|
|
297
299
|
preamble: names.length === 0
|
|
298
300
|
? SUBAGENT_PREAMBLE
|
|
299
301
|
: `${SUBAGENT_PREAMBLE}\n\n${loadSkillsFirstText(names)}`,
|
|
@@ -3,6 +3,7 @@ import type { EventPayload } from "../../conversations/events.js";
|
|
|
3
3
|
import { KernelDb } from "../../infra/database/kernel-db.js";
|
|
4
4
|
import { TransactionHost } from "../../infra/database/transaction-host.js";
|
|
5
5
|
import { KernelEvents } from "../../infra/events/kernel-events.js";
|
|
6
|
+
import { OutboxService } from "../../infra/outbox/outbox.service.js";
|
|
6
7
|
import type { KernelLogger } from "../../log.js";
|
|
7
8
|
import { type DispatchRow } from "./child.js";
|
|
8
9
|
/** What a caller of {@link SubagentDeliveries.deliverIn} gives; the rest comes from the dispatch. */
|
|
@@ -17,7 +18,7 @@ export declare const finishedDeliveryIdemKey: (childRunId: string) => string;
|
|
|
17
18
|
*
|
|
18
19
|
* A background child's run reaching a terminal state ({@link childFinished}) writes the
|
|
19
20
|
* display-only `subagent_finished` and a `finished` delivery in one transaction, both idempotent by
|
|
20
|
-
* the child run, so of two finishers (the worker
|
|
21
|
+
* the child run, so of two finishers (the worker, a stop, the `deliver-to-parent` job, the `run-orphan-check`) exactly one writes
|
|
21
22
|
* them. A run that handed back a report and then completed writes no delivery (acceptance
|
|
22
23
|
* 2026-11-07): the report already told the parent everything, and a content-free "completed" line
|
|
23
24
|
* only woke an idle parent for nothing and pushed the report away from the end of its request. Fork invocations (phase D, `for_skill`) do not deliver: their parent run waits on the child
|
|
@@ -29,7 +30,8 @@ export declare class SubagentDeliveries {
|
|
|
29
30
|
private readonly events;
|
|
30
31
|
private readonly log;
|
|
31
32
|
readonly txHost: TransactionHost;
|
|
32
|
-
|
|
33
|
+
private readonly outbox;
|
|
34
|
+
constructor(kdb: KernelDb, eventLog: EventLog, events: KernelEvents, log: Pick<KernelLogger, "warn">, txHost: TransactionHost, outbox: Pick<OutboxService, "add">);
|
|
33
35
|
/** The context's handle (the transaction of a `@Transactional` method, else the pool). */
|
|
34
36
|
private get db();
|
|
35
37
|
/**
|
|
@@ -38,7 +40,8 @@ export declare class SubagentDeliveries {
|
|
|
38
40
|
* the child run's (a wake runs as that person, §7). Idempotent by `opts.idemKey` (a finish's
|
|
39
41
|
* default is {@link finishedDeliveryIdemKey}; a report or a note must name its own): under the
|
|
40
42
|
* parent conversation's row lock, an existing delivery returns null and writes nothing. After
|
|
41
|
-
* the commit: the log's notify and `subagent.delivered
|
|
43
|
+
* the commit: the log's notify and `subagent.delivered`; the parent's ensure-run backstop is
|
|
44
|
+
* owed in the transaction. Returns the new event's seq.
|
|
42
45
|
*/
|
|
43
46
|
deliverIn(row: DispatchRow, d: DeliveryInput, opts?: {
|
|
44
47
|
idemKey?: string;
|
|
@@ -15,8 +15,9 @@ import { KernelDb } from "../../infra/database/kernel-db.js";
|
|
|
15
15
|
import { TransactionHost } from "../../infra/database/transaction-host.js";
|
|
16
16
|
import { Transactional } from "../../infra/database/transactional.decorator.js";
|
|
17
17
|
import { KernelEvents } from "../../infra/events/kernel-events.js";
|
|
18
|
+
import { OutboxService } from "../../infra/outbox/outbox.service.js";
|
|
18
19
|
import { KERNEL_LOGGER } from "../../infra/tokens.js";
|
|
19
|
-
import { TERMINAL_STATUSES } from "../run-
|
|
20
|
+
import { oweEnsureRun, TERMINAL_STATUSES } from "../run-jobs.js";
|
|
20
21
|
import { childResult, deliveryRowOfChildRun, finishedEvent } from "./child.js";
|
|
21
22
|
import { dispatchedIdemKey } from "./dispatch.js";
|
|
22
23
|
/** Idempotency key of a child run's finished delivery (one per child run). */
|
|
@@ -31,7 +32,7 @@ const DELIVERY_TEXT_MAX = 200_000;
|
|
|
31
32
|
*
|
|
32
33
|
* A background child's run reaching a terminal state ({@link childFinished}) writes the
|
|
33
34
|
* display-only `subagent_finished` and a `finished` delivery in one transaction, both idempotent by
|
|
34
|
-
* the child run, so of two finishers (the worker
|
|
35
|
+
* the child run, so of two finishers (the worker, a stop, the `deliver-to-parent` job, the `run-orphan-check`) exactly one writes
|
|
35
36
|
* them. A run that handed back a report and then completed writes no delivery (acceptance
|
|
36
37
|
* 2026-11-07): the report already told the parent everything, and a content-free "completed" line
|
|
37
38
|
* only woke an idle parent for nothing and pushed the report away from the end of its request. Fork invocations (phase D, `for_skill`) do not deliver: their parent run waits on the child
|
|
@@ -43,12 +44,14 @@ let SubagentDeliveries = class SubagentDeliveries {
|
|
|
43
44
|
events;
|
|
44
45
|
log;
|
|
45
46
|
txHost;
|
|
46
|
-
|
|
47
|
+
outbox;
|
|
48
|
+
constructor(kdb, eventLog, events, log, txHost, outbox) {
|
|
47
49
|
this.kdb = kdb;
|
|
48
50
|
this.eventLog = eventLog;
|
|
49
51
|
this.events = events;
|
|
50
52
|
this.log = log;
|
|
51
53
|
this.txHost = txHost;
|
|
54
|
+
this.outbox = outbox;
|
|
52
55
|
}
|
|
53
56
|
/** The context's handle (the transaction of a `@Transactional` method, else the pool). */
|
|
54
57
|
get db() {
|
|
@@ -60,7 +63,8 @@ let SubagentDeliveries = class SubagentDeliveries {
|
|
|
60
63
|
* the child run's (a wake runs as that person, §7). Idempotent by `opts.idemKey` (a finish's
|
|
61
64
|
* default is {@link finishedDeliveryIdemKey}; a report or a note must name its own): under the
|
|
62
65
|
* parent conversation's row lock, an existing delivery returns null and writes nothing. After
|
|
63
|
-
* the commit: the log's notify and `subagent.delivered
|
|
66
|
+
* the commit: the log's notify and `subagent.delivered`; the parent's ensure-run backstop is
|
|
67
|
+
* owed in the transaction. Returns the new event's seq.
|
|
64
68
|
*/
|
|
65
69
|
async deliverIn(row, d, opts = {}) {
|
|
66
70
|
const idemKey = opts.idemKey ?? (d.kind === "finished" ? finishedDeliveryIdemKey(row.childRunId) : undefined);
|
|
@@ -68,9 +72,9 @@ let SubagentDeliveries = class SubagentDeliveries {
|
|
|
68
72
|
throw new Error(`a ${d.kind} delivery needs its idempotency key`);
|
|
69
73
|
const t = this.db;
|
|
70
74
|
const parent = row.parentConversationId;
|
|
71
|
-
await t
|
|
75
|
+
const conv = await t
|
|
72
76
|
.selectFrom("conversations")
|
|
73
|
-
.select("
|
|
77
|
+
.select("org_id")
|
|
74
78
|
.where("id", "=", parent)
|
|
75
79
|
.forUpdate()
|
|
76
80
|
.executeTakeFirst();
|
|
@@ -103,6 +107,10 @@ let SubagentDeliveries = class SubagentDeliveries {
|
|
|
103
107
|
]);
|
|
104
108
|
if (!event)
|
|
105
109
|
return null;
|
|
110
|
+
// the parent's wake is owed with the delivery: the wake after the commit (`BackgroundWake`)
|
|
111
|
+
// may never happen (transactional outbox spec §6)
|
|
112
|
+
if (conv)
|
|
113
|
+
await oweEnsureRun(this.outbox, parent, event.seq, conv.org_id);
|
|
106
114
|
afterCommit(async () => {
|
|
107
115
|
await this.eventLog.notify(parent, event.seq);
|
|
108
116
|
await this.events.emit("subagent.delivered", { conversationId: parent });
|
|
@@ -223,6 +231,7 @@ SubagentDeliveries = __decorate([
|
|
|
223
231
|
__param(1, Inject(EventLog)),
|
|
224
232
|
__param(2, Inject(KernelEvents)),
|
|
225
233
|
__param(3, Inject(KERNEL_LOGGER)),
|
|
226
|
-
__param(4, Inject(TransactionHost))
|
|
234
|
+
__param(4, Inject(TransactionHost)),
|
|
235
|
+
__param(5, Inject(OutboxService))
|
|
227
236
|
], SubagentDeliveries);
|
|
228
237
|
export { SubagentDeliveries };
|
|
@@ -18,8 +18,11 @@ export interface DispatchDeps {
|
|
|
18
18
|
purposes: Pick<ModelPurposesService, "resolve">;
|
|
19
19
|
registry: Pick<ProviderRegistry, "resolve">;
|
|
20
20
|
config: Pick<KernelConfigService, "get">;
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Owes a child run's job in the dispatch's transaction (`RunJobs.owe`: on the sub-agent run
|
|
23
|
+
* queue, `kind` is always `subagent`); false when the job id is already owed.
|
|
24
|
+
*/
|
|
25
|
+
owe: (data: RunJobData, jobId: string, kind: ConversationKind, orgId: string) => Promise<boolean>;
|
|
23
26
|
log: Pick<Logger, "error" | "warn">;
|
|
24
27
|
/**
|
|
25
28
|
* Runs {@link commitDispatchIn} in a transaction of its own (`SubagentsService.commitDispatch`,
|
|
@@ -121,9 +124,9 @@ export interface DispatchPlan {
|
|
|
121
124
|
* dispatches of one run serialize) inserts the child conversation, appends `subagent_started` and
|
|
122
125
|
* the task message, inserts the child run (`queued`) and the `subagent_dispatches` row, appends
|
|
123
126
|
* `subagent_dispatched` and the call's `tool_result` ({@link agentStartedText}: the sub-agent runs
|
|
124
|
-
* in the background) to the parent and audits `subagent.dispatched` and `tool.called`.
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
+
* in the background) to the parent and audits `subagent.dispatched` and `tool.called`. The child
|
|
128
|
+
* run's job is owed in the same transaction (transactional outbox spec §6), so the committed
|
|
129
|
+
* dispatch always starts its child. A fork invocation (`forSkill`) writes no `tool_result`: its run waits on
|
|
127
130
|
* the child (`advanceSkillForks`).
|
|
128
131
|
*
|
|
129
132
|
* Refusals (§4.5) start nothing: a call from a run at `subagents.maxDepth` (agent map spec §4.1:
|
|
@@ -188,7 +191,8 @@ export declare const sentMessageIdemKey: (runId: string, callId: string) => stri
|
|
|
188
191
|
* row, then the parent run row (the order every terminal path uses),
|
|
189
192
|
* runs `child` (writes the child conversation's first events and returns the task message, or
|
|
190
193
|
* null to refuse), then inserts the child run and the dispatch row, appends `subagent_dispatched`
|
|
191
|
-
* and the audit row
|
|
194
|
+
* and the audit row, and owes the child run's job (transactional outbox spec §6). After commit:
|
|
195
|
+
* notifies both conversations.
|
|
192
196
|
* Returns null when `child` refused.
|
|
193
197
|
*
|
|
194
198
|
* Under the parent run's row lock it first re-checks what the pipeline checked without it: a call
|
|
@@ -205,10 +209,6 @@ export type DispatchCommit = {
|
|
|
205
209
|
kind: "existing";
|
|
206
210
|
childRunId: string;
|
|
207
211
|
childConversationId: string;
|
|
208
|
-
requeue: {
|
|
209
|
-
conversationId: string;
|
|
210
|
-
seq: number;
|
|
211
|
-
} | null;
|
|
212
212
|
/** The call's logged result (null for a fork dispatch) and its seq, to notify. */
|
|
213
213
|
result: {
|
|
214
214
|
content: string;
|
|
@@ -233,7 +233,7 @@ export type DispatchCommit = {
|
|
|
233
233
|
* {@link commit}'s transaction (run by `SubagentsService.commitDispatch`, `d.db` its handle).
|
|
234
234
|
* Null when `child` refused.
|
|
235
235
|
*/
|
|
236
|
-
export declare function commitDispatchIn(d: Pick<DispatchDeps, "db" | "eventLog" | "config">, a: DispatchArgs, plan: DispatchPlan, child: ChildWriter): Promise<DispatchCommit | null>;
|
|
237
|
-
export declare function commit(d: Pick<DispatchDeps, "commitDispatch" | "
|
|
236
|
+
export declare function commitDispatchIn(d: Pick<DispatchDeps, "db" | "eventLog" | "config" | "owe">, a: DispatchArgs, plan: DispatchPlan, child: ChildWriter): Promise<DispatchCommit | null>;
|
|
237
|
+
export declare function commit(d: Pick<DispatchDeps, "commitDispatch" | "eventLog">, a: DispatchArgs, plan: DispatchPlan,
|
|
238
238
|
/** Writes the child's events; `checked` is the org agent version the in-lock gates passed. */
|
|
239
239
|
child: ChildWriter): Promise<DispatchOutcome | null>;
|
|
@@ -31,9 +31,9 @@ export const dispatchedIdemKey = (runId, callId) => `subagent_dispatched:${runId
|
|
|
31
31
|
* dispatches of one run serialize) inserts the child conversation, appends `subagent_started` and
|
|
32
32
|
* the task message, inserts the child run (`queued`) and the `subagent_dispatches` row, appends
|
|
33
33
|
* `subagent_dispatched` and the call's `tool_result` ({@link agentStartedText}: the sub-agent runs
|
|
34
|
-
* in the background) to the parent and audits `subagent.dispatched` and `tool.called`.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* in the background) to the parent and audits `subagent.dispatched` and `tool.called`. The child
|
|
35
|
+
* run's job is owed in the same transaction (transactional outbox spec §6), so the committed
|
|
36
|
+
* dispatch always starts its child. A fork invocation (`forSkill`) writes no `tool_result`: its run waits on
|
|
37
37
|
* the child (`advanceSkillForks`).
|
|
38
38
|
*
|
|
39
39
|
* Refusals (§4.5) start nothing: a call from a run at `subagents.maxDepth` (agent map spec §4.1:
|
|
@@ -121,6 +121,7 @@ export async function dispatchSubagent(d, a) {
|
|
|
121
121
|
parent_conversation_id: ctx.conversationId,
|
|
122
122
|
subagent_type: entry.type,
|
|
123
123
|
subagent_depth: childDepth,
|
|
124
|
+
source: "subagent",
|
|
124
125
|
})
|
|
125
126
|
.execute();
|
|
126
127
|
const [, task] = await d.eventLog.appendIn(childId, [
|
|
@@ -226,7 +227,7 @@ const isActiveStatus = (status) => ACTIVE_RUN_STATUSES.includes(status);
|
|
|
226
227
|
* delivered (agent map spec, rc upgrade: a foreground-era dispatch whose rc finisher wrote
|
|
227
228
|
* `subagent_finished` and resumed the parent): the child's report (`childResult`), with the
|
|
228
229
|
* parent's `subagent_finished` appended in this transaction when it is missing (idempotent by its
|
|
229
|
-
* key), so the
|
|
230
|
+
* key), so the `deliver-to-parent` job never delivers it a second time. Null when the parent already
|
|
230
231
|
* has a delivery for the run (it carries the result) or the run has no terminal event yet.
|
|
231
232
|
*/
|
|
232
233
|
async function rcFinishedResult(d, row) {
|
|
@@ -272,7 +273,7 @@ export async function commitDispatchIn(d, a, plan, child) {
|
|
|
272
273
|
const existing = await t
|
|
273
274
|
.selectFrom("subagent_dispatches as sd")
|
|
274
275
|
.leftJoin("runs as cr", "cr.id", "sd.child_run_id")
|
|
275
|
-
.select(["sd.child_run_id", "sd.child_conversation_id", "cr.status"
|
|
276
|
+
.select(["sd.child_run_id", "sd.child_conversation_id", "cr.status"])
|
|
276
277
|
.where("sd.parent_run_id", "=", ctx.runId)
|
|
277
278
|
.where("sd.parent_call_id", "=", callId)
|
|
278
279
|
.executeTakeFirst();
|
|
@@ -284,10 +285,10 @@ export async function commitDispatchIn(d, a, plan, child) {
|
|
|
284
285
|
let result = null;
|
|
285
286
|
if (a.forSkill === undefined) {
|
|
286
287
|
// an rc child that already ended under the foreground wait, whose rc finisher wrote
|
|
287
|
-
// `subagent_finished` and resumed this run (no delivery;
|
|
288
|
-
//
|
|
288
|
+
// `subagent_finished` and resumed this run (no delivery; a run with `subagent_finished` is
|
|
289
|
+
// never delivered): its report is this call's result, as the rc gave it, or it is lost.
|
|
289
290
|
// Only while the call has no result: a call that has one (a background dispatch's second
|
|
290
|
-
// holder) keeps it, and its child's finish stays to its delivery or
|
|
291
|
+
// holder) keeps it, and its child's finish stays to its delivery (or its `deliver-to-parent` job).
|
|
291
292
|
const resultKey = resultEvent(ctx, callId, AGENT_TOOL, "").idemKey;
|
|
292
293
|
const finished = a.sent === undefined &&
|
|
293
294
|
existing.status !== null &&
|
|
@@ -312,13 +313,6 @@ export async function commitDispatchIn(d, a, plan, child) {
|
|
|
312
313
|
childRunId: existing.child_run_id,
|
|
313
314
|
childConversationId: existing.child_conversation_id,
|
|
314
315
|
result,
|
|
315
|
-
// still queued: the first holder may have died before its enqueue (review M4)
|
|
316
|
-
requeue: existing.status === "queued" && existing.trigger_seq !== null
|
|
317
|
-
? {
|
|
318
|
-
conversationId: existing.child_conversation_id,
|
|
319
|
-
seq: Number(existing.trigger_seq),
|
|
320
|
-
}
|
|
321
|
-
: null,
|
|
322
316
|
};
|
|
323
317
|
}
|
|
324
318
|
if (parent?.status !== "running")
|
|
@@ -384,6 +378,9 @@ export async function commitDispatchIn(d, a, plan, child) {
|
|
|
384
378
|
for_skill: a.forSkill !== undefined,
|
|
385
379
|
})
|
|
386
380
|
.execute();
|
|
381
|
+
// the child run's job is owed with its row (transactional outbox spec §6): a queued child
|
|
382
|
+
// always has its job, whatever happens after the commit
|
|
383
|
+
await d.owe({ runId: childRunId, conversationId: plan.childConversationId }, runJobId(plan.childConversationId, task.seq), "subagent", ctx.orgId);
|
|
387
384
|
// an org agent runs on its own model (§5.4): a `model` on the call was ignored
|
|
388
385
|
const ownModel = plan.source === "agent" && input.model !== undefined;
|
|
389
386
|
const content = a.sent?.content ?? agentStartedText(plan.childConversationId, { ownModel });
|
|
@@ -475,19 +472,7 @@ child) {
|
|
|
475
472
|
if (out === null)
|
|
476
473
|
return null;
|
|
477
474
|
if (out.kind === "existing") {
|
|
478
|
-
//
|
|
479
|
-
// it while that job exists), so a holder that died before its enqueue does not leave the
|
|
480
|
-
// child to the wait sweep
|
|
481
|
-
if (out.requeue !== null) {
|
|
482
|
-
const jobId = runJobId(out.requeue.conversationId, out.requeue.seq);
|
|
483
|
-
await d
|
|
484
|
-
.enqueue({ runId: out.childRunId, conversationId: out.requeue.conversationId }, jobId, "subagent")
|
|
485
|
-
.catch((err) => d.log.error("cannot enqueue sub-agent run; the sweep retries", {
|
|
486
|
-
childRunId: out.childRunId,
|
|
487
|
-
jobId,
|
|
488
|
-
err,
|
|
489
|
-
}));
|
|
490
|
-
}
|
|
475
|
+
// the child's job was owed with the first dispatch (a still queued child has it)
|
|
491
476
|
if (out.result !== null)
|
|
492
477
|
await d.eventLog.notify(ctx.conversationId, out.result.seq);
|
|
493
478
|
return {
|
|
@@ -507,18 +492,9 @@ child) {
|
|
|
507
492
|
return out.outcome;
|
|
508
493
|
await d.eventLog.notify(plan.childConversationId, out.childSeq);
|
|
509
494
|
await d.eventLog.notify(ctx.conversationId, out.parentSeq);
|
|
510
|
-
const childRunId = out.childRunId;
|
|
511
|
-
const jobId = runJobId(plan.childConversationId, out.childSeq);
|
|
512
|
-
try {
|
|
513
|
-
await d.enqueue({ runId: childRunId, conversationId: plan.childConversationId }, jobId, "subagent");
|
|
514
|
-
}
|
|
515
|
-
catch (err) {
|
|
516
|
-
// the dispatch is committed: the wait sweep re-enqueues the queued child run
|
|
517
|
-
d.log.error("cannot enqueue sub-agent run; the sweep retries", { childRunId, jobId, err });
|
|
518
|
-
}
|
|
519
495
|
return {
|
|
520
496
|
kind: "dispatched",
|
|
521
|
-
childRunId,
|
|
497
|
+
childRunId: out.childRunId,
|
|
522
498
|
childConversationId: plan.childConversationId,
|
|
523
499
|
content: out.content,
|
|
524
500
|
};
|
|
@@ -50,12 +50,16 @@ export declare class SubagentMessages {
|
|
|
50
50
|
private readonly kdb;
|
|
51
51
|
private readonly eventLog;
|
|
52
52
|
private readonly config;
|
|
53
|
+
/** Owes a restarted sub-agent's run job in the dispatch's transaction. */
|
|
54
|
+
private readonly jobs;
|
|
53
55
|
private readonly deliveries;
|
|
54
56
|
readonly txHost: TransactionHost;
|
|
55
57
|
private readonly hooks?;
|
|
56
58
|
/** What the dispatch transaction of a restart needs (`commit`). */
|
|
57
59
|
private readonly deps;
|
|
58
|
-
constructor(kdb: KernelDb, eventLog: EventLog, config: KernelConfigService,
|
|
60
|
+
constructor(kdb: KernelDb, eventLog: EventLog, config: KernelConfigService,
|
|
61
|
+
/** Owes a restarted sub-agent's run job in the dispatch's transaction. */
|
|
62
|
+
jobs: Pick<RunJobs, "owe">, log: KernelLogger, deliveries: SubagentDeliveries, txHost: TransactionHost, hooks?: SubagentMessagesHooks | undefined);
|
|
59
63
|
/** The restart's dispatch writes in a transaction of their own (see `commitDispatchIn`). */
|
|
60
64
|
private commitDispatch;
|
|
61
65
|
/** The context's handle (the transaction of a `@Transactional` method, else the pool). */
|
|
@@ -56,28 +56,36 @@ let SubagentMessages = class SubagentMessages {
|
|
|
56
56
|
kdb;
|
|
57
57
|
eventLog;
|
|
58
58
|
config;
|
|
59
|
+
jobs;
|
|
59
60
|
deliveries;
|
|
60
61
|
txHost;
|
|
61
62
|
hooks;
|
|
62
63
|
/** What the dispatch transaction of a restart needs (`commit`). */
|
|
63
64
|
deps;
|
|
64
|
-
constructor(kdb, eventLog, config,
|
|
65
|
+
constructor(kdb, eventLog, config,
|
|
66
|
+
/** Owes a restarted sub-agent's run job in the dispatch's transaction. */
|
|
67
|
+
jobs, log, deliveries, txHost, hooks) {
|
|
65
68
|
this.kdb = kdb;
|
|
66
69
|
this.eventLog = eventLog;
|
|
67
70
|
this.config = config;
|
|
71
|
+
this.jobs = jobs;
|
|
68
72
|
this.deliveries = deliveries;
|
|
69
73
|
this.txHost = txHost;
|
|
70
74
|
this.hooks = hooks;
|
|
71
75
|
this.deps = {
|
|
72
76
|
eventLog,
|
|
73
|
-
enqueue: (data, jobId, kind) => jobs.enqueue(data, jobId, kind),
|
|
74
77
|
log,
|
|
75
78
|
commitDispatch: (a, plan, child) => this.commitDispatch(a, plan, child),
|
|
76
79
|
};
|
|
77
80
|
}
|
|
78
81
|
/** The restart's dispatch writes in a transaction of their own (see `commitDispatchIn`). */
|
|
79
82
|
commitDispatch(a, plan, child) {
|
|
80
|
-
return commitDispatchIn({
|
|
83
|
+
return commitDispatchIn({
|
|
84
|
+
db: this.db,
|
|
85
|
+
eventLog: this.eventLog,
|
|
86
|
+
config: this.config,
|
|
87
|
+
owe: (data, jobId, kind, orgId) => this.jobs.owe(data, jobId, kind, orgId),
|
|
88
|
+
}, a, plan, child);
|
|
81
89
|
}
|
|
82
90
|
/** The context's handle (the transaction of a `@Transactional` method, else the pool). */
|
|
83
91
|
get db() {
|
|
@@ -11,8 +11,8 @@ import { type DispatchDeps } from "./dispatch.js";
|
|
|
11
11
|
* through phase C's `dispatchSubagent` before any model call and waits on it (`subagents` wait
|
|
12
12
|
* `sa-<runId>-0`; the dispatch row has `for_skill`, agent map spec §5.4: a fork stays in the
|
|
13
13
|
* foreground while `Agent` calls run in the background). When the child has ended, `prepare` appends the model-visible
|
|
14
|
-
* `skill_fork_result` and the parent's model answers. Every terminal path of the run
|
|
15
|
-
*
|
|
14
|
+
* `skill_fork_result` and the parent's model answers. Every terminal path of the run
|
|
15
|
+
* (`RunFinish.finishIn`) pairs a fork invocation without a report ({@link pairStoppedForks}), so the log never holds
|
|
16
16
|
* a fork lead whose report is missing before the next model call.
|
|
17
17
|
*/
|
|
18
18
|
/** The dispatch's parent call id (no `:`; there is no tool call). */
|
|
@@ -108,7 +108,7 @@ export declare const recordedSkillForks: (eventLog: Pick<EventLog, "append" | "f
|
|
|
108
108
|
payload: unknown;
|
|
109
109
|
}[]) => SkillForks;
|
|
110
110
|
/**
|
|
111
|
-
* In the transaction of a run's terminal path (
|
|
111
|
+
* In the transaction of a run's terminal path (`RunFinish.finishIn`): the run's fork invocation
|
|
112
112
|
* (its trigger message, by the run boundary) without a report gets one now: the ended child's
|
|
113
113
|
* result (and the parent's missing `subagent_finished`), {@link AGENT_STOPPED_WITH_RUN_TEXT} for a
|
|
114
114
|
* child still active (the caller stops it after its commit, as for `Agent` calls), or
|