@sema-agent/server 7.43.0 → 7.44.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/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- package/dist/capabilities/scenario-alias.js +0 -61
package/dist/boot/stores.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* design/158 A10:composition root 分段 —— 持久层装配(StoreBackend / memory engine / roster /
|
|
3
|
-
* background-agent / attachment / mailbox / memory sync / session store + 姿势断言 / breaker)。
|
|
4
|
-
*
|
|
5
|
-
* 纯搬运:函数体逐字来自 `main.ts`(原 627-932 行),缩进不变;新增的只有 import 与包壳。
|
|
6
|
-
*
|
|
7
|
-
* ⚠️ **位置即契约**:
|
|
8
|
-
* 1. 本段**就地改写 `config.sessionBackend`**(`auto` → `tidb|memory`,local backend 再归一为 `tidb`)。
|
|
9
|
-
* 这两行是后续所有消费点(createSessionStore / ensureChildSessionDurable 的 tidb 门 / /health 标签)
|
|
10
|
-
* 的前置条件,必须留在本段这个位置,不能上移(backend 还没开)也不能下移(消费点已读)。
|
|
11
|
-
* 2. `assertCloudSnapshotBlobPosture` 与两条 REQUIRE_PRINCIPAL 拒启断言必须在 sessionStore 造出来之后、
|
|
12
|
-
* 任何路由装配之前 —— fail-loud 拒启的意义就在于"还没开始服务"。
|
|
13
|
-
* 3. `breakerState` 放在段尾:brain(下一段)要它,而它要 backend。
|
|
14
|
-
*/
|
|
15
1
|
import { join } from "node:path";
|
|
16
2
|
import { FileBackgroundAgentStore, FileMailboxStore, FileRosterStore, FileUsageWindowStore, InMemoryUsageWindowStore } from "@sema-agent/core";
|
|
17
3
|
import { createMemorySyncRunner, createMemorySyncTransport } from "../memory-sync-client.js";
|
|
@@ -34,10 +20,9 @@ import { ensurePgTaskListSchema, ensureTiDBTaskListSchema } from "../plugins/tas
|
|
|
34
20
|
import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "../plugins/store-backend.js";
|
|
35
21
|
import { buildMemoryRemoteLaneWarn, memoryEngineBackendFor, memoryEngineRemoteLanePosture } from "../memory-scope.js";
|
|
36
22
|
import { assertToolResultProvenanceSchema } from "../plugins/tool-result-store-sql.js";
|
|
23
|
+
import { assertPermissionRuleApprovalSchema } from "../plugins/permission-rule-store-sql.js";
|
|
37
24
|
import { buildMemoryWriteBoundaryAudit, effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
38
25
|
import { buildMemoryPosture } from "../memory-posture.js";
|
|
39
|
-
/** #252:dark 三词 → 启动日志的人话(词表是机器面的真源,散文是它的**投影**,不是第二个真源)。
|
|
40
|
-
* 穷举 `Record<MemoryDarkReason, …>`:词表加员 ⇒ 这里编译红,不会静默漏一句人话。 */
|
|
41
26
|
const DARK_REASON_PROSE = {
|
|
42
27
|
engine_off: () => "MEMORY_ENGINE=off",
|
|
43
28
|
multi_tenant_file_backend: () => "multi-tenant on the FILE backend (no tenant isolation; set MEMORY_ENGINE_BACKEND=pg|tidb to light up)",
|
|
@@ -45,32 +30,17 @@ const DARK_REASON_PROSE = {
|
|
|
45
30
|
};
|
|
46
31
|
export async function openStores(ctx) {
|
|
47
32
|
const { config, logger, metrics, localRoot } = ctx;
|
|
48
|
-
// One shared SQL store backend for L1 + L2 (TiDB/MySQL or PostgreSQL per DB_BACKEND). Owned here.
|
|
49
33
|
let backend;
|
|
50
|
-
let storeBackendDegraded = false;
|
|
51
|
-
// `auto` probes a configured DB and degrades to in-memory if it's unreachable (local/intranet binaries:
|
|
52
|
-
// "use my DB if I can reach it, else memory"). Explicit `tidb` fails fast instead — silently dropping
|
|
53
|
-
// persistence the operator asked for would lose runs. (`tidb` here = "the SQL DB"; DB_BACKEND picks the engine.)
|
|
34
|
+
let storeBackendDegraded = false;
|
|
54
35
|
const wantDb = config.sessionBackend === "tidb" ||
|
|
55
|
-
config.dbBackend === "local" ||
|
|
36
|
+
config.dbBackend === "local" ||
|
|
56
37
|
(config.sessionBackend === "auto" && !!(config.tidb || config.pg));
|
|
57
38
|
if (wantDb) {
|
|
58
|
-
// 构造 + ensureSchema 同罩一层降级臂(2026-07-28 修):原先 try 只罩 ensureSchema,而 local 形真正
|
|
59
|
-
// 会抛的是构造里的 mkdir + 数据根 BootLock ——「裸 boot 不得拒启」那条口径对 local 从未生效过。
|
|
60
|
-
// 降级/fail-loud 的判据与理由见 openStoreBackendWithFallback 顶注。
|
|
61
39
|
const opened = await openStoreBackendWithFallback(config, logger);
|
|
62
40
|
backend = opened.backend;
|
|
63
41
|
storeBackendDegraded = opened.degraded;
|
|
64
42
|
}
|
|
65
|
-
// S5 review LOW-1: always render the series (0 = healthy) — gauge absence is indistinguishable from
|
|
66
|
-
// "old build without this metric", which breaks `== 0`-style alert rules.
|
|
67
43
|
metrics.setGauge("store_backend_degraded", storeBackendDegraded ? 1 : 0);
|
|
68
|
-
// #119 升级前置断言(core 5.26.0 提货):`CREATE TABLE IF NOT EXISTS` 对**存量** tool_result 是空操作 ⇒
|
|
69
|
-
// 没删表就升上来的部署,出处两列与加宽的 ref 列都不在,而每一次 offload 写都会撞 unknown column、被
|
|
70
|
-
// core 的失败臂吞成一条内联占位(服务照跑、工具产物全丢)。判据与恢复动作见
|
|
71
|
-
// assertToolResultProvenanceSchema 的头注。
|
|
72
|
-
// 🔴 位置:**不在** `ensureSchema` 里 —— 那条通道的契约是「只发 CREATE」(test/ensure-schema.test.ts 的
|
|
73
|
-
// 运行时门),一条只读探针进去也算破例。放在 DDL 之后、任何路由装配之前,拒启的意义仍在(还没开始服务)。
|
|
74
44
|
{
|
|
75
45
|
const mysqlPool = backend?.mysqlPool?.();
|
|
76
46
|
const pgPool = backend?.pgPool?.();
|
|
@@ -78,9 +48,13 @@ export async function openStores(ctx) {
|
|
|
78
48
|
await assertToolResultProvenanceSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
|
|
79
49
|
else if (mysqlPool)
|
|
80
50
|
await assertToolResultProvenanceSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
51
|
+
if (config.permissionRulesEnabled) {
|
|
52
|
+
if (pgPool)
|
|
53
|
+
await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await pgPool.query(sql)).rows }), "pg");
|
|
54
|
+
else if (mysqlPool)
|
|
55
|
+
await assertPermissionRuleApprovalSchema(async (sql) => ({ rows: (await mysqlPool.query(sql))[0] }), "tidb");
|
|
56
|
+
}
|
|
81
57
|
}
|
|
82
|
-
// S21 (SILENT-FALLBACK P1): MINIO_* partially set silently falls back to SQL-blob snapshots. Warn on the
|
|
83
|
-
// partial config and always render which backend blobs actually use.
|
|
84
58
|
{
|
|
85
59
|
const minioReq = ["MINIO_ENDPOINT", "MINIO_ACCESS_KEY", "MINIO_SECRET_KEY"];
|
|
86
60
|
const present = minioReq.filter((v) => (process.env[v] ?? "") !== "");
|
|
@@ -89,36 +63,15 @@ export async function openStores(ctx) {
|
|
|
89
63
|
}
|
|
90
64
|
metrics.setGauge("snapshot_blob_backend", 1, { backend: config.snapshotBlobStore ? "minio" : "sql" });
|
|
91
65
|
}
|
|
92
|
-
// Resolve `auto` to the concrete backend the rest of the wiring understands (createSessionStore,
|
|
93
|
-
// runStore, the startup summary). A DB-backed L2 with no backend degrades to in-memory the same way.
|
|
94
66
|
if (config.sessionBackend === "auto")
|
|
95
67
|
config.sessionBackend = backend ? "tidb" : "memory";
|
|
96
|
-
// local backend: route the session store through backend.session() (LocalSessionStore — the §0.5 OwnerAware twin),
|
|
97
|
-
// NOT the bare TtlSessionStore the "memory" path returns; "tidb" here means "the backend's durable store" generically.
|
|
98
68
|
if (config.dbBackend === "local" && backend)
|
|
99
69
|
config.sessionBackend = "tidb";
|
|
100
|
-
// Long-term memory (design/138 S1, clay 2026-07-08): the injection-first file-based memory ENGINE is the
|
|
101
|
-
// only memory plane — `RunnerDeps.memoryBackend` is core's switch (materialize → session file ops →
|
|
102
|
-
// harvest; no remember/recall tools). SINGLE-USER TURNKEY ONLY: the file basement has no tenant
|
|
103
|
-
// isolation, so a multi-tenant deployment (requirePrincipal) gets `undefined` = memory dark, fail-closed
|
|
104
|
-
// (memoryEngineBackendFor + memoryScopeFor enforce the same gate). The legacy MemoryStore plane
|
|
105
|
-
// (MEMORY_BACKEND/EMBEDDING_*) was dropped without migration; `scripts/drop-memory-tables.sql` drops the table.
|
|
106
|
-
// S3-TOB(设计 §1.3,后经改判与边界重切):backend 选择器——file=现状(单用户/host);pg|tidb=
|
|
107
|
-
// DB durable 真身(零卷主档:memory/ 文件面=materialize 的 ephemeral 工作副本,harvest 回 DB=持久化
|
|
108
|
-
// 时点)。DB backend 是多租户点亮的唯一门(显式 opt-in);选了 DB 但池不可用/方言不匹配=fail-loud 拒启
|
|
109
|
-
// (no-stopgap:绝不静默降 File/dark)。
|
|
110
70
|
let memoryEngine;
|
|
111
|
-
// 142-S2.5:per-(scope,peer) 同步游标面(sync_cursors)——POST /v1/memory/sync/:scope 的持久化半场。
|
|
112
|
-
// 只在 DB memory plane 上点亮(file 形态路由 501,不接);与 entry plane 同池同方言。
|
|
113
71
|
let memorySyncCursors;
|
|
114
|
-
/** #252:两支 SQL 后端从实例 getter 读到的档位真值;file/off 腿留 undefined(该腿无此指示面)。 */
|
|
115
72
|
let vectorMode;
|
|
116
73
|
if (config.memoryEngineBackend !== "file" && config.memoryEngineEnabled) {
|
|
117
74
|
const dialect = config.memoryEngineBackend;
|
|
118
|
-
// 142-S5.1 production history sink: every applied patch appends one
|
|
119
|
-
// agent_memory_engine_history row via the backend's optional history opts. The wrapper's ONLY
|
|
120
|
-
// job is the metrics leg — count lost rows BEFORE rethrowing (the backend swallows + warns with
|
|
121
|
-
// its own cumulative count; the audit line's breakage must itself be auditable).
|
|
122
75
|
const countedHistorySink = (store) => ({
|
|
123
76
|
appendHistory: async (rows) => {
|
|
124
77
|
try {
|
|
@@ -130,30 +83,15 @@ export async function openStores(ctx) {
|
|
|
130
83
|
}
|
|
131
84
|
},
|
|
132
85
|
});
|
|
133
|
-
// #228:检索档位(lexical|portable|native)是「后端上限 × embedder 在场」的**推断结果**,不是旋钮
|
|
134
|
-
// ([3590] 裁①)。下面两支各自从**实例的 getter** 读真值——不在这里自己推断,推断出的档与实际跑的档
|
|
135
|
-
// 一旦分家,启动日志就成了另一句谎([3606]①:lexical 在跑必须运维可见)。
|
|
136
|
-
// ⚠️ #252:声明上移到函数作用域(启动日志之外,`buildMemoryPosture` 也要读这个真值)——两支的赋值
|
|
137
|
-
// 逐字不变,file/off 那一臂照旧留 `undefined`(file 引擎没有档位指示面,不折成 lexical)。
|
|
138
86
|
if (dialect === "pg") {
|
|
139
87
|
const pool = backend?.pgPool();
|
|
140
88
|
if (!pool)
|
|
141
89
|
throw new Error("MEMORY_ENGINE_BACKEND=pg requires DB_BACKEND=pg (the memory engine binds the same PG pool) — refusing to start half-configured");
|
|
142
90
|
const q = async (text, params) => { const r = await pool.query(text, params); return { rows: r.rows }; };
|
|
143
|
-
// ⚠️ 维度守卫的**位置**(诚实记档,不编造对表):这里 ensure schema 不传 `memoryVector`,即 embedding
|
|
144
|
-
// 列是 `jsonb`(portable 档),schema 侧**没有维度**可与 MEMORY_EMBEDDER_DIM 对表。boot 期能做的
|
|
145
|
-
// 只有「DIM 是正整数」(config.ts parseMemoryEmbedder);真正的维度守卫在写入路径两处:
|
|
146
|
-
// ① 本仓 embedder 拿到长度不符的响应直接抛(绝不截断/补零);
|
|
147
|
-
// ② `PgMemoryEngineBackend.embeddingParam` 对长度不符的向量返回 null,该行退回词面档、不写坏向量。
|
|
148
91
|
await ensurePgMemoryEngineSchema(q);
|
|
149
92
|
await ensurePgMemoryHistorySchema(q);
|
|
150
|
-
await ensurePgMemorySyncSchema(q);
|
|
93
|
+
await ensurePgMemorySyncSchema(q);
|
|
151
94
|
memorySyncCursors = new PgMemorySyncStore(q);
|
|
152
|
-
// #228:配了 MEMORY_EMBEDDER_*(config 层已把半配/坏值/错后端全拒掉)⇒ 注入,vectorMode 由 lexical
|
|
153
|
-
// 升到 portable;没配 ⇒ undefined,逐字保持改前行为。
|
|
154
|
-
// onFailure(codex 复审 F2):embed 抛出去之后,applyPatches 的外层 catch 会把它折成一条
|
|
155
|
-
// `io error: …` **冲突**(core 的冲突词表把它讲成「并发改动」),search 那腿则直接退回词面档 ——
|
|
156
|
-
// 两条路都不会在部署面留下「向量供应商挂了」的信号。这条腿就是那个信号(抛照抛,只是被看见)。
|
|
157
95
|
const embedder = memoryEmbedderFor(config, {
|
|
158
96
|
onFailure: (err) => {
|
|
159
97
|
metrics.inc("memory_embed_failed_total", { backend: dialect });
|
|
@@ -164,14 +102,6 @@ export async function openStores(ctx) {
|
|
|
164
102
|
});
|
|
165
103
|
},
|
|
166
104
|
});
|
|
167
|
-
// design/234 embedder 指纹门(clay 终裁 [3647]⑤ 方向=清空重建):同维度换模型是**静默**混空间形
|
|
168
|
-
// ——旧空间与新空间的向量在同一列里做 cosine,排序变噪音,没有任何一层会说出来。指纹
|
|
169
|
-
// `{model,dimensions}` 明文存单行元表,boot 一次比对:不等/无主/不可解析 ⇒ 先清 `embedding` 列、
|
|
170
|
-
// 后写元表(次序即正确性,反序中途崩溃=新 identity 已记而旧向量还在=正是被修的病),写后 CAS
|
|
171
|
-
// 重读收敛并发副本。⚠️ 位置:ensure*Schema 之后、`new PgMemoryEngineBackend` **之前** —— 比对跑在
|
|
172
|
-
// backend 构造之后 = 服务已经能用旧空间向量检索了。门自身失败一律抛(拒启)。
|
|
173
|
-
// A 态(embedder 缺席)门整个不装:连 ensure 都不调,元表不动(旧 identity 保留,配置回归同
|
|
174
|
-
// identity 时存量向量直接续用)。⚠️ ③b 扫的是**源码文本**,调用写在 if 内照样入册(K1)。
|
|
175
105
|
if (embedder !== undefined && config.memoryEmbedder !== undefined) {
|
|
176
106
|
await ensurePgMemoryEmbedderMetaSchema(q);
|
|
177
107
|
await reconcileEmbedderFingerprint(q, { model: config.memoryEmbedder.model, dimensions: config.memoryEmbedder.dimensions }, { log: logger });
|
|
@@ -183,26 +113,11 @@ export async function openStores(ctx) {
|
|
|
183
113
|
"SAME identity later reuses vectors only for rows that have not been touched in the meantime",
|
|
184
114
|
});
|
|
185
115
|
}
|
|
186
|
-
// #319 copy-out 生产化站(core 5.47/5.48 契约冻结面)—— **本装配点即换装点,不另起一支**:
|
|
187
|
-
// 这条腿上的 `PgMemoryEngineBackend` 就是 [4706] 点名的 PG twin(它是 core 1.267 整段移交过来的
|
|
188
|
-
// copy-out;生产化=把它补到冻结形,不是在旁边再写一只)。本站补的两条行为条款(header 携
|
|
189
|
-
// `exposure` / `search` 两带序)落在**读面**,所以换装的实际形状是:
|
|
190
|
-
// · DDL 零变化 —— origin 在库里是 frontmatter jsonb 里的普通字段(138 S3 形),没有新列、
|
|
191
|
-
// 没有迁移、没有回填;ensure*Schema 的调用序逐字未动。
|
|
192
|
-
// · 旋钮零新增 —— 两带序不是部署开关:后端只在调用方**显式**传 `opts.exposureBands` 时分带,
|
|
193
|
-
// 缺席 = pre-336 单带字节形。请求方是 core 引擎的读侧,按 `RunnerDeps.memoryProvenance`
|
|
194
|
-
// (本仓 MEMORY_PROVENANCE=off|carry,见 boot/runner-deps.ts)自己决定 —— server 不代它翻。
|
|
195
|
-
// · 因此本行**不需要**任何前置开关或灰度位:同一只 backend,老调用方拿到逐字节相同的答复,
|
|
196
|
-
// 新调用方(升到 5.47+ 的 core)拿到带序与 exposure 事实。
|
|
197
|
-
// 验收面 = `test/memory-engine-db-integration.test.ts`:core 自己的 28 格契约(两方言真库)+
|
|
198
|
-
// 钉1-钉7(重启存续/并发抢 slug/无副作用读/跨 scope 拒/原生档两带序/谓词对表/同分截断)。
|
|
199
116
|
const pgMem = new PgMemoryEngineBackend(q, {
|
|
200
117
|
history: countedHistorySink(new PgMemoryHistoryStore(q)),
|
|
201
118
|
...(embedder !== undefined ? { embedder } : {}),
|
|
202
119
|
});
|
|
203
120
|
vectorMode = pgMem.vectorMode;
|
|
204
|
-
// 工作面根:DB 形态下 memory/ 目录=per-worker ephemeral 物化区(丢了重建,控制面同);
|
|
205
|
-
// 复用 localDataRoot 下独立子树,绝不与 File backend 的持久 memory/ 混写。
|
|
206
121
|
memoryEngine = { backend: pgMem, root: join(config.localDataRoot ?? localRoot, "memory-work") };
|
|
207
122
|
}
|
|
208
123
|
else {
|
|
@@ -211,18 +126,12 @@ export async function openStores(ctx) {
|
|
|
211
126
|
throw new Error("MEMORY_ENGINE_BACKEND=tidb requires DB_BACKEND=mysql — refusing to start half-configured");
|
|
212
127
|
await ensureTiDBMemoryEngineSchema(pool);
|
|
213
128
|
await ensureTiDBMemoryHistorySchema(pool);
|
|
214
|
-
await ensureTiDBMemorySyncSchema(pool);
|
|
129
|
+
await ensureTiDBMemorySyncSchema(pool);
|
|
215
130
|
memorySyncCursors = new TiDBMemorySyncStore(pool);
|
|
216
|
-
// tidb 记忆后端 v1 无向量档(传 embedder 它自己 fail-loud 拒);config 层已保证 MEMORY_EMBEDDER_*
|
|
217
|
-
// 只可能与 pg 后端同时在场,所以这一支不注入,恒 lexical。
|
|
218
131
|
const tidbMem = new TiDBMemoryEngineBackend(pool, { history: countedHistorySink(new TiDBMemoryHistoryStore(pool)) });
|
|
219
132
|
vectorMode = tidbMem.vectorMode;
|
|
220
133
|
memoryEngine = { backend: tidbMem, root: join(config.localDataRoot ?? localRoot, "memory-work") };
|
|
221
134
|
}
|
|
222
|
-
// embedder 身份(model + dim)一并自报(codex 复审 F1 的**部分**缓解,记档):本仓没有向量指纹列
|
|
223
|
-
// (要加列 = 动 SQL,超出 #228 单),所以「同维度换模型 ⇒ 旧向量与新查询向量不同空间、排序变噪音」
|
|
224
|
-
// 这件事在库里查不出来;能做的是把当前跑的模型写进启动日志,让换模型这件事在运维面留痕(USAGE 里
|
|
225
|
-
// 的对应纪律:换模型/换维度前先清 `agent_memory_engine_entry.embedding`)。
|
|
226
135
|
logger.info("memory_engine_enabled", {
|
|
227
136
|
enabled: true,
|
|
228
137
|
backend: dialect,
|
|
@@ -234,10 +143,6 @@ export async function openStores(ctx) {
|
|
|
234
143
|
}
|
|
235
144
|
else {
|
|
236
145
|
memoryEngine = memoryEngineBackendFor(config);
|
|
237
|
-
// [1845]②(cli 桌面撞坑;壳侧此前同坑已各自修过——两个宿主都踩=第三个宿主还会踩):操作员用
|
|
238
|
-
// LOCAL_DATA_ROOT 明确要了隔离数据根,MEMORY_ENGINE_DIR 却缺省 ⇒ file 形 memory engine 落 core
|
|
239
|
-
// 默认链(AGENT_DATA_DIR → ~/.ai-agent)= **静默共享全机 memory 库**。不改行为(单机用户可能就要
|
|
240
|
-
// 共享),只把「你现在在共享」说出来。
|
|
241
146
|
if (memoryEngine && process.env.LOCAL_DATA_ROOT && !config.memoryEngineDir) {
|
|
242
147
|
logger.warn("memory_engine_dir_defaulted", {
|
|
243
148
|
root: memoryEngine.root,
|
|
@@ -245,40 +150,22 @@ export async function openStores(ctx) {
|
|
|
245
150
|
});
|
|
246
151
|
}
|
|
247
152
|
}
|
|
248
|
-
// #214 记忆边界不变式([3492]② 立案):记忆没有写工具 —— 模型是用 fs 工具往记忆根写文件的,所以整条
|
|
249
|
-
// 「记住 X」链的成立条件是**记忆根落在该次任务的 fs 授权边界内**。判据本体(含为什么是 warn 不是拒启、
|
|
250
|
-
// 为什么围栏根未知时闭嘴)在 boot/memory-boundary.ts;这里只负责把 boot 期的真事实喂进去。
|
|
251
|
-
// 围栏根的口径与 resolve-spec 的 fs 写门同源:host 语义车道才有本机围栏可谈 —— `REMOTE_EXEC` 未设的
|
|
252
|
-
// in-process 形,手就在本进程 cwd 跑;显式 `host` 形取 operator 配的 workspaceBase(没配 = 每任务临时
|
|
253
|
-
// 目录,boot 期不可知 ⇒ 空数组 ⇒ 不判)。其它车道一律非 host 语义,走 remote 那一臂。
|
|
254
153
|
{
|
|
255
154
|
const lane = config.remoteExec?.provider;
|
|
256
155
|
const hostSemanticsLane = lane === undefined || lane === "host";
|
|
257
|
-
// core 的 remote 判决(与文件平面是两根轴):`isRemoteExecutionEnv` 是鸭子类型,我方**所有**
|
|
258
|
-
// REMOTE_EXEC 车道(含 `host` —— remote-env-host.ts 实现了 suspendVM/workspaceHandle/execStream,
|
|
259
|
-
// 亲验)都满足;未设 provider = in-process(core 拿 StubExecutionEnv)。
|
|
260
156
|
const coreRemoteExecutionEnv = config.remoteExec !== undefined;
|
|
261
|
-
// 🔴 codex 复审(medium,已核真):`REMOTE_EXEC=host` 的 `workspaceBase` **不是**任务围栏 —— host
|
|
262
|
-
// factory 每任务在它下面另铸一个 `sema-host-*` 子目录,而且调用方的 per-session cwd 还能整个换掉它。
|
|
263
|
-
// 拿 workspaceBase 当围栏,会把「记忆根是真任务目录的**兄弟**」这一形误判成「在围栏内」而闭嘴 ——
|
|
264
|
-
// 恰恰是本判据要抓的那种坏部署。所以 host 腿一律报**未知**(空数组 ⇒ 不判),只有 in-process 腿
|
|
265
|
-
// (手就在本进程 cwd 上跑,boot 期这一位是真的)才给围栏根。宁可少说,不可说错。
|
|
266
157
|
const containmentRoots = lane === undefined ? [process.cwd()] : [];
|
|
267
158
|
const audit = buildMemoryWriteBoundaryAudit({
|
|
268
159
|
memoryRoot: memoryEngine?.root,
|
|
269
160
|
lane: lane ?? "in-process",
|
|
270
161
|
hostSemanticsLane,
|
|
271
162
|
coreRemoteExecutionEnv,
|
|
272
|
-
// #266 A3 源头修:审计读**有效值**(host 腿 env 缺席时装配层自动 true)——自动补位后 ① 号 warn
|
|
273
|
-
// 不再响(它警的正是「写指令被撤且无人声明」,现在装配层声明了);显式 env 恒赢在 derive 单源里执法。
|
|
274
163
|
declaredCapable: effectiveMemoryPersistenceCapable(config),
|
|
275
164
|
containmentRoots,
|
|
276
|
-
engineBackend: config.memoryEngineBackend,
|
|
165
|
+
engineBackend: config.memoryEngineBackend,
|
|
277
166
|
});
|
|
278
167
|
for (const w of audit.warnings)
|
|
279
168
|
logger.warn(w.tag, { detail: w.detail, lane: lane ?? "in-process", root: memoryEngine?.root ?? null });
|
|
280
|
-
// #266:自动补位必须在 boot 日志可见(感知链路纪律)——部署方一眼可核「这台机的 capable 是装配层
|
|
281
|
-
// 按 host 腿车道事实补的」,并知道显式 MEMORY_PERSISTENCE_CAPABLE 可覆盖。只在真自动时发一行。
|
|
282
169
|
if (config.memoryPersistenceCapable === undefined && effectiveMemoryPersistenceCapable(config) === true) {
|
|
283
170
|
logger.info?.("memory_persistence_capable_auto_declared", {
|
|
284
171
|
lane: lane ?? "in-process",
|
|
@@ -286,10 +173,6 @@ export async function openStores(ctx) {
|
|
|
286
173
|
});
|
|
287
174
|
}
|
|
288
175
|
}
|
|
289
|
-
// RosterStore(agent-team S1 server 半场,[1070]① 提货单;core 1.316 `RunnerDeps.rosterStore`):
|
|
290
|
-
// 具名子 agent 持久名册。形态跟 StoreBackend:tidb/pg=SQL twins(语义三条+真双库验证,
|
|
291
|
-
// roster-store-sql.ts 顶注);local=core FileRosterStore(dataRoot 下 roster.json,core 自带原子写/
|
|
292
|
-
// 损坏安全);无 backend(纯内存 dev)=不挂(core 用活注册表,跨 run 指针面自然缺席——诚实)。
|
|
293
176
|
let rosterStore;
|
|
294
177
|
{
|
|
295
178
|
const mysqlPool = backend?.mysqlPool?.();
|
|
@@ -304,8 +187,6 @@ export async function openStores(ctx) {
|
|
|
304
187
|
rosterStore = new TiDBRosterStore(mysqlPool);
|
|
305
188
|
}
|
|
306
189
|
else if (backend?.kind === "local") {
|
|
307
|
-
// #109([2392] 提货):onCorruptRead 披露座接线——腐读响亮 warn([2195] 族:不静默折空)。
|
|
308
|
-
// 三挂点里 server 真用的只有这一个(session-policy=自家 SQL 双店;mailbox 用的 FileMailboxStore 无此座)。
|
|
309
190
|
rosterStore = new FileRosterStore(join(config.localDataRoot ?? localRoot, "roster.json"), {
|
|
310
191
|
onCorruptRead: (info) => logger.warn("roster_corrupt_read", { path: info.path, reason: info.reason }),
|
|
311
192
|
});
|
|
@@ -313,15 +194,6 @@ export async function openStores(ctx) {
|
|
|
313
194
|
if (rosterStore)
|
|
314
195
|
logger.info("roster_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
|
|
315
196
|
}
|
|
316
|
-
// BackgroundAgentStore(design/151 S1 server 半场,[1503] 提货单;core 1.364 durable background agents):
|
|
317
|
-
// 后台子代 `a*` 行的 durable 执行记录——settle 后转录 session 不再 eager release(TaskOutput/
|
|
318
|
-
// AgentTranscript 完成后照读全程),清理移交 reapDurableAgents(reaper 区)。形态跟 roster:
|
|
319
|
-
// tidb/pg=SQL twins(真双库验证,background-agent-store-sql.ts 顶注);local=core
|
|
320
|
-
// FileBackgroundAgentStore(dataRoot 下 background-agents/,core 自带 ledger+snapshot 原子写);
|
|
321
|
-
// 无 backend(纯内存 dev)=不挂(core 契约:store 不接线=pre-151 逐字节等价——单进程 live 注册表
|
|
322
|
-
// 已覆盖读面,诚实缺席)。⚠️ 同实例双点挂载:RunnerDeps.backgroundAgentStore(读半场)+
|
|
323
|
-
// ScenarioDeps→SubagentToolOptions.background.agentStore(写半场)都用这一个引用——engine 无法核对
|
|
324
|
-
// 配对,半接=静默死特性(RB-37①)。
|
|
325
197
|
let backgroundAgentStore;
|
|
326
198
|
{
|
|
327
199
|
const mysqlPool = backend?.mysqlPool?.();
|
|
@@ -336,28 +208,16 @@ export async function openStores(ctx) {
|
|
|
336
208
|
backgroundAgentStore = new TiDBBackgroundAgentStore(mysqlPool);
|
|
337
209
|
}
|
|
338
210
|
else if (backend?.kind === "local") {
|
|
339
|
-
// core 1.368([1516]②)listScopes 落地:file 实现自带枚举——1.248 拍的「local+多租户 reap 缺口」
|
|
340
|
-
// warn-once 已撤(reaper 腿现在真枚举,不再假设单 scope)。
|
|
341
211
|
backgroundAgentStore = new FileBackgroundAgentStore(config.localDataRoot ?? localRoot);
|
|
342
212
|
}
|
|
343
213
|
if (backgroundAgentStore)
|
|
344
214
|
logger.info("background_agent_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
|
|
345
215
|
}
|
|
346
|
-
// D-1 通用文件上传(clay 拍 2026-07-27):独立附件 store(不骑 snapshot blob 面——那套的 orphan GC
|
|
347
|
-
// 会把非 manifest 引用的 bytes 误收;生命周期也不同:附件跟 task/session 绑定)。形态跟 StoreBackend
|
|
348
|
-
// 三态:tidb/pg=SQL twins(真双库验证)、local=文件店;无 backend(纯内存 dev)=不挂 ⇒ 路由 501。
|
|
349
|
-
// 四半场:①上传/取回/删除(http/server.ts 路由)②提交时绑定+objective 告知+host lane 物化
|
|
350
|
-
// (resolveSpec 内,下方)③远程 lane env 建立时物化(executionEnvFactory 包装,下方)④生命周期
|
|
351
|
-
// (E21 purge 级联 + 未绑定 TTL reaper)。
|
|
352
216
|
let taskAttachmentStore;
|
|
353
217
|
{
|
|
354
218
|
const mysqlPool = backend?.mysqlPool?.();
|
|
355
219
|
const pgPool = backend?.pgPool?.();
|
|
356
220
|
if (pgPool || mysqlPool) {
|
|
357
|
-
// clay 裁(2026-07-27):**云形态对象存储必配**——附件字节本体进 MinIO(SQL 只存 meta/门/生命周期)。
|
|
358
|
-
// 复用快照 lane 的同一 MinIO 部署配置(MINIO_ENDPOINT/ACCESS/SECRET,零重映射),但**附件专属
|
|
359
|
-
// keyPrefix**:对象键=sha256,与快照 blob 同 sha 不同生命周期,同名字空间会互删。未配 ⇒ 附件面
|
|
360
|
-
// 不接线(路由 501)+ error 级日志——这是部署配置错误,不静默降级回「字节进 DB」(该形已被裁掉)。
|
|
361
221
|
const minio = config.snapshotBlobStore;
|
|
362
222
|
if (!minio) {
|
|
363
223
|
logger.error("attachments_disabled_object_store_required", {
|
|
@@ -383,11 +243,6 @@ export async function openStores(ctx) {
|
|
|
383
243
|
if (taskAttachmentStore)
|
|
384
244
|
logger.info("task_attachment_store_enabled", { backend: pgPool ? "pg+minio" : mysqlPool ? "tidb+minio" : "file", maxBytes: config.attachmentMaxBytes });
|
|
385
245
|
}
|
|
386
|
-
// S3c(core 1.374 行为车,[1531]):teammate 信箱——SendMessage 对 SETTLED named teammate 的 tier-3
|
|
387
|
-
// 懒复活链(durable 行解析→claim-CAS→mailbox append→reviveSpawn→attach 屏障后 ack)。激活三件套=
|
|
388
|
-
// RunnerDeps.mailboxStore + backgroundAgentStore 同挂 + delegation 工具在场,三缺一=1.373 文本字节
|
|
389
|
-
// 不变(诚实拒)。形态同上:tidb/pg=SQL twins(mailbox-store-sql.ts,发车复审八修顶注);local=
|
|
390
|
-
// core FileMailboxStore;纯内存 dev=不挂。回执句族(details.error 枚举)wire 透传零改动。
|
|
391
246
|
let mailboxStore;
|
|
392
247
|
{
|
|
393
248
|
const mysqlPool = backend?.mysqlPool?.();
|
|
@@ -401,7 +256,6 @@ export async function openStores(ctx) {
|
|
|
401
256
|
mailboxStore = new TiDBMailboxStore(mysqlPool);
|
|
402
257
|
}
|
|
403
258
|
else if (backend?.kind === "local") {
|
|
404
|
-
// #113([2399]③→[2408] core 5.2.0 补座):腐读披露——照 roster 同形;torn-tail 静默=core 有意边界。
|
|
405
259
|
mailboxStore = new FileMailboxStore(config.localDataRoot ?? localRoot, {
|
|
406
260
|
onCorruptRead: (info) => logger.warn("mailbox_corrupt_read", { path: info.path, reason: info.reason }),
|
|
407
261
|
});
|
|
@@ -409,11 +263,6 @@ export async function openStores(ctx) {
|
|
|
409
263
|
if (mailboxStore)
|
|
410
264
|
logger.info("mailbox_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
|
|
411
265
|
}
|
|
412
|
-
// design/166-T1:治理窗账本店——只在 USAGE_WINDOWS 配置时构造(两键成对进 RunnerDeps,core 的
|
|
413
|
-
// 「windows 有 store 无=INACTIVE 警告」在构造上被排除)。形态跟 mailbox:tidb/pg=SQL twins
|
|
414
|
-
// (ensure-first+行锁,真双库验证,usage-window-store-sql.ts 顶注);local=core FileUsageWindowStore
|
|
415
|
-
// (构造器内部自拼 usage-windows/,直传数据根——复审新6);纯内存 dev=core InMemoryUsageWindowStore
|
|
416
|
-
// (进程内计数,单进程 dev 的诚实形——治理窗设了就得生效,不因无持久层而静默失活)。
|
|
417
266
|
let usageWindowStore;
|
|
418
267
|
if (config.usageWindows) {
|
|
419
268
|
const mysqlPool = backend?.mysqlPool?.();
|
|
@@ -434,15 +283,8 @@ export async function openStores(ctx) {
|
|
|
434
283
|
}
|
|
435
284
|
logger.info("usage_window_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : backend?.kind === "local" ? "file" : "memory", windows: config.usageWindows.length });
|
|
436
285
|
}
|
|
437
|
-
// 142-S5 §1.4: the per-scope export READ face lights up only on the DB memory plane (the multi-tenant
|
|
438
|
-
// truth lives in the scope-partitioned tables; the file posture exports by copying the memory dir, so
|
|
439
|
-
// the route 501s honestly there). History-table WRITE wiring: inside the backend construction above
|
|
440
|
-
// (S5.1, opts.history — the write point lives in the handed-over backend code).
|
|
441
286
|
const memoryExportBackend = config.memoryEngineBackend !== "file" ? memoryEngine?.backend : undefined;
|
|
442
|
-
const memoryLane = memoryEngineRemoteLanePosture(config);
|
|
443
|
-
// #252 件2/件3:记忆面姿态 —— **单一推导点**(纯,memory-posture.ts),两个读面(operator 诊断 /
|
|
444
|
-
// 能力位)都投影它,启动日志的 dark 报因也走它的闭集词,于是「日志说暗、能力位说亮」不可能发生。
|
|
445
|
-
// 位置:两支引擎装配都结束之后(要 `memoryEngine` 与 `vectorMode` 两件装配结果)。
|
|
287
|
+
const memoryLane = memoryEngineRemoteLanePosture(config);
|
|
446
288
|
const memoryPosture = buildMemoryPosture({
|
|
447
289
|
config,
|
|
448
290
|
engineWired: memoryEngine !== undefined,
|
|
@@ -454,23 +296,12 @@ export async function openStores(ctx) {
|
|
|
454
296
|
? { enabled: true, backend: "file", dir: memoryEngine.root }
|
|
455
297
|
: {
|
|
456
298
|
enabled: false,
|
|
457
|
-
// 复审 F-11:按最终门结果报因,多租户 file=隔离判据,其余照旧。
|
|
458
|
-
// #252:散文由**闭集词**派生(`memoryPosture.darkReason`)——机器面与人面从此不会各报各的因。
|
|
459
299
|
reason: DARK_REASON_PROSE[memoryPosture.darkReason ?? "engine_off"](memoryLane?.lane),
|
|
460
300
|
});
|
|
461
301
|
}
|
|
462
|
-
// N0 boot warn: loud in BOTH postures — "dark" so an upgrade that silently turns memory off is visible,
|
|
463
|
-
// "forced" so an operator override states what it depends on (harvest only sees the WORKER fs). 文案与分腿
|
|
464
|
-
// 判据在 memory-scope.buildMemoryRemoteLaneWarn(纯,可单测);这里只喂**装配结果**(引擎真接上了没有)——
|
|
465
|
-
// DB 腿的引擎在 :113 就点亮了,与车道姿态无关,照旧打 dark 文案会与上面的 memory_engine_enabled 对撞。
|
|
466
302
|
const laneWarn = buildMemoryRemoteLaneWarn(config, memoryEngine !== undefined);
|
|
467
303
|
if (laneWarn)
|
|
468
304
|
logger.warn("memory_engine_remote_lane", laneWarn);
|
|
469
|
-
// 142-S2.5-W1: TOC 同步 client 腿——只在 file memory 形态接线(loadConfig 已拒 DB backend
|
|
470
|
-
// 上的 MEMORY_SYNC_*,这条分支到不了)。boot 后 fire-and-forget 一轮(失败 warn 不阻断——纯本地现状
|
|
471
|
-
// 是安全降级面);之后 harvest 真有 patch 落地时再触发(onMemoryHarvestReport 站点,inflight 节流)。
|
|
472
|
-
// 引擎 dark(多租户/MEMORY_ENGINE=off/remote lane)⇒ 无本地盘可同步:warn 不 throw(dark 的三个成因
|
|
473
|
-
// 各有自己的 loud 日志在上方,这里补“sync 因此没跑”这半句,operator 可见不半配)。
|
|
474
305
|
let memorySyncRunner;
|
|
475
306
|
if (config.memorySync) {
|
|
476
307
|
if (memoryEngine) {
|
|
@@ -480,7 +311,6 @@ export async function openStores(ctx) {
|
|
|
480
311
|
memoryRoot: memoryEngine.root,
|
|
481
312
|
transport: createMemorySyncTransport({ url: config.memorySync.url, token: config.memorySync.token }),
|
|
482
313
|
log: logger,
|
|
483
|
-
// S2.5 分批(core 1.284):未设=不分批 wire 字节不变;设了=续轮 loop 至收敛(MAX_SYNC_ROUNDS 警戒)。
|
|
484
314
|
...(config.memorySync.maxPushEntries !== undefined ? { maxPushEntries: config.memorySync.maxPushEntries } : {}),
|
|
485
315
|
...(config.memorySync.maxPullEntries !== undefined ? { maxPullEntries: config.memorySync.maxPullEntries } : {}),
|
|
486
316
|
});
|
|
@@ -491,13 +321,6 @@ export async function openStores(ctx) {
|
|
|
491
321
|
logger.warn("memory_sync_configured_but_memory_dark", { note: "MEMORY_SYNC_URL is set but the file memory engine is dark (multi-tenant / MEMORY_ENGINE=off / remote exec lane) — no sync rounds will run" });
|
|
492
322
|
}
|
|
493
323
|
}
|
|
494
|
-
// #318([4659] F2 → [4692] 定谳):会话级任务清单车道。形态与 roster/mailbox/background-agent 同族
|
|
495
|
-
// (pg/tidb = SQL twins;无 SQL 后端 = 进程级 per-session 内存店 —— 这一支**刻意不缺席**:缺席就是
|
|
496
|
-
// 修前那个「每 turn 一只新私店」的病本身,而 local/内存形至少要把同一会话的跨 turn 连续性拿回来)。
|
|
497
|
-
// 全部判据(listKey 派生、LRU、为什么 SQL 形也缓存实例)见 boot/task-list-lane.ts 顶注。
|
|
498
|
-
// ⚠️ 建表在**本文件**发 —— `test/schema-baseline-generated.test.ts` 判据 ③b 拿「boot/stores.ts 里真被
|
|
499
|
-
// await 的 ensure 名」与 schema 基线生成器的驱动清单做集合相等对账(消灭「两条方言同时漏一族表」的
|
|
500
|
-
// 对称盲区,`usage_window` 曾整族漏在基线外)。DDL 藏进车道文件 = 那道门看不见它。
|
|
501
324
|
const taskListLane = await (async () => {
|
|
502
325
|
const mysqlPool = backend?.mysqlPool?.();
|
|
503
326
|
const pgPool = backend?.pgPool?.();
|
|
@@ -507,20 +330,7 @@ export async function openStores(ctx) {
|
|
|
507
330
|
await ensureTiDBTaskListSchema(mysqlPool);
|
|
508
331
|
return createTaskListLane({ mysqlPool, pgPool, logger });
|
|
509
332
|
})();
|
|
510
|
-
const sessionStore = createSessionStore(config, backend, metrics);
|
|
511
|
-
// 🪦 S6 启动门(旧):判据曾是 `!sessionStore.ownerOf`,core 2.11.0 给 TtlSessionStore 补了 owner 面后**恒假**。
|
|
512
|
-
// 2026-08-01 复审一度把判据改成「归属能否跨重启存活」以复活它 —— **那是错的,已撤**(cli [C46] 的
|
|
513
|
-
// 多租真机围栏当场证伪:`REQUIRE_PRINCIPAL=true` + 内存店必须**起得来**且真隔离)。
|
|
514
|
-
// 错在威胁模型:内存店重启后**会话数据本身也没了**,"先到者认领 session id" 认领到的是空壳,
|
|
515
|
-
// alice 的历史随进程消失 —— 归属丢失 ≠ 数据泄露。真正危险的是**数据留存而归属丢失**的 file 形,
|
|
516
|
-
// 那一形由下面那道 local 门拦住(它的论证里 "session/run CONTENT is durable there" 正是这个区别)。
|
|
517
|
-
// ⇒ 这道门防的威胁(store 没有归属能力)已被 core 2.11.0 消除,补偿该撤,不该换个判据续命。
|
|
518
|
-
// 判据跟目的走、不跟补偿走(cli [C46] 的原话,我抄下)。反向钉见 test/security.test.ts。
|
|
519
|
-
// The local in-memory backend HAS an ownerOf (LocalSessionStore), so the guard above passes — but its owner map is
|
|
520
|
-
// process-local + lost on restart, so it cannot DURABLY enforce multi-tenant ownership (post-restart a session id is
|
|
521
|
-
// re-claimable by whoever attaches first). Refuse REQUIRE_PRINCIPAL on it: a real multi-tenant
|
|
522
|
-
// boundary needs the durable DB backend; single-user local runs with REQUIRE_PRINCIPAL=false (the principal may
|
|
523
|
-
// still ride for memory-scoping). The file-backed follow-on (durable owners) can revisit this.
|
|
333
|
+
const sessionStore = createSessionStore(config, backend, metrics);
|
|
524
334
|
if (config.requirePrincipal && backend?.kind === "local") {
|
|
525
335
|
throw new Error("REQUIRE_PRINCIPAL=true is not supported on the local file backend (DB_BACKEND=local): session/run CONTENT is " +
|
|
526
336
|
"durable there, but OWNER attribution is process-local and lost on restart (store-backend.ts §0.5 — durable " +
|
|
@@ -528,27 +338,17 @@ export async function openStores(ctx) {
|
|
|
528
338
|
"(DB_BACKEND=mysql|pg) for multi-tenant, or run local single-user with REQUIRE_PRINCIPAL=false (a BFF may " +
|
|
529
339
|
"still inject x-agent-principal per request for memory scoping and audit attribution).");
|
|
530
340
|
}
|
|
531
|
-
// (c)(clay 拍 a+c,2026-07-27)云形快照 blob 姿势门:mysql|pg 后端缺 MinIO ⇒ fail-loud(bytes-in-DB
|
|
532
|
-
// 撞包墙已两役实证);SNAPSHOT_BLOB_ALLOW_SQL_BYTES=true 显式逃生(单机/测试台,吃 (a) 的 per-blob 帽)。
|
|
533
341
|
if (backend)
|
|
534
342
|
assertCloudSnapshotBlobPosture(backend.kind, config);
|
|
535
|
-
// Posture warning (audit B, security.ts): an owner-aware store without REQUIRE_PRINCIPAL means the
|
|
536
|
-
// principal layer is optional per request. Owned sessions are still protected (the authorizer rejects
|
|
537
|
-
// anonymous/mismatched attach), but new headerless submissions create anonymous sessions any token
|
|
538
|
-
// holder can attach to — a multi-tenant deployment should set REQUIRE_PRINCIPAL=true.
|
|
539
343
|
if (!config.requirePrincipal && sessionStore.ownerOf) {
|
|
540
344
|
logger.warn("principal_optional", {
|
|
541
345
|
note: "owner-aware session store with REQUIRE_PRINCIPAL=false — owned sessions are protected, but headerless callers can create/share anonymous sessions; set REQUIRE_PRINCIPAL=true for multi-tenant",
|
|
542
346
|
});
|
|
543
347
|
}
|
|
544
348
|
metrics.dynamicGauge("sessions_warm", "Sessions held in the warm cache", () => sessionStore.size);
|
|
545
|
-
// 1.38 cross-replica circuit-breaker state: shared via TiDB when a pool exists AND the breaker is
|
|
546
|
-
// enabled; otherwise core's per-process Map (single replica / no DB / breaker off). Refresh loop is
|
|
547
|
-
// unref'd so it never holds the process open.
|
|
548
349
|
const breakerState = backend?.breaker && config.resilience.circuitBreaker
|
|
549
350
|
? backend
|
|
550
351
|
.breaker((streak) => {
|
|
551
|
-
// LOW (SILENT-FALLBACK P1): cross-replica breaker write-through failures were a bare swallow.
|
|
552
352
|
metrics.setGauge("counter_flush_fail_streak", streak, { table: "circuit_breaker", kind: "write_through" });
|
|
553
353
|
if (streak > 0)
|
|
554
354
|
metrics.inc("breaker_writethrough_failed_total", { backend: backend.kind });
|
|
@@ -558,7 +358,7 @@ export async function openStores(ctx) {
|
|
|
558
358
|
logger.info("breaker_writethrough_recovered", {});
|
|
559
359
|
})
|
|
560
360
|
.startRefresh()
|
|
561
|
-
: undefined;
|
|
361
|
+
: undefined;
|
|
562
362
|
return {
|
|
563
363
|
backend, storeBackendDegraded, memoryEngine, memorySyncCursors, rosterStore, backgroundAgentStore,
|
|
564
364
|
taskAttachmentStore, mailboxStore, memoryExportBackend, memorySyncRunner, sessionStore, breakerState,
|
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
import { createMemoryTaskListStore } from "@sema-agent/core";
|
|
2
2
|
import { BoundedSessionMap } from "../bounded-session-map.js";
|
|
3
3
|
import { createPgTaskListStore, createTiDBTaskListStore, deletePgTaskList, deleteTiDBTaskList, taskListKeyFor, } from "../plugins/task-list-store-sql.js";
|
|
4
|
-
/** 同时活着的会话清单实例上限(LRU,逐最老)。与 perSessionCwd/perSessionShellEnv 同量级。 */
|
|
5
4
|
export const MAX_TASK_LIST_SESSIONS = 4096;
|
|
6
|
-
// listKey 派生式的**属主是 store 文件**(`plugins/task-list-store-sql.ts` 的 {@link taskListKeyFor}
|
|
7
|
-
// ——字节约束在那边,留存腿也按同一只函数批量删行;派生有两份 = 在线删得掉、留存腿删不掉)。
|
|
8
|
-
// 这里只是把它一并导出,消费方(index.ts / 测试)不必知道它住在哪一层。
|
|
9
5
|
export { taskListKeyFor } from "../plugins/task-list-store-sql.js";
|
|
10
|
-
/**
|
|
11
|
-
* 车道构造(boot 期一次)。
|
|
12
|
-
*
|
|
13
|
-
* ⚠️ **建表不在这里**:`ensure{TiDB,Pg}TaskListSchema` 由 `boot/stores.ts` 在构造之前 await
|
|
14
|
-
* (与 roster/mailbox/background-agent/usage-window 四族逐字同姿势)。理由不是风格——
|
|
15
|
-
* `test/schema-baseline-generated.test.ts` 判据 ③b 拿「`boot/stores.ts` 里真被 await 的 ensure 名」
|
|
16
|
-
* 与「生成器驱动的清单」做**集合相等**对账,那是消灭「两条方言同时漏一族表」这个对称盲区的唯一
|
|
17
|
-
* 不对称真源(`usage_window` 曾整族漏在基线外)。DDL 藏在本文件里 = 那道门看不见它。
|
|
18
|
-
*/
|
|
19
6
|
export function createTaskListLane(opts = {}) {
|
|
20
7
|
const { mysqlPool, pgPool, logger } = opts;
|
|
21
8
|
const maxSessions = opts.maxSessions ?? MAX_TASK_LIST_SESSIONS;
|
|
22
9
|
const cache = new BoundedSessionMap(maxSessions);
|
|
23
10
|
let backend;
|
|
24
11
|
let mint;
|
|
25
|
-
/** 后端侧的整份清单抹除(memory 形无后端 ⇒ 只靠下面的缓存逐出)。 */
|
|
26
12
|
let purge;
|
|
27
13
|
if (pgPool) {
|
|
28
14
|
backend = "pg";
|
|
@@ -41,7 +27,6 @@ export function createTaskListLane(opts = {}) {
|
|
|
41
27
|
}
|
|
42
28
|
const storeFor = (sessionId) => {
|
|
43
29
|
const hit = cache.get(sessionId);
|
|
44
|
-
// 命中即回写 = 刷新 MRU(BoundedSessionMap 的 `get` 刻意不动顺序,逐出闩只看 `set` 的插入序)。
|
|
45
30
|
if (hit !== undefined) {
|
|
46
31
|
cache.set(sessionId, hit);
|
|
47
32
|
return hit;
|
|
@@ -51,9 +36,6 @@ export function createTaskListLane(opts = {}) {
|
|
|
51
36
|
return fresh;
|
|
52
37
|
};
|
|
53
38
|
const deleteBySession = async (sessionId) => {
|
|
54
|
-
// 先逐出缓存再删后端:反过来的话,两者之间的窗口里一次并发解析会拿到**旧实例**(memory 形
|
|
55
|
-
// 是旧数据本身;SQL 形是刚被删空的分区,新写会把行插回去)。缓存先走 = 那扇窗里的解析看到的
|
|
56
|
-
// 是一份新铸的空清单,与「会话已删」一致。
|
|
57
39
|
cache.delete(sessionId);
|
|
58
40
|
await purge(sessionId);
|
|
59
41
|
};
|
|
@@ -1,50 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A-057.5 [CONFIRMED high](2026-08-19 三轴组复审,真机探针复现)—— WebFetch 摘要面的
|
|
3
|
-
* **per-model key plane**,与 `boot/side-query-lane.ts` 同一只 wrapper、同一条纪律。
|
|
4
|
-
*
|
|
5
|
-
* ## 病灶(#303 的第四面,逐字同形)
|
|
6
|
-
*
|
|
7
|
-
* #303 的头注写「side-query 是 key plane 三面里**唯一**缺席的那一面」—— 那句话是假的。
|
|
8
|
-
* `createWebFetchSummarizer(brain, model)` 的 `brain` 是 `RunnerDeps.brain` 那只**裸网关 brain**
|
|
9
|
-
* (`boot/budget-tracing.ts` 的 `createBrain(config, …)`,`get apiKey()` 恒回 `config.gatewayApiKey`),
|
|
10
|
-
* 而 core 的摘要腿(`dist/tools/web.js`)铸 options 只放 `{ signal }`——`WebFetchSummarizerOptions`
|
|
11
|
-
* 结构性没有 key 座位。于是 openai brain 的那两行照旧:
|
|
12
|
-
* `const apiKey = options?.apiKey ?? config.apiKey;` ← 缺席即回落**主网关 key**
|
|
13
|
-
* `const root = (model.baseUrl || config.baseUrl || "")` ← 却**按模型**选路
|
|
14
|
-
* ⇒ summarize 角色解析到一只带自有 `baseUrl` + `apiKeyEnv/sealedApiKey` 的模型时,**主网关 key 被发到
|
|
15
|
-
* 那只模型自己的外部 URL**;而且这不落在 #303 已具名接受的那条残余里(那条说的是「**没有** per-model
|
|
16
|
-
* key 的 off-route 模型仍收网关 key」)—— 这只模型**有**自己的 key,却拿不到。
|
|
17
|
-
*
|
|
18
|
-
* 第二半同样成立:毒丸(sealed key 解不开)在本面**静默回落网关账号** —— 本面根本不经
|
|
19
|
-
* `resolveModelApiKey`,`key-resolver.ts` 顶注那句「a broken sealed key must NEVER silently burn the
|
|
20
|
-
* shared gateway account」在这条路上不成立。
|
|
21
|
-
*
|
|
22
|
-
* ## 修形 = 照 #303 的配方接第四面(不是新造语义)
|
|
23
|
-
*
|
|
24
|
-
* brain 换成 `createPerModelKeyBrain(brain, getKeyResolver)`:
|
|
25
|
-
* · 有 per-model key ⇒ 注入 `options.apiKey`,请求带模型自己的凭据;
|
|
26
|
-
* · 无 ⇒ 不注入 ⇒ 回落网关 key(与主推理链/side-query 逐字同语义,additive 契约;该残余的成文与
|
|
27
|
-
* 跨面收严件见 side-query-lane.ts 顶注「具名残余」段与 A-057.59);
|
|
28
|
-
* · 毒丸 ⇒ **上抛**,一个字节都不发(CLAUDE.md #157 安全轴 fail-closed)。
|
|
29
|
-
* wrapper 只包本席这一只引用,`RunnerDeps.brain` 零扰动(与 side-query 席同形)。
|
|
30
|
-
*
|
|
31
|
-
* ## 为什么住在 `boot/` 而不是继续躺在 `main()` 的闭包里
|
|
32
|
-
*
|
|
33
|
-
* ① 这是一条**可发射的 LLM 面**,必须能被黑盒探针(真 fetchImpl 捕 Authorization)直接驱动 —— 躺在
|
|
34
|
-
* `main()` 里只能靠源码字面锚,而本仓已成文「源码字面锚有致命假绿形」(A-057.4/.11 那一族);
|
|
35
|
-
* ② 发射面枚举门(`test/per-model-key.test.ts` 的 `DIRECT_EMISSION_FACES`)按**文件**登记在册,第四面
|
|
36
|
-
* 有自己的文件才登记得住。
|
|
37
|
-
*
|
|
38
|
-
* 原地保留的两条既有语义(E-MED-2/E-MED-3,[1900]/[1904] 复审批):
|
|
39
|
-
* · **惰性解析**:模型每次调用现取 —— `config.models`/`config.roles` 会被 center 的 effective 热应用
|
|
40
|
-
* `mutateInPlace` 整表替换,boot 期急求值会把摘要器永久 pin 在占位/旧模型上;
|
|
41
|
-
* · **fail-soft**:`resolveTaskModel` 在无可解析角色时 throw,这是全仓唯一 boot 期裸调用点;解析失败
|
|
42
|
-
* ⇒ 本次不摘要(core 的 summarize 抛错是 fail-open:回退原文 + note),绝不崩 boot。
|
|
43
|
-
*/
|
|
44
1
|
import { createWebFetchSummarizer, resolveTaskModel as coreResolveTaskModel } from "@sema-agent/core";
|
|
45
2
|
import { createPerModelKeyBrain } from "./side-query-lane.js";
|
|
46
3
|
export function createWebFetchSummarizeLane(ctx) {
|
|
47
|
-
// 与 side-query 席同形:wrapper 装配一次,resolver 靠 `getKeyResolver` 活取(热应用后下一次调用即生效)。
|
|
48
4
|
const brain = createPerModelKeyBrain(ctx.brain, ctx.getKeyResolver, { gatewayBaseUrl: ctx.config.gatewayBaseUrl });
|
|
49
5
|
return async (content, prompt, signal) => {
|
|
50
6
|
const model = (() => {
|
|
@@ -58,9 +14,6 @@ export function createWebFetchSummarizeLane(ctx) {
|
|
|
58
14
|
})();
|
|
59
15
|
if (!model)
|
|
60
16
|
throw new Error("summarize model unresolved for this deployment");
|
|
61
|
-
// core 2.13.0:返回形放宽为 additive union(`string | { text, truncated? }`)—— 这里**原样转发**
|
|
62
|
-
// core summarizer 的返回值,不在本仓收窄成 string(收窄会把 core 的截断披露 `truncated` 吃掉,
|
|
63
|
-
// 让「内容被截断」这个事实在 fence 外消失)。
|
|
64
17
|
return createWebFetchSummarizer(brain, model)(content, prompt, signal);
|
|
65
18
|
};
|
|
66
19
|
}
|