@capybara-hq/kernel 0.1.0-rc.24 → 0.1.0-rc.26
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/dist/admin/admin.module.js +2 -0
- package/dist/admin/health.service.d.ts +2 -2
- package/dist/admin/health.service.js +6 -2
- package/dist/admin/outbox-dead.service.d.ts +7 -3
- package/dist/admin/outbox-dead.service.js +17 -6
- package/dist/admin/overview.service.d.ts +6 -6
- package/dist/admin/overview.service.js +7 -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/background/wake-rules.d.ts +5 -0
- package/dist/background/wake-rules.js +16 -5
- 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.js +4 -3
- 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/plugin-import.d.ts +28 -25
- package/dist/catalog/plugin-import.js +90 -76
- package/dist/catalog/plugin-upgrade.d.ts +4 -4
- package/dist/catalog/plugin-upgrade.js +7 -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 +9 -8
- package/dist/channels/channels.module.js +11 -10
- package/dist/channels/connections.service.d.ts +3 -3
- package/dist/channels/connections.service.js +6 -6
- package/dist/channels/deliver-job.d.ts +10 -3
- package/dist/channels/deliver-job.js +7 -3
- package/dist/channels/inbound.js +2 -2
- package/dist/channels/jobs.d.ts +11 -4
- package/dist/channels/jobs.js +18 -3
- package/dist/channels/outbound.d.ts +5 -2
- package/dist/channels/outbound.js +9 -2
- package/dist/channels/threads.d.ts +4 -3
- package/dist/channels/threads.js +4 -3
- package/dist/conversations/conversations.controller.d.ts +4 -2
- package/dist/conversations/conversations.controller.js +8 -4
- package/dist/conversations/conversations.service.d.ts +54 -9
- package/dist/conversations/conversations.service.js +94 -25
- package/dist/conversations/events.d.ts +27 -0
- package/dist/conversations/events.js +30 -1
- package/dist/conversations/source.d.ts +10 -0
- package/dist/conversations/source.js +17 -0
- package/dist/conversations/tree.d.ts +10 -0
- package/dist/conversations/tree.js +35 -0
- package/dist/db/kernel-schema.d.ts +19 -15
- package/dist/devices/devices.service.d.ts +25 -14
- package/dist/devices/devices.service.js +36 -30
- package/dist/evals/evals.module.js +5 -1
- package/dist/evals/jobs.d.ts +14 -6
- package/dist/evals/jobs.js +21 -19
- package/dist/evals/run-replay.d.ts +13 -2
- package/dist/evals/run-replay.js +28 -1
- package/dist/evals/runs.service.d.ts +5 -6
- package/dist/evals/runs.service.js +11 -33
- package/dist/evals/snapshot.d.ts +7 -1
- package/dist/evals/snapshot.js +2 -1
- 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/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/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/infra/outbox/outbox.service.d.ts +6 -0
- package/dist/infra/outbox/outbox.service.js +51 -17
- package/dist/infra/outbox/registry.d.ts +176 -0
- package/dist/infra/outbox/registry.js +183 -0
- package/dist/infra/queue/queue-names.d.ts +1 -1
- package/dist/infra/queue/queue-names.js +1 -0
- package/dist/local-devices/device-policy.service.d.ts +131 -26
- package/dist/local-devices/device-policy.service.js +341 -145
- package/dist/local-devices/machines.d.ts +17 -2
- package/dist/local-devices/machines.js +66 -5
- package/dist/local-devices/policy-op-jobs.d.ts +15 -0
- package/dist/local-devices/policy-op-jobs.js +12 -0
- package/dist/local-devices/policy-summary.d.ts +36 -3
- package/dist/local-devices/policy-summary.js +47 -1
- 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 +19 -7
- package/dist/overrides.d.ts +7 -0
- package/dist/overrides.js +4 -0
- package/dist/platform/ops/conversations.ops.js +1 -1
- package/dist/platform/ops/inbox.ops.js +4 -20
- package/dist/platform/ops/platform.ops.d.ts +1 -0
- package/dist/platform/ops/platform.ops.js +6 -3
- package/dist/roles/worker-role.d.ts +10 -5
- package/dist/roles/worker-role.js +19 -9
- package/dist/roles/worker.module.js +2 -4
- 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 +4 -0
- package/dist/runtime/loop.d.ts +8 -0
- package/dist/runtime/maintenance.d.ts +9 -4
- package/dist/runtime/maintenance.js +52 -13
- package/dist/runtime/model-call.d.ts +6 -1
- package/dist/runtime/model-call.js +1 -0
- package/dist/runtime/plugin-context.service.d.ts +75 -0
- package/dist/runtime/plugin-context.service.js +220 -0
- package/dist/runtime/run-context.service.d.ts +7 -3
- package/dist/runtime/run-context.service.js +12 -2
- package/dist/runtime/run-control.d.ts +6 -1
- package/dist/runtime/run-control.js +13 -0
- package/dist/runtime/run-finish.d.ts +2 -2
- package/dist/runtime/run-finish.js +11 -6
- package/dist/runtime/run-jobs.d.ts +21 -4
- package/dist/runtime/run-jobs.js +29 -6
- package/dist/runtime/run-orphan-check.job.d.ts +14 -11
- package/dist/runtime/run-orphan-check.job.js +16 -11
- package/dist/runtime/run-queue.d.ts +29 -24
- package/dist/runtime/run-queue.js +118 -57
- package/dist/runtime/run-status.d.ts +12 -0
- package/dist/runtime/run-status.js +21 -0
- package/dist/runtime/run-worker.d.ts +32 -3
- package/dist/runtime/run-worker.js +143 -21
- package/dist/runtime/runtime.module.js +2 -0
- package/dist/runtime/step-log.d.ts +6 -5
- package/dist/runtime/step-log.js +6 -5
- package/dist/runtime/subagents/dispatch.js +1 -0
- package/dist/runtime/subagents/skill-fork.js +3 -0
- package/dist/runtime/usage-report.d.ts +3 -1
- package/dist/runtime/usage-report.js +4 -2
- package/dist/runtime/waits.d.ts +16 -6
- package/dist/runtime/waits.js +37 -15
- package/dist/sandbox/jobs.d.ts +20 -10
- package/dist/sandbox/jobs.js +23 -17
- package/dist/schedules/fire.d.ts +25 -4
- package/dist/schedules/fire.js +87 -13
- package/dist/schedules/job-ids.d.ts +66 -17
- package/dist/schedules/job-ids.js +81 -13
- package/dist/schedules/run-tracker.js +2 -1
- package/dist/schedules/scan.job.d.ts +16 -35
- package/dist/schedules/scan.job.js +38 -147
- package/dist/schedules/scheduled-tasks.service.d.ts +6 -6
- package/dist/schedules/scheduled-tasks.service.js +17 -14
- package/dist/schedules/schedules.module.js +0 -4
- package/dist/skills/catalog.d.ts +7 -3
- package/dist/skills/catalog.js +12 -2
- package/dist/skills/changes.controller.d.ts +1 -1
- package/dist/skills/changes.controller.js +1 -1
- package/dist/tools/approvals.service.d.ts +111 -23
- package/dist/tools/approvals.service.js +326 -77
- package/dist/tools/builtins/sandbox/task-output.js +21 -6
- package/dist/tools/device-op-resolver.d.ts +40 -0
- package/dist/tools/device-op-resolver.js +121 -0
- package/dist/tools/network-asks.d.ts +1 -1
- package/dist/tools/network-asks.js +4 -3
- package/dist/tools/pipeline.d.ts +11 -2
- package/dist/tools/pipeline.js +5 -0
- package/dist/tools/questions.service.d.ts +15 -4
- package/dist/tools/questions.service.js +21 -19
- package/dist/tools/registry.d.ts +8 -1
- package/dist/tools/registry.js +9 -0
- package/dist/tools/tools.module.js +4 -0
- package/package.json +3 -3
- 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/src/migrations/0125_conversation_tree_stopped_at.sql +5 -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/evals/run-replay.js
CHANGED
|
@@ -18,6 +18,7 @@ import { ApiError } from "../errors.js";
|
|
|
18
18
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
19
19
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
20
20
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
21
|
+
import { pluginContextIdemKey } from "../runtime/context/plugin-context.js";
|
|
21
22
|
import { estimateTokens } from "../runtime/context/tokens.js";
|
|
22
23
|
import { runDeadline, tightestLimit } from "../runtime/limits.js";
|
|
23
24
|
import { RunError } from "../runtime/model-call.js";
|
|
@@ -36,7 +37,7 @@ export class ReplayClaimLost extends Error {
|
|
|
36
37
|
/**
|
|
37
38
|
* The seed of a full-run replay (C6): the `kind = 'eval'` conversation with the events before the
|
|
38
39
|
* original run at their original seqs, the run row and its `run_started` (and the original
|
|
39
|
-
* `skills_catalog`), in one transaction of its own.
|
|
40
|
+
* `skills_catalog`, `run_context` and `plugin_context` events), in one transaction of its own.
|
|
40
41
|
*/
|
|
41
42
|
let EvalReplaySeeder = class EvalReplaySeeder {
|
|
42
43
|
db;
|
|
@@ -74,6 +75,7 @@ let EvalReplaySeeder = class EvalReplaySeeder {
|
|
|
74
75
|
consumed_seq: p.consumed,
|
|
75
76
|
kind: "eval",
|
|
76
77
|
eval_run_id: evalRunId,
|
|
78
|
+
source: p.source,
|
|
77
79
|
})
|
|
78
80
|
.execute();
|
|
79
81
|
for (let i = 0; i < p.seeds.length; i += SEED_BATCH) {
|
|
@@ -133,6 +135,12 @@ let EvalReplaySeeder = class EvalReplaySeeder {
|
|
|
133
135
|
},
|
|
134
136
|
]
|
|
135
137
|
: []),
|
|
138
|
+
...p.pluginContexts.map((c) => ({
|
|
139
|
+
type: "plugin_context",
|
|
140
|
+
runId,
|
|
141
|
+
idemKey: pluginContextIdemKey(runId, c.payload.plugin),
|
|
142
|
+
payload: c.payload,
|
|
143
|
+
})),
|
|
136
144
|
]);
|
|
137
145
|
if (onSeeded && !(await onSeeded(conversationId)))
|
|
138
146
|
throw new ReplayClaimLost();
|
|
@@ -333,6 +341,9 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
|
|
|
333
341
|
const trigger = replayTrigger(start.payload, seeds, consumed);
|
|
334
342
|
const catalog = s.events.find((e) => e.runId === s.runId && e.type === "skills_catalog" && e.seq > R);
|
|
335
343
|
const runContext = s.events.find((e) => e.runId === s.runId && e.type === "run_context" && e.seq > R);
|
|
344
|
+
const pluginContexts = s.events
|
|
345
|
+
.filter((e) => e.runId === s.runId && e.type === "plugin_context" && e.seq > R)
|
|
346
|
+
.map((e) => ({ payload: e.payload }));
|
|
336
347
|
// a sub-agent's case (spec §15.3) runs the effective definition frozen in its subagent_started
|
|
337
348
|
// (the request renders that event's preamble and instructions; its tools come from it too), with
|
|
338
349
|
// only the candidate's model and params, and the logged step limit
|
|
@@ -348,12 +359,16 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
|
|
|
348
359
|
const forkRun = triggerEvent?.type === "user_message" &&
|
|
349
360
|
triggerEvent.payload.skill !== undefined &&
|
|
350
361
|
triggerEvent.payload.dispatch !== undefined;
|
|
362
|
+
// the original conversation's source (recorded in the case); a case taken before it was
|
|
363
|
+
// recorded replays as its run did by default: a web conversation, or a sub-agent's for a child
|
|
364
|
+
const source = s.source ?? (subagent === undefined ? "web" : "subagent");
|
|
351
365
|
const conversationId = randomUUID();
|
|
352
366
|
const runId = randomUUID();
|
|
353
367
|
await d.seeder.seed({
|
|
354
368
|
evalRunId,
|
|
355
369
|
orgId: s.orgId,
|
|
356
370
|
agentId: s.agentId,
|
|
371
|
+
source,
|
|
357
372
|
accountId,
|
|
358
373
|
conversationId,
|
|
359
374
|
runId,
|
|
@@ -365,6 +380,7 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
|
|
|
365
380
|
model: agent.model,
|
|
366
381
|
catalog,
|
|
367
382
|
runContext,
|
|
383
|
+
pluginContexts,
|
|
368
384
|
}, d.onSeeded);
|
|
369
385
|
await d.hooks?.afterRunSeeded?.(evalRunId, conversationId);
|
|
370
386
|
// 停止:取消 / 越限 / 熔断 / 失去认领 / 截止时间 → 中止 loop(进行中的请求立即停下,loop 以 aborted 返回)
|
|
@@ -542,6 +558,13 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
|
|
|
542
558
|
// a fork invocation's report is the recorded one: a replay never dispatches a sub-agent (A5)
|
|
543
559
|
const skillForks = recordedSkillForks(eventLog, s.events.filter((e) => e.runId === s.runId));
|
|
544
560
|
const loop = d.loop({ toolPipeline: pipeline, registry, skillForks, ...(media && { media }) });
|
|
561
|
+
// a replay never executes a tool, so the role only completes the context
|
|
562
|
+
const membership = await db
|
|
563
|
+
.selectFrom("memberships")
|
|
564
|
+
.select("role")
|
|
565
|
+
.where("org_id", "=", s.orgId)
|
|
566
|
+
.where("account_id", "=", accountId)
|
|
567
|
+
.executeTakeFirst();
|
|
545
568
|
let outcome;
|
|
546
569
|
try {
|
|
547
570
|
outcome = await loop.run({
|
|
@@ -550,6 +573,10 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
|
|
|
550
573
|
runId,
|
|
551
574
|
agentId: s.agentId,
|
|
552
575
|
triggerAccountId: accountId,
|
|
576
|
+
// the seeded conversation's source (the original's): its tools are the original's
|
|
577
|
+
source,
|
|
578
|
+
ownerAccountId: accountId,
|
|
579
|
+
role: membership?.role ?? "guest",
|
|
553
580
|
agent,
|
|
554
581
|
agentVersion: candidate.agentVersion,
|
|
555
582
|
signal: loopSignal,
|
|
@@ -145,7 +145,7 @@ export declare const RESULTS_ASOF_OVERLAP_MS = 15000;
|
|
|
145
145
|
export declare class EvalRunsService {
|
|
146
146
|
readonly txHost: TransactionHost;
|
|
147
147
|
private readonly d;
|
|
148
|
-
constructor(kdb: KernelDb, orgLock: OrgLock, locks: LockService, config: KernelConfigService, registry: ProviderRegistry, prices: PricesService, settings: SettingsService,
|
|
148
|
+
constructor(kdb: KernelDb, orgLock: OrgLock, locks: LockService, config: KernelConfigService, registry: ProviderRegistry, prices: PricesService, settings: SettingsService, jobs: EvalJobs, budget: EvalBudget, purposes: ModelPurposesService, txHost: TransactionHost);
|
|
149
149
|
private liveSet;
|
|
150
150
|
/**
|
|
151
151
|
* 解析模型;不存在 / 不可用 → `eval.candidate_invalid`(供应商列表暂时失败照常抛出)。
|
|
@@ -187,8 +187,9 @@ export declare class EvalRunsService {
|
|
|
187
187
|
private tokenCaps;
|
|
188
188
|
/**
|
|
189
189
|
* 启动:校验 token 上限([1, `evals.maxTokenCap`],缺省 `evals.defaultTokenCap`)、候选、评委用途;
|
|
190
|
-
* 没有可回放的 → `eval.nothing_to_replay
|
|
191
|
-
*
|
|
190
|
+
* 没有可回放的 → `eval.nothing_to_replay`。One transaction writes the run row and its pending
|
|
191
|
+
* results and owes one case job per valid case (transactional outbox spec §3): the outbox adds
|
|
192
|
+
* them after the commit, so a run never waits for a job that was never added.
|
|
192
193
|
*/
|
|
193
194
|
start(orgId: string, actor: string, setId: string, input: {
|
|
194
195
|
mode: "step" | "run";
|
|
@@ -196,10 +197,8 @@ export declare class EvalRunsService {
|
|
|
196
197
|
judge: boolean;
|
|
197
198
|
tokenCap?: number;
|
|
198
199
|
}, actorTokenId?: string, auditDetail?: Record<string, unknown>): Promise<EvalRunView>;
|
|
199
|
-
/** The run row and its
|
|
200
|
+
/** The run row, its pending results and its owed case jobs, in a transaction of their own. */
|
|
200
201
|
private startIn;
|
|
201
|
-
/** The enqueue failed: the run is `failed`, its pending results `skipped`. */
|
|
202
|
-
private failStartIn;
|
|
203
202
|
/** 各运行的汇总(只算已结束的)。 */
|
|
204
203
|
private summaries;
|
|
205
204
|
private static toView;
|
|
@@ -154,7 +154,7 @@ const resultsViewedKey = (runId, accountId) => `capk:eval-results-viewed:${runId
|
|
|
154
154
|
let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
155
155
|
txHost;
|
|
156
156
|
d;
|
|
157
|
-
constructor(kdb, orgLock, locks, config, registry, prices, settings,
|
|
157
|
+
constructor(kdb, orgLock, locks, config, registry, prices, settings, jobs, budget, purposes, txHost) {
|
|
158
158
|
this.txHost = txHost;
|
|
159
159
|
this.d = {
|
|
160
160
|
orgLock,
|
|
@@ -166,7 +166,7 @@ let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
|
166
166
|
registry,
|
|
167
167
|
prices,
|
|
168
168
|
settings,
|
|
169
|
-
|
|
169
|
+
jobs,
|
|
170
170
|
budget,
|
|
171
171
|
purposes,
|
|
172
172
|
};
|
|
@@ -415,8 +415,9 @@ let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
|
415
415
|
}
|
|
416
416
|
/**
|
|
417
417
|
* 启动:校验 token 上限([1, `evals.maxTokenCap`],缺省 `evals.defaultTokenCap`)、候选、评委用途;
|
|
418
|
-
* 没有可回放的 → `eval.nothing_to_replay
|
|
419
|
-
*
|
|
418
|
+
* 没有可回放的 → `eval.nothing_to_replay`。One transaction writes the run row and its pending
|
|
419
|
+
* results and owes one case job per valid case (transactional outbox spec §3): the outbox adds
|
|
420
|
+
* them after the commit, so a run never waits for a job that was never added.
|
|
420
421
|
*/
|
|
421
422
|
async start(orgId, actor, setId, input, actorTokenId, auditDetail) {
|
|
422
423
|
const set = await this.liveSet(orgId, setId);
|
|
@@ -435,17 +436,10 @@ let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
|
435
436
|
if (firstProblem) {
|
|
436
437
|
throw candidateInvalid(firstProblem.message, firstProblem.details ?? []);
|
|
437
438
|
}
|
|
438
|
-
const { runId
|
|
439
|
-
try {
|
|
440
|
-
await this.d.queue.enqueue(plans.map((p) => ({ runId, caseId: p.caseId, orgId })));
|
|
441
|
-
}
|
|
442
|
-
catch (e) {
|
|
443
|
-
await this.failStartIn(runId);
|
|
444
|
-
throw e;
|
|
445
|
-
}
|
|
439
|
+
const { runId } = await this.startIn(orgId, actor, setId, set.agent_id, input, tokenCap, planned, judge, actorTokenId, auditDetail);
|
|
446
440
|
return this.get(orgId, runId);
|
|
447
441
|
}
|
|
448
|
-
/** The run row and its
|
|
442
|
+
/** The run row, its pending results and its owed case jobs, in a transaction of their own. */
|
|
449
443
|
async startIn(orgId, actor, setId, agentId, input, tokenCap, planned, judge, actorTokenId, auditDetail) {
|
|
450
444
|
const db = this.d.db;
|
|
451
445
|
await this.d.orgLock.lockAndAuthorize(orgId, actor, "evals.manage");
|
|
@@ -521,23 +515,10 @@ let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
|
521
515
|
},
|
|
522
516
|
});
|
|
523
517
|
await this.d.budget.recountCases(run.id);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const db = this.d.db;
|
|
529
|
-
await db
|
|
530
|
-
.updateTable("eval_runs")
|
|
531
|
-
.set({ status: "failed", finished_at: sql `now()` })
|
|
532
|
-
.where("id", "=", runId)
|
|
533
|
-
.execute();
|
|
534
|
-
await db
|
|
535
|
-
.updateTable("eval_results")
|
|
536
|
-
.set({ status: "skipped", updated_at: sql `now()` })
|
|
537
|
-
.where("run_id", "=", runId)
|
|
538
|
-
.where("status", "=", "pending")
|
|
539
|
-
.execute();
|
|
540
|
-
await this.d.budget.recountCases(runId);
|
|
518
|
+
await this.d.jobs.owe(plans
|
|
519
|
+
.filter((p) => p.problem === null)
|
|
520
|
+
.map((p) => ({ runId: run.id, caseId: p.caseId, orgId })));
|
|
521
|
+
return { runId: run.id };
|
|
541
522
|
}
|
|
542
523
|
/** 各运行的汇总(只算已结束的)。 */
|
|
543
524
|
async summaries(rows) {
|
|
@@ -836,9 +817,6 @@ let EvalRunsService = EvalRunsService_1 = class EvalRunsService {
|
|
|
836
817
|
__decorate([
|
|
837
818
|
Transactional({ propagation: "requires_new" })
|
|
838
819
|
], EvalRunsService.prototype, "startIn", null);
|
|
839
|
-
__decorate([
|
|
840
|
-
Transactional({ propagation: "requires_new" })
|
|
841
|
-
], EvalRunsService.prototype, "failStartIn", null);
|
|
842
820
|
__decorate([
|
|
843
821
|
Transactional({ propagation: "requires_new" })
|
|
844
822
|
], EvalRunsService.prototype, "cancelIn", null);
|
package/dist/evals/snapshot.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ToolSpec } from "@capybara-hq/plugin-sdk";
|
|
1
|
+
import type { ConversationSource, ToolSpec } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import { type AgentDefinition } from "../agents/definition.js";
|
|
3
3
|
import type { ConversationEvent, ConversationEventType } from "../conversations/events.js";
|
|
4
4
|
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
@@ -21,6 +21,12 @@ export interface CaseSnapshot {
|
|
|
21
21
|
runId: string;
|
|
22
22
|
agentId: string;
|
|
23
23
|
agentVersion: number;
|
|
24
|
+
/**
|
|
25
|
+
* The original conversation's source (memory plugin spec §6.2): a full-run replay offers the
|
|
26
|
+
* tools of this source. Cases taken before it was recorded have none (replayed as `web`, or as
|
|
27
|
+
* `subagent` for a child case).
|
|
28
|
+
*/
|
|
29
|
+
source?: ConversationSource;
|
|
24
30
|
/** seq ≤ 该运行终态事件的 seq,按 seq 升序。 */
|
|
25
31
|
events: SnapshotEvent[];
|
|
26
32
|
/** 事件里各次运行(`run_started`)与本运行引用的 agent 版本 → 定义。 */
|
package/dist/evals/snapshot.js
CHANGED
|
@@ -17,7 +17,7 @@ const PAGE = 1000;
|
|
|
17
17
|
export async function takeSnapshot(db, orgId, conversationId, runId, maxBytes) {
|
|
18
18
|
const conv = await db
|
|
19
19
|
.selectFrom("conversations")
|
|
20
|
-
.select(["agent_id", "kind"])
|
|
20
|
+
.select(["agent_id", "kind", "source"])
|
|
21
21
|
.where("id", "=", conversationId)
|
|
22
22
|
.where("org_id", "=", orgId)
|
|
23
23
|
.executeTakeFirst();
|
|
@@ -126,6 +126,7 @@ export async function takeSnapshot(db, orgId, conversationId, runId, maxBytes) {
|
|
|
126
126
|
runId,
|
|
127
127
|
agentId: conv.agent_id,
|
|
128
128
|
agentVersion: run.agent_version,
|
|
129
|
+
source: conv.source,
|
|
129
130
|
events,
|
|
130
131
|
definitions,
|
|
131
132
|
toolSpecs,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AvailableHook, type HookHandler, type HookOptions, type HookPayloads, type Logger, type PolicyHook } from "@capybara-hq/plugin-sdk";
|
|
1
|
+
import { type AvailableHook, type HookHandler, type HookOptions, type HookPayloads, type LIFECYCLE_HOOKS, type Logger, type PolicyHook } from "@capybara-hq/plugin-sdk";
|
|
2
2
|
import type { KernelConfig } from "../config/schema.js";
|
|
3
3
|
import type { LockService } from "../infra/lock/lock.service.js";
|
|
4
4
|
import { type EffectiveConfig } from "./effective-config.js";
|
|
@@ -63,7 +63,16 @@ export interface HookSource {
|
|
|
63
63
|
readonly name: string;
|
|
64
64
|
readonly hooks: readonly RegisteredHook[];
|
|
65
65
|
readonly inflight: InflightTracker;
|
|
66
|
+
/** The instance's platform deployment config (what lifecycle hooks are called with). */
|
|
67
|
+
readonly config?: unknown;
|
|
66
68
|
}
|
|
69
|
+
/** A lifecycle mount: an observe-only notice that a member, an agent or an org was removed. */
|
|
70
|
+
export type LifecycleHook = (typeof LIFECYCLE_HOOKS)[number];
|
|
71
|
+
/**
|
|
72
|
+
* Mounts delivered by a queue (at least once, by plugin) instead of {@link HookRegistry.run}:
|
|
73
|
+
* `usage.report` and the lifecycle mounts.
|
|
74
|
+
*/
|
|
75
|
+
export type QueuedHook = "usage.report" | LifecycleHook;
|
|
67
76
|
/** Error text that never throws itself (a hostile `message` getter or `toString`). */
|
|
68
77
|
export declare function errMsg(e: unknown): string;
|
|
69
78
|
/**
|
|
@@ -166,8 +175,18 @@ export declare class HookRegistry {
|
|
|
166
175
|
plugin: string;
|
|
167
176
|
handler: HookHandler<"usage.report">;
|
|
168
177
|
}[];
|
|
169
|
-
/**
|
|
170
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Lifecycle handlers by plugin name (delivered by the lifecycle queue, `lifecycle-hooks.ts`, not
|
|
180
|
+
* by {@link run}). Each call runs through the instance's `inflight.run` with the plugin's platform
|
|
181
|
+
* deployment config, never an org's copy: cleanup goes out whether or not the org's effective
|
|
182
|
+
* config is valid (or the org still exists).
|
|
183
|
+
*/
|
|
184
|
+
lifecycleHandlers<K extends LifecycleHook>(mount: K): {
|
|
185
|
+
plugin: string;
|
|
186
|
+
handler: HookHandler<K>;
|
|
187
|
+
}[];
|
|
188
|
+
/** Runs the hooks of a mount point (see the class comment); queue-delivered mounts excluded. */
|
|
189
|
+
run<K extends Exclude<AvailableHook, QueuedHook>>(mount: K, payload: HookPayloads[K], signal: AbortSignal): Promise<HookOutcome>;
|
|
171
190
|
/**
|
|
172
191
|
* The M-1 denial: `missing` (sorted) are enabled policy plugins that are not loaded on this replica.
|
|
173
192
|
* The model-visible reason is generic; the detail and a throttled warning name the plugin for the
|
package/dist/extensions/hooks.js
CHANGED
|
@@ -189,7 +189,21 @@ export class HookRegistry {
|
|
|
189
189
|
}),
|
|
190
190
|
}));
|
|
191
191
|
}
|
|
192
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* Lifecycle handlers by plugin name (delivered by the lifecycle queue, `lifecycle-hooks.ts`, not
|
|
194
|
+
* by {@link run}). Each call runs through the instance's `inflight.run` with the plugin's platform
|
|
195
|
+
* deployment config, never an org's copy: cleanup goes out whether or not the org's effective
|
|
196
|
+
* config is valid (or the org still exists).
|
|
197
|
+
*/
|
|
198
|
+
lifecycleHandlers(mount) {
|
|
199
|
+
return this.entries(mount).map(({ src, hook }) => ({
|
|
200
|
+
plugin: src.name,
|
|
201
|
+
handler: (payload, signal) => src.inflight.run(signal, async (s) => {
|
|
202
|
+
await hook.handler(payload, s, { config: src.config });
|
|
203
|
+
}),
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
/** Runs the hooks of a mount point (see the class comment); queue-delivered mounts excluded. */
|
|
193
207
|
async run(mount, payload, signal) {
|
|
194
208
|
if (signal.aborted)
|
|
195
209
|
throw signal.reason;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { HookPayloads } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { WorkerHost } from "@nestjs/bullmq";
|
|
3
|
+
import type { Job, Worker } from "bullmq";
|
|
4
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
5
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
6
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
7
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
8
|
+
import type { KernelLogger } from "../log.js";
|
|
9
|
+
import { type LifecycleHook } from "./hooks.js";
|
|
10
|
+
import { ExtensionHost } from "./host.js";
|
|
11
|
+
/** Queue of lifecycle hook deliveries (no `:` in the name). */
|
|
12
|
+
export declare const LIFECYCLE_QUEUE = "cap-kernel-lifecycle";
|
|
13
|
+
/** The job name of every delivery (registered in `infra/outbox/registry.ts`). */
|
|
14
|
+
export declare const LIFECYCLE_JOB = "lifecycle";
|
|
15
|
+
/** One handler call's time limit. */
|
|
16
|
+
export declare const LIFECYCLE_HOOK_TIMEOUT_MS = 5000;
|
|
17
|
+
/** Job data: one mount's payload for one subscribing plugin. */
|
|
18
|
+
export interface LifecycleJob<K extends LifecycleHook = LifecycleHook> {
|
|
19
|
+
mount: K;
|
|
20
|
+
plugin: string;
|
|
21
|
+
payload: HookPayloads[K];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The deterministic job id of one delivery: the mount, the plugin and the payload's ids (no `:`;
|
|
25
|
+
* kernel ids and plugin names carry none). Removing the same member, agent or org again while the
|
|
26
|
+
* first delivery is still owed is the same job.
|
|
27
|
+
*/
|
|
28
|
+
export declare function lifecycleJobId<K extends LifecycleHook>(mount: K, plugin: string, payload: HookPayloads[K]): string;
|
|
29
|
+
/**
|
|
30
|
+
* Plugins that subscribe to a lifecycle mount according to deployment state: the approved
|
|
31
|
+
* permission snapshot declares the mount in `permissions.hooks`, and that approved version is the
|
|
32
|
+
* one the deployment runs: an enabled install of that version, or a replica status row (not
|
|
33
|
+
* `unloaded`) that loaded or still serves it (an upgrade pending approval keeps serving the
|
|
34
|
+
* approved version; a config-declared plugin has only replica rows). A snapshot approved for
|
|
35
|
+
* another version than the one installed or served does not count. Org enablement does not count
|
|
36
|
+
* either: cleanup concerns data the plugin already holds (memory plugin spec §6.3). Sorted by name.
|
|
37
|
+
*/
|
|
38
|
+
export declare function queryLifecycleSubscribers(db: KernelSchemaDb, mount: LifecycleHook): Promise<string[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Durable delivery of the lifecycle hooks `org.member_removed`, `agent.deleted` and `org.deleted`
|
|
41
|
+
* (memory plugin spec §6.3), so extensions reliably learn to delete the data they hold:
|
|
42
|
+
* - **Owe** ({@link recordIn}): in the transaction that removes the member, the agent or the org,
|
|
43
|
+
* one outbox job per subscribing plugin ({@link queryLifecycleSubscribers}) on
|
|
44
|
+
* {@link LIFECYCLE_QUEUE}, under {@link lifecycleJobId}, with no `org_id` (it is the deletion's
|
|
45
|
+
* own cleanup work, transactional outbox spec §9); a rollback owes nothing. The outbox delivers
|
|
46
|
+
* it to BullMQ after the commit (registry: attempts and backoff).
|
|
47
|
+
* - **Deliver** ({@link process}, worker role): the plugin's handlers loaded on this replica are
|
|
48
|
+
* called in turn (5 s each). Not loaded on this replica -> the job fails and is retried (another
|
|
49
|
+
* replica or a later attempt). Loaded without a handler -> dropped with a warning. Handlers get
|
|
50
|
+
* the plugin's platform deployment config (`call.config`), never an org's copy, so an org whose
|
|
51
|
+
* effective config is not valid still gets its cleanup. The last failed attempt logs an error.
|
|
52
|
+
* Handlers must be idempotent (a delivery may repeat when a replica dies after the call).
|
|
53
|
+
*/
|
|
54
|
+
export declare class LifecycleHooks {
|
|
55
|
+
private readonly kdb;
|
|
56
|
+
readonly txHost: TransactionHost;
|
|
57
|
+
private readonly outbox;
|
|
58
|
+
/** The loaded plugins' handlers (`hooks.handlers`) and whether a plugin is active here. */
|
|
59
|
+
private readonly host;
|
|
60
|
+
private readonly log;
|
|
61
|
+
constructor(kdb: KernelDb, txHost: TransactionHost, outbox: Pick<OutboxService, "add">,
|
|
62
|
+
/** The loaded plugins' handlers (`hooks.handlers`) and whether a plugin is active here. */
|
|
63
|
+
host: Pick<ExtensionHost, "hooks" | "current">, log: KernelLogger);
|
|
64
|
+
/**
|
|
65
|
+
* Owes one delivery per subscribing plugin in the caller's transaction (`mandatory`); returns
|
|
66
|
+
* the plugins.
|
|
67
|
+
*/
|
|
68
|
+
recordIn<K extends LifecycleHook>(mount: K, payload: HookPayloads[K]): Promise<string[]>;
|
|
69
|
+
/** One delivery job (the consumer {@link LifecycleHooksProcessor} calls it). */
|
|
70
|
+
process(data: LifecycleJob, stop: AbortSignal): Promise<void>;
|
|
71
|
+
/** One handler call, aborted after {@link LIFECYCLE_HOOK_TIMEOUT_MS} or when the replica stops. */
|
|
72
|
+
private call;
|
|
73
|
+
/** A job failed (the worker's `failed` event): a retry warns, the last attempt logs an error. */
|
|
74
|
+
onFailed(j: Job<LifecycleJob> | undefined, err: Error): void;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The consumer of {@link LIFECYCLE_QUEUE}: {@link LifecycleHooks.process}. Worker role only
|
|
78
|
+
* (`LifecycleHookWorkersModule`); built with `autorun: false`, started by the worker role after the
|
|
79
|
+
* extensions loaded.
|
|
80
|
+
*/
|
|
81
|
+
export declare class LifecycleHooksProcessor extends WorkerHost<Worker<LifecycleJob>> {
|
|
82
|
+
private readonly hooks;
|
|
83
|
+
private readonly log;
|
|
84
|
+
private readonly stopping;
|
|
85
|
+
constructor(hooks: LifecycleHooks, log: Pick<KernelLogger, "error">);
|
|
86
|
+
process(job: Job<LifecycleJob>): Promise<void>;
|
|
87
|
+
/** Starts consuming (worker role, after the extensions loaded). */
|
|
88
|
+
start(): void;
|
|
89
|
+
/** Aborts the calls in flight and closes the worker. */
|
|
90
|
+
close(): Promise<void>;
|
|
91
|
+
failed(job: Job<LifecycleJob> | undefined, err: Error): void;
|
|
92
|
+
error(err: Error): void;
|
|
93
|
+
}
|
|
94
|
+
/** Lifecycle hook delivery: owing the jobs, and the queue the outbox adds them to, on every role. */
|
|
95
|
+
export declare class LifecycleHooksModule {
|
|
96
|
+
}
|
|
97
|
+
/** The lifecycle queue's consumer; imported only by the worker role (`WorkerModule`). */
|
|
98
|
+
export declare class LifecycleHookWorkersModule {
|
|
99
|
+
}
|