@sema-agent/server 7.138.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 +457 -7
- package/README.md +7 -4
- package/README.zh-CN.md +6 -4
- package/USAGE.md +91 -41
- package/deploy/sema-up/README.md +1 -1
- package/deploy/sema-up/lib/lanes.json +3 -2
- package/dist/adoption/runner.js +1 -1
- package/dist/adoption/sql.js +1 -1
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +26 -26
- package/dist/bench/s1/arms.d.ts +1 -1
- package/dist/bench/s1/arms.js +1 -3
- 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/bench/s1/run-firm.js +2 -2
- package/dist/boot/adoption.js +1 -1
- package/dist/boot/device-lane.d.ts +8 -3
- package/dist/boot/device-lane.js +7 -2
- package/dist/boot/execution-env.d.ts +4 -2
- package/dist/boot/execution-env.js +28 -34
- package/dist/boot/execution-lane.d.ts +9 -1
- package/dist/boot/execution-lane.js +6 -1
- package/dist/boot/governance-seams.d.ts +3 -2
- package/dist/boot/governance-seams.js +9 -11
- 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 +25 -14
- package/dist/boot/resolve-spec.d.ts +4 -6
- package/dist/boot/resolve-spec.js +10 -13
- package/dist/boot/retention-lane.d.ts +5 -5
- package/dist/boot/retention-lane.js +0 -6
- package/dist/boot/runner-deps.d.ts +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.d.ts +0 -3
- package/dist/boot/session-faces.js +15 -8
- package/dist/boot/stage-02-web-admin-pull.js +2 -2
- 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-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +2 -6
- package/dist/boot/stage-06-runners.js +2 -3
- 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-09-leader.js +1 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -6
- package/dist/boot/stage-10-http-server.js +7 -6
- 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 +37 -11
- package/dist/capabilities/execution-lane.d.ts +2 -2
- package/dist/capabilities/mcp-probe.js +1 -1
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capability-facts.d.ts +15 -7
- package/dist/capability-facts.js +8 -3
- package/dist/config-catalog.js +9 -8
- package/dist/config-invariants.d.ts +23 -3
- package/dist/config-invariants.js +42 -0
- package/dist/config-provider.d.ts +33 -37
- package/dist/config-provider.js +51 -30
- package/dist/config-types.d.ts +21 -7
- package/dist/config.d.ts +33 -0
- package/dist/config.js +46 -16
- package/dist/delegated-session-owner.d.ts +4 -3
- package/dist/delegated-session-owner.js +1 -1
- package/dist/deployment-shape.d.ts +10 -9
- package/dist/deployment-shape.js +4 -4
- package/dist/device-enrollment.d.ts +41 -2
- package/dist/device-enrollment.js +27 -12
- package/dist/device-store.d.ts +58 -85
- package/dist/device-store.js +19 -49
- package/dist/device-ws-hub.js +2 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -4
- package/dist/exec-cut.d.ts +60 -0
- package/dist/exec-cut.js +36 -0
- package/dist/execution-lane-caps.d.ts +115 -105
- package/dist/execution-lane-caps.js +76 -82
- package/dist/execution-placement.d.ts +259 -0
- package/dist/execution-placement.js +199 -0
- package/dist/field-conflict.d.ts +3 -2
- package/dist/field-conflict.js +1 -0
- package/dist/hosted-posture.d.ts +2 -2
- package/dist/http/admission.js +8 -19
- package/dist/http/checkpoint-ctx.d.ts +21 -12
- package/dist/http/checkpoint-ctx.js +4 -2
- package/dist/http/claimed-run.d.ts +1 -1
- package/dist/http/durable-run-leg.js +9 -5
- package/dist/http/execution-context.d.ts +218 -0
- package/dist/http/execution-context.js +330 -0
- 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 +63 -36
- package/dist/http/retired-service-deps.d.ts +1 -1
- package/dist/http/retired-service-deps.js +1 -1
- package/dist/http/route-ctx.d.ts +14 -8
- package/dist/http/routes/adoption.js +1 -1
- package/dist/http/routes/background.d.ts +29 -1
- package/dist/http/routes/background.js +29 -2
- package/dist/http/routes/devices.d.ts +13 -19
- package/dist/http/routes/devices.js +21 -26
- 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/session-sync.js +110 -15
- package/dist/http/routes/sessions.d.ts +6 -0
- package/dist/http/routes/sessions.js +143 -22
- package/dist/http/routes/side-query.d.ts +12 -4
- package/dist/http/routes/side-query.js +4 -5
- package/dist/http/routes/tasks.js +41 -33
- package/dist/http/server.d.ts +40 -44
- package/dist/http/server.js +13 -2
- package/dist/http/session-inherit-env.d.ts +3 -4
- package/dist/http/session-inherit-env.js +1 -1
- package/dist/http/wire-types.d.ts +8 -12
- package/dist/identity-source.d.ts +1 -1
- package/dist/identity-source.js +1 -1
- package/dist/index.d.ts +1 -0
- 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 +70 -18
- package/dist/memory-sync-client.js +215 -117
- package/dist/memory-sync.d.ts +1 -1
- package/dist/memory-sync.js +3 -2
- package/dist/observability/cost-taxonomy.d.ts +2 -2
- package/dist/observability/fail-open.d.ts +12 -0
- package/dist/observability/fail-open.js +12 -0
- package/dist/observability/run-terminal.js +0 -1
- package/dist/orchestration/workflow-notify-journal.js +4 -4
- package/dist/org-memory-admission.d.ts +4 -3
- package/dist/org-memory-admission.js +6 -6
- package/dist/parked-decide.d.ts +34 -9
- package/dist/parked-decide.js +12 -19
- package/dist/parked-revive-surface.d.ts +12 -15
- package/dist/parked-revive-surface.js +3 -6
- package/dist/peer-seat.d.ts +13 -7
- package/dist/peer-seat.js +37 -3
- package/dist/plugins/adoption-log-sql.js +4 -4
- package/dist/plugins/approval-ask-store-file.d.ts +7 -0
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
- package/dist/plugins/approval-ask-store-memory.js +12 -0
- package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
- package/dist/plugins/approval-ask-store-sql.js +44 -26
- 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/caching-session-store.d.ts +6 -2
- package/dist/plugins/caching-session-store.js +9 -3
- package/dist/plugins/checkpoint-index-columns.js +2 -2
- package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
- package/dist/plugins/checkpoint-store-sql.js +21 -23
- package/dist/plugins/device-store-sql.d.ts +25 -51
- package/dist/plugins/device-store-sql.js +68 -122
- package/dist/plugins/ensure-index.d.ts +1 -2
- package/dist/plugins/execution-placement-sql.d.ts +151 -0
- package/dist/plugins/execution-placement-sql.js +223 -0
- package/dist/plugins/file-history-store-sql.d.ts +9 -8
- package/dist/plugins/file-history-store-sql.js +9 -9
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +4 -0
- package/dist/plugins/fork-routing-session-store.d.ts +6 -0
- package/dist/plugins/fork-routing-session-store.js +16 -0
- 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/local-session-store.d.ts +149 -50
- package/dist/plugins/local-session-store.js +382 -107
- 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-key-guards.d.ts +4 -0
- package/dist/plugins/memory-key-guards.js +1 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-sync-store-tidb.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +117 -8
- package/dist/plugins/one-time-migrations.js +408 -38
- package/dist/plugins/org-delivery-quota-store.js +2 -2
- package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
- package/dist/plugins/outcome-ledger-sql.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
- package/dist/plugins/permission-rule-store-sql.js +29 -32
- package/dist/plugins/pg-pool.d.ts +7 -3
- package/dist/plugins/pg-session-storage.d.ts +31 -20
- package/dist/plugins/pg-session-storage.js +120 -52
- package/dist/plugins/remote-env-adb.d.ts +18 -19
- package/dist/plugins/remote-env-adb.js +91 -66
- package/dist/plugins/remote-env-device.d.ts +23 -31
- package/dist/plugins/remote-env-device.js +19 -17
- package/dist/plugins/remote-env-e2b.d.ts +27 -21
- package/dist/plugins/remote-env-e2b.js +91 -45
- package/dist/plugins/remote-env-file-error.d.ts +3 -1
- package/dist/plugins/remote-env-file-error.js +9 -3
- package/dist/plugins/remote-env-host.d.ts +31 -34
- package/dist/plugins/remote-env-host.js +91 -72
- package/dist/plugins/remote-env-k8s.d.ts +13 -29
- package/dist/plugins/remote-env-k8s.js +63 -55
- package/dist/plugins/remote-env-local-docker.d.ts +24 -12
- package/dist/plugins/remote-env-local-docker.js +49 -61
- package/dist/plugins/remote-env-ssh.d.ts +11 -19
- package/dist/plugins/remote-env-ssh.js +74 -57
- package/dist/plugins/remote-shell.d.ts +100 -3
- package/dist/plugins/remote-shell.js +166 -2
- 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 +10 -7
- package/dist/plugins/retention-store-sql.js +13 -7
- package/dist/plugins/run-store-sql.d.ts +13 -3
- package/dist/plugins/run-store-sql.js +20 -15
- package/dist/plugins/schema-consistency.d.ts +21 -11
- package/dist/plugins/schema-consistency.js +15 -9
- package/dist/plugins/schema-drift-sentence.d.ts +27 -0
- package/dist/plugins/schema-drift-sentence.js +38 -0
- 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-fork.d.ts +54 -0
- package/dist/plugins/session-fork.js +38 -1
- package/dist/plugins/session-row-sql.d.ts +22 -0
- package/dist/plugins/session-row-sql.js +81 -0
- package/dist/plugins/session-rules-column.d.ts +1 -1
- package/dist/plugins/session-rules-column.js +1 -1
- package/dist/plugins/session-store.d.ts +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 +5 -7
- package/dist/plugins/store-backend.js +23 -11
- package/dist/plugins/store-contracts.d.ts +25 -5
- package/dist/plugins/task-list-store-sql.js +11 -11
- package/dist/plugins/tidb-pool.d.ts +12 -7
- package/dist/plugins/tidb-pool.js +13 -7
- package/dist/plugins/tidb-session-storage.js +4 -4
- package/dist/plugins/tidb-session-store.d.ts +57 -26
- package/dist/plugins/tidb-session-store.js +127 -59
- package/dist/plugins/tool-result-store-sql.d.ts +5 -4
- package/dist/plugins/tool-result-store-sql.js +21 -13
- 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/project-memory.d.ts +9 -15
- package/dist/project-memory.js +5 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +6 -7
- package/dist/request-value-closure.js +1 -3
- 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.d.ts +6 -0
- package/dist/run-local.js +34 -35
- package/dist/runs.d.ts +10 -5
- package/dist/runs.js +52 -66
- package/dist/security.d.ts +38 -12
- package/dist/security.js +8 -2
- package/dist/server-secret-env.d.ts +9 -5
- package/dist/session-children-retire.d.ts +27 -9
- package/dist/session-children-retire.js +9 -5
- package/dist/session-incarnation.d.ts +20 -10
- package/dist/session-incarnation.js +5 -3
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-row.d.ts +114 -5
- package/dist/session-row.js +55 -5
- package/dist/session-titler.d.ts +2 -2
- 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.d.ts +1 -1
- package/dist/task-a2a.js +5 -6
- package/dist/task-cwd.d.ts +6 -1
- package/dist/task-mcp.d.ts +22 -9
- package/dist/task-mcp.js +17 -9
- package/dist/terminal.d.ts +27 -0
- package/dist/terminal.js +6 -0
- package/dist/tool-approval.d.ts +6 -0
- package/dist/tool-approval.js +8 -1
- package/dist/trace/project.d.ts +1 -0
- package/dist/trace/project.js +1 -0
- package/dist/trace/redact.d.ts +3 -1
- package/dist/trace/redact.js +80 -28
- package/dist/trace/self-minted-wire.d.ts +169 -2
- package/dist/trace/self-minted-wire.js +54 -1
- package/dist/url-refusal.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +17 -3
- package/dist/web-admin-client/apply-effective.js +20 -10
- 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/dist/web-admin-client/skills-mcp.js +3 -2
- package/dist/web-admin-client/types.d.ts +6 -0
- package/package.json +3 -3
- package/wire-changes/server@7.139.0.json +348 -0
- package/wire-changes/server@7.140.0.json +184 -0
- package/dist/http/device-placement.d.ts +0 -175
- package/dist/http/device-placement.js +0 -145
|
@@ -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 {
|
package/dist/project-memory.d.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { type PlatformPath } from "node:path";
|
|
2
|
-
import type { ProjectMemoryLoad } from "@sema-agent/core";
|
|
2
|
+
import type { ProjectMemoryLoad, RunnerDeps } from "@sema-agent/core";
|
|
3
3
|
import { type InstructionSourceSeat } from "./instruction-source-notice.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
handsEnabled: boolean;
|
|
7
|
-
isSubagent: boolean;
|
|
8
|
-
agentName?: string;
|
|
9
|
-
sessionId?: string;
|
|
10
|
-
phase?: "fresh" | "resume" | "post-compact" | "post-clear";
|
|
11
|
-
}
|
|
4
|
+
/** The engine's loader ctx, read from its seat type (one source: a hand-copied twin kept a phase word the engine had retired). */
|
|
5
|
+
type ProjectMemoryCtx = Parameters<NonNullable<RunnerDeps["loadProjectMemory"]>>[0];
|
|
12
6
|
/** The instruction-file name chain: the CLAUDE family first, the AGENTS family only when no CLAUDE file is
|
|
13
7
|
* present. The FIRST hit is the single declared instruction source.
|
|
14
8
|
*
|
|
@@ -37,17 +31,17 @@ export declare function instructionChainCoordinates(absPath: string, p?: Platfor
|
|
|
37
31
|
rel: InstructionChainMember;
|
|
38
32
|
} | null;
|
|
39
33
|
/**
|
|
40
|
-
* Build a `loadProjectMemory` for the host lane.
|
|
41
|
-
* directory. Reads the instruction-file chain (CLAUDE.md → .claude/CLAUDE.md → AGENTS.md → .claude/AGENTS.md, [ref]) + (non-subagent)
|
|
34
|
+
* Build a `loadProjectMemory` for the host lane. Answers `{ content: null }` (skip) unless hands are enabled AND cwd is a
|
|
35
|
+
* local directory — every answer is a `ProjectMemoryLoad`, the one form the engine reads. Reads the instruction-file chain (CLAUDE.md → .claude/CLAUDE.md → AGENTS.md → .claude/AGENTS.md, [ref]) + (non-subagent)
|
|
42
36
|
* `git log -5` / `git status`, redacts secrets, and caps the total. A subagent gets a trimmed instruction file and
|
|
43
|
-
* no git narrative (cost control, H7). When an instruction file is hit the
|
|
44
|
-
*
|
|
37
|
+
* no git narrative (cost control, H7). When an instruction file is hit the answer also declares it in
|
|
38
|
+
* `instructionSources` (path + sha256 over the raw bounded-read window) so core's
|
|
45
39
|
* instructions-change lane can probe it mid-run.
|
|
46
40
|
*
|
|
47
41
|
* Session snapshot cache (S-2): keyed on ctx.sessionId — a session keeps ONE stable instruction snapshot
|
|
48
42
|
* (mid-run file edits surface via the probe as tail attachments, never a silently re-rendered prefix).
|
|
49
43
|
* `phase: "post-compact"` forces a re-read (core re-renders the prefix there anyway). No entry for
|
|
50
|
-
* sessionless one-shot runs.
|
|
44
|
+
* sessionless one-shot runs.
|
|
51
45
|
*
|
|
52
46
|
* [ref] — source-change notice: with `instructionSource` wired, every prepare of a non-subagent session that WALKED the
|
|
53
47
|
* instruction chain hands the chain member it selected (`null` = none) to {@link announceInstructionSource}, which
|
|
@@ -72,7 +66,7 @@ export declare function makeLoadProjectMemory(opts: {
|
|
|
72
66
|
cacheMax?: number;
|
|
73
67
|
/** [ref]: the baseline store + notice exit. Absent ⇒ no source-change notice (the session store has no baseline face). */
|
|
74
68
|
instructionSource?: InstructionSourceSeat;
|
|
75
|
-
}): (ctx: ProjectMemoryCtx) => Promise<
|
|
69
|
+
}): (ctx: ProjectMemoryCtx) => Promise<ProjectMemoryLoad>;
|
|
76
70
|
/**
|
|
77
71
|
* ② The `RunnerDeps.probeInstructionSources` seam: re-fingerprint the declared instruction files mid-run so
|
|
78
72
|
* core's instructions-change lane can append a tail attachment when one changes. Same read posture as the
|
package/dist/project-memory.js
CHANGED
|
@@ -42,7 +42,8 @@ function instructionHash(raw) {
|
|
|
42
42
|
return `hmac-sha256:${createHmac("sha256", INSTRUCTION_HASH_KEY).update(raw).digest("hex")}`;
|
|
43
43
|
}
|
|
44
44
|
const ABSENT_HASH = null;
|
|
45
|
-
const
|
|
45
|
+
const NOTHING_TO_INJECT = Object.freeze({ content: null });
|
|
46
|
+
const NOT_APPLICABLE = { walked: false, answer: NOTHING_TO_INJECT };
|
|
46
47
|
export function instructionChainCoordinates(absPath, p = hostPath) {
|
|
47
48
|
const candidates = INSTRUCTION_FILE_CHAIN.filter((rel) => absPath.endsWith(p.sep + rel.split("/").join(p.sep))).sort((a, b) => b.length - a.length);
|
|
48
49
|
for (const rel of candidates) {
|
|
@@ -218,12 +219,12 @@ export function makeLoadProjectMemory(opts) {
|
|
|
218
219
|
if (gitNarrative)
|
|
219
220
|
sections.push(gitNarrative);
|
|
220
221
|
if (sections.length === 0)
|
|
221
|
-
return { walked: true, answer:
|
|
222
|
+
return { walked: true, answer: NOTHING_TO_INJECT, instructionFile };
|
|
222
223
|
const redacted = redactSecrets(sections.join("\n\n"));
|
|
223
224
|
const capped = capUtf8(redacted, totalCap);
|
|
224
225
|
opts.logger?.debug?.("project_memory_loaded", { cwd: root, bytes: Buffer.byteLength(capped, "utf8"), isSubagent: ctx.isSubagent, gitOk, ...(gitDropReason ? { gitDropReason } : {}), claudeTruncated, ...(hitFile ? { instructionFile: hitFile } : {}), ...(ctx.phase ? { phase: ctx.phase } : {}), cacheSize: cache.size });
|
|
225
226
|
if (!capped)
|
|
226
|
-
return { walked: true, answer:
|
|
227
|
+
return { walked: true, answer: NOTHING_TO_INJECT, instructionFile };
|
|
227
228
|
if (hitFile && hitHash) {
|
|
228
229
|
return {
|
|
229
230
|
walked: true,
|
|
@@ -237,7 +238,7 @@ export function makeLoadProjectMemory(opts) {
|
|
|
237
238
|
instructionFile,
|
|
238
239
|
};
|
|
239
240
|
}
|
|
240
|
-
return { walked: true, answer: capped, instructionFile };
|
|
241
|
+
return { walked: true, answer: { content: capped }, instructionFile };
|
|
241
242
|
}
|
|
242
243
|
}
|
|
243
244
|
export function makeProbeInstructionSources() {
|
|
@@ -28,7 +28,7 @@ const TASK_BODY_DECLARED_KEYS = [
|
|
|
28
28
|
"maxTokens", "mcpServers", "memory", "memoryCapture", "memoryWrite", "model", "objective", "oneShot", "outputRetries", "outputStyle",
|
|
29
29
|
"outputSchema", "permissionMode", "projectId", "projectMemory", "promptLean", "reasoningEffort", "requireExistingSession",
|
|
30
30
|
"resilience", "restoreFiles", "resumeAt", "resumeAtMode", "retainBackgroundProcesses", "retainSubagentSessions",
|
|
31
|
-
"
|
|
31
|
+
"rewindFilesTo", "sandboxImageProfile", "scenario", "scratchpadDir", "selfOrchestration",
|
|
32
32
|
"sessionId", "settings", "skills", "suggestNextPrompts", "systemPrompt", "taskId", "toolMaterializeStrategy",
|
|
33
33
|
"userAttachments", "userInvokedSkills", "verify", "verifyRounds",
|
|
34
34
|
];
|
|
@@ -67,18 +67,17 @@ export declare const PROJECT_MEMORY_OFF_SPELLING_MESSAGE = "projectMemory must b
|
|
|
67
67
|
* 判据:{@link fileHistoryRestoreConflict}。**只在 fresh 受理门**(`http/admission.ts`);续跑腿不过这道门(RESUME 重放不过受理门,
|
|
68
68
|
* 同律 —— 且续跑腿重建时整族剥掉一次性历史动作,矛盾在盘上的体里本就留不下来)。wire 可见、字节冻结。
|
|
69
69
|
*/
|
|
70
|
-
export declare const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled' cannot ride with a file restore (restoreFiles
|
|
70
|
+
export declare const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled' cannot ride with a file restore (restoreFiles or rewindFilesTo) \u2014 the request turns this run's file history off and asks to restore files from it in the same breath; the engine would refuse it (rewind.capture_disabled) only after the session had already been branched at resumeAt, which it does not undo, so it is refused here, before any side effect. Drop fileHistory to restore, or drop the restore to run without file history";
|
|
71
71
|
/**
|
|
72
|
-
* 「关断词 ∧ 还原」这一对的判据(纯函数,只看体)。还原 =
|
|
73
|
-
* (与 `boot/resolve-spec.ts` 的读法同:空串 / 非串按缺席)
|
|
74
|
-
* 正是这个词关掉的记录 —— 两义都与关断词矛盾)。调用前值形已由上面的单成员表与既有布尔门判过。
|
|
72
|
+
* 「关断词 ∧ 还原」这一对的判据(纯函数,只看体)。还原 = 两个键里任一个在请求:`restoreFiles: true`、非空串 `rewindFilesTo`
|
|
73
|
+
* (与 `boot/resolve-spec.ts` 的读法同:空串 / 非串按缺席)。调用前值形已由上面的单成员表与既有布尔门判过。
|
|
75
74
|
*/
|
|
76
|
-
export declare function fileHistoryRestoreConflict(body: Pick<TaskRequestBody, "fileHistory" | "restoreFiles" | "
|
|
75
|
+
export declare function fileHistoryRestoreConflict(body: Pick<TaskRequestBody, "fileHistory" | "restoreFiles" | "rewindFilesTo">): boolean;
|
|
77
76
|
/**
|
|
78
|
-
* 还原键里请求**真带了的**那几个(顺序固定:`restoreFiles` · `rewindFilesTo`
|
|
77
|
+
* 还原键里请求**真带了的**那几个(顺序固定:`restoreFiles` · `rewindFilesTo`)。{@link fileHistoryRestoreConflict} 的「还原」一半就是它非空 ——
|
|
79
78
|
* 判据只有这一份,拒体的 `detail.fields` 点名的也是它(判与点名不会各读各的)。
|
|
80
79
|
*/
|
|
81
|
-
export declare function fileHistoryRestoreKeysInBody(body: Pick<TaskRequestBody, "restoreFiles" | "
|
|
80
|
+
export declare function fileHistoryRestoreKeysInBody(body: Pick<TaskRequestBody, "restoreFiles" | "rewindFilesTo">): Array<"restoreFiles" | "rewindFilesTo">;
|
|
82
81
|
/**
|
|
83
82
|
* **单成员闭集键表** —— 每键合法值只有它自己那一个关断词(`word`),缺席=照常,没有「开」的拼法。
|
|
84
83
|
*
|
|
@@ -2,7 +2,7 @@ export const MEMORY_CAPTURE_SPELLING_MESSAGE = "memoryCapture must be the string
|
|
|
2
2
|
export const MEMORY_OFF_SPELLING_MESSAGE = "memory must be the string 'off' when present (the request-level declaration that this run mounts no memory face at all; absent = memory as usual — there is no 'on' spelling; to keep memory mounted but stop this session's content from entering long-term memory, send memoryCapture: 'off' instead)";
|
|
3
3
|
export const FILE_HISTORY_OFF_SPELLING_MESSAGE = "fileHistory must be the string 'disabled' when present (the request-level declaration that this run records no file history — no backup of an edited file, and no file restore in the same request; absent = the deployment's setting — there is no 'enabled' spelling)";
|
|
4
4
|
export const PROJECT_MEMORY_OFF_SPELLING_MESSAGE = "projectMemory must be the string 'disabled' when present (the request-level declaration that this run reads none of the deployment's project context — no project instruction files and no project layer; absent = the deployment's project context as usual — there is no 'on' spelling)";
|
|
5
|
-
export const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled' cannot ride with a file restore (restoreFiles
|
|
5
|
+
export const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled' cannot ride with a file restore (restoreFiles or rewindFilesTo) — the request turns this run's file history off and asks to restore files from it in the same breath; the engine would refuse it (rewind.capture_disabled) only after the session had already been branched at resumeAt, which it does not undo, so it is refused here, before any side effect. Drop fileHistory to restore, or drop the restore to run without file history";
|
|
6
6
|
export function fileHistoryRestoreConflict(body) {
|
|
7
7
|
return body.fileHistory === "disabled" && fileHistoryRestoreKeysInBody(body).length > 0;
|
|
8
8
|
}
|
|
@@ -12,8 +12,6 @@ export function fileHistoryRestoreKeysInBody(body) {
|
|
|
12
12
|
out.push("restoreFiles");
|
|
13
13
|
if (typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0)
|
|
14
14
|
out.push("rewindFilesTo");
|
|
15
|
-
if (body.rewindFiles === true)
|
|
16
|
-
out.push("rewindFiles");
|
|
17
15
|
return out;
|
|
18
16
|
}
|
|
19
17
|
const SINGLE_MEMBER_OFF_FIELDS = [
|
|
@@ -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.d.ts
CHANGED
|
@@ -196,6 +196,12 @@ export declare function promptYesNoOnTty(prompt: string, signal?: AbortSignal, s
|
|
|
196
196
|
* or whose approval no person could answer, see {@link unfinishedStopOf} — / a fatal error, 2 = bad usage / unmet env). Pure of
|
|
197
197
|
* `process.exit` so a test can assert the code; `main()` applies it.
|
|
198
198
|
*/
|
|
199
|
+
/**
|
|
200
|
+
* 本入口拒 `CONFIG_PROVIDER=remote` 的那一句(配置源的词要么兑现、要么拒)。本入口只装本地配置源:中心拉取的那一套 —— 凭据续签、托管模型钥解封、
|
|
201
|
+
* 名册门、LKG —— 只在 HTTP 服务里装配。修前它在 remote 的词下照读本地 `config.d`(判官对「没递中心」回落 local),零句。
|
|
202
|
+
* 配没配中心地址都是这一句:出路(不设词 / 写 `local` / 改跑 HTTP 服务)在本入口照做都兑现得了。
|
|
203
|
+
*/
|
|
204
|
+
export declare const RUN_LOCAL_CONFIG_SOURCE_REFUSAL: string;
|
|
199
205
|
export declare function runLocal(argv: string[], deps?: RunLocalDeps): Promise<number>;
|
|
200
206
|
/** {@link installRunLocalExitBoundary} 的把手(同进程内反复装配的调用方=测试必须用它收尾)。 */
|
|
201
207
|
export interface RunLocalExitBoundary {
|
package/dist/run-local.js
CHANGED
|
@@ -19,19 +19,19 @@ import { applyRuntimeGovernance, autonomyModeFloor, entryPermissionMode } from "
|
|
|
19
19
|
import { ForkRoutingSessionStore } from "./plugins/fork-routing-session-store.js";
|
|
20
20
|
import { taskWallClockSec } from "./task-workflow.js";
|
|
21
21
|
import { applyCenterArtifact, centerSourceOnError } from "./capabilities/center-prompts.js";
|
|
22
|
-
import { buildUnpricedCeilingNotice, loadConfig, logConfigDiagnostics, parseNumOrFailNonNegative } from "./config.js";
|
|
22
|
+
import { buildUnpricedCeilingNotice, loadConfig, logConfigDiagnostics, parseConfigProvider, parseNumOrFailNonNegative } from "./config.js";
|
|
23
23
|
import { buildStoreOpenRefusalTail } from "./plugins/store-open-refusal.js";
|
|
24
24
|
import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
|
|
25
|
-
import { configLocalRoot,
|
|
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";
|
|
@@ -62,7 +63,6 @@ import { installProcessExitBoundary } from "./boot/exit-boundary.js";
|
|
|
62
63
|
import { createMetrics } from "./observability/metrics.js";
|
|
63
64
|
import { installSecretEnvScrubRecorder } from "./observability/secret-env-scrub.js";
|
|
64
65
|
import { createHostLspManager } from "./host-lsp-manager.js";
|
|
65
|
-
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
66
66
|
import { installOutboundDispatcher } from "./outbound-dispatcher.js";
|
|
67
67
|
import { provisionSemaConfigDir } from "./sema-config-dir.js";
|
|
68
68
|
import { bindOwnCredentialsConfig, declareServerWithheldEnv } from "./server-secret-env.js";
|
|
@@ -315,6 +315,9 @@ function buildUnfinishedStopFooter(stop, sessionId) {
|
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
+
export const RUN_LOCAL_CONFIG_SOURCE_REFUSAL = "CONFIG_PROVIDER=remote: run-local reads its configuration from the local config directory only — it does not pull a web-admin center " +
|
|
319
|
+
"(center credential renewal, sealed model keys and the roster gate are assembled by the HTTP service). Unset CONFIG_PROVIDER or set " +
|
|
320
|
+
"CONFIG_PROVIDER=local for this command, or run the HTTP service to use the center.";
|
|
318
321
|
export async function runLocal(argv, deps = {}) {
|
|
319
322
|
const print = deps.print ?? ((l) => console.log(l));
|
|
320
323
|
const printErr = deps.printErr ?? ((l) => console.error(l));
|
|
@@ -329,7 +332,12 @@ export async function runLocal(argv, deps = {}) {
|
|
|
329
332
|
}
|
|
330
333
|
throw err;
|
|
331
334
|
}
|
|
332
|
-
|
|
335
|
+
const configWord = parseConfigProvider();
|
|
336
|
+
if (configWord === "remote") {
|
|
337
|
+
printErr(RUN_LOCAL_CONFIG_SOURCE_REFUSAL);
|
|
338
|
+
return 2;
|
|
339
|
+
}
|
|
340
|
+
if (configWord === undefined)
|
|
333
341
|
process.env.CONFIG_PROVIDER = "local";
|
|
334
342
|
process.env.SESSION_BACKEND = "memory";
|
|
335
343
|
process.env.REQUIRE_PRINCIPAL = "false";
|
|
@@ -346,20 +354,17 @@ export async function runLocal(argv, deps = {}) {
|
|
|
346
354
|
logConfigDiagnostics(logger);
|
|
347
355
|
provisionSemaConfigDir(config, logger);
|
|
348
356
|
installOutboundDispatcher(logger);
|
|
349
|
-
const providerInput = { provider:
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
await assertLocalConfigDirTrusted({ root, declaredOwnerUid: config.configLocalOwnerUid });
|
|
354
|
-
}
|
|
355
|
-
catch (err) {
|
|
356
|
-
printErr(err instanceof Error ? err.message : String(err));
|
|
357
|
-
return 2;
|
|
358
|
-
}
|
|
359
|
-
logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
|
|
357
|
+
const providerInput = { provider: "local", localDir: root, localOwnerUid: config.configLocalOwnerUid };
|
|
358
|
+
try {
|
|
359
|
+
await assertLocalConfigDirTrusted({ root, declaredOwnerUid: config.configLocalOwnerUid });
|
|
360
360
|
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
printErr(err instanceof Error ? err.message : String(err));
|
|
363
|
+
return 2;
|
|
364
|
+
}
|
|
365
|
+
logConfigDirMigration(logger, await migrateLocalConfigDirectory(root));
|
|
361
366
|
try {
|
|
362
|
-
await composeExecutionLane(config, { configSource, localRoot: root, logger, drivesFromFile: ["host"] });
|
|
367
|
+
await composeExecutionLane(config, { configSource: "local", localRoot: root, logger, drivesFromFile: ["host"] });
|
|
363
368
|
}
|
|
364
369
|
catch (err) {
|
|
365
370
|
printErr(err instanceof Error ? err.message : String(err));
|
|
@@ -468,17 +473,22 @@ export async function runLocal(argv, deps = {}) {
|
|
|
468
473
|
const hostRx = config.remoteExec?.provider === "host" ? config.remoteExec : undefined;
|
|
469
474
|
const workspaceDir = args.workspace ?? hostRx?.workspaceBase ?? process.cwd();
|
|
470
475
|
await settleHostLaneShell(config, logger);
|
|
476
|
+
warnReadDenyFloorUnkept(config, logger);
|
|
477
|
+
const homeDirSeat = buildLaneHomeClaim(config);
|
|
471
478
|
const executionEnvFactory = hostRx
|
|
472
479
|
? hostExecutionEnvFactory({
|
|
473
480
|
workspaceDir,
|
|
474
|
-
...
|
|
481
|
+
...homeDirSeat,
|
|
475
482
|
backgroundShell: config.requirePrincipal !== true,
|
|
476
483
|
...(hostRx.commandTimeoutMs != null ? { commandTimeoutMs: hostRx.commandTimeoutMs } : {}),
|
|
477
484
|
})
|
|
478
485
|
: undefined;
|
|
479
486
|
const lspManager = hostRx && config.lspHostEnabled && config.requirePrincipal !== true ? createHostLspManager(config, (event, fields) => logger.info(event, fields)) : undefined;
|
|
480
|
-
const memoryEngine = memoryEngineBackendFor(config, root, memoryEngineIncident);
|
|
481
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;
|
|
482
492
|
try {
|
|
483
493
|
judgeConsolidationValve({ config, memoryEngine });
|
|
484
494
|
}
|
|
@@ -490,17 +500,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
490
500
|
}
|
|
491
501
|
let memorySync;
|
|
492
502
|
if (config.memorySync && memoryEngine) {
|
|
493
|
-
memorySync =
|
|
494
|
-
backend: memoryEngine.backend,
|
|
495
|
-
scope: config.memorySync.scope,
|
|
496
|
-
memoryRoot: memoryEngine.root,
|
|
497
|
-
transport: createMemorySyncTransport({ url: config.memorySync.url, token: config.memorySync.token }),
|
|
498
|
-
log: logger,
|
|
499
|
-
...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
|
|
500
|
-
...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
|
|
501
|
-
});
|
|
502
|
-
logger.info("memory_sync_enabled", { url: buildDisplaySafeUrl(config.memorySync.url), scope: config.memorySync.scope, cursorPath: memorySync.cursorPathFor(config.memorySync.scope) });
|
|
503
|
-
memorySync.trigger("boot");
|
|
503
|
+
memorySync = startMemorySyncRunner({ sync: config.memorySync, stores: memoryEngine, log: logger });
|
|
504
504
|
}
|
|
505
505
|
else if (config.memorySync) {
|
|
506
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" });
|
|
@@ -564,7 +564,6 @@ export async function runLocal(argv, deps = {}) {
|
|
|
564
564
|
}
|
|
565
565
|
assertRetentionLaneWirable({
|
|
566
566
|
intervalSec: config.retentionSweep.intervalSec,
|
|
567
|
-
policy: config.retentionPolicy,
|
|
568
567
|
executor: undefined,
|
|
569
568
|
stores: [
|
|
570
569
|
{ name: "sessionStore", store: sessionStore },
|
|
@@ -683,7 +682,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
683
682
|
}
|
|
684
683
|
}
|
|
685
684
|
const projectKey = memoryEngine
|
|
686
|
-
? await createMemoryProjectLayers({
|
|
685
|
+
? await createMemoryProjectLayers({ stores: memoryEngine, syncRunner: memorySync, log: logger }).prepare(config, scope, workspaceDir)
|
|
687
686
|
: undefined;
|
|
688
687
|
const taskTimeoutSec = Math.floor(parseNumOrFailNonNegative("TASK_TIMEOUT_SEC", process.env.TASK_TIMEOUT_SEC || "0"));
|
|
689
688
|
const timeoutSec = taskWallClockSec(taskTimeoutSec, false);
|