@sema-agent/server 7.122.0 → 7.124.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 +209 -0
- package/README.md +7 -2
- package/README.zh-CN.md +5 -2
- package/USAGE.md +76 -56
- package/dist/approval-ask-audit-store.d.ts +27 -32
- package/dist/approval-ask-audit-store.js +10 -9
- package/dist/approval-crash-convergence.d.ts +2 -2
- package/dist/approval-crash-convergence.js +5 -5
- package/dist/approval-deny-reasons.d.ts +163 -51
- package/dist/approval-deny-reasons.js +79 -8
- package/dist/approval-policy-settlement.d.ts +4 -1
- package/dist/approval-policy-settlement.js +3 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval-reconciler.js +10 -10
- package/dist/approval.d.ts +1 -1
- package/dist/approval.js +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +53 -23
- package/dist/auth-bridge.d.ts +8 -8
- package/dist/auth-bridge.js +6 -6
- package/dist/auth-keys.d.ts +2 -2
- package/dist/auto-mode-face.d.ts +13 -9
- package/dist/auto-mode-face.js +8 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/execution-env.js +1 -0
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +4 -4
- package/dist/boot/org-memory.d.ts +3 -3
- package/dist/boot/org-memory.js +5 -5
- package/dist/boot/resolve-spec.js +7 -7
- package/dist/boot/runner-deps.d.ts +1 -1
- package/dist/boot/runtime-caps.d.ts +1 -1
- package/dist/boot/runtime-caps.js +10 -10
- package/dist/boot/shutdown.d.ts +2 -2
- package/dist/boot/shutdown.js +2 -2
- package/dist/boot/side-query-lane.d.ts +3 -3
- package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
- package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
- package/dist/boot/stage-03-store-backend.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +6 -6
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +6 -5
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -3
- package/dist/boot/stage-09-leader.js +7 -7
- package/dist/boot/stage-10-http-server.d.ts +3 -3
- package/dist/boot/stage-10-http-server.js +19 -19
- package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
- package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
- package/dist/boot/{config-center.js → web-admin.js} +39 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
- package/dist/brain.d.ts +1 -1
- package/dist/brain.js +1 -1
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +12 -5
- package/dist/capabilities/center-wiring.js +11 -2
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/team.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/center-credential-renewer.d.ts +1 -1
- package/dist/center-credential-renewer.js +7 -7
- package/dist/center-credential.d.ts +9 -9
- package/dist/center-credential.js +6 -6
- package/dist/config-catalog.d.ts +7 -10
- package/dist/config-catalog.js +16 -16
- package/dist/config-d-migration.d.ts +32 -0
- package/dist/config-d-migration.js +59 -0
- package/dist/config-invariants.d.ts +14 -4
- package/dist/config-invariants.js +31 -2
- package/dist/config-lkg.d.ts +34 -11
- package/dist/config-lkg.js +76 -48
- package/dist/config-provider.d.ts +26 -21
- package/dist/config-provider.js +25 -27
- package/dist/config-types.d.ts +59 -50
- package/dist/config.d.ts +17 -54
- package/dist/config.js +99 -181
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/drain-entry.d.ts +1 -1
- package/dist/fleet/engine-signal.d.ts +61 -30
- package/dist/fleet/engine-signal.js +29 -5
- package/dist/fleet/fleet-bus.d.ts +12 -3
- package/dist/fleet/fleet-bus.js +13 -9
- package/dist/fleet/serving-lease.d.ts +3 -3
- package/dist/fleet/serving-lease.js +1 -1
- package/dist/fleet-client.d.ts +15 -13
- package/dist/fleet-client.js +9 -7
- package/dist/fleet-lease.d.ts +3 -3
- package/dist/fleet-lease.js +2 -2
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/hosted-posture.d.ts +4 -4
- package/dist/http/admission.js +4 -4
- package/dist/http/checkpoint-ctx.d.ts +20 -3
- package/dist/http/checkpoint-ctx.js +13 -5
- package/dist/http/dispatch.js +7 -16
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +7 -4
- package/dist/http/health-self-report.js +3 -3
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +31 -18
- package/dist/http/route-ctx.d.ts +8 -0
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.d.ts +1 -1
- package/dist/http/routes/admin-drain.js +5 -4
- package/dist/http/routes/approvals-assistant.js +4 -4
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/config-catalog.js +2 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/runs.js +8 -4
- package/dist/http/routes/sessions-list.js +2 -1
- package/dist/http/routes/sessions.js +2 -5
- package/dist/http/routes/side-query.js +3 -3
- package/dist/http/routes/tasks.js +3 -2
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/run-meta.js +2 -2
- package/dist/http/server.d.ts +7 -7
- package/dist/http/server.js +1 -1
- package/dist/http/stored-body-replay.d.ts +4 -3
- package/dist/http/stored-body-replay.js +5 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/leader.d.ts +7 -6
- package/dist/leader/leader.js +3 -1
- package/dist/leader/run-entry.d.ts +2 -2
- package/dist/leader/run-entry.js +3 -3
- package/dist/leader/wire.d.ts +4 -4
- package/dist/leader/wire.js +2 -1
- package/dist/main.js +1 -1
- package/dist/mcp-tool-faces.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +20 -11
- package/dist/model-entry-refusal.js +22 -17
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +22 -2
- package/dist/model-route-endpoint.js +9 -3
- package/dist/model-route-gap.d.ts +103 -0
- package/dist/model-route-gap.js +80 -0
- package/dist/model-route-url.d.ts +1 -1
- package/dist/model-route-url.js +2 -1
- package/dist/model-select.d.ts +24 -21
- package/dist/model-select.js +22 -17
- package/dist/namespaced-rule-name.d.ts +16 -30
- package/dist/namespaced-rule-name.js +2 -20
- package/dist/observability/fail-open.d.ts +0 -4
- package/dist/observability/fail-open.js +0 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/org-memory-admission.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -2
- package/dist/plugins/approval-ask-store-file.js +3 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
- package/dist/plugins/approval-ask-store-memory.js +10 -4
- package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
- package/dist/plugins/approval-ask-store-sql.js +20 -13
- package/dist/plugins/caching-session-store.d.ts +0 -10
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/file-run-store.js +9 -3
- package/dist/plugins/leader-run-store-sql.d.ts +3 -2
- package/dist/plugins/leader-run-store-sql.js +3 -2
- package/dist/plugins/local-session-store.d.ts +20 -27
- package/dist/plugins/local-session-store.js +19 -17
- package/dist/plugins/memory-run-store.js +9 -3
- package/dist/plugins/one-time-migrations.js +51 -0
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- package/dist/plugins/session-policy-store-sql.js +1 -2
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +20 -4
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
- package/dist/posture-source.d.ts +1 -1
- package/dist/read-face-posture.d.ts +3 -3
- package/dist/read-face-posture.js +1 -1
- package/dist/rule-entry-list.d.ts +3 -13
- package/dist/rule-entry-list.js +1 -12
- package/dist/run-local.js +10 -7
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +36 -13
- package/dist/runtime-governance.js +7 -2
- package/dist/sealed-key.d.ts +4 -4
- package/dist/sealed-key.js +3 -2
- package/dist/security.d.ts +3 -3
- package/dist/service-version.d.ts +1 -1
- package/dist/service-version.js +5 -0
- package/dist/session-policy-wire.d.ts +47 -49
- package/dist/session-policy-wire.js +41 -36
- package/dist/session-sync.d.ts +5 -1
- package/dist/session-sync.js +2 -1
- package/dist/session-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/spec-fields.d.ts +4 -4
- package/dist/spec-fields.js +1 -4
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-settings.d.ts +4 -5
- package/dist/task-settings.js +5 -8
- package/dist/tool-approval.d.ts +43 -4
- package/dist/tool-approval.js +147 -98
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +3 -3
- package/dist/trace/redact.d.ts +2 -23
- package/dist/trace/redact.js +1 -6
- package/dist/trace/self-minted-wire.d.ts +147 -3
- package/dist/trace/self-minted-wire.js +50 -9
- package/dist/unattended-permission-mode.d.ts +3 -3
- package/dist/unattended-permission-mode.js +2 -2
- package/dist/url-refusal.d.ts +35 -0
- package/dist/url-refusal.js +15 -0
- package/dist/user-authored-text.d.ts +31 -0
- package/dist/user-authored-text.js +18 -0
- package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
- package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
- package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
- package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
- package/dist/{config-center → web-admin-client}/center-request.js +5 -4
- package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
- package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
- package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
- package/dist/{config-center → web-admin-client}/facade.js +2 -2
- package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
- package/dist/{config-center → web-admin-client}/http-client.js +15 -15
- package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/read-face.js +4 -4
- package/dist/web-admin-client/read-warnings.d.ts +137 -0
- package/dist/web-admin-client/read-warnings.js +168 -0
- package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
- package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
- package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
- package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
- package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
- package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
- package/package.json +3 -3
- package/skills/find-skills.md +2 -2
- package/dist/config-center/read-warnings.d.ts +0 -109
- package/dist/config-center/read-warnings.js +0 -110
- package/dist/url-shape.d.ts +0 -31
- package/dist/url-shape.js +0 -41
- /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
- /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
- /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/types.js +0 -0
package/dist/audit.js
CHANGED
|
@@ -4,6 +4,7 @@ import { PgSessionStorage } from "./plugins/pg-session-storage.js";
|
|
|
4
4
|
import { createLocalSessionRepo } from "./plugins/local-session-store.js";
|
|
5
5
|
import { redactModelText } from "./observability/run-terminal.js";
|
|
6
6
|
import { redactDeepWith } from "./trace/redact.js";
|
|
7
|
+
import { INJECTED_BLOCK_RE } from "./user-authored-text.js";
|
|
7
8
|
export async function buildSessionAudit(pool, sessionId) {
|
|
8
9
|
return auditFromStorage(await TiDBSessionStorage.wake(pool, sessionId), sessionId);
|
|
9
10
|
}
|
|
@@ -45,48 +46,78 @@ async function auditFromStorage(storage, sessionId) {
|
|
|
45
46
|
}
|
|
46
47
|
const deepScrub = (v) => redactDeepWith(v, redactModelText);
|
|
47
48
|
const textSlot = (v) => (typeof v === "string" ? redactModelText(v) : deepScrub(v));
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
function readLeaf(treatment, v) {
|
|
50
|
+
switch (treatment) {
|
|
51
|
+
case "text": return textSlot(v);
|
|
52
|
+
case "structure": return deepScrub(v);
|
|
53
|
+
case "parts": return readParts(v);
|
|
54
|
+
case "verbatim": return v;
|
|
55
|
+
default: {
|
|
56
|
+
const unhandled = treatment;
|
|
57
|
+
throw new Error(`unhandled leaf treatment: ${String(unhandled)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const isPlainRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
62
|
+
function readByTable(node, table) {
|
|
63
|
+
let changed = false;
|
|
64
|
+
const entries = Object.entries(node).map(([key, v]) => {
|
|
65
|
+
const next = readLeaf(Object.hasOwn(table, key) ? table[key] : "structure", v);
|
|
66
|
+
if (next !== v)
|
|
67
|
+
changed = true;
|
|
68
|
+
return [key, next];
|
|
69
|
+
});
|
|
70
|
+
return changed ? Object.fromEntries(entries) : node;
|
|
54
71
|
}
|
|
55
72
|
const PART_READ_TREATMENT = {
|
|
56
|
-
text:
|
|
57
|
-
thinking:
|
|
58
|
-
toolCall:
|
|
59
|
-
image:
|
|
60
|
-
document:
|
|
73
|
+
text: { type: "verbatim", text: "text" },
|
|
74
|
+
thinking: { type: "verbatim", thinking: "text", thinkingSignature: "verbatim", redacted: "verbatim" },
|
|
75
|
+
toolCall: { type: "verbatim", id: "verbatim", wireId: "verbatim", name: "verbatim", arguments: "structure", executionMode: "verbatim" },
|
|
76
|
+
image: { type: "verbatim", data: "verbatim", mimeType: "verbatim" },
|
|
77
|
+
document: { type: "verbatim", data: "verbatim", mimeType: "verbatim" },
|
|
61
78
|
};
|
|
62
79
|
function readParts(content) {
|
|
63
80
|
if (!Array.isArray(content))
|
|
64
81
|
return textSlot(content);
|
|
65
82
|
const next = content.map((part) => {
|
|
66
|
-
if (
|
|
83
|
+
if (isPlainRecord(part)) {
|
|
67
84
|
const type = part.type;
|
|
68
85
|
if (typeof type === "string" && Object.hasOwn(PART_READ_TREATMENT, type)) {
|
|
69
|
-
return PART_READ_TREATMENT[type]
|
|
86
|
+
return readByTable(part, PART_READ_TREATMENT[type]);
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
return deepScrub(part);
|
|
73
90
|
});
|
|
74
91
|
return next.every((x, i) => x === content[i]) ? content : next;
|
|
75
92
|
}
|
|
76
|
-
const readContent = (m) => scrubSlot(m, "content", readParts);
|
|
77
93
|
const MESSAGE_READ_TREATMENT = {
|
|
78
|
-
user:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
user: {
|
|
95
|
+
role: "verbatim", content: "verbatim", timestamp: "verbatim", enginePrefixChars: "verbatim", engineSegments: "verbatim",
|
|
96
|
+
engineMinted: "verbatim", engineNoteKey: "verbatim", provenance: "verbatim", actor: "verbatim",
|
|
97
|
+
},
|
|
98
|
+
custom: { role: "verbatim", customType: "verbatim", content: "verbatim", display: "verbatim", details: "verbatim", provenance: "verbatim", timestamp: "verbatim" },
|
|
99
|
+
assistant: {
|
|
100
|
+
role: "verbatim", content: "parts", errorMessage: "text", diagnostics: "structure", repetition: "structure",
|
|
101
|
+
api: "verbatim", provider: "verbatim", model: "verbatim", responseModel: "verbatim", responseId: "verbatim", requestId: "verbatim",
|
|
102
|
+
isApiErrorMessage: "verbatim", apiErrorStatus: "verbatim", apiErrorCode: "verbatim", usage: "verbatim", usageMissing: "verbatim",
|
|
103
|
+
stopReason: "verbatim", errorKind: "verbatim", inputTooLongRuledOut: "verbatim", partialFinalized: "verbatim",
|
|
104
|
+
staticReasoningCut: "verbatim", timestamp: "verbatim",
|
|
105
|
+
},
|
|
106
|
+
toolResult: { role: "verbatim", toolCallId: "verbatim", toolName: "verbatim", content: "parts", details: "structure", isError: "verbatim", timestamp: "verbatim" },
|
|
107
|
+
bashExecution: {
|
|
108
|
+
role: "verbatim", command: "text", output: "text", exitCode: "verbatim", cancelled: "verbatim", truncated: "verbatim",
|
|
109
|
+
fullOutputPath: "verbatim", timestamp: "verbatim", excludeFromContext: "verbatim",
|
|
110
|
+
},
|
|
111
|
+
compactionSummary: {
|
|
112
|
+
role: "verbatim", summary: "text", details: "structure", tokensBefore: "verbatim", timestamp: "verbatim", elidedMessages: "verbatim",
|
|
113
|
+
unsummarizedMessages: "verbatim", tokensAfter: "verbatim", firstKeptEntryId: "verbatim",
|
|
114
|
+
},
|
|
84
115
|
};
|
|
85
116
|
function readMessage(m) {
|
|
86
|
-
if (
|
|
117
|
+
if (isPlainRecord(m)) {
|
|
87
118
|
const role = m.role;
|
|
88
119
|
if (typeof role === "string" && Object.hasOwn(MESSAGE_READ_TREATMENT, role)) {
|
|
89
|
-
return MESSAGE_READ_TREATMENT[role]
|
|
120
|
+
return readByTable(m, MESSAGE_READ_TREATMENT[role]);
|
|
90
121
|
}
|
|
91
122
|
}
|
|
92
123
|
return deepScrub(m);
|
|
@@ -112,7 +143,6 @@ export function windowMessages(messages, opts) {
|
|
|
112
143
|
const offset = Math.max(0, total - tail);
|
|
113
144
|
return { messages: messages.slice(offset), window: { offset, total } };
|
|
114
145
|
}
|
|
115
|
-
const INJECTED_BLOCK_RE = /<(system-reminder|task-notification)(?:\s[^>]*)?>[\s\S]*?<\/\1>\s*/g;
|
|
116
146
|
function capWithInjectionAwareness(s, capBytes) {
|
|
117
147
|
const total = Buffer.byteLength(s, "utf8");
|
|
118
148
|
if (total <= capBytes)
|
package/dist/auth-bridge.d.ts
CHANGED
|
@@ -4,22 +4,22 @@ import type { Metrics } from "./observability/metrics.js";
|
|
|
4
4
|
export type { VerifiedIdentity } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
5
5
|
/**
|
|
6
6
|
* S-866 ② —— 鉴权桥 issuer 的**唯一**取值(装配 `boot/stage-09-leader.ts` 与 caps `centerWiring.issuer` 同读,不各写一份回退):
|
|
7
|
-
* 显式 `AUTH_BRIDGE_ISSUER`(`config.authBridgeIssuer`)恒赢 ⇒ `source:"explicit"`;缺席则回退中心基址 `
|
|
7
|
+
* 显式 `AUTH_BRIDGE_ISSUER`(`config.authBridgeIssuer`)恒赢 ⇒ `source:"explicit"`;缺席则回退中心基址 `webAdmin.baseUrl`
|
|
8
8
|
* (配了中心即默认开桥)⇒ `source:"fallback"`;两者都没有 ⇒ `undefined`(桥不装)。
|
|
9
9
|
*/
|
|
10
10
|
export declare function authBridgeIssuerOf(config: {
|
|
11
11
|
readonly authBridgeIssuer?: string | undefined;
|
|
12
|
-
readonly
|
|
12
|
+
readonly webAdmin?: {
|
|
13
13
|
readonly baseUrl: string;
|
|
14
14
|
} | undefined;
|
|
15
15
|
}): {
|
|
16
16
|
readonly issuer: string;
|
|
17
17
|
readonly source: "explicit" | "fallback";
|
|
18
18
|
} | undefined;
|
|
19
|
-
export interface
|
|
20
|
-
/** R4 — 期望 iss(registry 的 SSO_ISSUER;默认=
|
|
19
|
+
export interface WebAdminJwtVerifierOptions {
|
|
20
|
+
/** R4 — 期望 iss(registry 的 SSO_ISSUER;默认=SEMA_WEB_ADMIN_URL,双侧去尾斜杠比较)。 */
|
|
21
21
|
issuer: string;
|
|
22
|
-
/** R2 — JWKS 绝对 URL(默认=issuer +
|
|
22
|
+
/** R2 — JWKS 绝对 URL(默认=issuer + WEB_ADMIN_JWKS_PATH)。 */
|
|
23
23
|
jwksUrl?: string;
|
|
24
24
|
/** R7 — 设了则 aud 必须包含它;不设=忽略 aud。 */
|
|
25
25
|
audience?: string;
|
|
@@ -41,13 +41,13 @@ export type VerifyOutcome = {
|
|
|
41
41
|
ok: false;
|
|
42
42
|
error: AuthBridgeErrorCode;
|
|
43
43
|
};
|
|
44
|
-
/** The live object `
|
|
45
|
-
export interface
|
|
44
|
+
/** The live object `createWebAdminJwtVerifier` produces — a single `verify` entry point over the process-level JWKS cache. */
|
|
45
|
+
export interface WebAdminJwtVerifier {
|
|
46
46
|
verify: (bearer: string) => Promise<VerifyOutcome>;
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
49
|
* registry-JWT verifier(单例,进程级 JWKS 缓存)。`verify(bearer)` 全程不 throw——一切异常折为
|
|
50
50
|
* AUTH_BRIDGE_ERROR_CODES(HTTP 面由调用方恒答 generic 401,码只进日志/metrics,R9)。
|
|
51
51
|
*/
|
|
52
|
-
export declare function
|
|
52
|
+
export declare function createWebAdminJwtVerifier(opts: WebAdminJwtVerifierOptions): WebAdminJwtVerifier;
|
|
53
53
|
//# sourceMappingURL=auth-bridge.d.ts.map
|
package/dist/auth-bridge.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
2
|
-
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC,
|
|
2
|
+
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, WEB_ADMIN_JWKS_PATH, WebAdminJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/settings-schema/api/auth-bridge";
|
|
3
3
|
import { buildDisplaySafeUrl } from "./trace/redact.js";
|
|
4
4
|
export function authBridgeIssuerOf(config) {
|
|
5
5
|
if (config.authBridgeIssuer !== undefined)
|
|
6
6
|
return { issuer: config.authBridgeIssuer, source: "explicit" };
|
|
7
|
-
if (config.
|
|
8
|
-
return { issuer: config.
|
|
7
|
+
if (config.webAdmin !== undefined)
|
|
8
|
+
return { issuer: config.webAdmin.baseUrl, source: "fallback" };
|
|
9
9
|
return undefined;
|
|
10
10
|
}
|
|
11
11
|
const DEFAULT_JWKS_TTL_SEC = 15 * 60;
|
|
@@ -25,10 +25,10 @@ function b64urlJson(seg) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
const stripSlash = (s) => s.replace(/\/+$/, "");
|
|
28
|
-
export function
|
|
28
|
+
export function createWebAdminJwtVerifier(opts) {
|
|
29
29
|
const issuer = stripSlash(opts.issuer);
|
|
30
30
|
const displayIssuer = buildDisplaySafeUrl(issuer);
|
|
31
|
-
const jwksUrl = opts.jwksUrl ?? `${issuer}${
|
|
31
|
+
const jwksUrl = opts.jwksUrl ?? `${issuer}${WEB_ADMIN_JWKS_PATH}`;
|
|
32
32
|
const clockSkewSec = opts.clockSkewSec ?? DEFAULT_CLOCK_SKEW_SEC;
|
|
33
33
|
const refreshMin = opts.jwksRefreshMinIntervalSec ?? DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC;
|
|
34
34
|
const offlineGraceSec = opts.offlineGraceSec ?? DEFAULT_OFFLINE_GRACE_SEC;
|
|
@@ -59,7 +59,7 @@ export function createRegistryJwtVerifier(opts) {
|
|
|
59
59
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
60
60
|
if (buf.byteLength > MAX_JWKS_BYTES)
|
|
61
61
|
throw new Error("jwks body too large");
|
|
62
|
-
const doc =
|
|
62
|
+
const doc = WebAdminJwks.parse(JSON.parse(buf.toString("utf8")));
|
|
63
63
|
const next = new Map();
|
|
64
64
|
for (const k of doc.keys) {
|
|
65
65
|
try {
|
package/dist/auth-keys.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* (verifyApprovalHmac / verifyPrincipalJwt) stay in ./approval-hmac.ts and ./principal-jwt.ts; consumers import these four names from HERE ([ref] 兼容面全清).
|
|
9
9
|
*/
|
|
10
10
|
/** One key in the rotating HMAC key-set. `kid` lets the verifier pick the signing key (or fall back to trying the
|
|
11
|
-
* whole set); `status` lets
|
|
11
|
+
* whole set); `status` lets web-admin rotate without breaking in-flight approvals: `active` = sign + verify,
|
|
12
12
|
* `retiring` = verify-only (kept for the overlap window so a MAC signed with the old key still verifies). */
|
|
13
13
|
export interface ApprovalHmacKey {
|
|
14
14
|
kid: string;
|
|
@@ -36,7 +36,7 @@ export interface KeySetRejection {
|
|
|
36
36
|
* 门数的 SHAPE B;这两条钥又都在凭据轴上,所以由**类型**逼每个调用点当场表态,而不是靠人记得去接。
|
|
37
37
|
*/
|
|
38
38
|
export type OnKeySetRejection = (rejection: KeySetRejection) => void;
|
|
39
|
-
/** Parse APPROVAL_HMAC_KEYS — a
|
|
39
|
+
/** Parse APPROVAL_HMAC_KEYS — a web-admin-managed, rotating key-SET, as a JSON array of {kid,key,status}.
|
|
40
40
|
* Empty / unset / unparseable ⇒ `[]` ⇒ HMAC verification is OFF (D-G inactive; back-compat, BFF-only door).
|
|
41
41
|
* fail-closed 语义与改前**逐字相同**;新增的只有 `onReject`([ref]:每一条被丢弃的条目都要说出来)。 */
|
|
42
42
|
export declare function parseApprovalHmacKeys(raw: string | undefined, onReject: OnKeySetRejection): ApprovalHmacKey[];
|
package/dist/auto-mode-face.d.ts
CHANGED
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
*
|
|
16
16
|
* 本模块按**server 侧可知的同三项**算一份「若此刻提交会不会武装」的裁决,供壳(cli `sema doctor permissions`)
|
|
17
17
|
* 与人自查。三项分别对应三个未武装原因(判序 = 谓词的合取序,先判到的先报):
|
|
18
|
-
* · `mode_not_auto` —— 本次意图不是 auto(`?permissionMode=` 查询串给的;缺席 = 按 auto 意图答)
|
|
19
|
-
*
|
|
18
|
+
* · `mode_not_auto` —— 本次意图不是 auto(`?permissionMode=` 查询串给的;缺席 = 按 auto 意图答),且原样到得了引擎(本部署的入口地板没改它);
|
|
19
|
+
* · `operator_floor` —— 本部署的运维入口地板(`AUTONOMY=plan`)把本次意图改成了别的词、那个词不是 auto(`runtime-governance.ts`
|
|
20
|
+
* `entryPermissionMode` 的 `clamped`,与受理门同一只函数)—— 到得了引擎的词由运维定,出路在运维换档,不在请求的词;
|
|
20
21
|
* · `deployment_incapable` —— 装配面没挂 `RunnerDeps.autoMode` 分类器席位(生产装配恒挂;桩/一次性 CLI 不挂);
|
|
21
22
|
* · `org_denied` —— per-principal caps 的 `autoMode === false` 且本地 deny 未设(center 显式 deny、center
|
|
22
23
|
* 硬失败的 fail-closed 拒项);
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
* 规则集少一整支;**不再读任何 dist 文本**。
|
|
36
37
|
*
|
|
37
38
|
* ## 闭集纪律([ref])
|
|
38
|
-
*
|
|
39
|
+
* 七词:core [ref] seam ⑤ + [ref] PM 裁定的六词 + `operator_floor`(意图被运维入口地板改词;与 `local_denied` / `org_denied` 同理按「指路不同」拆出);
|
|
40
|
+
* `AUTO_MODE_UNARMED_REASON_SEMANTICS` 是 `Record<Reason, string>` 锁步表——
|
|
39
41
|
* 词表加员而语义表不加、或反之,都是编译红。本面**不**给壳发 prose(机器码上 wire,人话归壳),语义表只
|
|
40
42
|
* 服务于文档/测试对拍。
|
|
41
43
|
*
|
|
@@ -76,12 +78,13 @@ export type ClassifierRoute = {
|
|
|
76
78
|
readonly id: undefined;
|
|
77
79
|
readonly fault: string;
|
|
78
80
|
};
|
|
79
|
-
/** core [ref] seam ⑤
|
|
80
|
-
export declare const AUTO_MODE_UNARMED_REASONS: readonly ["mode_not_auto", "deployment_incapable", "org_denied", "local_denied", "settings_denied", "resolver_fault"];
|
|
81
|
+
/** 未武装原因闭集(七词:core [ref] seam ⑤ + [ref] settings_denied + 入口地板改词 operator_floor;顺序 = 判序)。 */
|
|
82
|
+
export declare const AUTO_MODE_UNARMED_REASONS: readonly ["mode_not_auto", "operator_floor", "deployment_incapable", "org_denied", "local_denied", "settings_denied", "resolver_fault"];
|
|
81
83
|
export type AutoModeUnarmedReason = (typeof AUTO_MODE_UNARMED_REASONS)[number];
|
|
82
84
|
/** 锁步表:词表与语义一一对应(加员/删员任一侧不同步 = tsc 红)。语义只供文档/测试,不上 wire。 */
|
|
83
85
|
export declare const AUTO_MODE_UNARMED_REASON_SEMANTICS: {
|
|
84
|
-
readonly mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\")
|
|
86
|
+
readonly mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\"),且原样到得了引擎(本部署的运维入口地板没改它)—— 出路是请求 auto";
|
|
87
|
+
readonly operator_floor: "本部署的运维入口地板(AUTONOMY=plan)把本次意图改成了别的词、那个词不是 auto —— 与受理门同一只函数,提交时到得了引擎的词由运维定;出路是找运维换档,改请求的词到不了 auto";
|
|
85
88
|
readonly deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)";
|
|
86
89
|
readonly org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed 拒项";
|
|
87
90
|
readonly local_denied: "本地 catalog 键 PERMISSIONS_DISABLE_AUTO_MODE=true(center/settings 键名 permissions.disableAutoMode)把 caps.autoMode 折成 false";
|
|
@@ -101,7 +104,7 @@ export interface AutoModeFaceDeps {
|
|
|
101
104
|
/** 分类器**配置**的模型路由(server 侧按 core 的 role 回落序 `classifier → summarize → default` 从
|
|
102
105
|
* `config.roles` 读到的 catalog 名)。这是「配置了什么」,不是「这次真用了什么」——core 的
|
|
103
106
|
* `derivedRouteFallsBack` 可能在运行期回落到主模型;真值候 core 状态座。
|
|
104
|
-
* 🔴 codex r3 [medium]:是 **getter** 不是快照——
|
|
107
|
+
* 🔴 codex r3 [medium]:是 **getter** 不是快照——web-admin 会原地热更新 `config.roles`(Runner 每任务从活引用
|
|
105
108
|
* 重解),boot 期铸的字符串会在热切换后永久陈旧;生产装配递的 getter 调 `classifierRouteFor({ models: config.models, roles: config.roles })` 并把 fault 记 debug。 */
|
|
106
109
|
readonly classifierModel?: (() => string | undefined) | undefined;
|
|
107
110
|
}
|
|
@@ -120,8 +123,9 @@ export type AutoModeVerdict = {
|
|
|
120
123
|
* 调用方经门验证的身份(匿名 ⇒ undefined ⇒ center 客户端答 undefined,本地 deny 层照样罩)。
|
|
121
124
|
*
|
|
122
125
|
* 意图那一项判的是**提交之后到得了引擎的那个词**:本次意图先过本部署的运维入口地板(`floor`,调用方传 `runtime-governance.ts`
|
|
123
|
-
* `autonomyModeFloor(<活 config 的 AUTONOMY>)` —— 与受理门盖章读同一只属主)
|
|
124
|
-
*
|
|
126
|
+
* `autonomyModeFloor(<活 config 的 AUTONOMY>)` —— 与受理门盖章读同一只属主),经 `entryPermissionMode`(受理门盖章调的同一只函数)。
|
|
127
|
+
* 到得了引擎的词不是 auto ⇒ 未武装,原因按「谁定了那个词」分:地板改了词(`clamped`)⇒ `operator_floor`;词原样 ⇒ `mode_not_auto`。
|
|
128
|
+
* `AUTONOMY=plan` 部署上意图缺席 / auto / 任何比 plan 松的词 ⇒ `operator_floor`;意图本身是 `plan` ⇒ `mode_not_auto`。
|
|
125
129
|
*
|
|
126
130
|
* 🔴 resolver 抛错**不吞**:合成腿的每一层都自带 fail-closed/缺席臂(center 客户端 catch-all、grant 腿 onFault),
|
|
127
131
|
* 走到这里还在抛 = 装配缺陷,读面 500 比一句编出来的 reason 诚实。
|
package/dist/auto-mode-face.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { classifierSeatModel } from "@sema-agent/core";
|
|
2
2
|
import { resolveMainModel } from "./model-select.js";
|
|
3
|
+
import { entryPermissionMode } from "./runtime-governance.js";
|
|
3
4
|
export function classifierRouteFor(deps) {
|
|
4
5
|
try {
|
|
5
6
|
const main = resolveMainModel(deps);
|
|
@@ -9,9 +10,10 @@ export function classifierRouteFor(deps) {
|
|
|
9
10
|
return { id: undefined, fault: err instanceof Error ? err.message : String(err) };
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
|
-
export const AUTO_MODE_UNARMED_REASONS = ["mode_not_auto", "deployment_incapable", "org_denied", "local_denied", "settings_denied", "resolver_fault"];
|
|
13
|
+
export const AUTO_MODE_UNARMED_REASONS = ["mode_not_auto", "operator_floor", "deployment_incapable", "org_denied", "local_denied", "settings_denied", "resolver_fault"];
|
|
13
14
|
export const AUTO_MODE_UNARMED_REASON_SEMANTICS = {
|
|
14
|
-
mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\")
|
|
15
|
+
mode_not_auto: "本次意图不是 auto(壳发的 permissionMode 不是 \"auto\"),且原样到得了引擎(本部署的运维入口地板没改它)—— 出路是请求 auto",
|
|
16
|
+
operator_floor: "本部署的运维入口地板(AUTONOMY=plan)把本次意图改成了别的词、那个词不是 auto —— 与受理门同一只函数,提交时到得了引擎的词由运维定;出路是找运维换档,改请求的词到不了 auto",
|
|
15
17
|
deployment_incapable: "装配面没挂 RunnerDeps.autoMode 分类器席位(本部署/本进程形不具备分类器)",
|
|
16
18
|
org_denied: "per-principal caps.autoMode === false 且本地 deny 未设:center 显式 deny / center 硬失败 fail-closed 拒项",
|
|
17
19
|
local_denied: "本地 catalog 键 PERMISSIONS_DISABLE_AUTO_MODE=true(center/settings 键名 permissions.disableAutoMode)把 caps.autoMode 折成 false",
|
|
@@ -21,10 +23,9 @@ export const AUTO_MODE_UNARMED_REASON_SEMANTICS = {
|
|
|
21
23
|
export async function judgeAutoModeArming(face, input) {
|
|
22
24
|
const route = face?.seatMounted ? face.classifierModel?.() : undefined;
|
|
23
25
|
const model = route !== undefined ? { model: route } : {};
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return { armed: false, reason: "mode_not_auto", ...model };
|
|
26
|
+
const entry = entryPermissionMode(input.requestedMode ?? "auto", input.floor);
|
|
27
|
+
if (entry.effective !== "auto")
|
|
28
|
+
return { armed: false, reason: entry.clamped ? "operator_floor" : "mode_not_auto", ...model };
|
|
28
29
|
if (face === undefined || !face.seatMounted)
|
|
29
30
|
return { armed: false, reason: "deployment_incapable" };
|
|
30
31
|
let caps;
|
|
@@ -2,7 +2,7 @@ import { createBrainAssembly } from "../brain.js";
|
|
|
2
2
|
import { ModelUsageTracker, PromptManifestTracker, buildPricing, createSideQueryAccountant, createTracer } from "../budget.js";
|
|
3
3
|
import { FleetUsageAccumulator } from "../fleet-client.js";
|
|
4
4
|
import { createFleetLeaseFromEnv } from "../fleet-lease.js";
|
|
5
|
-
import { centerLaneConfigured } from "../
|
|
5
|
+
import { centerLaneConfigured } from "../web-admin-client/center-request.js";
|
|
6
6
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
7
7
|
import { buildQuotaBounds } from "./limit-sync.js";
|
|
8
8
|
import { assembleFileHistory } from "../file-history-capture.js";
|
|
@@ -209,6 +209,7 @@ export function createExecutionEnv(ctx) {
|
|
|
209
209
|
const hostScheduler = facts.hostScheduler(config).available
|
|
210
210
|
? new FileSchedulerBackend({
|
|
211
211
|
storePath: schedulerStorePath,
|
|
212
|
+
log: logger,
|
|
212
213
|
...(config.schedulerSessionWakeup === false || config.schedulerSessionLifetime === false
|
|
213
214
|
? {
|
|
214
215
|
caps: {
|
package/dist/boot/leader.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface LeaderCtx {
|
|
|
37
37
|
/** [ref]([ref],[ref]-T1)—— 治理窗**账本店**(与 `config.usageWindows` 声明成对;声明直接从
|
|
38
38
|
* 本 ctx 的 config 取,leader 不另读)。缺席 = 未配治理窗的部署。必填键,理由同 `tracer`。 */
|
|
39
39
|
usageWindowStore: RunnerDeps["usageWindowStore"];
|
|
40
|
-
/** [ref]([ref])—— center 发布的 prompt catalog(`
|
|
40
|
+
/** [ref]([ref])—— center 发布的 prompt catalog(`webAdmin.promptSource`,与主 runner/subRunner
|
|
41
41
|
* 同一只)。缺席 ⇒ leader 的四类顶层任务跑引擎内置提示词,而同部署其余三条腿跑运维发布的那一份,
|
|
42
42
|
* 且 core 顶层新任务是**静默**落回(无 notice)。必填键,理由同 `tracer`。 */
|
|
43
43
|
promptSource: RunnerDeps["promptSource"];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RestartSliceCtx } from "../
|
|
1
|
+
import type { RestartSliceCtx } from "../web-admin-client/restart-signal.js";
|
|
2
2
|
import type { MemoryConsolidationDriverConfig, ServiceConfig } from "../config-types.js";
|
|
3
3
|
import { type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type RunMemoryConsolidationOptions, type SessionCaptureRecordStore } from "@sema-agent/core";
|
|
4
4
|
/** D3 投影的座标签闭集。`role:<name>` 里的 name 只可能是 core 的 role 链两跳之一。 */
|
|
@@ -178,14 +178,14 @@ export declare function consolidationDriverUnwirable(input: ConsolidationWiringF
|
|
|
178
178
|
* ({@link seatLabel} 注里同一条理由:抄一份就是第二真源,而 `ROLE_TIER_DEFAULTS` 的 flash 缺省会让手抄版答错)。
|
|
179
179
|
*
|
|
180
180
|
* 为什么不按 env `MODEL_CHEAP_ID` 的拼写判:它只是供座的一条路。env 角色表在它缺席时把 summarize 指回
|
|
181
|
-
* `default`(`config.ts` 的 `cheapRef`),而目录(`config.d/models.json` /
|
|
181
|
+
* `default`(`config.ts` 的 `cheapRef`),而目录(`config.d/models.json` / web-admin)的 roles / 档位同样能供
|
|
182
182
|
* consolidate / summarize 两跳 —— 判「装配后的座落不落主模型」才与计费事实同形(整理跑按座的模型计费)。
|
|
183
183
|
*
|
|
184
184
|
* 主模型 = 本仓给每条 task 铸的 `DEFAULT_MODEL_REF` 解到的那只(`boot/resolve-spec.ts` 每条 spec 都盖 `spec.model`),
|
|
185
185
|
* **不是** core 的 `default` 角色链 —— 与 `auto-mode-face.ts` 的 `classifierRouteFor` 同一口径(共用 `model-select.ts`
|
|
186
186
|
* `resolveMainModel`);喂**展开**目录,与引擎构造期 `expandTiers` 之后再解逐字同源。比的是**目录条目身份**(对象引用),
|
|
187
187
|
* **不比 `Model.id` 串**(车PI 修复轮 ⑤ / codex C-2:两条不同名的条目可以共享上游 id 却各带不同的 baseUrl / 凭据 / 价,那是两只
|
|
188
|
-
* 模型;与 `model-select.ts` `
|
|
188
|
+
* 模型;与 `model-select.ts` `isAtMentionable` 同一口径)。env 的「cheap id == 主 id」不会走到这里变成两只:`config.ts` 在铸造处
|
|
189
189
|
* 就不铸那只影子条目(车PI 验修轮 B)。
|
|
190
190
|
* 探针 brain 零请求:座解析只 `brainToRuntime` 它一次,真被调用 = 装配缺陷,响亮抛。
|
|
191
191
|
* ⚠️ **爆炸半径**(车PI 验修轮 F10,如实登记):判决的每一臂 —— 包括未设 + 没配便宜模型的派生关(TOC 最常见的形)—— 都走
|
|
@@ -212,7 +212,7 @@ export declare function consolidationSeatBillingOf(plane: ConsolidationSeatPlane
|
|
|
212
212
|
* 拒因说清「为什么没开」。在 `loadConfig` 判会把「未设 + scope + 便宜模型在场」这台本该派生成开的部署当场拒掉。
|
|
213
213
|
*
|
|
214
214
|
* ⚠️ **起服判一次**(restart-to-apply):判决落在 boot 第 4 段的装配点 {@link createConsolidationValve} —— 目录已应用
|
|
215
|
-
* (`config.d/models.json` /
|
|
215
|
+
* (`config.d/models.json` / web-admin 的 boot 采纳或 LKG)、记忆引擎已接线;座解析在第 6 段读这份判决。之后中心热改了 roles / 档位(或 boot 拉取超窗、目录迟到),**阀门不跟着翻**,
|
|
216
216
|
* 但翻的**需要**由 `memory-consolidation` 重启片报出来({@link createConsolidationValveWatch}):开着的那台盯座位漂移;
|
|
217
217
|
* 派生关的那台盯「此刻重判会不会开」(codex 车内复审 F2:修前派生关没有任何读数,热加一只便宜模型零信号、阀门永远关着)。
|
|
218
218
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* 的两个 seam(`RunnerDeps.memoryScopeAdmission` / `RunnerDeps.deploymentMemoryScopes`)。
|
|
4
4
|
*
|
|
5
5
|
* 目录源三态(单选,授权面不做双源合并):
|
|
6
|
-
* · center 在场(
|
|
6
|
+
* · center 在场(webAdmin 且非 dryRun)⇒ 远程腿:per-principal caps 响应的 `orgMemory` 段
|
|
7
7
|
* (走 `fetchPrincipalOrgMemory` —— 与 caps 腿同一条 HTTP 请求形与同一道 principal 回声核,但**只
|
|
8
8
|
* 投影 org 段**读,治理面值漂移不连坐;段键缺席=旧 center 能力握手 ⇒ 目录记 section_absent 瞬时)。
|
|
9
9
|
* **独立 fetch,不复用 caps 缓存条目**(C3:org 授权段自带判别联合缓存,两张表的失败域互不干扰
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* 能力探测(C12,fail-loud):多租户(requirePrincipal)部署 **且记忆面真点亮**(MEMORY_ENGINE 开 +
|
|
19
19
|
* backend 非 file——见下方 `memoryPlaneLive` 注)的 projects 登记簿里挂了 org 键 ——这些键在多租户下
|
|
20
|
-
* 按 request-origin 盖章(N2 部署形态维)——而目录源缺席(含
|
|
20
|
+
* 按 request-origin 盖章(N2 部署形态维)——而目录源缺席(含 webAdmin dryRun 形)⇒ 启动报错:
|
|
21
21
|
* 该部署的每个 projectId 请求都会在 prepare 期被整拒,「audit 在跑但恒拒」不是可运行状态,响亮拒
|
|
22
22
|
* 启动比静默全拒服务诚实(clay 三裁 [ref]:直接 BREAKING,不留兼容臂)。记忆面 dark 的部署里这些
|
|
23
23
|
* 键根本到不了准入门,不在探测范围(复审 D-1)。
|
|
@@ -46,7 +46,7 @@ export interface OrgMemoryAdmissionWiring {
|
|
|
46
46
|
*
|
|
47
47
|
* 为什么这个消费点必须活取而上面那个可以不:共享记忆读面对 principal-less 请求**直接**把这组 scope
|
|
48
48
|
* 当作全部授权事实交出去(没有第二道盖章腿能纠正它)⇒ 快照在新增方向让新登记的 org 库变成终局式
|
|
49
|
-
* 空集、在撤销方向让已下架的 scope 继续被放行(fail-open),而 `config.projects` 恰恰是
|
|
49
|
+
* 空集、在撤销方向让已下架的 scope 继续被放行(fail-open),而 `config.projects` 恰恰是 web-admin
|
|
50
50
|
* 标注「🟢 热生效」的字段、且 env 腿恒空(只可能由 center 灌)。判据本体与快照同源(同一个
|
|
51
51
|
* `collectDeploymentOrgScopes`),差别只有取值时机。
|
|
52
52
|
*/
|
package/dist/boot/org-memory.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fetchPrincipalOrgMemory } from "../
|
|
1
|
+
import { fetchPrincipalOrgMemory } from "../web-admin-client/http-client.js";
|
|
2
2
|
import { createIdentityBins } from "../center-credential.js";
|
|
3
3
|
import { createMemoryScopeAdmission, createOrgMemoryDirectory, parseOrgDirectoryStatic } from "../org-memory-admission.js";
|
|
4
4
|
const ORG_PREFIX = "org:";
|
|
@@ -18,11 +18,11 @@ function collectDeploymentOrgScopes(config) {
|
|
|
18
18
|
export function createOrgMemoryAdmissionWiring(opts) {
|
|
19
19
|
const { config, logger, metrics } = opts;
|
|
20
20
|
const deploymentMemoryScopes = collectDeploymentOrgScopes(config);
|
|
21
|
-
const centerLeg = config.
|
|
21
|
+
const centerLeg = config.webAdmin !== undefined && !config.webAdmin.dryRun ? config.webAdmin : undefined;
|
|
22
22
|
const staticJson = config.memoryOrgDirectoryJson;
|
|
23
23
|
if (centerLeg !== undefined && staticJson !== undefined) {
|
|
24
24
|
logger.warn("org_memory_directory_env_ignored", {
|
|
25
|
-
reason: "MEMORY_ORG_DIRECTORY_JSON is set but a
|
|
25
|
+
reason: "MEMORY_ORG_DIRECTORY_JSON is set but a web-admin is wired — the center directory wins; the env table is IGNORED (authorization faces never merge two sources)",
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
const directory = centerLeg !== undefined
|
|
@@ -48,8 +48,8 @@ export function createOrgMemoryAdmissionWiring(opts) {
|
|
|
48
48
|
.map(([id]) => id);
|
|
49
49
|
if (orgProjects.length > 0) {
|
|
50
50
|
throw new Error(`multi-tenant deployment has org: keys in projects[${orgProjects.join(", ")}].defaultScopes but NO org-memory directory source ` +
|
|
51
|
-
`(
|
|
52
|
-
`(memory.admission_required, fail-closed). Wire a
|
|
51
|
+
`(web-admin absent/dry-run and MEMORY_ORG_DIRECTORY_JSON unset) — every request selecting these projects would be refused at prepare ` +
|
|
52
|
+
`(memory.admission_required, fail-closed). Wire a web-admin or set MEMORY_ORG_DIRECTORY_JSON, or remove the org keys.`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
const memoryScopeAdmission = directory !== undefined
|
|
@@ -17,7 +17,7 @@ import { composeHooks, createTaskHooks } from "../hooks/hook-runner.js";
|
|
|
17
17
|
import { HOST_POSTURE_REFUSED_CODE, taskInheritEnvRefusal, taskWriteFaceRefusal } from "../hosted-posture.js";
|
|
18
18
|
import { headerStr } from "../http/principal-gate.js";
|
|
19
19
|
import { explicitOperatorOk } from "../http/server.js";
|
|
20
|
-
import {
|
|
20
|
+
import { isAtMentionable, matchCatalogModel, modelSupportsImages, refusedCatalogEntry, resolveTaskModel, selectableCatalog, terminalCatalogName } from "../model-select.js";
|
|
21
21
|
import { modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
22
22
|
import { PerTaskImageRegistry, resolveSandboxImageRef } from "../per-task-image.js";
|
|
23
23
|
import { isRemoteScratchpadLane, remoteScratchpadDirFor } from "../plugins/remote-scratchpad.js";
|
|
@@ -30,7 +30,7 @@ import { applyRuntimeGovernance } from "../runtime-governance.js";
|
|
|
30
30
|
import { HttpError, createCodedHttpError, encodeCheckpointScope } from "../security.js";
|
|
31
31
|
import { memoryProjectKeyFor, memorySpecForRequest } from "../memory-scope.js";
|
|
32
32
|
import { inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
|
|
33
|
-
import { a2aForScenario, mcpForScenario } from "../
|
|
33
|
+
import { a2aForScenario, mcpForScenario } from "../web-admin-client/facade.js";
|
|
34
34
|
import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolMaterializeStrategyFromBody, toolNameListFromBody } from "../spec-fields.js";
|
|
35
35
|
import { cwdHonored, deviceCwdHonored, effectiveHostWorkspace, inProcessSingleUserLane, isValidCwd, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
|
|
36
36
|
import { assertRequestA2aUnlocked, resolveRequestA2a } from "../task-a2a.js";
|
|
@@ -259,7 +259,7 @@ export function createResolveSpec(ctx) {
|
|
|
259
259
|
logger.warn("task_additional_read_directories_ignored", { honored: false, sessionId: auth?.sessionId ?? null });
|
|
260
260
|
}
|
|
261
261
|
const wireCatalog = selectableCatalog(config.models, config.tiers, config.modelRefusals);
|
|
262
|
-
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog, config.
|
|
262
|
+
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog, config.atMention, config.modelRefusals);
|
|
263
263
|
if (picked.unavailable !== undefined) {
|
|
264
264
|
const { requested, name, refusal, source } = picked.unavailable;
|
|
265
265
|
if (opts?.leg === "fresh") {
|
|
@@ -271,7 +271,7 @@ export function createResolveSpec(ctx) {
|
|
|
271
271
|
if (picked.notAllowed !== undefined) {
|
|
272
272
|
const { requested, resolved, source } = picked.notAllowed;
|
|
273
273
|
if (opts?.leg === "fresh") {
|
|
274
|
-
throw new HttpError(400, `model "${requested.slice(0, 120)}" is not
|
|
274
|
+
throw new HttpError(400, `model "${requested.slice(0, 120)}" is not @-mentionable on this deployment (it resolves to catalog model "${resolved}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
|
|
275
275
|
}
|
|
276
276
|
metrics.inc("task_model_not_allowlisted_resume_total");
|
|
277
277
|
logger.warn("task_model_not_allowlisted_resume", { requested: requested.slice(0, 120), resolved, source, sessionId: auth?.sessionId ?? null, note: "resumed leg keeps running the model it was started on — the allowlist gates fresh picks only" });
|
|
@@ -395,10 +395,10 @@ export function createResolveSpec(ctx) {
|
|
|
395
395
|
logger.warn("compaction_model_unknown_fallback", { requested: body.compactionModel.slice(0, 120), sessionId: auth?.sessionId ?? null });
|
|
396
396
|
return {};
|
|
397
397
|
}
|
|
398
|
-
if (!
|
|
398
|
+
if (!isAtMentionable(cm, wireCatalog, config.atMention, config.modelRefusals)) {
|
|
399
399
|
const terminal = terminalCatalogName(cm, wireCatalog, config.modelRefusals) ?? cm;
|
|
400
400
|
if (opts?.leg === "fresh") {
|
|
401
|
-
throw new HttpError(400, `compactionModel "${body.compactionModel.slice(0, 120)}" is not
|
|
401
|
+
throw new HttpError(400, `compactionModel "${body.compactionModel.slice(0, 120)}" is not @-mentionable on this deployment (it resolves to catalog model "${terminal}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
|
|
402
402
|
}
|
|
403
403
|
metrics.inc("task_model_not_allowlisted_resume_total");
|
|
404
404
|
logger.warn("task_model_not_allowlisted_resume", { requested: body.compactionModel.slice(0, 120), resolved: terminal, source: "compaction", sessionId: auth?.sessionId ?? null, note: "resumed leg keeps the compaction model it was started with — the allowlist gates fresh picks only" });
|
|
@@ -622,7 +622,7 @@ export function createResolveSpec(ctx) {
|
|
|
622
622
|
throw new HttpError(400, "sandboxImageProfile is only supported on the k8s sandbox backend");
|
|
623
623
|
}
|
|
624
624
|
if (!imageIndex) {
|
|
625
|
-
throw new HttpError(400, "sandboxImageProfile requires the image index (
|
|
625
|
+
throw new HttpError(400, "sandboxImageProfile requires the image index (web-admin backend not configured)");
|
|
626
626
|
}
|
|
627
627
|
if (!auth?.sessionId) {
|
|
628
628
|
throw new HttpError(400, "sandboxImageProfile requires a resolved session");
|
|
@@ -204,7 +204,7 @@ export interface RunnerDepsCtx {
|
|
|
204
204
|
permissionRuleStore: RunnerDeps["permissionRuleStore"];
|
|
205
205
|
/** [ref](core 5.50 [ref]):mid-turn MCP 撤销台账席 —— core 每次 MCP dispatch 前同步探
|
|
206
206
|
* `isRevoked(serverName)`,被撤服务器的调用结算为 coded 拒绝 `mcp.server_revoked`(known-not-executed)。
|
|
207
|
-
* 来源=
|
|
207
|
+
* 来源=webAdmin.takeMcpRevocations()(取走即声明接线,restart 豁免与承接绑同一动作)。
|
|
208
208
|
* 缺席=undefined=pre-338 语义(纯 env 部署无中心撤销面)。 */
|
|
209
209
|
mcpRevocations: RunnerDeps["mcpRevocations"];
|
|
210
210
|
/**
|
|
@@ -23,7 +23,7 @@ export interface RuntimeCapsCtx {
|
|
|
23
23
|
*
|
|
24
24
|
* governed 的语义是「per-principal verdict **必答**」:core 对 verdict 缺席一律**拒跑**(fail-closed,部署显式
|
|
25
25
|
* 选的方向)。verdict 源**两条**(析取,[ref] 起):①SQL 后端上的 `memory_optout_grant` 表(三层折叠后
|
|
26
|
-
* 恒答显式 boolean),②非 dry-run 的
|
|
26
|
+
* 恒答显式 boolean),②非 dry-run 的 web-admin 发 `EntitlementRuntimeCaps.allowMemoryOptOut`。
|
|
27
27
|
* governed 而两源皆无 ⇒ 每一个 `capture:"off"` 声明都被 core 以
|
|
28
28
|
* `memory.capture_optout_denied` 拒掉,而运维看到的只是一台「启动成功、opt-out 全拒」的机器 —— 正是
|
|
29
29
|
* 「阀门开着而配不出来 ⇒ 悄悄读成别的」那一形。所以在**启动期**点名:接 SQL 后端(表随中央
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyGovernedVerdictAbsenceWarning, applyLocalAutoModeDeny, applyMemoryOptOutGrant, applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, } from "../runtime-caps-resolver.js";
|
|
2
2
|
import { scopedTokenNeedsWorker } from "../center-credential.js";
|
|
3
|
-
import {
|
|
3
|
+
import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
|
|
4
4
|
export function assertMemoryCapturePolicyWirable(input) {
|
|
5
5
|
if (input.policy !== "governed")
|
|
6
6
|
return;
|
|
@@ -13,9 +13,9 @@ export function assertMemoryCapturePolicyWirable(input) {
|
|
|
13
13
|
`own contract), so a governed worker without a source would refuse every \`memory.capture:"off"\` declaration and the ` +
|
|
14
14
|
`refusal would read as an entitlement denial rather than the misconfiguration it is. This version has TWO verdict sources ` +
|
|
15
15
|
`— wire either one: (1) the \`memory_optout_grant\` table on a SQL store backend (DB_BACKEND=mysql|pg; the table is ` +
|
|
16
|
-
`created by the central ensureSchema and administered through /v1/admin/memory-optout), or (2) a
|
|
17
|
-
`EMITS \`allowMemoryOptOut\` in each principal's entitlement caps (
|
|
18
|
-
|
|
16
|
+
`created by the central ensureSchema and administered through /v1/admin/memory-optout), or (2) a web-admin that ` +
|
|
17
|
+
`EMITS \`allowMemoryOptOut\` in each principal's entitlement caps (${WEB_ADMIN_ENV.url} + ${WEB_ADMIN_ENV.token}, ` +
|
|
18
|
+
`${WEB_ADMIN_ENV.dryRun} off — dry-run observes without applying, so it is not a source; and note the key is OPTIONAL in ` +
|
|
19
19
|
`the entitlement schema: a center that never emits it leaves every verdict absent, i.e. every opt-out still refused). ` +
|
|
20
20
|
`Or set MEMORY_CAPTURE_POLICY=open (opt-outs take effect; only an explicit per-principal false denies) or ` +
|
|
21
21
|
`MEMORY_CAPTURE_POLICY=capture-required (every opt-out declaration refused, no source consulted).`);
|
|
@@ -35,18 +35,18 @@ export function createRuntimeCaps(ctx) {
|
|
|
35
35
|
const governedCenterOnlySource = config.memoryCapturePolicy === "governed" && !grantSourceWired && centerEntitlementSourceWired(config);
|
|
36
36
|
if (governedCenterOnlySource) {
|
|
37
37
|
logger.warn("memory_capture_governed_center_only_source", {
|
|
38
|
-
reason: "MEMORY_CAPTURE_POLICY=governed with NO local memory_optout_grant table: the only verdict source is the
|
|
38
|
+
reason: "MEMORY_CAPTURE_POLICY=governed with NO local memory_optout_grant table: the only verdict source is the web-admin, and `allowMemoryOptOut` is an OPTIONAL entitlement key — for any principal whose caps omit it the verdict is ABSENT and core refuses that session's memory.capture:\"off\" (memory.capture_optout_denied, fail-closed). ANONYMOUS/system runs are worse off still: the center source is per-principal and is never consulted without an identity, so on this shape a principal-less run can never obtain a verdict at all. Verify the center emits allowMemoryOptOut for every principal, or wire a SQL backend (DB_BACKEND=mysql|pg) so the grant table answers (its deployment-default row also covers anonymous runs).",
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
if (centerEntitlementSourceWired(config) && config.
|
|
41
|
+
if (centerEntitlementSourceWired(config) && config.webAdmin && scopedTokenNeedsWorker(config.webAdmin.credential.read(), config.webAdmin.worker)) {
|
|
42
42
|
logger.warn("runtime_caps_scoped_token_no_worker", {
|
|
43
|
-
reason: `${
|
|
43
|
+
reason: `${WEB_ADMIN_ENV.token} is a worker-scoped wpt_ token but ${WEB_ADMIN_ENV.worker} is unset → web-admin 403s per-principal caps → ALL workflow self-orchestration will be fail-closed denied. Set ${WEB_ADMIN_ENV.worker} (the orchestrator normally injects it) or use the full SERVICE_PULL_TOKEN.`,
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
-
const principalCaps = centerEntitlementSourceWired(config) && config.
|
|
46
|
+
const principalCaps = centerEntitlementSourceWired(config) && config.webAdmin
|
|
47
47
|
? createPrincipalEntitlementsClient({
|
|
48
|
-
center: config.
|
|
49
|
-
...(config.
|
|
48
|
+
center: config.webAdmin,
|
|
49
|
+
...(config.webAdmin.worker ? { worker: config.webAdmin.worker } : {}),
|
|
50
50
|
onError: (err, principal) => logger.warn("runtime_caps_resolve_failed", { principal, err: String(err) }),
|
|
51
51
|
})
|
|
52
52
|
: undefined;
|
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -79,9 +79,9 @@ export interface ShutdownCtx {
|
|
|
79
79
|
* HTTP 层不能自作主张。所以 `drainState.draining` 翻真的那一刻,这里同步调 `beginDrain()`。
|
|
80
80
|
*/
|
|
81
81
|
deviceHub: import("../device-ws-hub.js").DeviceWsHub | undefined;
|
|
82
|
-
/** [ref]-2:config 60s 刷新环(
|
|
82
|
+
/** [ref]-2:config 60s 刷新环(web-admin startRefreshLoop)——不停的话停机中途还可能热应用
|
|
83
83
|
* 一份新配置。缺席 = 纯 env 部署没起环。 */
|
|
84
|
-
|
|
84
|
+
webAdmin: {
|
|
85
85
|
stopRefreshLoop(): void;
|
|
86
86
|
} | undefined;
|
|
87
87
|
/** S-929:活体审批协调器(`TOOL_APPROVAL_ENABLED` 关 ⇒ 缺席)。hardShutdown 起点调它的 `drainForShutdown`:本进程握着的活卡
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -17,7 +17,7 @@ export function backgroundGraceRemainingMs(a) {
|
|
|
17
17
|
return Math.max(0, Math.min(a.softStoppedAt + a.graceMs, a.deadlineMs) - a.now);
|
|
18
18
|
}
|
|
19
19
|
export function installShutdownHandlers(ctx) {
|
|
20
|
-
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe,
|
|
20
|
+
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, webAdmin, version, deviceHub, toolApproval, parkCommits, servingLease, } = ctx;
|
|
21
21
|
const dataRoot = config.localDataRoot;
|
|
22
22
|
if (dataRoot) {
|
|
23
23
|
const prior = readCrashLast(dataRoot);
|
|
@@ -107,7 +107,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
107
107
|
storeLiveProbe?.stop();
|
|
108
108
|
servingLease?.stop();
|
|
109
109
|
void deviceHub?.close().catch((err) => logger.warn("device_hub_close_failed", { err: String(err) }));
|
|
110
|
-
|
|
110
|
+
webAdmin?.stopRefreshLoop();
|
|
111
111
|
otelExporter?.stop();
|
|
112
112
|
breakerState?.stop();
|
|
113
113
|
runner.sessions.dispose();
|