@sema-agent/server 7.144.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 +621 -0
- package/README.md +3 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +233 -54
- 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/audit.d.ts +2 -21
- package/dist/audit.js +0 -9
- 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.d.ts +1 -1
- package/dist/boot/session-faces.js +6 -4
- 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 +4 -1
- package/dist/boot/stage-10-http-server.d.ts +4 -1
- package/dist/boot/stage-10-http-server.js +4 -3
- 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-d-migration.d.ts +3 -2
- 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 +15 -4
- package/dist/fleet/fleet-bus.js +17 -3
- 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 +13 -2
- package/dist/http/checkpoint-ctx.d.ts +60 -71
- package/dist/http/checkpoint-ctx.js +35 -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 +8 -6
- 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 +31 -20
- package/dist/http/route-ctx.d.ts +26 -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.d.ts +20 -1
- package/dist/http/routes/approvals-assistant.js +29 -7
- 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/rules.d.ts +1 -1
- package/dist/http/routes/rules.js +5 -2
- package/dist/http/routes/runs.js +7 -3
- package/dist/http/routes/session-sync.js +24 -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 +35 -14
- 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/run-meta.d.ts +14 -7
- package/dist/http/run-meta.js +5 -2
- package/dist/http/server.d.ts +27 -16
- package/dist/http/server.js +21 -3
- package/dist/http/stored-body-replay.d.ts +9 -6
- package/dist/http/stored-body-replay.js +19 -5
- package/dist/http/submit-ctx.d.ts +12 -0
- package/dist/http/submit-ctx.js +23 -0
- 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 +28 -12
- package/dist/observability/fail-open.js +28 -12
- 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/approval-ask-store-file.d.ts +16 -2
- package/dist/plugins/approval-ask-store-file.js +21 -1
- package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
- package/dist/plugins/approval-ask-store-memory.js +11 -8
- package/dist/plugins/caching-session-store.d.ts +6 -1
- package/dist/plugins/caching-session-store.js +6 -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 +13 -7
- package/dist/plugins/file-run-store.js +12 -13
- 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 +16 -5
- package/dist/plugins/local-checkpoint-store.js +25 -6
- package/dist/plugins/local-session-store.d.ts +80 -21
- package/dist/plugins/local-session-store.js +79 -22
- 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/memory-run-store.d.ts +2 -0
- package/dist/plugins/memory-run-store.js +6 -0
- package/dist/plugins/one-time-migrations.d.ts +32 -56
- package/dist/plugins/one-time-migrations.js +27 -119
- 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.d.ts +4 -0
- package/dist/plugins/run-store-sql.js +5 -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/session-store.d.ts +1 -1
- 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 +18 -0
- package/dist/prompt-screen.js +5 -0
- package/dist/rules-consent.d.ts +56 -51
- package/dist/rules-consent.js +86 -14
- package/dist/run-acceptance.d.ts +40 -10
- package/dist/run-acceptance.js +38 -5
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/runs.js +2 -2
- 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 +48 -9
- package/dist/security.js +9 -2
- package/dist/session-agent.d.ts +39 -0
- package/dist/session-agent.js +16 -0
- package/dist/session-error-wire.d.ts +4 -4
- 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 +33 -429
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +70 -209
- 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/model-segment.d.ts +3 -2
- package/dist/trace/model-segment.js +16 -8
- package/dist/trace/project.js +9 -0
- package/dist/trace/redact.d.ts +79 -4
- package/dist/trace/redact.js +523 -123
- package/dist/trace/self-minted-wire.d.ts +391 -1
- package/dist/trace/self-minted-wire.js +145 -0
- 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.145.0.json +146 -0
- 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,10 +1,10 @@
|
|
|
1
1
|
import { jaccardDistance, termSet } from "@sema-agent/core";
|
|
2
2
|
import { readFrontmatterColumn } from "./memory-engine-vector-util.js";
|
|
3
3
|
import { decodeJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { serializeEntryFile } from "@sema-agent/core";
|
|
5
|
+
import { assertMemoryScopeWidth } from "./memory-key-guards.js";
|
|
6
|
+
import { exposureBandOf, exposureCarriage, distilledCarriage } from "./memory-origin-law.js";
|
|
7
|
+
import { applySqlPatches, } from "./memory-engine-sql-apply.js";
|
|
8
8
|
import { isMysqlDupKeyError } from "./sql-errors.js";
|
|
9
9
|
import { ensureIndexes } from "./ensure-index.js";
|
|
10
10
|
import { MEMORY_ENGINE_INDEXES, PG_MEMORY_ENGINE_TABLES } from "./memory-engine-pg.js";
|
|
@@ -40,6 +40,7 @@ const isDupEntry = isMysqlDupKeyError;
|
|
|
40
40
|
function isPrimaryKeyDup(err) {
|
|
41
41
|
return isDupEntry(err) && /for key '[^']*PRIMARY'/i.test(String(err.message ?? ""));
|
|
42
42
|
}
|
|
43
|
+
const AT_PLANNED_PROJECTION = "CAST(scope AS BINARY) = CAST(? AS BINARY) AND CAST(slug AS BINARY) = CAST(? AS BINARY)";
|
|
43
44
|
function inPlaceholders(count) {
|
|
44
45
|
return Array.from({ length: count }, () => "?").join(", ");
|
|
45
46
|
}
|
|
@@ -56,6 +57,7 @@ export class TiDBMemoryEngineBackend {
|
|
|
56
57
|
clock;
|
|
57
58
|
history;
|
|
58
59
|
historyRowsLost = 0;
|
|
60
|
+
leg;
|
|
59
61
|
get vectorMode() {
|
|
60
62
|
return "lexical";
|
|
61
63
|
}
|
|
@@ -66,6 +68,18 @@ export class TiDBMemoryEngineBackend {
|
|
|
66
68
|
}
|
|
67
69
|
this.clock = opts.now ?? Date.now;
|
|
68
70
|
this.history = opts.history;
|
|
71
|
+
this.leg = {
|
|
72
|
+
reads: { rowOf: (id) => this.rowOf(id), idsAt: (scope, slug) => this.idsAt(scope, slug) },
|
|
73
|
+
writes: {
|
|
74
|
+
prepare: async () => undefined,
|
|
75
|
+
add: (w, prepared, confirm) => this.writeAdd(w, prepared, confirm),
|
|
76
|
+
update: (w, prepared, confirm) => this.writeUpdate(w, prepared, confirm),
|
|
77
|
+
remove: (w, confirm) => this.writeDelete(w, confirm),
|
|
78
|
+
},
|
|
79
|
+
unstorableReason: "unstorable_bytes (utf8mb4 cannot store NUL/lone surrogates without mangling; strip them at the source — the store never rewrites content)",
|
|
80
|
+
now: () => this.clock(),
|
|
81
|
+
...(this.history !== undefined ? { appendHistory: (rows) => this.appendHistory(rows) } : {}),
|
|
82
|
+
};
|
|
69
83
|
}
|
|
70
84
|
async selectRows(sql, params) {
|
|
71
85
|
const [rows] = await this.pool.query(sql, params);
|
|
@@ -141,242 +155,98 @@ export class TiDBMemoryEngineBackend {
|
|
|
141
155
|
scored.sort((a, b) => (bands ? exposureBandOf(a) - exposureBandOf(b) : 0) || a.score - b.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
142
156
|
return scored.slice(0, limit);
|
|
143
157
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: "duplicate id in batch: another add/update for this id is already planned (copied file keeping its frontmatter id?)" });
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
nonDeleteIds.add(patch.id);
|
|
158
|
-
}
|
|
159
|
-
await this.applyOne(patch, report, plannedSlugs, historyRows, originBaseline);
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (this.history && historyRows.length > 0) {
|
|
166
|
-
try {
|
|
167
|
-
await this.history.appendHistory(historyRows);
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
this.historyRowsLost += historyRows.length;
|
|
171
|
-
console.warn(`TiDBMemoryEngineBackend: best-effort history append failed (${historyRows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return report;
|
|
158
|
+
admitsLandings = true;
|
|
159
|
+
async applyPatches(patches, opts) {
|
|
160
|
+
return applySqlPatches(patches, opts, this.leg);
|
|
161
|
+
}
|
|
162
|
+
async rowOf(id) {
|
|
163
|
+
const rows = await this.selectRows(`SELECT slug, rev, scope, ${jsonColumnText("mysql", "frontmatter")} FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
|
|
164
|
+
const r = rows[0];
|
|
165
|
+
if (r === undefined)
|
|
166
|
+
return undefined;
|
|
167
|
+
return { scope: String(r.scope), slug: String(r.slug), rev: String(r.rev), frontmatter: readFrontmatter(r.frontmatter, id) };
|
|
175
168
|
}
|
|
176
|
-
async
|
|
169
|
+
async idsAt(scope, slug) {
|
|
170
|
+
const rows = await this.selectRows(`SELECT id FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE scope = ? AND slug = ?`, [scope, slug]);
|
|
171
|
+
return rows.map((r) => String(r.id));
|
|
172
|
+
}
|
|
173
|
+
async freshRow(id) {
|
|
174
|
+
const rows = await this.selectRows(`SELECT rev, scope, slug FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
|
|
175
|
+
const r = rows[0];
|
|
176
|
+
return r === undefined ? undefined : { rev: String(r.rev), scope: String(r.scope), slug: String(r.slug) };
|
|
177
|
+
}
|
|
178
|
+
async writeAdd({ stored, rev, prior }, _prepared, confirm) {
|
|
177
179
|
const T = TIDB_MEMORY_ENGINE_TABLES.entry;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (refusal !== undefined) {
|
|
192
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (patch.op !== "delete" && patch.entry !== undefined) {
|
|
197
|
-
const refusal = ambiguousOriginRefusal(patch.entry.frontmatter);
|
|
198
|
-
if (refusal !== undefined) {
|
|
199
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: refusal });
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (patch.op === "add") {
|
|
204
|
-
const entry = patch.entry;
|
|
205
|
-
if (!entry) {
|
|
206
|
-
report.conflicts.push({ op: "add", id: patch.id, reason: "add patch without an entry" });
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
if (pgHasUnstorable(entry.frontmatter) || pgHasUnstorable(entry.body) || pgHasUnstorable(entry.slug)) {
|
|
210
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: "unstorable_bytes (utf8mb4 cannot store NUL/lone surrogates without mangling; strip them at the source — the store never rewrites content)" });
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
const prior = await this.selectRows(`SELECT scope, slug, rev, ${jsonColumnText("mysql", "frontmatter")} FROM ${T} WHERE id = ?`, [entry.id]);
|
|
214
|
-
const priorRow = prior.length > 0 ? prior[0] : undefined;
|
|
215
|
-
let existsById = priorRow !== undefined;
|
|
216
|
-
{
|
|
217
|
-
const committedBaseFm = rememberBatchCommitted(originBaseline, entry.id, priorRow !== undefined ? readFrontmatter(priorRow.frontmatter, entry.id) : undefined);
|
|
218
|
-
const refusal = originWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
|
|
219
|
-
if (refusal !== undefined) {
|
|
220
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: refusal });
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
const dRefusal = distilledWhitewashRefusal("add", committedBaseFm, entry.frontmatter);
|
|
224
|
-
if (dRefusal !== undefined) {
|
|
225
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: dRefusal });
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (patch.guard === "absent" && priorRow) {
|
|
230
|
-
const currentRev = String(priorRow.rev);
|
|
231
|
-
if (currentRev !== computeEntryRev(entry)) {
|
|
232
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev });
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (String(priorRow.scope) !== entry.scope || String(priorRow.slug) !== entry.slug) {
|
|
236
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${String(priorRow.scope)}/${String(priorRow.slug)}`)}; add-if-absent refuses to duplicate)`, currentRev });
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
if (priorRow) {
|
|
241
|
-
const held = String(priorRow.scope);
|
|
242
|
-
if (held !== entry.scope) {
|
|
243
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `id already exists in scope ${JSON.stringify(held)} (cross-scope add refused)` });
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
let slug = entry.slug;
|
|
248
|
-
for (let n = 2;; n++) {
|
|
249
|
-
const derivedRefusal = memoryEntryKeyWidthRefusal(entry.scope, slug);
|
|
250
|
-
if (derivedRefusal !== undefined) {
|
|
251
|
-
report.conflicts.push({ op: "add", id: entry.id, reason: `${derivedRefusal} (slug collision suffix "-${n - 1}" no longer fits the column — shorten the entry name)` });
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
const key = `${entry.scope}|${slug}`;
|
|
255
|
-
if (!plannedSlugs.has(key)) {
|
|
256
|
-
const taken = await this.selectRows(`SELECT id FROM ${T} WHERE scope = ? AND slug = ?`, [entry.scope, slug]);
|
|
257
|
-
const otherId = taken.find((r) => String(r.id) !== entry.id);
|
|
258
|
-
if (!otherId) {
|
|
259
|
-
const stored = { ...entry, slug };
|
|
260
|
-
const rev = computeEntryRev(stored);
|
|
261
|
-
const sizeBytes = Buffer.byteLength(serializeEntryFile(stored), "utf8");
|
|
262
|
-
try {
|
|
263
|
-
if (existsById) {
|
|
264
|
-
const res = await this.write(`UPDATE ${T} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ?`, [stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes, stored.id]);
|
|
265
|
-
if (res.affectedRows === 0) {
|
|
266
|
-
const still = await this.selectRows(`SELECT id FROM ${T} WHERE id = ?`, [stored.id]);
|
|
267
|
-
if (still.length === 0) {
|
|
268
|
-
existsById = false;
|
|
269
|
-
continue;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
await this.write(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)`, [stored.id, stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes]);
|
|
275
|
-
}
|
|
180
|
+
const sizeBytes = Buffer.byteLength(serializeEntryFile(stored), "utf8");
|
|
181
|
+
let overwrite = prior;
|
|
182
|
+
for (;;) {
|
|
183
|
+
try {
|
|
184
|
+
if (overwrite !== undefined) {
|
|
185
|
+
const params = [stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes, stored.id, overwrite.scope, overwrite.slug];
|
|
186
|
+
confirm();
|
|
187
|
+
const res = await this.write(`UPDATE ${T} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ? AND ${AT_PLANNED_PROJECTION}`, params);
|
|
188
|
+
if (res.affectedRows === 0) {
|
|
189
|
+
const fresh = await this.freshRow(stored.id);
|
|
190
|
+
if (fresh === undefined) {
|
|
191
|
+
overwrite = undefined;
|
|
192
|
+
continue;
|
|
276
193
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
slug = `${entry.slug}-${n}`;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
throw err;
|
|
194
|
+
if (fresh.scope !== overwrite.scope || fresh.slug !== overwrite.slug)
|
|
195
|
+
return { kind: "moved" };
|
|
196
|
+
if (fresh.rev !== rev) {
|
|
197
|
+
throw new Error(`memory-engine: the add of ${JSON.stringify(stored.id)} wrote no row, yet the row is still at the planned projection with other content — refusing to report it either way`);
|
|
287
198
|
}
|
|
288
|
-
plannedSlugs.add(key);
|
|
289
|
-
report.applied.push({ op: "add", id: stored.id, slug: stored.slug });
|
|
290
|
-
if (this.history)
|
|
291
|
-
historyRows.push({ id: stored.id, rev, op: "add", scope: stored.scope, snapshot: { ...stored, rev }, writtenAtMs: this.clock() });
|
|
292
|
-
return;
|
|
293
199
|
}
|
|
294
200
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (cur.length === 0) {
|
|
300
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
const currentRev = String(cur[0].rev);
|
|
304
|
-
const currentSlug = String(cur[0].slug);
|
|
305
|
-
const currentScope = String(cur[0].scope);
|
|
306
|
-
const committedFm = readFrontmatter(cur[0].frontmatter, patch.id);
|
|
307
|
-
const committedBaseFm = rememberBatchCommitted(originBaseline, patch.id, committedFm);
|
|
308
|
-
if (patch.op === "update" && patch.entry !== undefined) {
|
|
309
|
-
if (committedFm.provenance?.kind === "repo_file") {
|
|
310
|
-
const next = patch.entry.frontmatter;
|
|
311
|
-
const stripsProvenance = next.provenance === undefined;
|
|
312
|
-
const stripsTrust = committedFm.trust !== undefined && next.trust === undefined;
|
|
313
|
-
if (stripsProvenance || stripsTrust) {
|
|
314
|
-
report.conflicts.push({
|
|
315
|
-
op: "update",
|
|
316
|
-
id: patch.id,
|
|
317
|
-
reason: `repo_file provenance whitewash refused: update drops ${stripsProvenance ? "provenance" : "trust"} from a repo-ingested entry (malformed patch refused)`,
|
|
318
|
-
});
|
|
319
|
-
return;
|
|
201
|
+
else {
|
|
202
|
+
const params = [stored.id, stored.scope, stored.slug, JSON.stringify(stored.frontmatter), stored.body, rev, this.clock(), sizeBytes];
|
|
203
|
+
confirm();
|
|
204
|
+
await this.write(`INSERT INTO ${T} (id, scope, slug, frontmatter, body, rev, mtime_ms, size_bytes, embedding) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL)`, params);
|
|
320
205
|
}
|
|
321
206
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
const dRefusal = distilledWhitewashRefusal("update", committedBaseFm, patch.entry.frontmatter);
|
|
328
|
-
if (dRefusal !== undefined) {
|
|
329
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: dRefusal });
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
|
|
334
|
-
report.conflicts.push({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev });
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
if (patch.op === "delete") {
|
|
338
|
-
const res = await this.write(`DELETE FROM ${T} WHERE id = ? AND rev = ?`, [patch.id, currentRev]);
|
|
339
|
-
if (res.affectedRows === 0) {
|
|
340
|
-
report.conflicts.push({ op: "delete", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: await this.freshRev(patch.id, currentRev) });
|
|
341
|
-
return;
|
|
207
|
+
catch (err) {
|
|
208
|
+
if (!isDupEntry(err))
|
|
209
|
+
throw err;
|
|
210
|
+
return isPrimaryKeyDup(err) ? { kind: "moved" } : { kind: "slug-taken" };
|
|
342
211
|
}
|
|
343
|
-
|
|
344
|
-
if (this.history)
|
|
345
|
-
historyRows.push({ id: patch.id, rev: `tombstone:${currentRev}`, prevRev: currentRev, op: "delete", scope: currentScope, writtenAtMs: this.clock() });
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
const entry = patch.entry;
|
|
349
|
-
if (!entry) {
|
|
350
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: "update patch without an entry" });
|
|
351
|
-
return;
|
|
212
|
+
return { kind: "committed" };
|
|
352
213
|
}
|
|
353
|
-
|
|
354
|
-
|
|
214
|
+
}
|
|
215
|
+
async writeUpdate({ entry, rev, currentRev, current, baseRev }, _prepared, confirm) {
|
|
216
|
+
const params = [entry.scope, entry.slug, JSON.stringify(entry.frontmatter), entry.body, rev, this.clock(), Buffer.byteLength(serializeEntryFile(entry), "utf8"), entry.id, currentRev, current.scope, current.slug];
|
|
217
|
+
confirm();
|
|
218
|
+
const res = await this.write(`UPDATE ${TIDB_MEMORY_ENGINE_TABLES.entry} SET scope = ?, slug = ?, frontmatter = ?, body = ?, rev = ?, mtime_ms = ?, size_bytes = ?, embedding = NULL WHERE id = ? AND rev = ? AND ${AT_PLANNED_PROJECTION}`, params);
|
|
219
|
+
if (res.affectedRows > 0)
|
|
220
|
+
return { kind: "committed" };
|
|
221
|
+
const fresh = await this.freshRow(entry.id);
|
|
222
|
+
const atPlanned = fresh !== undefined && fresh.rev === currentRev && fresh.scope === current.scope && fresh.slug === current.slug;
|
|
223
|
+
const writesNothingNew = rev === currentRev && entry.scope === current.scope && entry.slug === current.slug;
|
|
224
|
+
if (atPlanned && writesNothingNew)
|
|
225
|
+
return { kind: "committed" };
|
|
226
|
+
if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
|
|
227
|
+
return { kind: "moved" };
|
|
228
|
+
return { kind: "lost", conflict: { op: "update", id: entry.id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
|
|
229
|
+
}
|
|
230
|
+
async writeDelete({ id, currentRev, current, baseRev }, confirm) {
|
|
231
|
+
confirm();
|
|
232
|
+
const res = await this.write(`DELETE FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ? AND rev = ? AND ${AT_PLANNED_PROJECTION}`, [id, currentRev, current.scope, current.slug]);
|
|
233
|
+
if (res.affectedRows > 0)
|
|
234
|
+
return { kind: "committed" };
|
|
235
|
+
const fresh = await this.freshRow(id);
|
|
236
|
+
if (fresh !== undefined && fresh.rev === currentRev && (fresh.scope !== current.scope || fresh.slug !== current.slug))
|
|
237
|
+
return { kind: "moved" };
|
|
238
|
+
return { kind: "lost", conflict: { op: "delete", id, reason: "rev mismatch (concurrent change)", baseRev, currentRev: fresh?.rev ?? currentRev } };
|
|
239
|
+
}
|
|
240
|
+
async appendHistory(rows) {
|
|
241
|
+
if (!this.history)
|
|
355
242
|
return;
|
|
243
|
+
try {
|
|
244
|
+
await this.history.appendHistory(rows);
|
|
356
245
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const fresh = await this.freshRevOrMissing(entry.id);
|
|
361
|
-
if (fresh === rev) {
|
|
362
|
-
report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
|
|
363
|
-
if (this.history)
|
|
364
|
-
historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
report.conflicts.push({ op: "update", id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev: fresh ?? currentRev });
|
|
368
|
-
return;
|
|
246
|
+
catch (err) {
|
|
247
|
+
this.historyRowsLost += rows.length;
|
|
248
|
+
console.warn(`TiDBMemoryEngineBackend: best-effort history append failed (${rows.length} row(s) lost, ${this.historyRowsLost} cumulative — audit face only, entries committed): ${err instanceof Error ? err.message : String(err)}`);
|
|
369
249
|
}
|
|
370
|
-
report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
|
|
371
|
-
if (this.history)
|
|
372
|
-
historyRows.push({ id: entry.id, rev, prevRev: currentRev, op: "update", scope: entry.scope, snapshot: { ...entry, rev }, writtenAtMs: this.clock() });
|
|
373
|
-
}
|
|
374
|
-
async freshRevOrMissing(id) {
|
|
375
|
-
const rows = await this.selectRows(`SELECT rev FROM ${TIDB_MEMORY_ENGINE_TABLES.entry} WHERE id = ?`, [id]);
|
|
376
|
-
return rows.length > 0 ? String(rows[0].rev) : undefined;
|
|
377
|
-
}
|
|
378
|
-
async freshRev(id, fallback) {
|
|
379
|
-
return (await this.freshRevOrMissing(id)) ?? fallback;
|
|
380
250
|
}
|
|
381
251
|
async getConsolidationCursor(scope) {
|
|
382
252
|
const rows = await this.selectRows(`SELECT \`cursor\` FROM ${TIDB_MEMORY_ENGINE_TABLES.cursor} WHERE scope = ?`, [scope]);
|
|
@@ -22,7 +22,7 @@ export declare const MEMORY_SYNC_PEER_COLUMN_CHARS = 190;
|
|
|
22
22
|
export declare function assertSlugWidth(slug: string): void;
|
|
23
23
|
export declare function assertMemoryScopeWidth(scope: string): void;
|
|
24
24
|
/**
|
|
25
|
-
* 一个 entry 写(add / update)的两个键宽一起判 ——
|
|
25
|
+
* 一个 entry 写(add / update)的两个键宽一起判 —— 两方言共用的判(`memory-engine-sql-apply.ts` 的 `planSqlPatch`)在**任何 I/O 之前**调用它。
|
|
26
26
|
*
|
|
27
27
|
* 为什么两条腿共用一个入口而不是各自展开:add 与 update 写的是**同两列**(update 的
|
|
28
28
|
* `SET scope = …, slug = …` 会改盘也会改名),R5 那批只护住了 add ⇒ 一次改名就能把超宽 slug 送进
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
* ① **判据本身**({@link originWhitewashRefusal}):`committedOriginOf` / `originEquals` 都用 core 的
|
|
31
31
|
* 导出实现,**不重写** —— 它们要处理 `frontmatter.origin` 与「保留在 `extra` 里的 origin 形字节块」
|
|
32
32
|
* 两种承载形(legacy / 外来),自己写一份近似的等于给洗白留一条旁路。
|
|
33
|
-
* ② **批次基线**({@link
|
|
34
|
-
*
|
|
33
|
+
* ② **批次基线**({@link rememberBatchCommitted}):两支 SQL 后端的提交阶段逐条 patch 现判、直打真库(落点问询的
|
|
34
|
+
* 计划阶段只是只读预测,不是 File backend 那种「先规划整批再落盘」),所以同批 `delete` 之后再 `add` 时,库里已经没有那一行了 ——
|
|
35
35
|
* 只看当下的库会把它误判成合法新生命。基线 map 按**本批第一次触碰**记下该 id 的已提交 origin,
|
|
36
36
|
* 之后同批的任何 op 都按那一份判。⇒「同批 delete+re-add 拒 / 已提交墓碑后 add 放」这条分界
|
|
37
37
|
* (core 契约逐字要求的那条)才成立。
|
|
@@ -128,7 +128,7 @@ export declare function rememberBatchCommitted(baseline: BatchCommittedBaseline,
|
|
|
128
128
|
/**
|
|
129
129
|
* 未知 op 拼写的**前置**拒绝(codex R1-[high],验真后采纳;**既有**缺口,不是本批引入)。
|
|
130
130
|
*
|
|
131
|
-
* 病:两支 SQL
|
|
131
|
+
* 病:两支 SQL 后端当时各一份的 `applyOne`(今两腿共用的判 `memory-engine-sql-apply.ts` 的 `planSqlPatch`)形状是「`if (op === "add") {…}` → 落到 update/delete 段」,而段内
|
|
132
132
|
* 的两道白洗守卫(repo_file provenance / 本模块的 origin 不可变律)都写成 `if (patch.op === "update")`。
|
|
133
133
|
* ⇒ 一个**词表外**的 op(`"upsert"` / 打错的字 / 将来 core 加的新词)会:跳过两道守卫 → 走到 update
|
|
134
134
|
* 的 SQL → 把行改掉 → 在 `report.applied` 里报成一次 update。TypeScript 的联合型是**编译期**的,
|
|
@@ -57,6 +57,8 @@ export declare class MemoryRunStore implements InProcessClaimFence {
|
|
|
57
57
|
bindIdemBodyFingerprint(taskId: string, idem: RunIdemBinding): Promise<string | null>;
|
|
58
58
|
/** The run a submission's scoped `Idempotency-Key` names, if any. */
|
|
59
59
|
getRunByIdem(idemKey: string): Promise<RunRecord | undefined>;
|
|
60
|
+
/** run 行预览的写一次补写(SQL 孪生同义:列仍是 null 才写,建行写过 / 已补过的不动;行不在 ⇒ 无事)。 */
|
|
61
|
+
fillObjectivePreview(taskId: string, preview: string): Promise<void>;
|
|
60
62
|
requestCancel(taskId: string, owner: string | null): Promise<boolean>;
|
|
61
63
|
isCancelRequested(taskId: string, owner: string | null): Promise<boolean>;
|
|
62
64
|
requestPreempt(taskId: string, owner: string | null): Promise<boolean>;
|
|
@@ -109,6 +109,12 @@ export class MemoryRunStore {
|
|
|
109
109
|
const r = taskId !== undefined ? this.runs.get(taskId) : undefined;
|
|
110
110
|
return r ? this.toRecord(r) : undefined;
|
|
111
111
|
}
|
|
112
|
+
async fillObjectivePreview(taskId, preview) {
|
|
113
|
+
const r = this.runs.get(taskId);
|
|
114
|
+
if (!r || r.objectivePreview !== null)
|
|
115
|
+
return;
|
|
116
|
+
r.objectivePreview = preview;
|
|
117
|
+
}
|
|
112
118
|
async requestCancel(taskId, owner) {
|
|
113
119
|
const r = this.runs.get(taskId);
|
|
114
120
|
if (!r || !ownerEq(r.owner, owner) || r.status !== "running")
|