@sema-agent/server 7.139.0 → 7.140.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 +181 -0
- package/USAGE.md +19 -13
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/approval-card.d.ts +6 -6
- package/dist/bench/s1/live-deps.js +3 -2
- package/dist/bench/s1/row.d.ts +5 -2
- package/dist/bench/s1/row.js +2 -22
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/execution-env.js +12 -10
- package/dist/boot/execution-lane.d.ts +8 -0
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/memory-boundary.d.ts +14 -51
- package/dist/boot/memory-boundary.js +10 -20
- package/dist/boot/memory-consolidation.d.ts +15 -11
- package/dist/boot/memory-consolidation.js +23 -12
- package/dist/boot/resolve-spec.d.ts +3 -5
- package/dist/boot/resolve-spec.js +2 -4
- package/dist/boot/runner-deps.d.ts +3 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +2 -6
- package/dist/boot/stage-03-store-backend.js +2 -3
- package/dist/boot/stage-04-stores.d.ts +2 -6
- package/dist/boot/stage-04-stores.js +5 -5
- package/dist/boot/stage-05-execution-env.d.ts +2 -6
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -6
- package/dist/boot/stage-08-reapers.d.ts +2 -6
- package/dist/boot/stage-09-leader.d.ts +2 -6
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +5 -4
- package/dist/boot/stores.d.ts +3 -6
- package/dist/boot/stores.js +27 -40
- package/dist/boot/task-list-lane.d.ts +1 -1
- package/dist/boot/task-list-lane.js +1 -1
- package/dist/boot/web-admin.js +35 -9
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/config-catalog.js +2 -1
- package/dist/config-provider.d.ts +14 -13
- package/dist/config-provider.js +24 -18
- package/dist/config-types.d.ts +11 -2
- package/dist/config.js +2 -1
- package/dist/delegated-session-owner.d.ts +2 -1
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +9 -8
- package/dist/deployment-shape.js +4 -4
- package/dist/execution-lane-caps.d.ts +97 -106
- package/dist/execution-lane-caps.js +67 -83
- package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
- package/dist/http/memory-compliance-failure-reply.js +5 -0
- package/dist/http/memory-layer-reply.d.ts +30 -0
- package/dist/http/memory-layer-reply.js +24 -0
- package/dist/http/resume-legs.js +13 -16
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +8 -1
- package/dist/http/routes/memory-consolidation.js +12 -1
- package/dist/http/routes/memory-origin.js +14 -2
- package/dist/http/routes/memory-policy.js +5 -0
- package/dist/http/routes/sessions.js +28 -11
- package/dist/http/routes/tasks.js +4 -2
- package/dist/http/server.d.ts +5 -25
- package/dist/http/server.js +2 -2
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/lane-home-probe.d.ts +68 -42
- package/dist/lane-home-probe.js +53 -30
- package/dist/leader/wire.js +5 -4
- package/dist/memory-bundle-engine.d.ts +16 -9
- package/dist/memory-bundle-engine.js +29 -6
- package/dist/memory-operator-faces.d.ts +85 -30
- package/dist/memory-operator-faces.js +136 -30
- package/dist/memory-project-layer.d.ts +3 -21
- package/dist/memory-project-layer.js +11 -8
- package/dist/memory-scope-stores.d.ts +73 -0
- package/dist/memory-scope-stores.js +86 -0
- package/dist/memory-scope.d.ts +29 -5
- package/dist/memory-scope.js +16 -4
- package/dist/memory-sync-client.d.ts +20 -7
- package/dist/memory-sync-client.js +31 -13
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-sql.js +14 -14
- package/dist/plugins/approval-nonce-store.js +4 -4
- package/dist/plugins/blob-backend.d.ts +4 -4
- package/dist/plugins/blob-backend.js +7 -7
- package/dist/plugins/breaker-state-sql.js +2 -2
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.js +16 -16
- package/dist/plugins/device-store-sql.js +19 -19
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +8 -8
- package/dist/plugins/execution-placement-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.d.ts +2 -2
- package/dist/plugins/file-history-store-sql.js +4 -4
- package/dist/plugins/image-bake-store-sql.js +9 -9
- package/dist/plugins/image-index-sql.js +11 -11
- package/dist/plugins/leader-run-store-sql.js +4 -4
- package/dist/plugins/mailbox-store-sql.d.ts +2 -1
- package/dist/plugins/mailbox-store-sql.js +4 -4
- package/dist/plugins/memory-engine-tidb.js +5 -5
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +10 -9
- package/dist/plugins/one-time-migrations.js +36 -36
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
- package/dist/plugins/permission-rule-store-sql.js +16 -16
- package/dist/plugins/remote-env-adb.d.ts +7 -24
- package/dist/plugins/remote-env-adb.js +22 -5
- package/dist/plugins/remote-env-device.d.ts +2 -28
- package/dist/plugins/remote-env-device.js +2 -1
- package/dist/plugins/remote-env-e2b.d.ts +18 -26
- package/dist/plugins/remote-env-e2b.js +51 -4
- package/dist/plugins/remote-env-file-error.d.ts +1 -1
- package/dist/plugins/remote-env-file-error.js +8 -2
- package/dist/plugins/remote-env-host.d.ts +19 -35
- package/dist/plugins/remote-env-host.js +26 -3
- package/dist/plugins/remote-env-k8s.d.ts +3 -14
- package/dist/plugins/remote-env-k8s.js +3 -2
- package/dist/plugins/remote-env-local-docker.d.ts +4 -15
- package/dist/plugins/remote-env-local-docker.js +5 -4
- package/dist/plugins/remote-env-ssh.d.ts +4 -24
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/resume-anchor-store-sql.js +2 -2
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +2 -2
- package/dist/plugins/retention-store-sql.d.ts +1 -1
- package/dist/plugins/retention-store-sql.js +6 -6
- package/dist/plugins/run-store-sql.js +15 -15
- package/dist/plugins/schema-consistency.d.ts +6 -6
- package/dist/plugins/schema-consistency.js +1 -1
- package/dist/plugins/schema-ensure-legs.d.ts +2 -3
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-capture-record-store-sql.js +1 -1
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-workspace-cell.d.ts +1 -1
- package/dist/plugins/session-workspace-cell.js +1 -1
- package/dist/plugins/shared-memory-store-sql.js +2 -2
- package/dist/plugins/sql-driver.d.ts +10 -5
- package/dist/plugins/sql-driver.js +6 -6
- package/dist/plugins/sql-errors.js +1 -1
- package/dist/plugins/store-backend.d.ts +4 -6
- package/dist/plugins/store-backend.js +6 -6
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.js +5 -5
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.js +13 -13
- package/dist/plugins/tool-result-store-sql.d.ts +2 -2
- package/dist/plugins/tool-result-store-sql.js +3 -3
- package/dist/plugins/user-input-ledger-sql.js +2 -2
- package/dist/plugins/workflow-journal-store-sql.js +5 -5
- package/dist/plugins/workflow-run-store-sql.js +19 -19
- package/dist/plugins/write-behind-counter.d.ts +2 -3
- package/dist/plugins/write-behind-counter.js +5 -5
- package/dist/resource-suspend.d.ts +14 -12
- package/dist/resource-suspend.js +1 -1
- package/dist/resource-window.d.ts +4 -3
- package/dist/run-local.js +14 -19
- package/dist/runs.d.ts +8 -4
- package/dist/runs.js +49 -65
- package/dist/session-incarnation.d.ts +1 -1
- package/dist/session-incarnation.js +1 -1
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/sql-engine-posture.d.ts +1 -1
- package/dist/sql-engine-posture.js +1 -1
- package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
- package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
- package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
- package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
- package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
- package/dist/task-a2a.js +5 -6
- package/dist/task-mcp.d.ts +20 -7
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +58 -0
- package/dist/trace/self-minted-wire.js +16 -0
- package/dist/web-admin-client/candidate-gate.d.ts +11 -7
- package/dist/web-admin-client/candidate-gate.js +1 -1
- package/dist/web-admin-client/http-client.d.ts +5 -4
- package/dist/web-admin-client/http-client.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +7 -17
- package/dist/web-admin-client/read-warnings.js +5 -9
- package/package.json +2 -2
- package/wire-changes/server@7.140.0.json +184 -0
|
@@ -24,7 +24,7 @@ export async function ensureSchema(pool) {
|
|
|
24
24
|
await ensureIndexes((t, p) => pool.query(t, p), "pg", TOOL_RESULT_INDEXES);
|
|
25
25
|
}
|
|
26
26
|
export async function assertToolResultProvenanceSchema(query, dialect) {
|
|
27
|
-
const widthRow = await query(dialect === "
|
|
27
|
+
const widthRow = await query(dialect === "mysql"
|
|
28
28
|
? "SELECT CHARACTER_MAXIMUM_LENGTH AS len FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'tool_result' AND column_name = 'ref'"
|
|
29
29
|
: "SELECT character_maximum_length AS len FROM information_schema.columns WHERE table_schema = current_schema() AND table_name = 'tool_result' AND column_name = 'ref'").catch(() => ({ rows: [] }));
|
|
30
30
|
const width = Number(widthRow.rows[0]?.len ?? NaN);
|
|
@@ -62,8 +62,8 @@ export class SqlToolResultStore {
|
|
|
62
62
|
this.db = db;
|
|
63
63
|
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
64
64
|
}
|
|
65
|
-
q(
|
|
66
|
-
return this.db.dialect === "
|
|
65
|
+
q(mysql, pg) {
|
|
66
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
67
67
|
}
|
|
68
68
|
isUnsafeRef(ref) {
|
|
69
69
|
try {
|
|
@@ -15,8 +15,8 @@ export class SqlWorkflowJournalStore {
|
|
|
15
15
|
this.db = db;
|
|
16
16
|
this.resumeClaimTtlMs = opts?.resumeClaimTtlMs ?? DEFAULT_RESUME_CLAIM_TTL_MS;
|
|
17
17
|
}
|
|
18
|
-
q(
|
|
19
|
-
return this.db.dialect === "
|
|
18
|
+
q(mysql, pg) {
|
|
19
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
20
20
|
}
|
|
21
21
|
async append(runId, scope, entry) {
|
|
22
22
|
assertJournalEntryFits(entry);
|
|
@@ -35,7 +35,7 @@ export class SqlWorkflowJournalStore {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
async load(runId, scope) {
|
|
38
|
-
const { rows } = await this.db.query(this.q(`SELECT call_key, ${jsonColumnText("
|
|
38
|
+
const { rows } = await this.db.query(this.q(`SELECT call_key, ${jsonColumnText("mysql", "result")} FROM workflow_journal JOIN workflow_journal_owner USING (run_id, incarnation) WHERE run_id = ? AND scope = ? ORDER BY ordinal ASC`, `SELECT call_key, ${jsonColumnText("pg", "result")} FROM workflow_journal JOIN workflow_journal_owner USING (run_id, incarnation) WHERE run_id = $1 AND scope = $2 ORDER BY ordinal ASC`), [runId, scope]);
|
|
39
39
|
return rows.map((r) => {
|
|
40
40
|
const callKey = String(r.call_key);
|
|
41
41
|
return journalEntryOfCell(runId, callKey, r.result, `workflow_journal.result for run ${runId} entry ${callKey}`);
|
|
@@ -69,10 +69,10 @@ export class SqlWorkflowJournalStore {
|
|
|
69
69
|
return row !== undefined && row.ordinal === ordinal && row.resultJson !== null ? row.resultJson : undefined;
|
|
70
70
|
}
|
|
71
71
|
async readRows(runId, scope, from, limit, inlineBytes) {
|
|
72
|
-
const params = this.db.dialect === "
|
|
72
|
+
const params = this.db.dialect === "mysql"
|
|
73
73
|
? [inlineBytes, runId, scope, from, limit]
|
|
74
74
|
: [runId, scope, inlineBytes, from, limit];
|
|
75
|
-
const { rows } = await this.db.query(this.q(`SELECT ordinal, call_key, CASE WHEN LENGTH(result) > ? THEN NULL ELSE ${jsonColumnTextExpr("
|
|
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
78
|
async deleteByRun(runId) {
|
|
@@ -57,8 +57,8 @@ export class SqlWorkflowRunStore {
|
|
|
57
57
|
this.db = db;
|
|
58
58
|
this.onWarn = onWarn;
|
|
59
59
|
}
|
|
60
|
-
q(
|
|
61
|
-
return this.db.dialect === "
|
|
60
|
+
q(mysql, pg) {
|
|
61
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
62
62
|
}
|
|
63
63
|
async put(id, run) {
|
|
64
64
|
const stored = { ...withRedactedError(run), id, rev: run.rev ?? 0 };
|
|
@@ -73,7 +73,7 @@ export class SqlWorkflowRunStore {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
async get(id) {
|
|
76
|
-
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("
|
|
76
|
+
const { rows } = await this.db.query(this.q(`SELECT ${jsonColumnText("mysql", "run")}, rev FROM workflow_run WHERE id = ?`, `SELECT ${jsonColumnText("pg", "run")}, rev FROM workflow_run WHERE id = $1`), [id]);
|
|
77
77
|
const r = rows[0];
|
|
78
78
|
if (!r)
|
|
79
79
|
return null;
|
|
@@ -100,7 +100,7 @@ export class SqlWorkflowRunStore {
|
|
|
100
100
|
const params = [scope];
|
|
101
101
|
let where;
|
|
102
102
|
let limit = "";
|
|
103
|
-
if (this.db.dialect === "
|
|
103
|
+
if (this.db.dialect === "mysql") {
|
|
104
104
|
where = "scope = ?";
|
|
105
105
|
if (opts?.status !== undefined) {
|
|
106
106
|
where += " AND status = ?";
|
|
@@ -160,9 +160,9 @@ export class SqlWorkflowRunStore {
|
|
|
160
160
|
}
|
|
161
161
|
if (doomed.length === 0)
|
|
162
162
|
return 0;
|
|
163
|
-
const res = await this.db.query(this.q(`DELETE FROM workflow_run WHERE scope = ? AND id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_run WHERE scope = $1 AND id = ANY($2::text[])"), this.db.dialect === "
|
|
164
|
-
await this.db.query(this.q(`DELETE FROM workflow_agent_session WHERE scope = ? AND run_id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_agent_session WHERE scope = $1 AND run_id = ANY($2::text[])"), this.db.dialect === "
|
|
165
|
-
await this.db.query(this.q(`DELETE FROM workflow_park_decision WHERE run_id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_park_decision WHERE run_id = ANY($1::text[])"), this.db.dialect === "
|
|
163
|
+
const res = await this.db.query(this.q(`DELETE FROM workflow_run WHERE scope = ? AND id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_run WHERE scope = $1 AND id = ANY($2::text[])"), this.db.dialect === "mysql" ? [scope, ...doomed] : [scope, doomed]);
|
|
164
|
+
await this.db.query(this.q(`DELETE FROM workflow_agent_session WHERE scope = ? AND run_id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_agent_session WHERE scope = $1 AND run_id = ANY($2::text[])"), this.db.dialect === "mysql" ? [scope, ...doomed] : [scope, doomed]);
|
|
165
|
+
await this.db.query(this.q(`DELETE FROM workflow_park_decision WHERE run_id IN (${doomed.map(() => "?").join(",")})`, "DELETE FROM workflow_park_decision WHERE run_id = ANY($1::text[])"), this.db.dialect === "mysql" ? [...doomed] : [doomed]);
|
|
166
166
|
return res.affected;
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -175,8 +175,8 @@ export class SqlWorkflowCompletionInbox {
|
|
|
175
175
|
this.db = db;
|
|
176
176
|
this.onWarn = onWarn;
|
|
177
177
|
}
|
|
178
|
-
q(
|
|
179
|
-
return this.db.dialect === "
|
|
178
|
+
q(mysql, pg) {
|
|
179
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
180
180
|
}
|
|
181
181
|
async sweepFences(now) {
|
|
182
182
|
await this.db.query(this.q("DELETE FROM workflow_inbox_fence WHERE until_ms < ?", "DELETE FROM workflow_inbox_fence WHERE until_ms < $1"), [now]);
|
|
@@ -213,7 +213,7 @@ export class SqlWorkflowCompletionInbox {
|
|
|
213
213
|
}
|
|
214
214
|
const over = await this.db.query(this.q("SELECT seq, run_id FROM workflow_completion_inbox WHERE session_id = ? ORDER BY seq DESC LIMIT 100000 OFFSET ?", "SELECT seq, run_id FROM workflow_completion_inbox WHERE session_id = $1 ORDER BY seq DESC OFFSET $2"), [entry.sessionId, MAX_PENDING_PER_SESSION]);
|
|
215
215
|
if (over.rows.length > 0) {
|
|
216
|
-
await this.db.query(this.q(`DELETE FROM workflow_completion_inbox WHERE session_id = ? AND seq IN (${over.rows.map(() => "?").join(",")})`, "DELETE FROM workflow_completion_inbox WHERE session_id = $1 AND seq = ANY($2::bigint[])"), this.db.dialect === "
|
|
216
|
+
await this.db.query(this.q(`DELETE FROM workflow_completion_inbox WHERE session_id = ? AND seq IN (${over.rows.map(() => "?").join(",")})`, "DELETE FROM workflow_completion_inbox WHERE session_id = $1 AND seq = ANY($2::bigint[])"), this.db.dialect === "mysql" ? [entry.sessionId, ...over.rows.map((r) => r.seq)] : [entry.sessionId, over.rows.map((r) => r.seq)]);
|
|
217
217
|
for (const r of over.rows)
|
|
218
218
|
this.onWarn?.("workflow_completion_inbox_overflow", { sessionId: entry.sessionId, droppedRunId: String(r.run_id) });
|
|
219
219
|
}
|
|
@@ -243,7 +243,7 @@ export class SqlWorkflowCompletionInbox {
|
|
|
243
243
|
await this.sweepFences(now);
|
|
244
244
|
await this.db.query(this.q("INSERT INTO workflow_inbox_fence (session_id, kind, run_id, owner, owner_known, until_ms) VALUES (?,?,?,?,?,?) " +
|
|
245
245
|
"ON DUPLICATE KEY UPDATE owner = VALUES(owner), owner_known = VALUES(owner_known), until_ms = VALUES(until_ms)", "INSERT INTO workflow_inbox_fence (session_id, kind, run_id, owner, owner_known, until_ms) VALUES ($1,$2,'',$3,$4,$5) " +
|
|
246
|
-
"ON CONFLICT (session_id, kind, run_id) DO UPDATE SET owner = EXCLUDED.owner, owner_known = EXCLUDED.owner_known, until_ms = EXCLUDED.until_ms"), this.db.dialect === "
|
|
246
|
+
"ON CONFLICT (session_id, kind, run_id) DO UPDATE SET owner = EXCLUDED.owner, owner_known = EXCLUDED.owner_known, until_ms = EXCLUDED.until_ms"), this.db.dialect === "mysql"
|
|
247
247
|
? [sessionId, KIND_PURGE, "", purgedOwner ?? null, purgedOwner !== undefined ? 1 : 0, now + PURGE_FENCE_MS]
|
|
248
248
|
: [sessionId, KIND_PURGE, purgedOwner ?? null, purgedOwner !== undefined ? 1 : 0, now + PURGE_FENCE_MS]);
|
|
249
249
|
await this.db.query(this.q("DELETE FROM workflow_completion_inbox WHERE session_id = ?", "DELETE FROM workflow_completion_inbox WHERE session_id = $1"), [sessionId]);
|
|
@@ -263,8 +263,8 @@ export class SqlWorkflowNotifyJournalStore {
|
|
|
263
263
|
constructor(db) {
|
|
264
264
|
this.db = db;
|
|
265
265
|
}
|
|
266
|
-
q(
|
|
267
|
-
return this.db.dialect === "
|
|
266
|
+
q(mysql, pg) {
|
|
267
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
268
268
|
}
|
|
269
269
|
async record(input) {
|
|
270
270
|
await this.db.query(this.q("INSERT IGNORE INTO workflow_notify_journal (run_id, scope, acked, source_task_id, principal, created_at_ms) VALUES (?,?,0,?,?,?)", "INSERT INTO workflow_notify_journal (run_id, scope, acked, source_task_id, principal, created_at_ms) VALUES ($1,$2,0,$3,$4,$5) ON CONFLICT (run_id) DO NOTHING"), [input.runId, input.scope, input.sourceTaskId ?? null, input.principal ?? null, input.createdAt]);
|
|
@@ -308,8 +308,8 @@ export class SqlWorkflowAgentSessionIndex {
|
|
|
308
308
|
constructor(db) {
|
|
309
309
|
this.db = db;
|
|
310
310
|
}
|
|
311
|
-
q(
|
|
312
|
-
return this.db.dialect === "
|
|
311
|
+
q(mysql, pg) {
|
|
312
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
313
313
|
}
|
|
314
314
|
async ensurePointers(_runId, rows) {
|
|
315
315
|
for (const r of rows) {
|
|
@@ -335,8 +335,8 @@ export class SqlWorkflowParkDecisionStore {
|
|
|
335
335
|
constructor(claims) {
|
|
336
336
|
this.claims = claims;
|
|
337
337
|
}
|
|
338
|
-
q(
|
|
339
|
-
return this.claims.db.dialect === "
|
|
338
|
+
q(mysql, pg) {
|
|
339
|
+
return this.claims.db.dialect === "mysql" ? mysql : pg;
|
|
340
340
|
}
|
|
341
341
|
async record(d) {
|
|
342
342
|
const fenced = await this.claims.whileHoldingClaim(d.hostSessionId, d.deliveredTaskId, async (tx) => {
|
|
@@ -347,12 +347,12 @@ export class SqlWorkflowParkDecisionStore {
|
|
|
347
347
|
return fenced.held;
|
|
348
348
|
}
|
|
349
349
|
async get(token) {
|
|
350
|
-
const { rows } = await this.claims.db.query(this.q(`SELECT token, run_id, host_session_id, ${jsonColumnText("
|
|
350
|
+
const { rows } = await this.claims.db.query(this.q(`SELECT token, run_id, host_session_id, ${jsonColumnText("mysql", "outcome")}, fingerprint, delivered_task_id, accepted_at_ms FROM workflow_park_decision WHERE token = ?`, `SELECT token, run_id, host_session_id, ${jsonColumnText("pg", "outcome")}, fingerprint, delivered_task_id, accepted_at_ms FROM workflow_park_decision WHERE token = $1`), [token]);
|
|
351
351
|
const r = rows[0];
|
|
352
352
|
return r ? rowToParkDecision(r) : null;
|
|
353
353
|
}
|
|
354
354
|
async listByHostSession(hostSessionId) {
|
|
355
|
-
const { rows } = await this.claims.db.query(this.q(`SELECT token, run_id, host_session_id, ${jsonColumnText("
|
|
355
|
+
const { rows } = await this.claims.db.query(this.q(`SELECT token, run_id, host_session_id, ${jsonColumnText("mysql", "outcome")}, fingerprint, delivered_task_id, accepted_at_ms FROM workflow_park_decision WHERE host_session_id = ?`, `SELECT token, run_id, host_session_id, ${jsonColumnText("pg", "outcome")}, fingerprint, delivered_task_id, accepted_at_ms FROM workflow_park_decision WHERE host_session_id = $1`), [hostSessionId]);
|
|
356
356
|
return rows.map(rowToParkDecision);
|
|
357
357
|
}
|
|
358
358
|
}
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
35
35
|
import type { Pool as PgPool } from "pg";
|
|
36
36
|
import { type AlignedWindow } from "../observability/cost-quota.js";
|
|
37
|
+
import type { SqlDialect } from "./sql-driver.js";
|
|
37
38
|
export interface CounterTable {
|
|
38
39
|
/** Table name; must have columns (<keyCol>, window_bucket BIGINT, <valCol>, updated_at). */
|
|
39
40
|
table: string;
|
|
@@ -56,7 +57,6 @@ export type CounterDegradeHook = (info: CounterDegradeInfo) => void;
|
|
|
56
57
|
* flush round forever; the stalled watchdog can then only report, not recover). The rejection lands in
|
|
57
58
|
* the existing flush/refresh catch → the S9 streak telemetry counts it; the round ENDS and retries. */
|
|
58
59
|
export declare const DEFAULT_COUNTER_QUERY_TIMEOUT_MS = 30000;
|
|
59
|
-
type CounterDialect = "tidb" | "pg";
|
|
60
60
|
/** Dual-dialect write-behind aggregating counter. See the file header for the dialect-delta ledger. */
|
|
61
61
|
export declare class SqlWriteBehindCounter {
|
|
62
62
|
private readonly dialect;
|
|
@@ -73,7 +73,7 @@ export declare class SqlWriteBehindCounter {
|
|
|
73
73
|
private flushing;
|
|
74
74
|
private flushStartedAt;
|
|
75
75
|
private failStreak;
|
|
76
|
-
constructor(dialect:
|
|
76
|
+
constructor(dialect: SqlDialect, pool: MySqlPool | PgPool, t: CounterTable,
|
|
77
77
|
/** 🔴 不再 `readonly`([ref]):`costQuotaWindowSec` 热更新经 {@link setWindowMs} 换代,语义见那里。 */
|
|
78
78
|
windowMs: number, now?: () => number, onDegraded?: CounterDegradeHook | undefined, // S9: observability tap — never affects counting
|
|
79
79
|
queryTimeoutMs?: number);
|
|
@@ -135,5 +135,4 @@ export declare class WriteBehindCounter extends SqlWriteBehindCounter {
|
|
|
135
135
|
export declare class PgWriteBehindCounter extends SqlWriteBehindCounter {
|
|
136
136
|
constructor(pool: PgPool, t: CounterTable, windowMs: number, now?: () => number, onDegraded?: CounterDegradeHook, queryTimeoutMs?: number);
|
|
137
137
|
}
|
|
138
|
-
export {};
|
|
139
138
|
//# sourceMappingURL=write-behind-counter.d.ts.map
|
|
@@ -25,7 +25,7 @@ export class SqlWriteBehindCounter {
|
|
|
25
25
|
this.queryTimeoutMs = queryTimeoutMs;
|
|
26
26
|
}
|
|
27
27
|
async exec(sql, params) {
|
|
28
|
-
if (this.dialect === "
|
|
28
|
+
if (this.dialect === "mysql") {
|
|
29
29
|
const [r] = (await this.pool.query({ sql, timeout: this.queryTimeoutMs }, params));
|
|
30
30
|
if (Array.isArray(r))
|
|
31
31
|
return { rows: r, affected: 0 };
|
|
@@ -92,7 +92,7 @@ export class SqlWriteBehindCounter {
|
|
|
92
92
|
}
|
|
93
93
|
async flushOnce() {
|
|
94
94
|
const { table, keyCol, valCol } = this.t;
|
|
95
|
-
const sql = this.dialect === "
|
|
95
|
+
const sql = this.dialect === "mysql"
|
|
96
96
|
? `INSERT INTO ${table} (${keyCol}, window_bucket, ${valCol}, updated_at) VALUES (?,?,?,?) ` +
|
|
97
97
|
`ON DUPLICATE KEY UPDATE ${valCol} = ${valCol} + VALUES(${valCol}), updated_at = VALUES(updated_at)`
|
|
98
98
|
: `INSERT INTO ${table} (${keyCol}, window_bucket, ${valCol}, updated_at) VALUES ($1,$2,$3,$4) ` +
|
|
@@ -129,7 +129,7 @@ export class SqlWriteBehindCounter {
|
|
|
129
129
|
const { table, keyCol, valCol } = this.t;
|
|
130
130
|
const b = this.bucket();
|
|
131
131
|
try {
|
|
132
|
-
const { rows } = await this.exec(this.dialect === "
|
|
132
|
+
const { rows } = await this.exec(this.dialect === "mysql"
|
|
133
133
|
? `SELECT ${keyCol}, ${valCol} FROM ${table} WHERE window_bucket = ?`
|
|
134
134
|
: `SELECT ${keyCol}, ${valCol} FROM ${table} WHERE window_bucket = $1`, [b]);
|
|
135
135
|
const next = new Map();
|
|
@@ -145,7 +145,7 @@ export class SqlWriteBehindCounter {
|
|
|
145
145
|
}
|
|
146
146
|
async reap() {
|
|
147
147
|
try {
|
|
148
|
-
const { affected } = await this.exec(this.dialect === "
|
|
148
|
+
const { affected } = await this.exec(this.dialect === "mysql"
|
|
149
149
|
? `DELETE FROM ${this.t.table} WHERE window_bucket < ?`
|
|
150
150
|
: `DELETE FROM ${this.t.table} WHERE window_bucket < $1`, [this.bucket()]);
|
|
151
151
|
this.bump("reap", false);
|
|
@@ -175,7 +175,7 @@ export class SqlWriteBehindCounter {
|
|
|
175
175
|
}
|
|
176
176
|
export class WriteBehindCounter extends SqlWriteBehindCounter {
|
|
177
177
|
constructor(pool, t, windowMs, now, onDegraded, queryTimeoutMs) {
|
|
178
|
-
super("
|
|
178
|
+
super("mysql", pool, t, windowMs, now, onDegraded, queryTimeoutMs);
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
export class PgWriteBehindCounter extends SqlWriteBehindCounter {
|
|
@@ -5,24 +5,26 @@
|
|
|
5
5
|
* task opts in, a budget/turns/walltime limit OR a scheduler preempt durably SUSPENDS the task (resumable via
|
|
6
6
|
* `POST /v1/assistant/tasks/:id/resume`) instead of FAILING; absent ⇒ a limit still FAILS.
|
|
7
7
|
*
|
|
8
|
-
* 🔴 EXCLUDE
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* remote VM — ORPHANING both (the run row is
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
8
|
+
* 🔴 EXCLUDE cascade tasks. Core runs a cascade through `runCascade`, which maps a rung's durable suspend to a FAILED
|
|
9
|
+
* result carrying the pause (`errorCode: "unexpected.suspended"`, 内层 status "needs_review" 时铸 `"unexpected.needs_review"`,
|
|
10
|
+
* 停驻因由在 `terminal.nestedPause` —— 真源是 core `agents/suspend-guard.js` 的 `mapNestedSuspend`;`suspended.*` 三码是 bg
|
|
11
|
+
* 子代/委派报告面的词,不落在这条 TaskResult 腿上). A rung's pause lands on the rung's own engine-minted session, which the
|
|
12
|
+
* host-boundary judge (`atHostBoundary`, src/terminal.ts) leaves terminal: the service would `setTerminal(failed)` while core
|
|
13
|
+
* had already minted a pending `resource_limit` checkpoint + suspended the remote VM — ORPHANING both (the run row is
|
|
14
|
+
* terminal, so nothing resumes them). A resource-limit hit on a cascade task must FAIL CLEANLY (no suspend).
|
|
15
|
+
* (Cross review wtyc7ist3 HIGH finding: without this, enabling RESOURCE_SUSPEND leaks a suspended VM + checkpoint on every
|
|
16
|
+
* cascade task that hits a resource limit.) The arm is the judge's session cell seen from the opt-in side: the day the engine
|
|
17
|
+
* lets a rung's pause land on a session the host's resume chain reaches (core [ref]), the judge's answer flips and this arm goes.
|
|
18
|
+
* Every other task — a verify task included — opts in alike. A verify task's implementation leg and fix rounds run on the
|
|
19
|
+
* run's own session, so the judge lifts their pause into a park of the run row (resumable through
|
|
20
|
+
* `POST /v1/assistant/tasks/:id/resume`); the verifier's own leg is built by the engine without an opt-in, so a limit there
|
|
21
|
+
* still fails that leg.
|
|
18
22
|
*/
|
|
19
23
|
export declare function resourceSuspendOptIn(opts: {
|
|
20
24
|
/** `RESOURCE_SUSPEND=true` (the worker-level switch). */
|
|
21
25
|
enabled: boolean;
|
|
22
26
|
/** `RESOURCE_SUSPEND_TTL_SEC` — 0 ⇒ core default (30d) by omitting `ttlMs`. */
|
|
23
27
|
ttlSec: number;
|
|
24
|
-
/** This task requested the developer-mode verify gate (`body.verify === true`). */
|
|
25
|
-
isVerify: boolean;
|
|
26
28
|
/** This task requested the cascade ladder (`body.cascade === true`). */
|
|
27
29
|
isCascade: boolean;
|
|
28
30
|
/** Multi-tenant isolation key — the SAME key durableApproval uses (the principal; "_" when auth is off). */
|
package/dist/resource-suspend.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 【两半各自的真源(刻意不自建第三本账)】
|
|
10
10
|
* · **上限半**:本模块的进程内登记册 —— 记的是**这条 run 真正铸给 core 的那只 `resourceSuspend`**
|
|
11
11
|
* (装配点 `boot/resolve-spec.ts` 的 `resourceSuspendOptIn`),不是读时现取 env。差别是承重的:
|
|
12
|
-
* ①
|
|
12
|
+
* ① cascade 腿被 `resourceSuspendOptIn` **整只排除**(opt-in 不成立)⇒ 登记册里没有它 ⇒
|
|
13
13
|
* 整键缺席,绝不显示一个没人执行的天花板;② 滚动改 env 之后,已在跑的 run 报的仍是它自己那份。
|
|
14
14
|
* · **已耗半**:run 自己的 durable 账本行 `model_usage`(`trace/project.ts` 的 `aggregateModelUsage`)——
|
|
15
15
|
* 与 `TaskStats.modelUsage` 回声**同一份账**,append-only、跨 slice、跨进程(每条腿只追加自己的
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* core 的 `spentTokens` 轴 = 每片 `TaskStats.tokens`(= Σ 每次调用 `usage.totalTokens`,**不含**委派子代,
|
|
22
22
|
* 子代在 `stats.nested`),而 `model_usage` 行正是同一批 `brain.call` 的逐 turn delta、同样只收顶层 run。
|
|
23
23
|
* 已知差:① **滞后至多一个 turn**(delta 在 turn 边界 drain,进行中的那一 turn 还没入账);② 账本行
|
|
24
|
-
* 写失败(F 类)
|
|
24
|
+
* 写失败(F 类)会少计;③ 只回结果的组合腿(verify)没有逐 turn 落账的流,`model_usage` 行只在停驻 / 终局那一拍写 ⇒
|
|
25
|
+
* running 期读到的是上一次停驻时的量,滞后**一整片**(钉:`test/resource-suspend.test.ts` 的 🚧 格)。⇒ 本投影是**分诊/预警**读面,**不是**任何门/CAS/resume 判定的输入。
|
|
25
26
|
*
|
|
26
27
|
* 【登记册的语义边界(与 `turn-activity.ts` 的 `msSinceLastActivity` 逐字同族)】
|
|
27
28
|
* · **同副本 best-effort**:只活在本进程。跨副本 poll(run 跑在别的副本)或本副本重启后 ⇒ 读不到 ⇒
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
* 【已声明的代价:每次 poll 一次全量账本读(codex 交叉复审 R2-[medium],如实登记、本批不修)】
|
|
35
36
|
* {@link buildCrossSliceUsage} 要对**全部** `model_usage` 行求和 ⇒ 调用点(`routes/runs.ts` 的 poll)在
|
|
36
37
|
* 窗已登记时每拍读一次 `getEvents(taskId, 0)`,工作量随「轮询次数 × 已积累事件数」增长。三条限幅是**结构性**
|
|
37
|
-
* 的,不是「应该很少见」:① **只有登记过窗的 run 才读**(没开三旋钮的部署、以及
|
|
38
|
+
* 的,不是「应该很少见」:① **只有登记过窗的 run 才读**(没开三旋钮的部署、以及 cascade 腿,一次都不读);
|
|
38
39
|
* ② 只在 `running` 且非 stale 时读;③ 同一条路上早已存在同形读(终局 + 配了 infra 价目表时的 `needCost` 臂,
|
|
39
40
|
* 同样是 `getEvents(taskId, 0)`)—— 本批加的是**跑动期**这一档,不是新病种。
|
|
40
41
|
* 🔴 真正的收口在**存储面**(不在本模块):给 run store 加一条「累计用量 + resource_limit park 计数」的
|
package/dist/run-local.js
CHANGED
|
@@ -25,13 +25,13 @@ import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
|
|
|
25
25
|
import { configLocalRoot, createConfigProvider } from "./config-provider.js";
|
|
26
26
|
import { CONFIG_DOMAIN_INVALID_NOTE, buildCandidateRejectedFields, judgeConfigCandidate } from "./web-admin-client/candidate-gate.js";
|
|
27
27
|
import { buildUnreadConfigFileFields, buildUnreadConfigKeyFields } from "./web-admin-client/read-warnings.js";
|
|
28
|
-
import { composeExecutionLane, settleHostLaneShell } from "./boot/execution-lane.js";
|
|
28
|
+
import { composeExecutionLane, settleHostLaneShell, warnReadDenyFloorUnkept } from "./boot/execution-lane.js";
|
|
29
29
|
import { judgeConsolidationValve } from "./boot/memory-consolidation.js";
|
|
30
30
|
import { logConfigDirMigration, migrateLocalConfigDirectory } from "./config-d-migration.js";
|
|
31
31
|
import { assertLocalConfigDirTrusted, ConfigDirUntrustedError } from "./config-dir-trust.js";
|
|
32
32
|
import { applyEffective, applyCenterReadFace, applySkillsManifest, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./web-admin-client/facade.js";
|
|
33
33
|
import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
|
|
34
|
-
import {
|
|
34
|
+
import { buildLaneHomeClaim, executionLaneOf } from "./execution-lane-caps.js";
|
|
35
35
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "./project-memory.js";
|
|
36
36
|
import { createInstructionSourceSeat } from "./instruction-source-notice.js";
|
|
37
37
|
import { loadDeploymentSkills } from "./capabilities/skills.js";
|
|
@@ -42,12 +42,13 @@ import { createTaskListLane } from "./boot/task-list-lane.js";
|
|
|
42
42
|
import { pickHandsRunner, withoutHands } from "./capabilities/hands-lane.js";
|
|
43
43
|
import { HttpError, sessionIdShapeIssue } from "./security.js";
|
|
44
44
|
import { createMemoryEngineIncidentSink } from "./memory-incident-sink.js";
|
|
45
|
-
import { fileMemoryEngineRoot, memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
|
|
45
|
+
import { fileMemoryEngineRoot, memoryEngineBackendFor, memoryLayersNamedBy, memorySpecForRequest } from "./memory-scope.js";
|
|
46
|
+
import { createMemoryScopeStores } from "./memory-scope-stores.js";
|
|
46
47
|
import { createMemoryProjectLayers } from "./memory-project-layer.js";
|
|
47
48
|
import { assertProjectLayerOwnable } from "./project-identity.js";
|
|
48
49
|
import { declaredCredential } from "./model-route-gap.js";
|
|
49
50
|
import { judgeServedModelRoute } from "./model-route-endpoint.js";
|
|
50
|
-
import {
|
|
51
|
+
import { startMemorySyncRunner } from "./memory-sync-client.js";
|
|
51
52
|
import { buildPricing, cappedCeiling, createTracer } from "./budget.js";
|
|
52
53
|
import { createSharedRunnerDeps } from "./boot/runner-deps.js";
|
|
53
54
|
import { createPeerDesk } from "./peer-seat.js";
|
|
@@ -472,17 +473,22 @@ export async function runLocal(argv, deps = {}) {
|
|
|
472
473
|
const hostRx = config.remoteExec?.provider === "host" ? config.remoteExec : undefined;
|
|
473
474
|
const workspaceDir = args.workspace ?? hostRx?.workspaceBase ?? process.cwd();
|
|
474
475
|
await settleHostLaneShell(config, logger);
|
|
476
|
+
warnReadDenyFloorUnkept(config, logger);
|
|
477
|
+
const homeDirSeat = buildLaneHomeClaim(config);
|
|
475
478
|
const executionEnvFactory = hostRx
|
|
476
479
|
? hostExecutionEnvFactory({
|
|
477
480
|
workspaceDir,
|
|
478
|
-
...
|
|
481
|
+
...homeDirSeat,
|
|
479
482
|
backgroundShell: config.requirePrincipal !== true,
|
|
480
483
|
...(hostRx.commandTimeoutMs != null ? { commandTimeoutMs: hostRx.commandTimeoutMs } : {}),
|
|
481
484
|
})
|
|
482
485
|
: undefined;
|
|
483
486
|
const lspManager = hostRx && config.lspHostEnabled && config.requirePrincipal !== true ? createHostLspManager(config, (event, fields) => logger.info(event, fields)) : undefined;
|
|
484
|
-
const memoryEngine = memoryEngineBackendFor(config, root, memoryEngineIncident);
|
|
485
487
|
const engineDataRoot = fileMemoryEngineRoot(config, root);
|
|
488
|
+
const fileEngine = memoryEngineBackendFor(config, root, memoryEngineIncident);
|
|
489
|
+
const memoryEngine = fileEngine !== undefined
|
|
490
|
+
? createMemoryScopeStores({ backend: fileEngine.backend, root: engineDataRoot, namedLayers: () => memoryLayersNamedBy({ ...config, memoryScope: args.user ?? "local" }), onIncident: memoryEngineIncident })
|
|
491
|
+
: undefined;
|
|
486
492
|
try {
|
|
487
493
|
judgeConsolidationValve({ config, memoryEngine });
|
|
488
494
|
}
|
|
@@ -494,18 +500,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
494
500
|
}
|
|
495
501
|
let memorySync;
|
|
496
502
|
if (config.memorySync && memoryEngine) {
|
|
497
|
-
|
|
498
|
-
memorySync = createMemorySyncRunner({
|
|
499
|
-
backend: memoryEngine.backend,
|
|
500
|
-
scope: config.memorySync.scope,
|
|
501
|
-
memoryRoot: memoryEngine.root,
|
|
502
|
-
transport,
|
|
503
|
-
log: logger,
|
|
504
|
-
...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
|
|
505
|
-
...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
|
|
506
|
-
});
|
|
507
|
-
logger.info("memory_sync_enabled", buildMemorySyncEnabledFields(transport.peer, config.memorySync.scope, memorySync.cursorPathFor(config.memorySync.scope)));
|
|
508
|
-
memorySync.trigger("boot");
|
|
503
|
+
memorySync = startMemorySyncRunner({ sync: config.memorySync, stores: memoryEngine, log: logger });
|
|
509
504
|
}
|
|
510
505
|
else if (config.memorySync) {
|
|
511
506
|
logger.warn("memory_sync_configured_but_memory_dark", { note: "MEMORY_SYNC_URL is set but the file memory engine is dark (MEMORY_ENGINE=off / remote exec lane) — no sync rounds will run" });
|
|
@@ -687,7 +682,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
687
682
|
}
|
|
688
683
|
}
|
|
689
684
|
const projectKey = memoryEngine
|
|
690
|
-
? await createMemoryProjectLayers({
|
|
685
|
+
? await createMemoryProjectLayers({ stores: memoryEngine, syncRunner: memorySync, log: logger }).prepare(config, scope, workspaceDir)
|
|
691
686
|
: undefined;
|
|
692
687
|
const taskTimeoutSec = Math.floor(parseNumOrFailNonNegative("TASK_TIMEOUT_SEC", process.env.TASK_TIMEOUT_SEC || "0"));
|
|
693
688
|
const timeoutSec = taskWallClockSec(taskTimeoutSec, false);
|
package/dist/runs.d.ts
CHANGED
|
@@ -263,10 +263,14 @@ export declare function graftParkToolCallId<T>(result: T, cs: ParkCheckpointRead
|
|
|
263
263
|
* Preemption (POST /v1/assistant/tasks/:id/preempt, [ref] seam #2): a SECOND, INDEPENDENT controller
|
|
264
264
|
* (`preemptCtrl`, registered in `preemptable`) carries the scheduler's graceful "yield this task" — when raised,
|
|
265
265
|
* core durably SUSPENDS the task at the next clean turn boundary (gate resource_limit, reason "preempt") so it is
|
|
266
|
-
* RESUMABLE, the opposite of cancel's kill. It is wired ONLY on the plain-stream path
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
266
|
+
* RESUMABLE, the opposite of cancel's kill. It is wired ONLY on the plain-stream path. A cascade cannot honor it: a
|
|
267
|
+
* rung's pause lands on the rung's own engine-minted session, which the host's resume chain cannot reach (the
|
|
268
|
+
* host-boundary judge settles it terminal). A verify task carries the resource-suspend opt-in (a budget / turns /
|
|
269
|
+
* walltime limit parks its implementation leg or fix round), but its FIRST slice here is not wired to the preempt
|
|
270
|
+
* signal (`preemptEligible` below is false for verify, so the preempt endpoint answers a no-op for a verify run this
|
|
271
|
+
* replica owns); a RESUMED verify leg is wired (`resume-legs.ts` registers every resume leg in `preemptableRuns` and
|
|
272
|
+
* threads `preemptSignal` into `resumeWithVerification`). Cross-replica via the `preempt_requested` flag (same heartbeat
|
|
273
|
+
* tick). Eligibility (resourceSuspend +
|
|
270
274
|
* durable store + durable tool-results + remote env) is core's call: an ineligible task's preemptSignal no-ops.
|
|
271
275
|
*
|
|
272
276
|
* Steering (POST /v1/runs/:id/steer, [ref]): the live core `TaskStream` is registered in `steerable` so the
|