@sema-agent/server 7.145.0 → 7.146.0
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/MIGRATION.md +492 -0
- package/USAGE.md +218 -47
- package/deploy/facts/CHANGES.json +25 -0
- package/deploy/facts/README.md +57 -0
- package/deploy/facts/lanes.json +54 -0
- package/deploy/facts/lanes.schema.json +57 -0
- package/deploy/facts/sandbox-rbac.json +113 -0
- package/deploy/facts/sandbox-rbac.schema.json +74 -0
- package/deploy/facts/sealed-key.json +9 -0
- package/deploy/facts/sealed-key.schema.json +52 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
- package/deploy/sema-up/chart/templates/server.yaml +4 -0
- package/deploy/sema-up/chart/values.yaml +7 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
- package/dist/adoption/import-limits.d.ts +6 -0
- package/dist/adoption/import-limits.js +7 -0
- package/dist/adoption/import.d.ts +62 -0
- package/dist/adoption/import.js +107 -0
- package/dist/adoption/wire.d.ts +52 -0
- package/dist/adoption/wire.js +9 -0
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +3 -12
- package/dist/approval-card.js +0 -4
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-gate-currency.js +1 -1
- package/dist/approval-reconciler.d.ts +1 -1
- package/dist/boot/deployment-mods.d.ts +11 -1
- package/dist/boot/deployment-mods.js +15 -2
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +193 -21
- package/dist/boot/engine-lease.js +146 -20
- package/dist/boot/execution-env.d.ts +4 -0
- package/dist/boot/execution-env.js +12 -0
- package/dist/boot/exit-boundary.d.ts +50 -0
- package/dist/boot/exit-boundary.js +32 -0
- package/dist/boot/exit-last.d.ts +20 -4
- package/dist/boot/exit-last.js +21 -4
- package/dist/boot/governance-seams.js +1 -0
- package/dist/boot/memory-consolidation.d.ts +29 -17
- package/dist/boot/memory-consolidation.js +26 -15
- package/dist/boot/reapers.d.ts +12 -4
- package/dist/boot/reapers.js +39 -15
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +38 -15
- package/dist/boot/runner-deps.js +1 -1
- package/dist/boot/session-faces.js +3 -1
- package/dist/boot/shutdown.js +27 -9
- package/dist/boot/stage-01-config.js +1 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +3 -0
- package/dist/boot/stage-05-execution-env.js +3 -3
- package/dist/boot/stage-06-runners.d.ts +3 -0
- package/dist/boot/stage-06-runners.js +11 -10
- package/dist/boot/stage-07-capability-layer.d.ts +3 -0
- package/dist/boot/stage-07-capability-layer.js +7 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -0
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +3 -2
- package/dist/boot/stores.d.ts +1 -0
- package/dist/boot/stores.js +35 -19
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/capabilities/composite-members.d.ts +3 -1
- package/dist/capabilities/composite-members.js +3 -1
- package/dist/capabilities/scenarios.d.ts +2 -2
- package/dist/capability-facts.d.ts +18 -1
- package/dist/capability-facts.js +25 -7
- package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
- package/dist/config-catalog.js +13 -4
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-types.d.ts +43 -4
- package/dist/config.d.ts +6 -1
- package/dist/config.js +67 -11
- package/dist/deleted-session-ids.d.ts +19 -0
- package/dist/deleted-session-ids.js +26 -0
- package/dist/deploy-facts.d.ts +155 -0
- package/dist/deploy-facts.js +94 -0
- package/dist/device-ws-hub.d.ts +48 -3
- package/dist/device-ws-hub.js +48 -2
- package/dist/error-code-family.d.ts +35 -0
- package/dist/error-code-family.js +26 -0
- package/dist/fleet/drain-entry.d.ts +39 -3
- package/dist/fleet/drain-entry.js +6 -0
- package/dist/fleet/fleet-bus.d.ts +2 -1
- package/dist/hooks/branch-transcript.d.ts +1 -1
- package/dist/hooks/branch-transcript.js +1 -0
- package/dist/hooks/classic-stations.d.ts +25 -8
- package/dist/hooks/classic-stations.js +29 -3
- package/dist/hooks/hook-runner.d.ts +33 -16
- package/dist/hooks/hook-runner.js +166 -73
- package/dist/hooks/hook-source.d.ts +14 -2
- package/dist/hooks/hook-source.js +8 -0
- package/dist/http/active-run-conflict.d.ts +1 -1
- package/dist/http/active-run-conflict.js +1 -1
- package/dist/http/admission.js +11 -1
- package/dist/http/checkpoint-ctx.d.ts +59 -71
- package/dist/http/checkpoint-ctx.js +34 -40
- package/dist/http/dispatch.js +18 -2
- package/dist/http/durable-run-leg.d.ts +5 -0
- package/dist/http/durable-run-leg.js +1 -0
- package/dist/http/execution-context.d.ts +4 -0
- package/dist/http/execution-context.js +9 -0
- package/dist/http/health-self-report.d.ts +6 -2
- package/dist/http/health-self-report.js +3 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.js +2 -15
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
- package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
- package/dist/http/principal-gate.d.ts +35 -12
- package/dist/http/principal-gate.js +16 -12
- package/dist/http/request-guards.d.ts +1 -1
- package/dist/http/request-guards.js +5 -5
- package/dist/http/resume-legs.d.ts +22 -0
- package/dist/http/resume-legs.js +26 -17
- package/dist/http/route-ctx.d.ts +11 -10
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/adoption.d.ts +11 -0
- package/dist/http/routes/adoption.js +80 -6
- package/dist/http/routes/agents-roster.js +1 -0
- package/dist/http/routes/approvals-assistant.js +2 -1
- package/dist/http/routes/background.js +1 -0
- package/dist/http/routes/capabilities.js +4 -1
- package/dist/http/routes/diagnostics.d.ts +9 -14
- package/dist/http/routes/diagnostics.js +10 -20
- package/dist/http/routes/engine.d.ts +31 -0
- package/dist/http/routes/engine.js +81 -0
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-consolidation.js +3 -5
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/memory-origin.js +2 -4
- package/dist/http/routes/memory-policy.js +5 -1
- package/dist/http/routes/observability.js +3 -6
- package/dist/http/routes/runs.js +7 -3
- package/dist/http/routes/session-sync.js +12 -25
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.js +4 -0
- package/dist/http/routes/tasks.js +23 -5
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/run-concurrency-cap.d.ts +86 -0
- package/dist/http/run-concurrency-cap.js +54 -0
- package/dist/http/server.d.ts +15 -12
- package/dist/http/server.js +18 -3
- package/dist/http/stored-body-replay.d.ts +9 -6
- package/dist/http/stored-body-replay.js +19 -5
- package/dist/http/wire-types.d.ts +8 -3
- package/dist/json-body-limit.d.ts +8 -0
- package/dist/json-body-limit.js +2 -0
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/local-data-root.d.ts +2 -2
- package/dist/memory-operator-faces.d.ts +9 -4
- package/dist/memory-scope-stores.d.ts +9 -7
- package/dist/memory-scope-stores.js +3 -14
- package/dist/memory-scope.d.ts +36 -0
- package/dist/memory-scope.js +32 -1
- package/dist/net-address.d.ts +53 -0
- package/dist/net-address.js +111 -0
- package/dist/observability/fail-open.d.ts +14 -10
- package/dist/observability/fail-open.js +14 -10
- package/dist/orchestration/workflow-notify-journal.js +2 -3
- package/dist/org-delivery-gate.js +1 -1
- package/dist/peer-directory.d.ts +6 -12
- package/dist/peer-directory.js +5 -1
- package/dist/plugins/caching-session-store.d.ts +3 -1
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-face.d.ts +426 -0
- package/dist/plugins/checkpoint-store-face.js +152 -0
- package/dist/plugins/file-run-store.d.ts +0 -6
- package/dist/plugins/file-run-store.js +1 -12
- package/dist/plugins/fork-routing-session-store.d.ts +6 -2
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
- package/dist/plugins/local-checkpoint-store.d.ts +2 -2
- package/dist/plugins/local-checkpoint-store.js +2 -1
- package/dist/plugins/local-session-store.d.ts +28 -5
- package/dist/plugins/local-session-store.js +32 -8
- package/dist/plugins/memory-engine-pg.d.ts +29 -6
- package/dist/plugins/memory-engine-pg.js +96 -214
- package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
- package/dist/plugins/memory-engine-sql-apply.js +358 -0
- package/dist/plugins/memory-engine-tidb.d.ts +35 -9
- package/dist/plugins/memory-engine-tidb.js +97 -227
- package/dist/plugins/memory-key-guards.d.ts +1 -1
- package/dist/plugins/memory-origin-law.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +32 -56
- package/dist/plugins/one-time-migrations.js +25 -117
- package/dist/plugins/permission-rule-store-file.d.ts +17 -3
- package/dist/plugins/permission-rule-store-file.js +8 -1
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +8 -4
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/session-fork.d.ts +31 -9
- package/dist/plugins/session-fork.js +3 -2
- package/dist/plugins/session-placement.d.ts +4 -2
- package/dist/plugins/sql-json-column.d.ts +5 -1
- package/dist/plugins/store-backend.d.ts +11 -8
- package/dist/plugins/store-backend.js +8 -7
- package/dist/plugins/store-contracts.d.ts +1 -11
- package/dist/plugins/store-contracts.js +0 -9
- package/dist/plugins/store-sweep.d.ts +63 -0
- package/dist/plugins/store-sweep.js +48 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/tidb-session-store.d.ts +16 -3
- package/dist/plugins/tidb-session-store.js +8 -4
- package/dist/prompt-screen.d.ts +6 -9
- package/dist/prompt-screen.js +2 -5
- package/dist/rules-consent.d.ts +20 -27
- package/dist/rules-consent.js +82 -6
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/runs.js +1 -1
- package/dist/sandbox-egress-policy.js +6 -11
- package/dist/sandbox-rbac-rules.d.ts +88 -0
- package/dist/sandbox-rbac-rules.js +80 -0
- package/dist/sealed-key-layout.d.ts +17 -0
- package/dist/sealed-key-layout.js +4 -0
- package/dist/sealed-key.js +5 -5
- package/dist/security.d.ts +38 -6
- package/dist/security.js +9 -2
- package/dist/session-notify-door.d.ts +5 -3
- package/dist/session-resident-background.d.ts +57 -0
- package/dist/session-resident-background.js +20 -0
- package/dist/session-sync-kernel.d.ts +53 -14
- package/dist/session-sync-kernel.js +70 -1
- package/dist/session-sync.d.ts +5 -3
- package/dist/session-workspace.d.ts +1 -0
- package/dist/session-workspace.js +1 -0
- package/dist/sighup-idle.d.ts +9 -7
- package/dist/sighup-idle.js +4 -5
- package/dist/spec-fields.d.ts +16 -0
- package/dist/spec-fields.js +7 -0
- package/dist/stored-request-env-credentials-m38.d.ts +3 -0
- package/dist/stored-request-env-credentials-m38.js +8 -0
- package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
- package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
- package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
- package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
- package/dist/task-settings.d.ts +59 -4
- package/dist/task-settings.js +50 -4
- package/dist/tool-approval.d.ts +2 -2
- package/dist/trace/core-keyset-guard.d.ts +8 -7
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +6 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/project.js +9 -0
- package/dist/trace/redact.d.ts +13 -2
- package/dist/trace/redact.js +305 -24
- package/dist/trace/self-minted-wire.d.ts +326 -8
- package/dist/trace/self-minted-wire.js +125 -7
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/usage-analytics.d.ts +4 -0
- package/package.json +12 -4
- package/scripts/drain-check-local.mjs +8 -29
- package/scripts/drain-check.mysql.sql +3 -24
- package/scripts/drain-check.pg.sql +3 -24
- package/skills/update-config.md +1 -1
- package/wire-changes/server@7.146.0.json +3221 -0
- package/dist/approval-batch-census.d.ts +0 -27
- package/dist/approval-batch-census.js +0 -27
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { parkedApprovalCard } from "../approval-content-kind.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { CHECKPOINT_FACET_SQL, CHECKPOINT_SWEEP_ORDER_SQL, CheckpointIndexRefusedError, judgeCheckpointIndexCells } from "
|
|
4
|
-
import { CheckpointError,
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { assertJsonColumnWritable, createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, jsonColumnTextExpr, jsonColumnTextSha256, readJsonArrayColumn, readJsonColumnTextSha256, readJsonObjectColumn, readNonNullJsonValueColumn, } from "./sql-json-column.js";
|
|
3
|
+
import { CHECKPOINT_FACET_SQL, CHECKPOINT_SWEEP_ORDER_SQL, CheckpointIndexRefusedError, judgeCheckpointIndexCells } from "../plugins/checkpoint-index-columns.js";
|
|
4
|
+
import { CheckpointError, validatePendingSteer, appendPendingSteer, winnerFromOutcome, summarizeCheckpoint, checkpointRevOf, judgeCheckpointRow, CONTRACT_KIT_ENGINE_VERSION, ExecutionOutcomeConflictError, executionRecordDisposition, executionVerdict, } from "@sema-agent/core";
|
|
5
|
+
import { parkRowFacts, skillCardFacts } from "../approval-card.js";
|
|
6
|
+
import { assertJsonColumnWritable, createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, jsonColumnTextSha256, readJsonArrayColumn, readJsonColumnTextSha256, readNonNullJsonValueColumn, StoreCorruptError, } from "../plugins/sql-json-column.js";
|
|
8
7
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
9
8
|
import { durableRowIdentity, withoutCheckpointToken } from "../checkpoint-identity.js";
|
|
10
|
-
import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "
|
|
11
|
-
import { isDupKeyError, isMissingColumnError, rowTooLargeOrSelf, StoreRowTooLargeError } from "
|
|
12
|
-
import { describeProbedTableDrift } from "
|
|
13
|
-
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "
|
|
14
|
-
import { approvalPayloadFingerprint } from "
|
|
9
|
+
import { mysqlDriver, pgDriver, dialectProtocolJsonEncoder } from "../plugins/sql-driver.js";
|
|
10
|
+
import { isDupKeyError, isMissingColumnError, rowTooLargeOrSelf, StoreRowTooLargeError } from "../plugins/sql-errors.js";
|
|
11
|
+
import { describeProbedTableDrift } from "../plugins/schema-drift-sentence.js";
|
|
12
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-store-sql.js";
|
|
13
|
+
import { approvalPayloadFingerprint } from "../plugins/approval-payload-fingerprint.js";
|
|
14
|
+
import { approvalDecisionOfWinner, boundedRuleOffers, boundedToolInput, candidateIdentityOf, DECIDED_REPLAY_SCAN_CAP, queueRowGateKind, TERMINAL_BACKSTOP_MS, TERMINAL_GRACE_MS, UnreadableCheckpointRowError, } from "../plugins/checkpoint-store-face.js";
|
|
15
15
|
const CTX_REWRITE_PAGE = 500;
|
|
16
|
-
const KINDLESS_SCAN_PAGE = 200;
|
|
17
|
-
export { approvalPayloadFingerprint } from "./approval-payload-fingerprint.js";
|
|
18
|
-
const MAX_TOOL_INPUT_CHARS = 8192;
|
|
19
|
-
export const TERMINAL_BACKSTOP_MS = Math.max(60_000, (Number.isFinite(Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS)) ? Number(process.env.APPROVAL_TERMINAL_BACKSTOP_MS) : 0) || 30 * 86_400_000);
|
|
20
|
-
export const TERMINAL_GRACE_MS = 3_600_000;
|
|
21
16
|
export function tokenFingerprint(token) {
|
|
22
17
|
return "sha256:" + createHash("sha256").update(token).digest("hex").slice(0, 12);
|
|
23
18
|
}
|
|
@@ -50,21 +45,6 @@ class StoredRowProjectionMemo {
|
|
|
50
45
|
}
|
|
51
46
|
const STORED_ROW_READ_BATCH = 100;
|
|
52
47
|
const CHECKPOINT_SHA256_AS = "checkpoint_sha256";
|
|
53
|
-
const GATE_KIND_IS_LIVE_RUN_PARK = {
|
|
54
|
-
human: true,
|
|
55
|
-
irreversible_ask: true,
|
|
56
|
-
resource_limit: true,
|
|
57
|
-
needs_review: true,
|
|
58
|
-
plan_review: true,
|
|
59
|
-
task_done: false,
|
|
60
|
-
};
|
|
61
|
-
export const LIVE_RUN_GATE_KINDS = Object.keys(GATE_KIND_IS_LIVE_RUN_PARK).filter((k) => GATE_KIND_IS_LIVE_RUN_PARK[k]);
|
|
62
|
-
export const TERMINAL_PARK_GATE_KINDS = Object.keys(GATE_KIND_IS_LIVE_RUN_PARK).filter((k) => !GATE_KIND_IS_LIVE_RUN_PARK[k]);
|
|
63
|
-
export function pendingRowPrecedes(a, b, pick) {
|
|
64
|
-
if (pick === "oldest")
|
|
65
|
-
return a.createdAt < b.createdAt || (a.createdAt === b.createdAt && a.token < b.token);
|
|
66
|
-
return a.createdAt > b.createdAt || (a.createdAt === b.createdAt && a.token > b.token);
|
|
67
|
-
}
|
|
68
48
|
export const CHECKPOINT_ADDED_COLUMNS = [
|
|
69
49
|
{
|
|
70
50
|
column: "has_bidi_controls",
|
|
@@ -99,53 +79,6 @@ export async function assertCheckpointColumnSchema(query, dialect) {
|
|
|
99
79
|
}
|
|
100
80
|
}
|
|
101
81
|
}
|
|
102
|
-
const MAX_RULE_OFFER_SCAN = 32;
|
|
103
|
-
function preboundBatchMembers(item) {
|
|
104
|
-
if (typeof item !== "object" || item === null)
|
|
105
|
-
return item;
|
|
106
|
-
const candidate = item;
|
|
107
|
-
if (candidate.kind !== "batch" || !Array.isArray(candidate.rules) || candidate.rules.length <= MAX_RULE_OFFER_BATCH_MEMBERS)
|
|
108
|
-
return item;
|
|
109
|
-
return { ...candidate, rules: candidate.rules.slice(0, MAX_RULE_OFFER_BATCH_MEMBERS) };
|
|
110
|
-
}
|
|
111
|
-
export function boundedReaderInput(raw) {
|
|
112
|
-
return Array.isArray(raw) ? raw.slice(0, MAX_RULE_OFFER_SCAN).map(preboundBatchMembers) : raw;
|
|
113
|
-
}
|
|
114
|
-
export function boundedRuleOffers(raw, opts = {}) {
|
|
115
|
-
const observe = opts.countRedactions ?? true;
|
|
116
|
-
const scrub = (text) => redactSecrets(text, { observe }).slice(0, MAX_RULE_TEXT_CHARS);
|
|
117
|
-
const read = readRuleOfferList(boundedReaderInput(raw));
|
|
118
|
-
const out = [];
|
|
119
|
-
for (const { offer } of read) {
|
|
120
|
-
if (out.length >= MAX_RULE_OFFERS)
|
|
121
|
-
break;
|
|
122
|
-
switch (offer.kind) {
|
|
123
|
-
case "single":
|
|
124
|
-
out.push({ kind: "single", rule: scrub(offer.rule), match: offer.match, command: scrub(offer.command) });
|
|
125
|
-
break;
|
|
126
|
-
case "batch":
|
|
127
|
-
out.push({
|
|
128
|
-
kind: "batch",
|
|
129
|
-
rules: offer.rules.slice(0, MAX_RULE_OFFER_BATCH_MEMBERS).map((r) => {
|
|
130
|
-
switch (r.kind) {
|
|
131
|
-
case "command":
|
|
132
|
-
return { kind: "command", rule: scrub(r.rule), match: r.match, command: scrub(r.command), segment: scrub(r.segment) };
|
|
133
|
-
case "directoryRead":
|
|
134
|
-
return { kind: "directoryRead", rule: scrub(r.rule), directory: scrub(r.directory), segment: scrub(r.segment) };
|
|
135
|
-
default:
|
|
136
|
-
throw new Error(`unknown rule-offer batch member kind: ${JSON.stringify(r)}`);
|
|
137
|
-
}
|
|
138
|
-
}),
|
|
139
|
-
uncoveredSegments: offer.uncoveredSegments,
|
|
140
|
-
...(offer.uncoveredDetail !== undefined ? { uncoveredDetail: offer.uncoveredDetail.map((d) => ({ segment: scrub(d.segment), reason: d.reason })) } : {}),
|
|
141
|
-
});
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
throw new Error(`unknown rule-offer kind: ${JSON.stringify(offer)}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return out.length > 0 ? out : undefined;
|
|
148
|
-
}
|
|
149
82
|
const readCheckpointBlobBody = createObjectColumnReader();
|
|
150
83
|
const readResumeOutcomeBody = createObjectColumnReader();
|
|
151
84
|
const readGateOutcomeBody = createObjectColumnReader();
|
|
@@ -156,6 +89,19 @@ function decodeCheckpointColumn(cell, where) {
|
|
|
156
89
|
function verdictOfUnreadableBody(cell) {
|
|
157
90
|
return judgeCheckpointRow(cell);
|
|
158
91
|
}
|
|
92
|
+
const UNREADABLE_SUMMARY_MEMBERS = new Set(["token", "rowVerdict", "sessionId", "scope", "gateKind", "createdAt", "deadline"]);
|
|
93
|
+
function isUnreadableSummaryForm(summary) {
|
|
94
|
+
const names = UNREADABLE_SUMMARY_MEMBERS;
|
|
95
|
+
return summary.rowVerdict.kind !== "ok" && Object.keys(summary).every((member) => names.has(member));
|
|
96
|
+
}
|
|
97
|
+
function readCheckpointBodyOrRefuse(cell, where) {
|
|
98
|
+
try {
|
|
99
|
+
return refusing("a checkpoint nobody can resume", () => decodeCheckpointColumn(cell, where));
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
throw e instanceof StoreCorruptError ? new UnreadableCheckpointRowError(e, verdictOfUnreadableBody(cell)) : e;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
159
105
|
function decodeOutcomeColumn(cell, where) {
|
|
160
106
|
return decodeNullableJsonColumn(cell, readResumeOutcomeBody, `checkpoint.outcome ${where}`);
|
|
161
107
|
}
|
|
@@ -228,80 +174,7 @@ function readCheckpointIdCell(cell) {
|
|
|
228
174
|
return null;
|
|
229
175
|
}
|
|
230
176
|
}
|
|
231
|
-
export function queueRowGateKind(kind) {
|
|
232
|
-
if (isGateKind(kind))
|
|
233
|
-
return kind;
|
|
234
|
-
recordFailOpen("server.approvals.queue-row-gate-kind-missing", `gate_kind=${kind === null || kind === undefined ? "NULL" : redactSecrets(String(kind)).slice(0, 40)}`);
|
|
235
|
-
return undefined;
|
|
236
|
-
}
|
|
237
177
|
const readPendingActionMemberBody = createObjectColumnReader();
|
|
238
|
-
export function boundedToolInput(args) {
|
|
239
|
-
if (args === undefined)
|
|
240
|
-
return null;
|
|
241
|
-
const redacted = redactDeep(args);
|
|
242
|
-
const json = JSON.stringify(redacted);
|
|
243
|
-
if (json === undefined)
|
|
244
|
-
return null;
|
|
245
|
-
if (json.length > MAX_TOOL_INPUT_CHARS)
|
|
246
|
-
return { truncated: true, bytes: json.length };
|
|
247
|
-
return redacted;
|
|
248
|
-
}
|
|
249
|
-
export const DECIDED_REPLAY_SCAN_CAP = 8;
|
|
250
|
-
export function approvalDecisionOfWinner(winner, boundCallId) {
|
|
251
|
-
if (winner === undefined)
|
|
252
|
-
return null;
|
|
253
|
-
if (winner.boundCallId !== boundCallId)
|
|
254
|
-
return null;
|
|
255
|
-
switch (winner.decision) {
|
|
256
|
-
case "allow":
|
|
257
|
-
return "approve";
|
|
258
|
-
case "deny":
|
|
259
|
-
return "deny";
|
|
260
|
-
case "approve":
|
|
261
|
-
case "reject":
|
|
262
|
-
case "edit":
|
|
263
|
-
return null;
|
|
264
|
-
default: {
|
|
265
|
-
const unhandled = winner.decision;
|
|
266
|
-
void unhandled;
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function pendingActionToolCallId(body) {
|
|
272
|
-
if (typeof body !== "object" || body === null)
|
|
273
|
-
return { readable: false };
|
|
274
|
-
if ("sourceTaskId" in body)
|
|
275
|
-
return { readable: false };
|
|
276
|
-
const rawSource = "sourceSessionId" in body ? body.sourceSessionId : null;
|
|
277
|
-
if (rawSource !== null && rawSource !== undefined && typeof rawSource !== "string")
|
|
278
|
-
return { readable: false };
|
|
279
|
-
const sourceSessionId = typeof rawSource === "string" ? rawSource : null;
|
|
280
|
-
if (!("pendingAction" in body))
|
|
281
|
-
return { readable: true, toolCallId: null, boundInputHash: null, kind: null, sourceSessionId };
|
|
282
|
-
const pa = body.pendingAction;
|
|
283
|
-
if (typeof pa !== "object" || pa === null)
|
|
284
|
-
return { readable: false };
|
|
285
|
-
const kind = "kind" in pa ? pa.kind : null;
|
|
286
|
-
if (kind !== null && typeof kind !== "string")
|
|
287
|
-
return { readable: false };
|
|
288
|
-
if (!("toolCallId" in pa))
|
|
289
|
-
return { readable: true, toolCallId: null, boundInputHash: null, kind, sourceSessionId };
|
|
290
|
-
const id = pa.toolCallId;
|
|
291
|
-
if (typeof id !== "string")
|
|
292
|
-
return { readable: false };
|
|
293
|
-
if (kind !== "tool_approval")
|
|
294
|
-
return { readable: false };
|
|
295
|
-
const bih = "boundInputHash" in pa ? pa.boundInputHash : null;
|
|
296
|
-
if (bih !== null && typeof bih !== "string")
|
|
297
|
-
return { readable: false };
|
|
298
|
-
return { readable: true, toolCallId: id, boundInputHash: bih, kind, sourceSessionId };
|
|
299
|
-
}
|
|
300
|
-
export function candidateIdentityOf(cp) {
|
|
301
|
-
if (judgeCheckpointRow(cp).kind === "lacking")
|
|
302
|
-
return { readable: false };
|
|
303
|
-
return pendingActionToolCallId(cp);
|
|
304
|
-
}
|
|
305
178
|
function candidateIdentityOfColumn(cell, where) {
|
|
306
179
|
let cp;
|
|
307
180
|
try {
|
|
@@ -374,7 +247,6 @@ export function readPendingSteerQueueColumn(queueRaw) {
|
|
|
374
247
|
}
|
|
375
248
|
const STEER_CAS_ATTEMPTS = 8;
|
|
376
249
|
const EXECUTION_RECORD_CAS_ATTEMPTS = 8;
|
|
377
|
-
export const CTX_CLAIM_REWRITES = ["written", "claim_released", "context_absent"];
|
|
378
250
|
export class SqlCheckpointStore {
|
|
379
251
|
db;
|
|
380
252
|
logger;
|
|
@@ -477,7 +349,7 @@ export class SqlCheckpointStore {
|
|
|
477
349
|
const r = rows[0];
|
|
478
350
|
if (!r)
|
|
479
351
|
return null;
|
|
480
|
-
const cp =
|
|
352
|
+
const cp = readCheckpointBodyOrRefuse(r.checkpoint, `for token ${tokenFingerprint(token)}`);
|
|
481
353
|
cp.status = r.status;
|
|
482
354
|
const outcomeRaw = refusing("a decision record nobody can read", () => decodeOutcomeColumn(r.outcome, `for token ${tokenFingerprint(token)}`));
|
|
483
355
|
if (outcomeRaw)
|
|
@@ -679,13 +551,21 @@ export class SqlCheckpointStore {
|
|
|
679
551
|
return { rowVerdict: verdictOfUnreadableBody(r.checkpoint) };
|
|
680
552
|
}
|
|
681
553
|
let summary;
|
|
554
|
+
const disclosed = [];
|
|
682
555
|
try {
|
|
683
|
-
summary = summarizeCheckpoint(cp,
|
|
556
|
+
summary = summarizeCheckpoint(cp, (sentence) => disclosed.push(sentence), memo?.rowVerdict);
|
|
684
557
|
}
|
|
685
558
|
catch {
|
|
686
559
|
recordFailOpen("server.approvals.park-row-blob-unreadable");
|
|
687
560
|
return { rowVerdict: judgeCheckpointRow(cp) };
|
|
688
561
|
}
|
|
562
|
+
if (isUnreadableSummaryForm(summary)) {
|
|
563
|
+
recordFailOpen("server.approvals.park-row-blob-unreadable");
|
|
564
|
+
return { rowVerdict: summary.rowVerdict };
|
|
565
|
+
}
|
|
566
|
+
const seat = discloseFor?.(cp);
|
|
567
|
+
for (const sentence of disclosed)
|
|
568
|
+
seat?.(sentence);
|
|
689
569
|
if (memo === undefined)
|
|
690
570
|
this.storedRowMemo.set(sha256, { rowVerdict: summary.rowVerdict, skillCardFacts: skillCardFacts(summary) });
|
|
691
571
|
return { rowVerdict: summary.rowVerdict, summary };
|
|
@@ -894,47 +774,6 @@ export class SqlCheckpointStore {
|
|
|
894
774
|
}
|
|
895
775
|
return out;
|
|
896
776
|
}
|
|
897
|
-
async scanKindlessBatchRows() {
|
|
898
|
-
const out = [];
|
|
899
|
-
let unreadableCells = 0;
|
|
900
|
-
const tolerant = (read) => {
|
|
901
|
-
try {
|
|
902
|
-
return read();
|
|
903
|
-
}
|
|
904
|
-
catch (e) {
|
|
905
|
-
if (!isJsonColumnBodyProblem(e))
|
|
906
|
-
throw e;
|
|
907
|
-
unreadableCells += 1;
|
|
908
|
-
return undefined;
|
|
909
|
-
}
|
|
910
|
-
};
|
|
911
|
-
const prefilter = (d) => `(rule_suggestions IS NOT NULL OR ${jsonColumnTextExpr(d, "checkpoint", PARK_ROW_PENDING_ACTION.key)} LIKE '%"batch"%')`;
|
|
912
|
-
let after = "";
|
|
913
|
-
for (;;) {
|
|
914
|
-
const { rows } = await this.db.query(this.q(`SELECT token, ${jsonColumnText("mysql", "rule_suggestions")}, ${jsonColumnText("mysql", "checkpoint", PARK_ROW_PENDING_ACTION)} FROM checkpoint WHERE token > ? AND ${prefilter("mysql")} ORDER BY token LIMIT ${KINDLESS_SCAN_PAGE}`, `SELECT token, ${jsonColumnText("pg", "rule_suggestions")}, ${jsonColumnText("pg", "checkpoint", PARK_ROW_PENDING_ACTION)} FROM checkpoint WHERE token > $1 AND ${prefilter("pg")} ORDER BY token LIMIT ${KINDLESS_SCAN_PAGE}`), [after]);
|
|
915
|
-
for (const row of rows) {
|
|
916
|
-
const token = String(row.token);
|
|
917
|
-
after = token;
|
|
918
|
-
const carriers = [];
|
|
919
|
-
const column = tolerant(() => decodeNullableJsonColumn(row.rule_suggestions, readJsonArrayColumn, "checkpoint.rule_suggestions (kind-less batch census)"));
|
|
920
|
-
if (countKindlessBatchOffers(boundedReaderInput(column)) > 0)
|
|
921
|
-
carriers.push("rule_suggestions");
|
|
922
|
-
const pendingAction = tolerant(() => decodeNullableJsonColumn(row[PARK_ROW_PENDING_ACTION.as], readJsonObjectColumn, "checkpoint.checkpoint pendingAction member (kind-less batch census)"));
|
|
923
|
-
if (typeof pendingAction === "object" && pendingAction !== null) {
|
|
924
|
-
const blobOffers = Reflect.get(pendingAction, "ruleOffers");
|
|
925
|
-
if (blobOffers !== undefined && !Array.isArray(blobOffers))
|
|
926
|
-
unreadableCells += 1;
|
|
927
|
-
else if (countKindlessBatchOffers(blobOffers) > 0)
|
|
928
|
-
carriers.push("pendingAction.ruleOffers");
|
|
929
|
-
}
|
|
930
|
-
if (carriers.length > 0)
|
|
931
|
-
out.push({ ref: tokenFingerprint(token), carriers });
|
|
932
|
-
}
|
|
933
|
-
if (rows.length < KINDLESS_SCAN_PAGE)
|
|
934
|
-
break;
|
|
935
|
-
}
|
|
936
|
-
return { rows: out, unreadableCells };
|
|
937
|
-
}
|
|
938
777
|
async reapCtx(cutoff) {
|
|
939
778
|
const res = await this.db.query(this.q("DELETE FROM checkpoint_ctx WHERE updated_at_ms < ? " +
|
|
940
779
|
"AND session_id NOT IN (SELECT session_id FROM checkpoint WHERE status='pending') " +
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
2
2
|
import type { Pool as PgPool } from "pg";
|
|
3
3
|
import type { MailboxAckResult, MailboxAppendMessage, MailboxDecision, MailboxDecisionOutcome, MailboxLease, MailboxRecipientTombstone, MailboxStore } from "@sema-agent/core";
|
|
4
|
-
import { type IndexSpec } from "
|
|
5
|
-
import type { SqlDialect } from "
|
|
4
|
+
import { type IndexSpec } from "../plugins/ensure-index.js";
|
|
5
|
+
import type { SqlDialect } from "../plugins/sql-driver.js";
|
|
6
6
|
export declare const MAILBOX_TABLE = "mailbox";
|
|
7
7
|
export declare const MAILBOX_MSG_TABLE = "mailbox_message";
|
|
8
8
|
/** [ref] 收件人墓碑表(预删除态的**唯一**真源;形与理由见 `mailbox-recipient-lifecycle.ts` 模块头)。
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isUtf8 } from "node:buffer";
|
|
2
2
|
import { MAILBOX_CONSUMED_ID_WINDOW, MAILBOX_INVALID_PEER_META_CODE, MAILBOX_RECORD_ID_MAX_CHARS, MAILBOX_REPLAY_FACETS, MAILBOX_TOMBSTONED_RECIPIENT_CODE, MailboxStoreError, assertMailboxDecisionMove, judgeMailboxAppendById, mailboxReplayDigests, readMailboxAppend, readMailboxPeerMeta, readStoredMailboxDecision } from "@sema-agent/core";
|
|
3
|
-
import { pgHasUnstorable, pgSanitizeText, PgUnstorableError } from "
|
|
3
|
+
import { pgHasUnstorable, pgSanitizeText, PgUnstorableError } from "../plugins/pg-safe-json.js";
|
|
4
4
|
import { isWellFormedUnicode } from "../principal-jwt.js";
|
|
5
|
-
import { ensureIndexes } from "
|
|
6
|
-
import { escapeLike } from "
|
|
7
|
-
import { SqlJsonColumnError, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, readStringArrayColumn } from "
|
|
5
|
+
import { ensureIndexes } from "../plugins/ensure-index.js";
|
|
6
|
+
import { escapeLike } from "../plugins/sql-escape.js";
|
|
7
|
+
import { SqlJsonColumnError, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, readStringArrayColumn } from "../plugins/sql-json-column.js";
|
|
8
8
|
export const MAILBOX_TABLE = "mailbox";
|
|
9
9
|
export const MAILBOX_MSG_TABLE = "mailbox_message";
|
|
10
10
|
export const MAILBOX_TOMBSTONE_TABLE = "mailbox_tombstone";
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import type { Pool } from "mysql2/promise";
|
|
24
24
|
import { type RosterStore, type RosterEntry, type RosterAccess } from "@sema-agent/core";
|
|
25
|
-
import type { PgQueryFn } from "
|
|
26
|
-
import { type IndexSpec } from "
|
|
25
|
+
import type { PgQueryFn } from "../plugins/pg-query.js";
|
|
26
|
+
import { type IndexSpec } from "../plugins/ensure-index.js";
|
|
27
27
|
export declare const ROSTER_TABLE = "agent_roster";
|
|
28
28
|
export declare function ensureTiDBRosterSchema(pool: Pool): Promise<void>;
|
|
29
29
|
/** [ref]:本 store 的索引**声明**(两方言共用一份)。PG 侧由下面的 `ensurePgRosterSchema` 应用,MySQL 侧由 `tidb-pool.ts` 的中央 `ensureSchema` 应用(那里内联 `KEY` 已在 `CREATE TABLE` 里 ⇒ 新建库探到即零 DDL,存量库缺谁补谁)。加索引以外的 schema 变更仍归运维,见 `plugins/ensure-index.ts` 头注。 */
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ToolResultProvenance, ToolResultStore, ToolResultSlice, ToolResultDeletionReport } from "@sema-agent/core";
|
|
2
2
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool, PoolClient as PgPoolClient } from "pg";
|
|
4
|
-
import { type SqlDriver, type SqlDialect } from "
|
|
4
|
+
import { type SqlDriver, type SqlDialect } from "../plugins/sql-driver.js";
|
|
5
5
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
6
|
-
import { type IndexSpec } from "
|
|
6
|
+
import { type IndexSpec } from "../plugins/ensure-index.js";
|
|
7
7
|
/** PG schema for the tool_result table — the PG translation of tidb-pool.ts's tool_result DDL
|
|
8
8
|
* (LONGTEXT→TEXT, DATETIME(3)→TIMESTAMPTZ(3), inline KEY→separate CREATE INDEX). Disjoint from other stores'
|
|
9
9
|
* tables, so a self-contained ensureSchema is safe (central pg-pool aggregation is done separately). */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { MAX_MINTED_TOOL_RESULT_REF_CHARS, assertSafeToolResultRef, assertToolResultProvenanceMatch, normalizeToolResultProvenance } from "@sema-agent/core";
|
|
2
|
-
import { pgSanitizeText } from "
|
|
3
|
-
import { mysqlDriver, pgDriver } from "
|
|
4
|
-
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "
|
|
5
|
-
import { ensureIndexes } from "
|
|
6
|
-
import { describeProbedTableDrift, schemaWaysOut } from "
|
|
7
|
-
import { isMissingColumnError } from "
|
|
2
|
+
import { pgSanitizeText } from "../plugins/pg-safe-json.js";
|
|
3
|
+
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
4
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-store-sql.js";
|
|
5
|
+
import { ensureIndexes } from "../plugins/ensure-index.js";
|
|
6
|
+
import { describeProbedTableDrift, schemaWaysOut } from "../plugins/schema-drift-sentence.js";
|
|
7
|
+
import { isMissingColumnError } from "../plugins/sql-errors.js";
|
|
8
8
|
export const PG_TOOL_RESULT_SCHEMA = [
|
|
9
9
|
`CREATE TABLE IF NOT EXISTS tool_result (
|
|
10
10
|
ref VARCHAR(518) COLLATE "C" NOT NULL,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* {@link import("@sema-agent/core").InMemoryWorkflowJournalStore} (single-replica, lost on crash); this is the
|
|
9
9
|
* byte-match durable twin so a workflow survives a replica crash and RESUMES (replay the longest unchanged
|
|
10
10
|
* PREFIX of recorded `ctx.agent` results, run only the first changed/new call + everything after it live). The
|
|
11
|
-
* journal is LOAD-BEARING (unlike the best-effort {@link import("
|
|
11
|
+
* journal is LOAD-BEARING (unlike the best-effort {@link import("../plugins/run-store-sql.js")} observation layer):
|
|
12
12
|
* append/load failures MUST throw — a silently-dropped entry would silently re-run already-done work.
|
|
13
13
|
*
|
|
14
14
|
* Schema = two tables (DDL in tidb-pool.ts / pg-pool.ts ensureSchema), the SQL normal form of core's per-run
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* `run_id = ? AND scope = ?`.
|
|
37
37
|
* Why the owner record's incarnation is in the row's PRIMARY KEY (one rule: **a row belongs to the owner record that
|
|
38
38
|
* wrote it — readable only through it, overwritable only by a write made through it**): a write can outlive the owner
|
|
39
|
-
* record it was judged against —
|
|
39
|
+
* record it was judged against — the GC sweep racing an append, an append stalled between its two
|
|
40
40
|
* statements. Keyed and joined on run_id alone, (a) a leftover row would be adopted by the next claim of that run_id by
|
|
41
41
|
* ANY scope, and (b) on PostgreSQL READ COMMITTED a stale guarded write whose SELECT still saw the old record would, via
|
|
42
42
|
* the ON CONFLICT arm (which updates a row its snapshot never saw, without re-checking the source), overwrite the NEW
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
78
78
|
import type { Pool as PgPool } from "pg";
|
|
79
79
|
import { type WorkflowJournalEntry, type WorkflowJournalStore } from "@sema-agent/core";
|
|
80
|
-
import { type SqlDriver } from "
|
|
80
|
+
import { type SqlDriver } from "../plugins/sql-driver.js";
|
|
81
81
|
/** Dual-dialect durable WorkflowJournalStore. See the file header for the dialect-delta ledger. */
|
|
82
82
|
/** [ref] 租约旋钮。TTL 只是**崩溃兜底**(engine 终态 finally 显式释放;[ref]/[ref] 两层分工:
|
|
83
83
|
* engine 崩了没释放 ⇒ 陈旧 claim 可被接管)。
|
|
@@ -137,11 +137,6 @@ export declare class SqlWorkflowJournalStore implements WorkflowJournalStore {
|
|
|
137
137
|
private oversizeCellOf;
|
|
138
138
|
/** 读面的**唯一**行读法(`loadPage` 的块读与超门行的单条读共用):序数 ≥ `from` 的至多 `limit` 行,字节超 `inlineBytes` 的行 `resultJson` 为 null(只回 `resultBytes`)。 */
|
|
139
139
|
private readRows;
|
|
140
|
-
/** GC — purge ALL journal entries for a run (every incarnation), then its owner row ([ref]). Scoped by run_id alone;
|
|
141
|
-
* idempotent (returns the journal rows removed). Mirrors the resume-anchor store's deleteBySession. An append racing the
|
|
142
|
-
* two DELETEs can leave a row behind without its owner record; it is keyed by the dead incarnation — readable and
|
|
143
|
-
* overwritable by no one (file header) — and the GC sweep removes it by age. */
|
|
144
|
-
deleteByRun(runId: string): Promise<number>;
|
|
145
140
|
/** [ref] / WF2([ref] core 拍板 a 形,签名逐字)—— cross-replica resume admission lease。
|
|
146
141
|
*
|
|
147
142
|
* 语义(bake-store `idem_key UNIQUE` 先例):PK (source_run_id, scope) 上的原子赢或观察。四步,每步
|
|
@@ -165,10 +160,10 @@ export declare class SqlWorkflowJournalStore implements WorkflowJournalStore {
|
|
|
165
160
|
newRunId: string;
|
|
166
161
|
scope: string;
|
|
167
162
|
}): Promise<void>;
|
|
168
|
-
/** GC — time-based sweep: purge journal entries older than `maxAgeMs` (created_at_ms < now - maxAgeMs).
|
|
169
|
-
*
|
|
170
|
-
* — wired into the service reaper
|
|
171
|
-
* bound. A resume of a journal older than the retention window simply re-runs live (resume is an optimization).
|
|
163
|
+
/** GC — time-based sweep: purge journal entries older than `maxAgeMs` (created_at_ms < now - maxAgeMs). This is the
|
|
164
|
+
* journal's ONE delete path (the engine's contract has no per-run delete; its File store's was retired in core 7.61.0,
|
|
165
|
+
* and this store's went with it) — wired into the service reaper, it is what keeps the heaviest table
|
|
166
|
+
* (TaskResult-bearing) from growing without bound. A resume of a journal older than the retention window simply re-runs live (resume is an optimization).
|
|
172
167
|
* Idempotent; returns the journal rows purged.
|
|
173
168
|
*
|
|
174
169
|
* [ref]: the same cutoff then purges owner rows whose OWN clock (`appended_at_ms`, pushed by every append of the
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { callKeyOrdinal } from "@sema-agent/core";
|
|
2
2
|
import { assertJournalEntryFits } from "@sema-agent/core";
|
|
3
|
-
import { journalEntryOfCell, journalRowPayloadOf } from "
|
|
3
|
+
import { journalEntryOfCell, journalRowPayloadOf } from "../plugins/workflow-journal-payload.js";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { mysqlDriver, pgDriver } from "
|
|
6
|
-
import { jsonColumnText, jsonColumnTextExpr } from "
|
|
5
|
+
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
6
|
+
import { jsonColumnText, jsonColumnTextExpr } from "../plugins/sql-json-column.js";
|
|
7
7
|
const DEFAULT_RESUME_CLAIM_TTL_MS = 60 * 60 * 1000;
|
|
8
8
|
const INT_MIN = -2147483648;
|
|
9
9
|
const INT_MAX = 2147483647;
|
|
@@ -75,11 +75,6 @@ export class SqlWorkflowJournalStore {
|
|
|
75
75
|
const { rows } = await this.db.query(this.q(`SELECT ordinal, call_key, CASE WHEN LENGTH(result) > ? THEN NULL ELSE ${jsonColumnTextExpr("mysql", "result")} END AS result_json, LENGTH(result) AS result_bytes FROM workflow_journal JOIN workflow_journal_owner USING (run_id, incarnation) WHERE run_id = ? AND scope = ? AND ordinal >= ? ORDER BY ordinal ASC LIMIT ?`, `SELECT ordinal, call_key, CASE WHEN OCTET_LENGTH(result) > $3 THEN NULL ELSE ${jsonColumnTextExpr("pg", "result")} END AS result_json, OCTET_LENGTH(result) AS result_bytes FROM workflow_journal JOIN workflow_journal_owner USING (run_id, incarnation) WHERE run_id = $1 AND scope = $2 AND ordinal >= $4 ORDER BY ordinal ASC LIMIT $5`), params);
|
|
76
76
|
return rows.map((r) => ({ ordinal: Number(r.ordinal), callKey: String(r.call_key), resultJson: r.result_json === null ? null : String(r.result_json), resultBytes: Number(r.result_bytes) }));
|
|
77
77
|
}
|
|
78
|
-
async deleteByRun(runId) {
|
|
79
|
-
const res = await this.db.query(this.q("DELETE FROM workflow_journal WHERE run_id = ?", "DELETE FROM workflow_journal WHERE run_id = $1"), [runId]);
|
|
80
|
-
await this.db.query(this.q("DELETE FROM workflow_journal_owner WHERE run_id = ?", "DELETE FROM workflow_journal_owner WHERE run_id = $1"), [runId]);
|
|
81
|
-
return res.affected;
|
|
82
|
-
}
|
|
83
78
|
async resumeClaim(input) {
|
|
84
79
|
const now = Date.now();
|
|
85
80
|
const ins = await this.db.query(this.q("INSERT IGNORE INTO workflow_resume_claim (source_run_id, scope, new_run_id, claimed_at_ms) VALUES (?, ?, ?, ?)", "INSERT INTO workflow_resume_claim (source_run_id, scope, new_run_id, claimed_at_ms) VALUES ($1, $2, $3, $4) ON CONFLICT (source_run_id, scope) DO NOTHING"), [input.sourceRunId, input.scope, input.newRunId, now]);
|
package/dist/task-settings.d.ts
CHANGED
|
@@ -195,6 +195,13 @@ export declare function skillListingBudgetFractionOk(v: unknown): v is number;
|
|
|
195
195
|
/** {@link skillListingBudgetFractionOk} 的孪生(`int().positive()`;`isSafeInteger` 而不是 `isInteger` 的
|
|
196
196
|
* 理由见那里)。 */
|
|
197
197
|
export declare function skillListingMaxDescOk(v: unknown): v is number;
|
|
198
|
+
/**
|
|
199
|
+
* `settings.autoCompactEnabled`(CC 2.1.309 settings 同名键,`cli309.js:252692` 的 settings 声明:布尔,「上下文装满时自动压缩对话」)的值域判据 —— **只收布尔**。
|
|
200
|
+
* 与上面两只谓词同姿势:FRESH 提交面的 400 门(`http/admission.ts`)问「合不合法」,RESUME 宽容层({@link parseTaskSettings})问「收不收下」,
|
|
201
|
+
* 这两句话是同一个问题的正反面,只写在这一处(`"false"` / `0` / `null` 这类假值形都不是布尔:不读成「开」也不读成「关」)。
|
|
202
|
+
* server 侧零加工:`true` / `false` 逐字交给引擎的自动压缩座 `TaskSpec.compaction.autoCompact`(`spec-fields.ts` 的 `compactionSpecFragment`),缺席 ⇒ 整键不写,默认值的属主是引擎。
|
|
203
|
+
*/
|
|
204
|
+
export declare function autoCompactEnabledOk(v: unknown): v is boolean;
|
|
198
205
|
/** The validated, service-trusted subset of `SemaSettings` we project onto the spec. `env` is parsed only to REPORT
|
|
199
206
|
* it as received-but-deferred when off the host lane (never silently dropped); a MALFORMED `hooks` likewise reports
|
|
200
207
|
* deferred (submit 路径另有 400 fail-loud),valid `hooks` 进 applied shape(hook-runner 阶段一)。 */
|
|
@@ -233,7 +240,7 @@ export interface ParsedTaskSettings {
|
|
|
233
240
|
ultracode?: boolean;
|
|
234
241
|
/** hooks hook-runner(阶段一):经 `parseHooksConfig`(契约包分类器 + 服务侧上限 + 本仓会跑的条目类型)判过的 hooks 配置。像 shellEnv 一样
|
|
235
242
|
* 这里只 PARSE;应用点(main.ts resolveSpec)按单用户闸(`requirePrincipal !== true`)决定翻不翻成
|
|
236
|
-
* 任务座 `TaskSpec.mods`
|
|
243
|
+
* 任务座 `TaskSpec.mods` 上的车道注册(非托管 `settings.hooks`,有托管组时另一张 `settings.hooks.managed`)——多租户 lane 收到只警告忽略(hook 命令跑在 worker host = class ② 能力授予)。 */
|
|
237
244
|
hooks?: RunnableHooksConfig;
|
|
238
245
|
/** [ref](7.77.0)—— CC settings 同名键:上下文窗口里**留给技能清单**的比例((0,1];CC 默认 0.01 = 1%)。
|
|
239
246
|
* 超预算时引擎把描述裁短、再不够退成 name-only(`cli259.js` 的清单渲染算法),**从不**拒掉一条技能 ——
|
|
@@ -242,6 +249,10 @@ export interface ParsedTaskSettings {
|
|
|
242
249
|
skillListingBudgetFraction?: number;
|
|
243
250
|
/** 同族第二键:每条技能描述在清单里的字符帽(正整数;CC 默认 1536)。超出由引擎**截断**,不是拒。 */
|
|
244
251
|
skillListingMaxDescChars?: number;
|
|
252
|
+
/** `settings.autoCompactEnabled`(CC 2.1.309 settings 同名键,布尔):这条 run 的自动压缩开关。逐字交给引擎的自动压缩座 `TaskSpec.compaction.autoCompact`
|
|
253
|
+
* (写点 = `boot/resolve-spec.ts` 经 `spec-fields.ts` 的 `compactionSpecFragment`,与顶层 `compaction.clampTolerance` 同一只映射)。
|
|
254
|
+
* `false` 是有意义的值(不是「没设」),所以 {@link parseTaskSettings} 把它收下、`settings` 因它在场。缺席 ⇒ 整键不写。 */
|
|
255
|
+
autoCompactEnabled?: boolean;
|
|
245
256
|
/** [ref] —— 「只收紧」座位族(`tighten-only-seats.ts` 的四座:读拒模式 / 写保护名的加法 / 合规额外禁项 / 永不自动放行名单)的归一值,**一个键**而不是四个散字段:
|
|
246
257
|
* wire 位置由座位表说(三座在 `settings` 顶层,`neverAuto` 在 `settings.permissions`),解析后与位置无关。空数组 ≡ 缺席(不铸键)。
|
|
247
258
|
* 去处:三座经 {@link applyTaskSettings} 落 core 任务层席;`neverAuto` 经 {@link deriveSettingsPolicy} 落请求叶策略。 */
|
|
@@ -263,9 +274,11 @@ export interface ParseTaskSettingsResult {
|
|
|
263
274
|
readonly stripped: readonly string[];
|
|
264
275
|
};
|
|
265
276
|
}
|
|
266
|
-
/** `parseTaskSettings` 的可选座:续跑重放腿才有的重读座(一次性迁移 M20;新提交腿与不问 hooks 的读者不递)
|
|
277
|
+
/** `parseTaskSettings` 的可选座:续跑重放腿才有的重读座(一次性迁移 M20;新提交腿与不问 hooks 的读者不递)与调用方已读(并已判)的 `settings.env` 那一份。 */
|
|
267
278
|
export interface ParseTaskSettingsSeats {
|
|
268
279
|
readonly storedHooksReread?: StoredHooksRereadM20;
|
|
280
|
+
/** {@link readSettingsEnv} 的一次读数(`resolveSpec` 两腿恒递:凭据判据判的就是这一份,解析层不再读第二次;续跑腿 M38 剥过键的是剥后那一份)。缺席 ⇒ 解析层自己读一次(不交子进程的读者)。 */
|
|
281
|
+
readonly settingsEnv?: SettingsEnvLayer;
|
|
269
282
|
}
|
|
270
283
|
/** Cap on `outputStyle` length — it lands in the system prompt, so it shares the `MAX_SYSTEM_PROMPT_CHARS` (16384)
|
|
271
284
|
* posture (an uncapped prompt body is a per-turn token-cost hole; cross review). Exported so the HTTP layer
|
|
@@ -275,6 +288,40 @@ export declare const MAX_SETTINGS_OUTPUT_STYLE_CHARS = 16384;
|
|
|
275
288
|
export declare const MAX_SETTINGS_ENV_VARS = 256;
|
|
276
289
|
export declare const MAX_SETTINGS_ENV_VALUE_CHARS = 32768;
|
|
277
290
|
export declare const MAX_SETTINGS_ENV_KEY_CHARS = 256;
|
|
291
|
+
/** 一条 `settings.env` 条目被判成凭据的根据(闭集;wire 字段 `entries[].match` 的全部词):`name` = 名字是本进程的凭据变量名;`value_shape` = 值是秘密形。两者都中按 `name` 报。 */
|
|
292
|
+
export declare const SETTINGS_ENV_CREDENTIAL_MATCHES: readonly ["name", "value_shape"];
|
|
293
|
+
export type SettingsEnvCredentialMatch = (typeof SETTINGS_ENV_CREDENTIAL_MATCHES)[number];
|
|
294
|
+
/** 拒体的机读位(原样进 wire 错误体 / `HttpError.extra`):`field` 恒为 `settings.env`;`entries` 按体内序列出每一条命中,键名过调用方串的唯一回显口径,值从不进来。 */
|
|
295
|
+
export interface SettingsEnvCredentialFields {
|
|
296
|
+
readonly field: "settings.env";
|
|
297
|
+
readonly entries: readonly {
|
|
298
|
+
readonly key: string;
|
|
299
|
+
readonly match: SettingsEnvCredentialMatch;
|
|
300
|
+
}[];
|
|
301
|
+
}
|
|
302
|
+
/** 一次裁决的产物:wire 文案 + 机读位 + 命中条目的**原键**(`keys`:不出门,只给续跑腿的一次性迁移按键剥)。 */
|
|
303
|
+
export interface SettingsEnvCredentialIssue {
|
|
304
|
+
readonly message: string;
|
|
305
|
+
readonly fields: SettingsEnvCredentialFields;
|
|
306
|
+
readonly keys: readonly string[];
|
|
307
|
+
}
|
|
308
|
+
/** `settings.env` 的一次读数:`sent` = 调用方送了这个键(不是缺席 / `null`);`reaching` = 会交到子进程的那几条({@link cleanEnvMap};形不对 / 没有一条够格 ⇒ `undefined`;一次性迁移 M38 剥空的是 `{}`,见 {@link withoutKeys})。 */
|
|
309
|
+
export interface SettingsEnvLayer {
|
|
310
|
+
readonly sent: boolean;
|
|
311
|
+
readonly reaching: Readonly<Record<string, string>> | undefined;
|
|
312
|
+
}
|
|
313
|
+
/** `settings.env` 的**唯一**读法:`settings` 不是对象 ⇒ 没送;否则 `env` 只取一次,形判与收取都对这一次的值做。判据、解析层与续跑腿的剥键都吃这一份。 */
|
|
314
|
+
export declare function readSettingsEnv(settings: unknown): SettingsEnvLayer;
|
|
315
|
+
/**
|
|
316
|
+
* `settings.env` 里凭据条目的**唯一**判据(纯函数;律见上方段头)。`reaching` = {@link readSettingsEnv} 读出的那一份(会交到子进程的条目;非串值、超帽的键 / 值本来就到不了子进程;
|
|
317
|
+
* 缺席 / 形不对 ⇒ `undefined` ⇒ 不判,形归受理门的形判)。`credentialNames` = 本进程的凭据变量名(调用方递 `serverCredentialValueSources(config.modelApiKeyEnv)`)。没有命中 ⇒ `null`。
|
|
318
|
+
*/
|
|
319
|
+
export declare function settingsEnvCredentialIssue(reaching: Readonly<Record<string, string>> | undefined, credentialNames: readonly string[]): SettingsEnvCredentialIssue | null;
|
|
320
|
+
/**
|
|
321
|
+
* 一次性迁移 M38(窗口见 `plugins/one-time-migrations.ts` 登记表):从读到的那一份里去掉判据点名的原键,交回剥后的一份。**剥空 = 空表**(调用方送了这一块,剥完什么都不剩):
|
|
322
|
+
* 解析层把它当作这次请求的环境层原样交出,`resolveSpec` 登记它 —— 覆盖这条会话上一条登记;若读成「缺席」,会话注册表按「缺席 = 留着上一条」把上一条(可能正是被剥的那个名字)留给 shell。
|
|
323
|
+
*/
|
|
324
|
+
export declare function withoutKeys(layer: SettingsEnvLayer, keys: readonly string[]): SettingsEnvLayer;
|
|
278
325
|
/** 三桶(闭集;判据按此序逐桶判)。 */
|
|
279
326
|
export declare const SETTINGS_PERMISSION_BUCKETS: readonly ["allow", "deny", "ask"];
|
|
280
327
|
export type SettingsPermissionBucket = (typeof SETTINGS_PERMISSION_BUCKETS)[number];
|
|
@@ -305,7 +352,7 @@ export interface SettingsPermissionBucketIssue {
|
|
|
305
352
|
*/
|
|
306
353
|
export declare function settingsPermissionBucketIssue(perms: unknown): SettingsPermissionBucketIssue | null;
|
|
307
354
|
/** 本 service 真正**消费**的 `settings` 顶层键 —— 闭集。每一个都有消费点:
|
|
308
|
-
* `env`/`hooks`/`model`/`outputStyle`/`permissions`/`ultracode` 与两个 `skillListing*` 在
|
|
355
|
+
* `autoCompactEnabled`/`env`/`hooks`/`model`/`outputStyle`/`permissions`/`ultracode` 与两个 `skillListing*` 在
|
|
309
356
|
* {@link parseTaskSettings};`webSearch` 在 `capabilities/scenarios.ts`(判决 `judgeRequestWebSearch`,单用户闸;形错在受理面 400,[ref])。
|
|
310
357
|
* 加键必须同时加消费点,否则就是往闭集里塞一个新的静默丢。
|
|
311
358
|
*
|
|
@@ -322,10 +369,18 @@ export declare function settingsPermissionBucketIssue(perms: unknown): SettingsP
|
|
|
322
369
|
* 消费点 = 本文件的 parse + `boot/resolve-spec.ts` 的 `TaskSpec` 透传。语义(预算怎么花、描述怎么裁、
|
|
323
370
|
* 溢出怎么退成 name-only)整个归引擎,本仓一个字节都不渲染,也**不复刻默认值**——缺席即整键不写。
|
|
324
371
|
*
|
|
372
|
+
* 🔴 `autoCompactEnabled` = **CC settings 同名键**(2.1.309 的 settings 声明,布尔):这条 run 的自动压缩开关,值域只收布尔({@link autoCompactEnabledOk},两层同问这一只);
|
|
373
|
+
* 消费点 = 本文件的 parse + `boot/resolve-spec.ts` 经 `spec-fields.ts` 的 `compactionSpecFragment` 逐字交给引擎的自动压缩座 `TaskSpec.compaction.autoCompact`(与顶层 `compaction.clampTolerance` 同一只映射、同一个对象)。
|
|
374
|
+
* 关掉的是引擎**自起**的三条道(窗阈值那一遍、prompt-too-long 恢复那一遍、任务尾摘要):守卫链先清旧工具结果、再按尾部裁剪 → 仍装不下则服务商的「prompt too long」拒原样成为
|
|
375
|
+
* 这条 run 的失败终局(不摘要、不重试);怎么终局整个归引擎,本仓不复刻、不夹紧。调用方要的那一遍(`POST /v1/runs/:id/compact`)归引擎的另一只座 `manualCompact`,
|
|
376
|
+
* 本服务不写它 ⇒ 关了自动压缩,手动 `/compact` 照样能跑(与参照实现的 `autoCompactEnabled` 同读)。壳的环境变量 `DISABLE_AUTO_COMPACT` / `DISABLE_COMPACT`
|
|
377
|
+
* 不在本服务的读法里:环境变量是壳进程的事 —— 壳把两者都折成 `autoCompactEnabled: false` 再发;`DISABLE_COMPACT` 多出的「手动也关」由壳自己不发 `/compact` 动词实现
|
|
378
|
+
* (本服务不另读 `settings.env` 里的同名变量 —— 那是 shell 子进程的环境,不是引擎的开关)。
|
|
379
|
+
*
|
|
325
380
|
* 🔴 `allowedHttpHookUrls` / `httpHookAllowedEnvVars` = **CC settings 同名键**(契约包的 http hook 两张名单,键表属主 = 契约包 `HTTP_HOOK_ALLOWLIST_KEYS`):
|
|
326
381
|
* 消费点 = {@link parseTaskSettings} 把它们原样收成一层({@link requestHttpHookAllowlistLayer})→ `boot/resolve-spec.ts` 交给 hooks 注册 → `hooks/hook-runner.ts` 的 http 腿
|
|
327
382
|
* 在拨出之前问契约包判官。受理面只判键名(本门),不判值:名单的读法只有判官那一只(坏形由判官答 `malformed`、拦)。 */
|
|
328
|
-
export declare const TASK_SETTINGS_KEYS: readonly ["allowedHttpHookUrls", "approvalFrameFamilies", "complianceAdditionalDenies", "env", "hooks", "httpHookAllowedEnvVars", "model", "outputStyle", "permissions", "readDenyPatterns", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch", "writeProtectedExtra"];
|
|
383
|
+
export declare const TASK_SETTINGS_KEYS: readonly ["allowedHttpHookUrls", "approvalFrameFamilies", "autoCompactEnabled", "complianceAdditionalDenies", "env", "hooks", "httpHookAllowedEnvVars", "model", "outputStyle", "permissions", "readDenyPatterns", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch", "writeProtectedExtra"];
|
|
329
384
|
/** 本 service 消费的 `settings.permissions` 子键 —— 闭集(值形校验另有既有门,本门只判键名)。 */
|
|
330
385
|
export declare const TASK_SETTINGS_PERMISSION_KEYS: readonly ["allow", "ask", "defaultMode", "deny", "disableAutoMode", "neverAuto"];
|
|
331
386
|
/** CC/SDK 合约里合法、本 service **不接线**的顶层键。词表外的 CC 键落 `unknown` —— 两列都是 400,标签只影响
|