@sema-agent/server 7.136.0 → 7.137.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.
Files changed (214) hide show
  1. package/MIGRATION.md +173 -0
  2. package/USAGE.md +84 -16
  3. package/deploy/sema-up/README.md +14 -0
  4. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  5. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  6. package/dist/approval-content-kind.d.ts +6 -0
  7. package/dist/approval-content-kind.js +7 -0
  8. package/dist/approval-gate-currency.d.ts +48 -6
  9. package/dist/approval-gate-currency.js +16 -9
  10. package/dist/approval-hmac.d.ts +13 -1
  11. package/dist/approval-hmac.js +1 -1
  12. package/dist/approval.js +3 -3
  13. package/dist/auth-bridge.js +2 -2
  14. package/dist/boot/execution-env.d.ts +24 -1
  15. package/dist/boot/execution-env.js +69 -6
  16. package/dist/boot/reapers.d.ts +3 -0
  17. package/dist/boot/reapers.js +15 -1
  18. package/dist/boot/resolve-spec.d.ts +4 -0
  19. package/dist/boot/resolve-spec.js +16 -17
  20. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  21. package/dist/boot/stage-04-stores.d.ts +1 -1
  22. package/dist/boot/stage-05-execution-env.d.ts +3 -1
  23. package/dist/boot/stage-05-execution-env.js +11 -2
  24. package/dist/boot/stage-06-runners.d.ts +3 -1
  25. package/dist/boot/stage-06-runners.js +5 -1
  26. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  27. package/dist/boot/stage-07-capability-layer.js +1 -1
  28. package/dist/boot/stage-08-reapers.d.ts +4 -1
  29. package/dist/boot/stage-08-reapers.js +2 -1
  30. package/dist/boot/stage-09-leader.d.ts +4 -1
  31. package/dist/boot/stage-10-http-server.d.ts +4 -1
  32. package/dist/boot/stage-10-http-server.js +3 -2
  33. package/dist/boot/stores.d.ts +1 -1
  34. package/dist/broker/broker.d.ts +89 -0
  35. package/dist/broker/broker.js +287 -0
  36. package/dist/broker/constants.d.ts +39 -0
  37. package/dist/broker/constants.js +15 -0
  38. package/dist/broker/http1.d.ts +111 -0
  39. package/dist/broker/http1.js +256 -0
  40. package/dist/broker/lease-book.d.ts +87 -0
  41. package/dist/broker/lease-book.js +142 -0
  42. package/dist/broker/lease-file.d.ts +60 -0
  43. package/dist/broker/lease-file.js +127 -0
  44. package/dist/broker/main.d.ts +2 -0
  45. package/dist/broker/main.js +20 -0
  46. package/dist/capabilities/composite-members.d.ts +2 -1
  47. package/dist/capabilities/composite-members.js +2 -1
  48. package/dist/capabilities/engine-capabilities.js +1 -0
  49. package/dist/capabilities/scenarios.d.ts +23 -8
  50. package/dist/capabilities/scenarios.js +13 -8
  51. package/dist/capabilities/skills.d.ts +28 -5
  52. package/dist/capabilities/skills.js +8 -0
  53. package/dist/center-credential-renewer.js +5 -1
  54. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  55. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  56. package/dist/checkpoint-identity.d.ts +3 -3
  57. package/dist/config-catalog.js +9 -6
  58. package/dist/config-types.d.ts +9 -0
  59. package/dist/config.d.ts +1 -1
  60. package/dist/config.js +34 -8
  61. package/dist/deployment-governance.d.ts +2 -2
  62. package/dist/deployment-governance.js +7 -9
  63. package/dist/device-ws-protocol.d.ts +1 -0
  64. package/dist/device-ws-protocol.js +2 -1
  65. package/dist/file-history-disclosure.d.ts +4 -2
  66. package/dist/file-history-disclosure.js +2 -0
  67. package/dist/hooks/classic-stations.d.ts +11 -54
  68. package/dist/http/admission.js +10 -7
  69. package/dist/http/approval-sweeps.js +4 -3
  70. package/dist/http/caller-trust.d.ts +2 -1
  71. package/dist/http/caller-trust.js +1 -3
  72. package/dist/http/checkpoint-ctx.d.ts +48 -7
  73. package/dist/http/checkpoint-ctx.js +40 -0
  74. package/dist/http/dispatch.js +15 -10
  75. package/dist/http/durable-run-leg.d.ts +5 -1
  76. package/dist/http/durable-run-leg.js +1 -1
  77. package/dist/http/health-self-report.d.ts +2 -2
  78. package/dist/http/mcp-remote-text.d.ts +5 -0
  79. package/dist/http/mcp-remote-text.js +7 -0
  80. package/dist/http/principal-gate.d.ts +15 -10
  81. package/dist/http/principal-gate.js +48 -9
  82. package/dist/http/resume-legs.d.ts +2 -20
  83. package/dist/http/resume-legs.js +52 -38
  84. package/dist/http/route-ctx.d.ts +8 -2
  85. package/dist/http/routes/approvals-assistant.js +18 -4
  86. package/dist/http/routes/capabilities.js +11 -1
  87. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  88. package/dist/http/routes/mcp-reconnect.js +5 -7
  89. package/dist/http/routes/runs.js +2 -1
  90. package/dist/http/routes/session-sync.js +42 -6
  91. package/dist/http/routes/sessions.js +2 -1
  92. package/dist/http/routes/tasks.js +8 -6
  93. package/dist/http/server.d.ts +4 -0
  94. package/dist/http/stored-body-replay.d.ts +3 -3
  95. package/dist/http/stored-body-replay.js +6 -1
  96. package/dist/http/wire-types.d.ts +52 -27
  97. package/dist/identity-source.d.ts +65 -0
  98. package/dist/identity-source.js +45 -0
  99. package/dist/memory-store-refusal.d.ts +3 -3
  100. package/dist/model-entry-refusal.d.ts +2 -0
  101. package/dist/model-entry-refusal.js +11 -0
  102. package/dist/model-select.d.ts +6 -17
  103. package/dist/model-select.js +0 -3
  104. package/dist/namespaced-rule-name.d.ts +1 -1
  105. package/dist/observability/fail-open.d.ts +13 -1
  106. package/dist/observability/fail-open.js +13 -1
  107. package/dist/observability/metrics.js +1 -1
  108. package/dist/observability/run-terminal.js +1 -0
  109. package/dist/operator-ask.d.ts +2 -2
  110. package/dist/org-delivery-gate.js +1 -1
  111. package/dist/org-memory-admission.d.ts +2 -2
  112. package/dist/org-memory-admission.js +39 -2
  113. package/dist/parked-decide.js +3 -2
  114. package/dist/peer-directory.js +2 -0
  115. package/dist/permission-rule-list.d.ts +2 -2
  116. package/dist/plugins/checkpoint-store-sql.d.ts +19 -9
  117. package/dist/plugins/checkpoint-store-sql.js +6 -6
  118. package/dist/plugins/file-history-store-sql.js +7 -14
  119. package/dist/plugins/file-run-store.js +8 -2
  120. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  121. package/dist/plugins/k8s-exec-protocol.js +116 -28
  122. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  123. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  124. package/dist/plugins/k8s-pod-reaper.d.ts +112 -0
  125. package/dist/plugins/k8s-pod-reaper.js +122 -0
  126. package/dist/plugins/local-checkpoint-store.d.ts +3 -6
  127. package/dist/plugins/local-checkpoint-store.js +3 -3
  128. package/dist/plugins/memory-run-store.js +2 -0
  129. package/dist/plugins/one-time-migrations.d.ts +28 -9
  130. package/dist/plugins/one-time-migrations.js +48 -5
  131. package/dist/plugins/permission-rule-store-file.js +2 -2
  132. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  133. package/dist/plugins/permission-rule-store-sql.js +16 -17
  134. package/dist/plugins/pg-pool.js +4 -0
  135. package/dist/plugins/pg-session-storage.js +2 -2
  136. package/dist/plugins/remote-env-adb.d.ts +3 -0
  137. package/dist/plugins/remote-env-adb.js +1 -0
  138. package/dist/plugins/remote-env-device.d.ts +3 -0
  139. package/dist/plugins/remote-env-device.js +4 -0
  140. package/dist/plugins/remote-env-e2b.d.ts +3 -0
  141. package/dist/plugins/remote-env-e2b.js +1 -0
  142. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  143. package/dist/plugins/remote-env-file-error.js +7 -1
  144. package/dist/plugins/remote-env-host.d.ts +7 -1
  145. package/dist/plugins/remote-env-host.js +7 -1
  146. package/dist/plugins/remote-env-k8s.d.ts +137 -10
  147. package/dist/plugins/remote-env-k8s.js +276 -14
  148. package/dist/plugins/remote-env-local-docker.d.ts +3 -0
  149. package/dist/plugins/remote-env-local-docker.js +1 -0
  150. package/dist/plugins/remote-env-ssh.d.ts +3 -0
  151. package/dist/plugins/remote-env-ssh.js +1 -0
  152. package/dist/plugins/run-store-sql.js +10 -4
  153. package/dist/plugins/session-ownership.d.ts +17 -3
  154. package/dist/plugins/session-ownership.js +19 -5
  155. package/dist/plugins/sql-errors.d.ts +23 -2
  156. package/dist/plugins/sql-errors.js +15 -0
  157. package/dist/plugins/store-contracts.d.ts +10 -1
  158. package/dist/plugins/store-fault.d.ts +2 -2
  159. package/dist/plugins/store-fault.js +4 -2
  160. package/dist/plugins/tidb-pool.js +7 -0
  161. package/dist/plugins/tidb-session-store.js +2 -2
  162. package/dist/request-key-closure.js +1 -1
  163. package/dist/request-value-closure.d.ts +31 -2
  164. package/dist/request-value-closure.js +7 -1
  165. package/dist/rule-entry-list.d.ts +3 -2
  166. package/dist/rule-entry-list.js +2 -2
  167. package/dist/rules-consent.js +7 -4
  168. package/dist/run-local.d.ts +2 -2
  169. package/dist/runs.js +2 -1
  170. package/dist/runtime-governance.d.ts +5 -5
  171. package/dist/sandbox-git-lease.d.ts +49 -0
  172. package/dist/sandbox-git-lease.js +60 -0
  173. package/dist/sandbox-git-plane.d.ts +84 -0
  174. package/dist/sandbox-git-plane.js +105 -0
  175. package/dist/security.d.ts +16 -4
  176. package/dist/security.js +8 -3
  177. package/dist/server-secret-env.d.ts +6 -0
  178. package/dist/server-secret-env.js +14 -0
  179. package/dist/session-error-wire.d.ts +14 -6
  180. package/dist/session-error-wire.js +2 -1
  181. package/dist/session-policy-wire.d.ts +1 -1
  182. package/dist/session-policy-wire.js +2 -2
  183. package/dist/session-sync.d.ts +1 -1
  184. package/dist/spec-fields.d.ts +43 -13
  185. package/dist/spec-fields.js +33 -12
  186. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  187. package/dist/stored-request-prompt-profile-m30.js +25 -0
  188. package/dist/task-mcp.d.ts +1 -1
  189. package/dist/task-settings.d.ts +2 -2
  190. package/dist/tool-approval.d.ts +12 -2
  191. package/dist/tool-approval.js +8 -3
  192. package/dist/tool-rule-names.d.ts +5 -0
  193. package/dist/trace/core-keyset-guard.d.ts +4 -4
  194. package/dist/trace/engine-notice-wire.d.ts +1 -1
  195. package/dist/trace/engine-notice-wire.js +2 -0
  196. package/dist/trace/exit-seat.js +2 -2
  197. package/dist/trace/ledger-sink.d.ts +4 -5
  198. package/dist/trace/ledger-sink.js +3 -7
  199. package/dist/trace/project.d.ts +37 -3
  200. package/dist/trace/project.js +20 -6
  201. package/dist/trace/redact.d.ts +18 -6
  202. package/dist/trace/redact.js +118 -53
  203. package/dist/trace/self-minted-wire.d.ts +377 -3
  204. package/dist/trace/self-minted-wire.js +122 -0
  205. package/dist/trace/wire-projection-faces.d.ts +5 -3
  206. package/dist/trace/wire-projection-faces.js +7 -3
  207. package/dist/web-admin-client/apply-effective.js +0 -1
  208. package/dist/web-admin-client/center-request.d.ts +20 -2
  209. package/dist/web-admin-client/center-request.js +40 -5
  210. package/dist/web-admin-client/http-client.js +6 -6
  211. package/dist/web-admin-client/types.d.ts +5 -5
  212. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  213. package/package.json +2 -2
  214. package/wire-changes/server@7.137.0.json +825 -0
@@ -61,7 +61,15 @@ export async function handleSessionSync(req, res, match, ctx) {
61
61
  const mayTouch = face !== undefined && (scope.fleetWide || face.owner === scope.gateOwner || legacyUnownedSessionOk(deps.config, sessionCallerOf(req, deps), await sessionOwnerCellOf(sessionStorage, sessionId, face.owner)));
62
62
  return { face, mayPull: mayTouch, mayPush: face === undefined || mayTouch };
63
63
  };
64
- const gate = await judgeSessionGate();
64
+ let gate;
65
+ try {
66
+ gate = await judgeSessionGate();
67
+ }
68
+ catch (e) {
69
+ if (isPullPort(match.decl.id) && sendPullUnreadable(req, res, deps.logger, e))
70
+ return;
71
+ throw e;
72
+ }
65
73
  const gateFace = gate.face;
66
74
  const owner = gateFace === undefined ? undefined : gateFace.owner;
67
75
  const sendSessionAbsent = () => sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
@@ -586,6 +594,21 @@ export async function handleSessionSync(req, res, match, ctx) {
586
594
  }
587
595
  }
588
596
  }
597
+ function isPullPort(id) {
598
+ switch (id) {
599
+ case "session-sync-manifest":
600
+ case "session-sync-entries":
601
+ case "session-sync-history-blob":
602
+ return true;
603
+ case "session-sync-plan":
604
+ case "session-sync-import":
605
+ case "session-sync-import-entries":
606
+ case "session-sync-blob-put":
607
+ return false;
608
+ default:
609
+ return assertNever(id);
610
+ }
611
+ }
589
612
  function sendPullUnreadable(req, res, logger, e) {
590
613
  if (e instanceof FileHistoryUnreadableError) {
591
614
  const permanence = e.failure.permanence;
@@ -593,11 +616,24 @@ function sendPullUnreadable(req, res, logger, e) {
593
616
  sendError(res, 503, "state.file_history_unreadable", `this session's file history cannot be read whole (${e.failure.code}), so nothing was exported — ${advice}`, permanence === undefined ? undefined : { permanence });
594
617
  return true;
595
618
  }
596
- if (storeFaultClassOf(e) !== "connection")
597
- return false;
598
- logRequestError(logger, req, e);
599
- sendError(res, 503, "state.file_history_unreadable", "this session's stored state could not be read right now (the store connection failed), so nothing was exported — retry later", { permanence: "transient" });
600
- return true;
619
+ const fault = storeFaultClassOf(e);
620
+ switch (fault) {
621
+ case "connection":
622
+ logRequestError(logger, req, e);
623
+ sendError(res, 503, "state.file_history_unreadable", "this session's stored state could not be read right now (the store connection failed), so nothing was exported — retry later", { permanence: "transient" });
624
+ return true;
625
+ case "deployment":
626
+ logRequestError(logger, req, e);
627
+ sendError(res, 503, "state.file_history_unreadable", "this session's stored state cannot be read: the store does not match what this deployment requires (a table is missing or the database account lacks a privilege), so nothing was exported — retrying will not help until an operator repairs the store", { permanence: "terminal" });
628
+ return true;
629
+ case "corrupt":
630
+ case "unclassified":
631
+ return false;
632
+ default: {
633
+ const unhandled = fault;
634
+ throw new Error(`store fault class without a session-sync pull-port answer: ${String(unhandled)}`);
635
+ }
636
+ }
601
637
  }
602
638
  function sendMissingBlob(res) {
603
639
  sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
@@ -3,6 +3,7 @@ import { a2aForScenario, mcpForScenario } from "../../web-admin-client/facade.js
3
3
  import { HttpError, isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
4
4
  import { windowMessages, truncateMessageBlobs, redactSessionViewForRead } from "../../audit.js";
5
5
  import { redactSecrets } from "../../trace/redact.js";
6
+ import { redactMcpRemoteText } from "../mcp-remote-text.js";
6
7
  import { recordFailOpen } from "../../observability/fail-open.js";
7
8
  import { MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
8
9
  import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
@@ -185,7 +186,7 @@ export async function handleSessions(req, res, match, ctx) {
185
186
  status: s.status,
186
187
  ...(s.serverInfo ? { serverInfo: s.serverInfo } : {}),
187
188
  ...(s.toolNames ? { toolNames: s.toolNames } : {}),
188
- ...(s.error ? { error: redactSecrets(String(s.error)).slice(0, 200) } : {}),
189
+ ...(s.error ? { error: redactMcpRemoteText(String(s.error)) } : {}),
189
190
  })),
190
191
  };
191
192
  }
@@ -25,7 +25,7 @@ import { approvalPreambleReplays, createApprovalCardEmitter, declaredApprovalFra
25
25
  import { buildActiveRunConflict, isActiveRunConflictBody, toDoneFrameResult } from "../active-run-conflict.js";
26
26
  import { commitPlacement, devicePlacementErrorBody } from "../device-placement.js";
27
27
  import { commitSessionInheritEnv } from "../session-inherit-env.js";
28
- import { headerStr, gatedPrincipal, explicitOperatorOk } from "../principal-gate.js";
28
+ import { headerStr, gatedPrincipal, explicitOperatorOk, runIdentityOf } from "../principal-gate.js";
29
29
  import { failOpenTagForDroppedFrame, recordFailOpen } from "../../observability/fail-open.js";
30
30
  import { buildSyncSubmitBody } from "../sync-submit-body.js";
31
31
  import { assertNever } from "../route-ctx.js";
@@ -33,6 +33,7 @@ import * as facts from "../../capability-facts.js";
33
33
  import { persistSubmitCtx } from "../submit-ctx.js";
34
34
  import { serviceVersion } from "../../service-version.js";
35
35
  import { withModelReachScope } from "../../model-reach-scope.js";
36
+ import { runSkillsOf } from "../../capabilities/skills.js";
36
37
  import { createInstructionSelectionLeg } from "../../instruction-selection.js";
37
38
  import { fieldConflictFacts } from "../../field-conflict.js";
38
39
  import { refusalBody } from "../refusal-body.js";
@@ -166,6 +167,7 @@ export async function handleTasks(req, res, match, ctx) {
166
167
  const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
167
168
  let wiringReceipt;
168
169
  const instructionLeg = createInstructionSelectionLeg();
170
+ const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(prepared.spec) });
169
171
  const withRunReceipt = (out) => wiringReceipt !== undefined ? { ...out, wiringManifest: wiringReceipt } : out;
170
172
  if (liveStream) {
171
173
  if (prepared.verify || prepared.cascade) {
@@ -298,7 +300,7 @@ export async function handleTasks(req, res, match, ctx) {
298
300
  };
299
301
  if (deps.runStore && prepared.spec.sessionId) {
300
302
  const tid = earlyDurableTid ?? uuidv7();
301
- const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), idem: idem ?? null });
303
+ const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), identity: runIdentityOf(req, deps.config, principal ?? null), idem: idem ?? null });
302
304
  if (created.ok)
303
305
  clearTurnActivity(tid);
304
306
  if (created.ok)
@@ -338,7 +340,7 @@ export async function handleTasks(req, res, match, ctx) {
338
340
  if (durableTaskId && deps.runStore) {
339
341
  const rs = deps.runStore;
340
342
  const tid = durableTaskId;
341
- ledgerSink = createLedgerSink({ appendEvent: (seq, type, data) => rs.appendEvent(tid, seq, type, data), persistThinking: deps.config.traceThinking, onActivity: (kind, statusData) => recordTurnActivity(tid, kind, statusData), instructionsSegment: instructionLeg.segment });
343
+ ledgerSink = createLedgerSink({ appendEvent: (seq, type, data) => rs.appendEvent(tid, seq, type, data), persistThinking: deps.config.traceThinking, onActivity: (kind, statusData) => recordTurnActivity(tid, kind, statusData), legSections: legWiringSections });
342
344
  usageKey = tid;
343
345
  deps.modelUsage?.register(tid);
344
346
  const owner = principal ?? null;
@@ -589,7 +591,7 @@ export async function handleTasks(req, res, match, ctx) {
589
591
  sseData(res, { type: "compaction_started", ...compactionStartedEventData(ev) });
590
592
  }
591
593
  else if (ev.type === "wiring_manifest") {
592
- const wiringFace = wiringManifestFaceEventData(ev, wiringOperatorFace, instructionLeg.segment());
594
+ const wiringFace = wiringManifestFaceEventData(ev, wiringOperatorFace, legWiringSections());
593
595
  wiringReceipt ??= wiringFace;
594
596
  sseData(res, { type: "wiring_manifest", ...wiringFace });
595
597
  }
@@ -890,7 +892,7 @@ export async function handleTasks(req, res, match, ctx) {
890
892
  let durableHeartbeat;
891
893
  if (deps.runStore && prepared.spec.sessionId) {
892
894
  const tid = uuidv7();
893
- const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), idem: idem ?? null });
895
+ const created = await deps.runStore.createRun(tid, prepared.spec.sessionId, principal ?? null, deps.instanceId ?? "default", { ...runMeta(prepared, source), identity: runIdentityOf(req, deps.config, principal ?? null), idem: idem ?? null });
894
896
  if (created.ok)
895
897
  clearTurnActivity(tid);
896
898
  if (created.ok)
@@ -937,7 +939,7 @@ export async function handleTasks(req, res, match, ctx) {
937
939
  const observeSyncLegEvent = (ev) => {
938
940
  if (ev.type !== "wiring_manifest" || wiringReceipt !== undefined)
939
941
  return;
940
- wiringReceipt = wiringManifestFaceEventData(ev, wiringOperatorFace, instructionLeg.segment());
942
+ wiringReceipt = wiringManifestFaceEventData(ev, wiringOperatorFace, legWiringSections());
941
943
  };
942
944
  let result;
943
945
  counters.uncountedBillableInflight++;
@@ -695,6 +695,10 @@ export interface ServiceDeploymentDeps {
695
695
  /** [ref] ②:caps `centerWiring` 的读面(`capabilities/center-wiring.ts` `createCenterWiringReader`;入参 = 请求的已验 principal)。
696
696
  * 缺席 = 没接中心(或测试夹具)⇒ 键整个缺席。 */
697
697
  centerWiring?: (principal: string | undefined) => import("../capabilities/center-wiring.js").CenterWiring;
698
+ /** The member git-credential plane's one reading (`sandbox-git-plane.ts`; stage 5 computes it once — config premises + the boot's secret
699
+ * seat answer + the static patch judge). Caps `credentialPlane.sandboxGit` projects it as is. Absent = not built by the composition root
700
+ * (a fixture) ⇒ the same judge on config alone, the seat counted as not asked. */
701
+ sandboxGitPlane?: import("../sandbox-git-plane.js").SandboxGitPlane;
698
702
  /**
699
703
  * Graceful drain — shared mutable state between main.ts (flips `draining` on SIGTERM) and this server:
700
704
  * • while `draining`, NEW model-running submissions (the billable submit paths) get 503 + Retry-After, so an
@@ -1,7 +1,7 @@
1
1
  /**
2
- * 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(三问一只;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
2
+ * 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(四问一只;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
3
3
  * plan_review 的 prepare 段、SLA 拒扫腿的跳过臂 `approval-sweeps.ts`、终态 run 的 steer 铸唤醒卡之前 `routes/runs.ts`;`resolveSpec` 本身留作提交腿的拒点)。
4
- * 三问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
4
+ * 四问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
5
5
  *
6
6
  * 为什么判据住在这里而不是 `checkpoint-ctx.ts`:第三问要读体的**生效模式词**(`task-settings.ts` `storedBodyPermissionMode`,请求设置的解析层)与本部署此刻的
7
7
  * **入口地板**(`runtime-governance.ts` `autonomyModeFloor`)—— 这两只属主带着配置层的包外依赖;`checkpoint-ctx.ts` 被随包的本地排空脚本经编译产物 import,
@@ -28,7 +28,7 @@ export type StoredReplayDeployment = LaneHomeDeployment & {
28
28
  readonly autonomy?: Autonomy | undefined;
29
29
  };
30
30
  /**
31
- * 三问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法记号 → 请求设置里的条目表(**与拒点同序**:桶门〔形 / 空串 / 超帽〕→ 工具名清单读成空〔**只问限制方向**:放行方向的存量条目读成空,续跑照旧、只留一行运维 warn〕→ deny / ask 的名字层 + 规则文法)→ 模式词读法记号(几问同中时答先中的那一问 ——
31
+ * 四问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法记号 → 请求设置里的条目表(**与拒点同序**:桶门〔形 / 空串 / 超帽〕→ 工具名清单读成空〔**只问限制方向**:放行方向的存量条目读成空,续跑照旧、只留一行运维 warn〕→ deny / ask 的名字层 + 规则文法)→ 模式词读法记号 → 体里的退役请求键(几问同中时答先中的那一问 ——
32
32
  * 任一问中都不重放,句子只需一句)。`deployment` = 本部署**此刻**的 `config`(活 config:热改即生效):`autonomy` 的地板由它的唯一属主算,`~/` 形规则的 home 由 `executionLaneHomeDir` 算,问点都不自己算。
33
33
  */
34
34
  export declare function storedBodyReplayRefusal(ctx: CheckpointCtx, deployment: StoredReplayDeployment): StoredBodyReplayRefusal | undefined;
@@ -4,13 +4,15 @@ import { entryProblemsFacts } from "../entry-problems.js";
4
4
  import { autonomyModeFloor, entryPermissionMode } from "../runtime-governance.js";
5
5
  import { inertToolListEntryOf, replayInertEntry } from "../rule-entry-list.js";
6
6
  import { executionLaneHomeDir } from "../execution-lane-caps.js";
7
- import { allowListReadingEraOf, allowListReadingUnstated, permissionModeReadingStated } from "./checkpoint-ctx.js";
7
+ import { migrationWindowEnd } from "../plugins/one-time-migrations.js";
8
+ import { allowListReadingEraOf, allowListReadingUnstated, permissionModeReadingStated, retiredRequestKeyOf } from "./checkpoint-ctx.js";
8
9
  export function permissionModeReadingUnstated(ctx, floor) {
9
10
  if (floor === undefined || permissionModeReadingStated(ctx))
10
11
  return undefined;
11
12
  const stored = storedBodyPermissionMode(ctx.body);
12
13
  return entryPermissionMode(stored, floor).effective === stored ? undefined : { stored, floor };
13
14
  }
15
+ const RETIRED_KEY_REWRITE_MIGRATION = { promptProfile: "M30" };
14
16
  const BUCKET_GATE_CODE = "request.field_invalid";
15
17
  function storedPermissions(body) {
16
18
  const permissions = body?.settings?.permissions;
@@ -52,6 +54,9 @@ export function storedBodyReplayRefusal(ctx, deployment) {
52
54
  const mode = permissionModeReadingUnstated(ctx, autonomyModeFloor(deployment.autonomy));
53
55
  if (mode !== undefined)
54
56
  return { kind: "permission_mode_reading", ...mode, ...writer };
57
+ const retiredKey = retiredRequestKeyOf(ctx.body);
58
+ if (retiredKey !== undefined)
59
+ return { kind: "retired_request_key", key: retiredKey, rewriteWindowEnd: migrationWindowEnd(RETIRED_KEY_REWRITE_MIGRATION[retiredKey]), ...writer };
55
60
  return undefined;
56
61
  }
57
62
  //# sourceMappingURL=stored-body-replay.js.map
@@ -11,6 +11,31 @@ import type { RequestMcpServerSpec } from "../mcp-assertion-header.js";
11
11
  import type { wiringManifestFaceEventData } from "../trace/project.js";
12
12
  import type { buildSyncSubmitBody } from "./sync-submit-body.js";
13
13
  import type { EntryProblem } from "../entry-problems.js";
14
+ /**
15
+ * 请求面上的一条技能 = core 的 `SkillSpec` 去掉 `mods`(core 7.56.0 [ref] 的技能座扩展注册:带 `register` 函数的代码对象,不是 wire 数据)。
16
+ * 带 `mods` 的请求技能受理门 400(`http/admission.ts` 的 `validateUserSkills`);本服务不编技能 hooks(能力位 `mods.skill_seat` 恒假)。
17
+ * 键集仍由 core 本体派生([ref]:core 加键,本型同批跟上;删 `mods` 是唯一的一处减法)。
18
+ */
19
+ export type RequestSkill = Omit<SkillSpec, "mods">;
20
+ /**
21
+ * `TaskRequestBody.attachments` 的子键集。本类型是这十个键在导出类型面上的**唯一**声明处;受理门(`http/admission.ts`)与重放翻译口
22
+ * (`spec-fields.ts` 的 `normalizeAttachments`)读 `spec-fields.ts` 的 `ATTACHMENT_KEY_KINDS` 那一张表,表与本接口互为差集门
23
+ * (`_GuardAttachmentKeys*`,漏一边 ⇒ tsc 红)。加 / 删一个键:本接口、那张表、`normalizeAttachments` 的逐键赋值三处同批改。
24
+ */
25
+ export interface TaskRequestAttachments {
26
+ todoReminder?: boolean;
27
+ todoReminderMode?: "baseline" | "off";
28
+ changedFiles?: boolean | {
29
+ maxFiles?: number;
30
+ };
31
+ budgetUsd?: true;
32
+ backgroundTasks?: boolean;
33
+ toolsDelta?: boolean;
34
+ mcpInstructions?: true;
35
+ agentListing?: boolean;
36
+ skillsListing?: boolean;
37
+ mcpUnavailable?: boolean;
38
+ }
14
39
  export interface TaskRequestBody {
15
40
  objective: string;
16
41
  sessionId?: string;
@@ -114,20 +139,20 @@ export interface TaskRequestBody {
114
139
  jobId?: string;
115
140
  /** Personalization seam: the caller's OWN skills for this task, threaded into core's
116
141
  * `TaskSpec.skills`. Merged AFTER the scenario's skills with SCENARIO-WINS on a name clash (the security
117
- * baseline can never be shadowed by user content — see mergeUserSkills). User skills are user-authored
142
+ * baseline can never be shadowed by user content — see buildRunSkills). User skills are user-authored
118
143
  * content in the user's OWN principal-isolated task (self-harm surface, not privilege widening);
119
144
  * scenario/center skills remain the only trusted layer.
120
145
  *
121
146
  * 🔴 **类型 = core 的 `SkillSpec` 本体,不是它的手抄子集**([ref]):这里曾写死
122
147
  * `{ name; description; content }` —— core 闭集六位里的三位,而 `manifest` / `files` / `baseDir`
123
- * 三位在运行期一直是**收的**(受理门 `validateUserSkills` 不判未知键,`mergeUserSkills` 原样透传到
148
+ * 三位在运行期一直是**收的**(受理门 `validateUserSkills` 不判未知键,`buildRunSkills` 原样透传到
124
149
  * `TaskSpec.skills`)。一份会漂的手抄 = 声明面比真受理面**窄**,SDK 消费方按声明写代码就以为发不了,
125
150
  * 而 core 加键(7.20.0 [ref] 的 `baseDir`)时这里连红都不会红。改成 core 本体后,闭集由 tsc 看守。
126
151
  * ⚠️ 受理**判据**(形/尺寸)仍在 `validateUserSkills` + `spec-fields.ts` 的 `SKILL_FIELD_SHAPES`——
127
152
  * 类型说「哪些键存在」,门说「值合不合法」,两者不是一件事。
128
153
  * (旧注里的「Caps: ≤10 skills, content ≤32KB each」两条帽早已随 [ref] / core 1.293 退役,一并纠正:
129
154
  * 今天只剩 `content ≤ 1 MiB` 这一条 core 加载门孪生。) */
130
- skills?: SkillSpec[];
155
+ skills?: RequestSkill[];
131
156
  /** §7 P0.5 (用户按需选像): the sandbox image PROFILE this task wants (e.g.
132
157
  * "code-full" / "code-python"). An INTENT, never a digest — the service resolves it to a published digest with
133
158
  * the caller's principal (fail-closed visibility re-admit) and applies it per-pod. Only supported on the k8s
@@ -247,19 +272,7 @@ export interface TaskRequestBody {
247
272
  * boolean 透传(core DEFAULT-ON,explicit false 才关);budgetUsd/mcpInstructions 只认 literal true;
248
273
  * limits 三个 opt-out 只认 literal false(normalizer 同判)。 */
249
274
  /** core 7.39.0 [ref]:`planModeReminder` 退役(硬破坏,零别名)—— 提交即 400 点名退役;plan 姿态由引擎从 `permissionMode:"plan"` 自己陈述。 */
250
- attachments?: {
251
- todoReminder?: boolean;
252
- todoReminderMode?: "baseline" | "off";
253
- changedFiles?: boolean | {
254
- maxFiles?: number;
255
- };
256
- budgetUsd?: true;
257
- backgroundTasks?: boolean;
258
- toolsDelta?: boolean;
259
- mcpInstructions?: true;
260
- agentListing?: boolean;
261
- skillsListing?: boolean;
262
- };
275
+ attachments?: TaskRequestAttachments;
263
276
  /** C1 (core 1.219, subagent viewing pane): opt-in — forward a delegated child's live CONTENT events
264
277
  * (text_delta/text_end/reasoning_delta/tool_start/tool_end, each stamped `parentToolCallId`) onto this run's stream/durable
265
278
  * log, so a shell can render the child's transcript live ("enter 看详情"). Default OFF = progress-only (prior
@@ -337,9 +350,13 @@ export interface TaskRequestBody {
337
350
  /** [ref]② (core 1.314): [ref] 延迟披露清单(占位上 wire,ToolSearch 激活)——cli「Workflow 默认开
338
351
  * 不暴露」的承载位。同 excludeTools 的校验/继承姿势。 */
339
352
  deferTools?: string[];
340
- /** [ref]/[ref] (core 1.328 R2): 提示词双形轴——simple(CC 212 短形,引擎缺省)| classic(长形,可按
341
- * 任务/模型试分)。纯呈现轴无租户门;枚举 fail-loud at submit;缺省不挂键。 */
342
- promptProfile?: "simple" | "classic";
353
+ /** core 7.56.0([ref]):提示词形的**唯一**任务开关 —— `true` 加 `lean_prompt` 特征(短形)、`false` 去掉它(长的 classic 形)、
354
+ * 缺省 = 模型目录条目自己的声明(引擎缺省 lean)。只动这一个特征,不碰其余特征;原样透传进 `TaskSpec.promptLean`,随引擎铸的每个子代走。
355
+ * 纯呈现轴无租户门;非布尔 400 fail-loud at submit;缺省不挂键。
356
+ * 退役键 `promptProfile`(7.136.x 及以前的 `"simple" | "classic"`)整键删、零别名:fresh 提交体仍带它 ⇒ 键闭集门 400 `request.body_shape`
357
+ * (`unknownKeys:["promptProfile"]`);迁移 = `"classic"` ⇒ `promptLean: false`,`"simple"` ⇒ 不带键。续跑重放不过那道门:盘上 7.136.x 体里的旧键由一次性迁移 M30 在起服时按同一张映射原地改写(`stored-request-prompt-profile-m30.ts`;M30 · 窗口见 `plugins/one-time-migrations.ts` 登记表),
358
+ * 改写不到的残留行续跑 409(`http/stored-body-replay.ts` 第四问)—— 续跑腿不读旧键。 */
359
+ promptLean?: boolean;
343
360
  /** [ref]②(core 5.14.0 座已在,`TaskSpec.toolMaterializeStrategy`):deferred 工具在**激活之后**怎么给
344
361
  * 模型供 schema。`static` = 占位符形不变(激活只改可调用性,广告的 schema 仍是空对象);`swap` = 激活
345
362
  * 后下一轮把占位符换成真 schema。
@@ -352,7 +369,7 @@ export interface TaskRequestBody {
352
369
  * core 把 `"static"` 重新定性为「a strict explicit opt-in」)。本注上一版还写着 `?? "static"`,照它推
353
370
  * 「不挂键 ⇒ 落 static」会反。缺省词的属主是 core,本仓不复述第二份——要确认取值去读 core 的
354
371
  * `prepare-task` 与其 CHANGELOG。
355
- * 缺省不挂键(交给 core 的 env/缺省链);未知词 400 fail-loud(与 promptProfile/permissionMode 同姿势 ——
372
+ * 缺省不挂键(交给 core 的 env/缺省链);未知词 400 fail-loud(与 permissionMode 同姿势 ——
356
373
  * 静默折缺省会让调用方以为切了策略却没切)。 */
357
374
  toolMaterializeStrategy?: "static" | "swap";
358
375
  /** R4 (CC parity): the LIGHT top-level per-turn permission-mode intent (CC `permissionMode`). The shell sends
@@ -363,7 +380,7 @@ export interface TaskRequestBody {
363
380
  * `deniedBy:"mode"`); none can subtract from deployment/operator policy or the request's own deny / ask rules (tightenTaskSpec
364
381
  * deny-wins). The top-level word wins over `settings.permissions.defaultMode` (the heavier bundle) — one precedence, read in one place.
365
382
  * [ref]-②: CLOSED enum on the wire — an unknown word 400s at submit (`request.field_invalid`, sibling of
366
- * promptProfile) instead of silently coercing to `default`; resume replay of a stored body stays lenient
383
+ * toolMaterializeStrategy) instead of silently coercing to `default`; resume replay of a stored body stays lenient
367
384
  * (coercePermissionMode).
368
385
  * 🔴 型与闭集的属主是 core 的 `PermissionMode` / `PERMISSION_MODES`(受理腿 `isPermissionMode` 与三句 400 文案同读那一份)—— 本仓不持词表。 */
369
386
  permissionMode?: PermissionMode;
@@ -432,7 +449,7 @@ export interface TaskRequestBody {
432
449
  cwd?: string;
433
450
  /**
434
451
  * [ref](7.106.0,core [ref] [ref] ②)—— 模型驱动的 host shell **继承多少用户环境**,由调用方按请求声明。
435
- * 闭集两词(词表外 ⇒ 400 `request.field_invalid`,两腿同判,判据属主 `request-value-closure.ts` 的 `inheritEnvFieldIssue`):
452
+ * 闭集两词(词表外 ⇒ 400 `request.field_invalid` + 机读位 `field: "inheritEnv"` / `reason`〔`unknown_word` | `not_a_string`〕,两腿同判,判据与机读位的属主 `request-value-closure.ts` 的 `inheritEnvFieldIssue`):
436
453
  * · `"all"` —— 整份用户环境**减本服务自有凭据名**(配置目录 secret 名 / 名单型旋钮名 / 模型条目 `apiKeyEnv`,起服向引擎声明一次,判在引擎;7.129.0 起,CC 交互形);只在**单用户**部署兑现,射程 = 写容纳面那一只
437
454
  * 部署形表行 `taskHostPostureDeclarations`(`deployment-shape.ts`)⇒ 托管部署(`REQUIRE_PRINCIPAL=true`)响亮拒
438
455
  * 422 `request.host_posture_refused`;
@@ -440,7 +457,7 @@ export interface TaskRequestBody {
440
457
  * **缺席 = 缺省清洗**:不带键的请求把本会话的绑定清掉(不继承上一条请求的声明 —— 这一位是「本条请求要什么」,
441
458
  * 粘到下一条上就是替一个没说话的请求放宽)。名单形(`string[]`)**不上 wire**(那是嵌入方构造执行环境的选项)。
442
459
  * 🔒 **只有 host 车道有消费点**:别的车道(e2b / k8s / local-docker / ssh / adb / device / in-process)带 `"all"` ⇒
443
- * 400 `request.field_invalid`「applies to the host lane only」,不静默忽略、不映射到别的车道的 env 名单;`"scrub"` 在那些车道上照受理(无消费点,无害)。
460
+ * 400 `request.field_invalid`(`reason: lane_not_host`)「applies to the host lane only」,不静默忽略、不映射到别的车道的 env 名单;`"scrub"` 在那些车道上照受理(无消费点,无害)。
444
461
  * Rides the persisted body onto resume legs:重放照射程与车道重判(部署由单用户改托管后 revive ⇒ 同一只拒,
445
462
  * resume-legs 折成 `409 resume_blocked_by_policy`)。
446
463
  */
@@ -586,12 +603,20 @@ export type DecideBinding = {
586
603
  * mints carry it verbatim when present — the engine owns what counts as written (blank = nothing) and judges it again pre-CAS. */
587
604
  feedback?: string;
588
605
  };
589
- /** [ref]([ref]④→[ref] 坐标轮换判定):409 `approval_stale` 拒体上的 additive 机读指路 ——
606
+ /** 409 `approval_stale` 拒体的 additive 机读指路 `currentPending`:**本会话此刻在这道门上待决的那道门**的回显坐标 = 这道门的决断体回显的那几位
607
+ * (一条规则,两道决断门各一形):`/decide` ⇒ {@link DecideStaleCurrentPending};计划审阅([ref])⇒ {@link PlanReviewStaleCurrentPending}。
608
+ * 🔴 恒**不含** checkpointToken(resume 凭证从不外发);只在当前门在场、属这道门的门型、且已过属主门的域内铸 —— 否则键缺席(不造键)。 */
609
+ export type ApprovalStaleCurrentPending = DecideStaleCurrentPending | PlanReviewStaleCurrentPending;
610
+ /** [ref]:计划审阅门的回显坐标 = 门身份 `checkpointId`(过信任边界的那个值;当前门说不出身份 ⇒ 整个 `currentPending` 缺席)。 */
611
+ export type PlanReviewStaleCurrentPending = {
612
+ /** 当前待决 plan_review 门的非秘密身份 —— 壳据此重取那道门的计划给人看,再带它决。 */
613
+ checkpointId: string;
614
+ };
615
+ /** [ref]([ref]④→[ref] 坐标轮换判定):`/decide` 那一形 ——
590
616
  * **本会话当前 pending** 的 D-1 回显坐标,让持旧坐标的壳一跳重定位(免重拉列表)。
591
617
  * 键名/键形与 GET /v1/approvals 的 pending 行逐字同名(壳复用同一解析)。
592
- * 🔴 恒**不含** checkpointToken(runs.ts §12-C:resume 凭证从不外发);只在当前 pending **在场**、
593
- * 属 tool_approval、且已过路由级 owner 门的域内铸 —— 无 pending / 非工具门 / 读失败 ⇒ 键缺席(不造键)。 */
594
- export type ApprovalStaleCurrentPending = {
618
+ * 只在当前 pending 属 tool_approval 时铸 —— 无 pending / 非工具门 / 读失败 ⇒ 键缺席(不造键)。 */
619
+ export type DecideStaleCurrentPending = {
595
620
  /** 当前 pending 被门住的工具名(与 pending 行的 `toolName` 同源同值)。 */
596
621
  toolName: string;
597
622
  /** 当前 pending 的 `pendingAction.toolCallId` —— 壳重定位后 decide 时回显的 D-1 锚。 */
@@ -0,0 +1,65 @@
1
+ /**
2
+ * **身份来源闭集 + run 行身份元组** —— 叶子模块(零依赖):凭据门(`http/principal-gate.ts`)、run 店契约(`plugins/store-contracts.ts`)、
3
+ * 三只 run 店、中央建表语句(`plugins/tidb-pool.ts` / `plugins/pg-pool.ts`)与 `/health` 自报位读同一份。
4
+ *
5
+ * ## 律(三句;全仓只在这里写一次)
6
+ * 1. **一张表、一个次序**:{@link IDENTITY_SOURCES} 的序 = 凭据门的判定次序(`verifiedIdentitySource` 答表里第一个验得过的词)= `/health.auth.kinds` 的出现序。
7
+ * 出示了部署的 service 凭据就是 `service_token` —— 哪怕同一枚 Bearer 也被鉴权桥验成登录令牌、哪怕运维给这枚凭据起的系统名叫 `sso`;
8
+ * 验不过 service 凭据而鉴权桥挂了身份 ⇒ `sso`;都没有而直连门 principal 令牌验过 ⇒ `direct_door_jwt`。
9
+ * 2. **一只元组、受理时铸一次**:run 行的身份元组 {@link RunIdentity}(三列 `identity_source` / `identity_scope` / `identity_principal_inc`)在凭据门上随来源
10
+ * 一起定下(`principal-gate.ts` 的 `admitRunIdentity`,唯一调用点是凭据门),建行处原样写入,之后只读 —— 续跑认领、挂起、终局、重启都不改它,
11
+ * 没有任何读者按当前状态重推它。`RunRecord.source`(系统名 / `"sso"` / null)只作归因,不是认证来源。
12
+ * 3. **缺席一种读法**:`null` = 这一行**没有「属主在受理时验过的凭据」的记录** —— 三列存在之前写下的行、没有任何验过凭据的受理(无鉴权写面
13
+ * `ALLOW_UNAUTHED_WRITES`)、以及别人替属主按下的那一跑(受理请求验过的主体不是这一行的属主:唤醒 / 决定投递铸的新一跑)。读者一律按「不合格」处置
14
+ * (fail-closed),不分辨三种成因;存量行不回填(没有事实可回填)。
15
+ *
16
+ * 化身号 `principalInc`:令牌 `sub_inc` 声明原样,经契约包 `VerifiedIdentity.principalInc` 读(settings-schema 14.7.0 加的可选字段);本版契约包还没有这一位 ⇒ 恒 `null`,
17
+ * 接线点在 `admitRunIdentity` 的 `sso` 臂(不在本仓另定一份读法)。
18
+ */
19
+ /** 验过的身份来源的**闭集**(序 = 判定次序 = `/health.auth.kinds` 的出现序;加一个来源 = 加一个词,读它的各只穷举 `switch` 不接就编译红)。 */
20
+ export declare const IDENTITY_SOURCES: readonly ["service_token", "sso", "direct_door_jwt"];
21
+ export type IdentitySource = (typeof IDENTITY_SOURCES)[number];
22
+ /**
23
+ * run 行身份元组(受理时铸、持久、之后只读;律见文件头)。三键恒在、与三列一一对应:`scope` / `principalInc` 只随 `sso` 有值 ——
24
+ * service 凭据与直连门令牌不带登录令牌的 scope / 化身号,判别联合让「`service_token` 带 scope」这种形写不出来。
25
+ */
26
+ export type RunIdentity = {
27
+ readonly source: "sso";
28
+ readonly scope: string;
29
+ readonly principalInc: string | null;
30
+ } | {
31
+ readonly source: "service_token" | "direct_door_jwt";
32
+ readonly scope: null;
33
+ readonly principalInc: null;
34
+ };
35
+ /** `identity_scope` 的列宽(字符;两方言 VARCHAR 同口径数码点)。与主体列同宽:scope 来自验过签名的令牌,契约的 scope id 形最长 64,读口不判形 ⇒ 留余量。 */
36
+ export declare const RUN_IDENTITY_SCOPE_MAX_CHARS = 190;
37
+ /** `identity_principal_inc` 的列宽(字符):化身号是签发方插入时铸的不透明随机串(与会话化身同宽)。 */
38
+ export declare const RUN_IDENTITY_PRINCIPAL_INC_MAX_CHARS = 64;
39
+ /**
40
+ * `task_run` 三列的列定义 —— 两方言各一段,**唯一属主**:中央建表语句(`tidb-pool.ts` / `pg-pool.ts` 的 `CREATE TABLE task_run`)内插这同一段;
41
+ * 存量库缺列时起服列册对账(`schema-consistency.ts`)拒启,拒句里的 `ALTER TABLE task_run ADD COLUMN …` 由同一份建表语句解析生成 ⇒
42
+ * 「新库建出来的列」与「运维按拒句 / MIGRATION 补上的列」逐字同形。三列都可空(存量行与律 3 的三种成因都是 NULL);PG 钉 `COLLATE "C"`
43
+ * (身份键按字节判等,与 MySQL 协议表级 `utf8mb4_bin` 同形)。
44
+ */
45
+ export declare const RUN_IDENTITY_COLUMNS: {
46
+ readonly tidb: string;
47
+ readonly pg: string;
48
+ };
49
+ /** 元组落盘的三格(SQL 三列 / File 车道 run.json 的三键,同名同义)。 */
50
+ export interface RunIdentityCells {
51
+ readonly identitySource: IdentitySource | null;
52
+ readonly identityScope: string | null;
53
+ readonly identityPrincipalInc: string | null;
54
+ }
55
+ /** 元组 → 三格(写口;三只 run 店同一只)。 */
56
+ export declare function runIdentityCells(identity: RunIdentity | null): RunIdentityCells;
57
+ /**
58
+ * 三格 → 元组(读口;SQL 两方言的行映射与 File 车道的 run.json 读回同一只)。读不出一只**合形**元组的三格一律读成 `null`(律 3:不合格,fail-closed),
59
+ * 这是运行期无法避免的缺省臂,明写在这里:
60
+ * · 来源格缺席 ⇒ 没有记录(三列之前的行 / 律 3 的另两种成因);
61
+ * · 来源格不是闭集里的词(更新的版本写下、回滚到本版读到的词,或手改的行)⇒ 本版认不得的来源不合格;
62
+ * · `sso` 却没有 scope、化身号不是非空串,或别的来源带着 scope / 化身号 ⇒ 不是本仓写口写得出的形(手改 / 半截写),不合格。
63
+ */
64
+ export declare function readRunIdentityCells(source: unknown, scope: unknown, principalInc: unknown): RunIdentity | null;
65
+ //# sourceMappingURL=identity-source.d.ts.map
@@ -0,0 +1,45 @@
1
+ export const IDENTITY_SOURCES = ["service_token", "sso", "direct_door_jwt"];
2
+ export const RUN_IDENTITY_SCOPE_MAX_CHARS = 190;
3
+ export const RUN_IDENTITY_PRINCIPAL_INC_MAX_CHARS = 64;
4
+ export const RUN_IDENTITY_COLUMNS = {
5
+ tidb: [
6
+ "identity_source VARCHAR(32) NULL",
7
+ `identity_scope VARCHAR(${RUN_IDENTITY_SCOPE_MAX_CHARS}) NULL`,
8
+ `identity_principal_inc VARCHAR(${RUN_IDENTITY_PRINCIPAL_INC_MAX_CHARS}) NULL`,
9
+ ].join(",\n "),
10
+ pg: [
11
+ `identity_source VARCHAR(32) COLLATE "C"`,
12
+ `identity_scope VARCHAR(${RUN_IDENTITY_SCOPE_MAX_CHARS}) COLLATE "C"`,
13
+ `identity_principal_inc VARCHAR(${RUN_IDENTITY_PRINCIPAL_INC_MAX_CHARS}) COLLATE "C"`,
14
+ ].join(",\n "),
15
+ };
16
+ export function runIdentityCells(identity) {
17
+ return identity === null
18
+ ? { identitySource: null, identityScope: null, identityPrincipalInc: null }
19
+ : { identitySource: identity.source, identityScope: identity.scope, identityPrincipalInc: identity.principalInc };
20
+ }
21
+ const isNonEmptyString = (v) => typeof v === "string" && v !== "";
22
+ const isAbsent = (v) => v === null || v === undefined;
23
+ export function readRunIdentityCells(source, scope, principalInc) {
24
+ if (isAbsent(source) || typeof source !== "string")
25
+ return null;
26
+ const word = IDENTITY_SOURCES.find((w) => w === source);
27
+ if (word === undefined)
28
+ return null;
29
+ switch (word) {
30
+ case "sso":
31
+ if (!isNonEmptyString(scope))
32
+ return null;
33
+ if (isAbsent(principalInc))
34
+ return { source: word, scope, principalInc: null };
35
+ return isNonEmptyString(principalInc) ? { source: word, scope, principalInc } : null;
36
+ case "service_token":
37
+ case "direct_door_jwt":
38
+ return isAbsent(scope) && isAbsent(principalInc) ? { source: word, scope: null, principalInc: null } : null;
39
+ default: {
40
+ const unknownWord = word;
41
+ throw new Error(`readRunIdentityCells: identity source ${String(unknownWord)} has no reading`);
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=identity-source.js.map
@@ -23,11 +23,11 @@
23
23
  * 那几行的前缀是**条目路径**(模型可写)—— 本仓今天不读 warnings 车道(既有面,不是本批回归),也不在模型可写的文本上
24
24
  * 找码;这一半候 core 的结构化码位(登记在案,codex 一审 C3)。
25
25
  *
26
- * ## 不是这一族的三形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂)
26
+ * ## 不是这一族的形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂;今两形 + 一只已退的形)
27
27
  * · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,KL-1094-b)⇒ 路由 typed 500 `internal.memory_control_plane_corrupt`
28
28
  * (core 7.44.0 起 scope home 非目录**不再**走这一类 —— 它有了自己的码,见上;`ControlPlaneCorruptError` 只剩真控制面损坏);
29
- * · 引擎原地写撞硬链(nlink>1)⇒ 文本 `has N names (a hard link)`、无码(KL-1094-g / [ref])⇒ 走该写点既有的失败车道(harvest
30
- * warnings / 挂载失败),抛出面够不着;
29
+ * · (已不存在的一形)引擎原地写撞硬链(nlink>1):≤ 引擎 7.55.x 是无码文本 `has N names (a hard link) … not written`、走该写点既有的失败车道;
30
+ * 引擎 7.56.0 起那只写给**这个名字**另建一个新文件(原子改名落位,其余名字保留原文件),拒绝与那句文本一并消失 —— 本仓从未读过那句文本,零码;
31
31
  * · 解析故障(`EACCES` / `ELOOP` / `ENOTDIR`)⇒ 以 errno 本身抛 ⇒ 路由未分类 500 + 运维 warn(`String(err)` 带 core 补救句)。
32
32
  *
33
33
  * ## 运维行也在这里铸(两受众同一只,{@link logStoreFormRefusal})
@@ -49,6 +49,8 @@ export interface CatalogEntryLike {
49
49
  readonly api?: unknown;
50
50
  /** [ref]:供应商附加头的承载形(`unknown`:判据在 `model-entry-headers.ts`,不信这张型)。 */
51
51
  readonly headers?: unknown;
52
+ /** 引擎已退役的每模型引导句(core 7.56.0 [ref];settings-schema 的 `ModelEntry` 仍收它)—— 只读在场与否,见 {@link judgeCatalogEntry}。 */
53
+ readonly promptGuidance?: unknown;
52
54
  }
53
55
  /**
54
56
  * **逐条判据**:`undefined` = 本部署能完整服务它。判序即语义:先形(不合形的条目谈不上走哪条腿),再腿。
@@ -31,6 +31,17 @@ export function judgeCatalogEntry(m, ctx) {
31
31
  const headers = readCatalogEntryHeaders(m.headers, m.api);
32
32
  if (!headers.ok)
33
33
  return entryInvalidRefusal(m.id, m.provider, headers.fields, headers.issue);
34
+ if (Array.isArray(m.promptGuidance) && m.promptGuidance.length > 0) {
35
+ return {
36
+ ...refusalCause("config.model_entry_invalid"),
37
+ id: m.id,
38
+ provider: m.provider,
39
+ fields: ["promptGuidance"],
40
+ detail: "the catalog entry carries per-model guidance sentences (promptGuidance), which the engine no longer delivers — the entry is not served here " +
41
+ "rather than served with its sentences silently dropped; move each sentence into a center or deployment prompt overlay on the behavior band " +
42
+ "and remove promptGuidance from the entry to bring it back",
43
+ };
44
+ }
34
45
  const lane = catalogBrainLane(m.provider);
35
46
  const mount = laneMount(lane, ctx);
36
47
  if (!mount.mounted) {
@@ -187,11 +187,10 @@ export declare function matchCatalogModel(ref: string, catalog: Record<string, u
187
187
  export declare const MODEL_IMAGE_INPUTS: readonly ["yes", "no", "undeclared"];
188
188
  export type ModelImageInput = (typeof MODEL_IMAGE_INPUTS)[number];
189
189
  /**
190
- * 「这个目录条目收不收图」的**唯一读法**。两个读者都投影它,不各写各的:
190
+ * 「这个目录条目收不收图」的**唯一读法**。读者都投影它,不各写各的:
191
191
  * · 目录行 `GET /v1/models` 的 `vision`:`yes` ⇒ `true`,`no` ⇒ `false`,`undeclared` ⇒ **键缺席**(不替没声明的模型答「收」也不答「不收」);
192
- * · 运行期的带图预检 {@link modelSupportsImages}:只有明说 `no` 才出信号。
193
- * 此前两处各判各的,且对「没声明」答法相反(目录行报 false、预检放行)——客户端只读得到目录那一位,于是在手写、没声明 `input` 的
194
- * 条目上把用户的图拦在了本地,而引擎其实会把图交给模型。env 车道与 web-admin 车道恒写 `input`,分叉只落在手写目录条目上。
192
+ * · 配置目录 `GET /v1/config/catalog` 的 `MODEL_VISION` 行。
193
+ * 「图被换成占位句」这件事实不在本仓判:引擎 7.56.0([ref])在真替换的那一刻铸给人(`model.capability_downgraded`,会话流),本仓提交面的带图预检随之退役。
195
194
  * `input` 不是数组(手写错形)与条目不在,同归 `undeclared`:没有可信的声明。
196
195
  */
197
196
  export declare function modelImageInput(model: {
@@ -212,19 +211,9 @@ export interface ModelCapabilityDecl {
212
211
  /**
213
212
  * 能力位声明 ⇒ `Model` 上的两个键,**缺席不铸键**:`reasoning` 原样;`vision` 翻成 `input`(`true` ⇒ `["text","image"]`,`false` ⇒ `["text"]`)。
214
213
  * env 腿(`MODEL_REASONING` / `MODEL_VISION`)、cheap 槽(`MODEL_CHEAP_*`)与中心腿(`models[].reasoning` / `vision`)都经它铸 —— 三条腿一个铸法、一个「缺席」的意思。
215
- * 读回的唯一读法是 {@link modelReasoningDecl} 与 {@link modelImageInput}(带图预检与 `GET /v1/models` 同读后者)。
216
- *
217
- * 🔴 **本仓唯一的类型接缝**:引擎 7.51.2 的 `Model` 型面把 `reasoning` / `input` 写成必填,而它自己的读法对缺席有定义 ——
218
- * `input` 缺席 ⇒ 支持图(`modelSupportsVision`:`model?.input === undefined ? true : …`),`reasoning` 缺席 ⇒ 真值判假(`!!model.reasoning`)。所以交给引擎的目录里缺席的键是安全的,
219
- * 只是型面还没跟上;返回型因此对 `Pick<Model, …>` 说了一句「可能为空」的谎,把断言收在这一处 —— 调用点的 `Model` 字面量照旧带 `Model` 注解(其余每个键仍被 tsc 逐个核,
220
- * 读表门按注解收字面量的 core 键)。型面归引擎:引擎把这两位放成可选之日,本接缝(返回型 + 这一处断言)整件删除。
214
+ * 读回的唯一读法是 {@link modelReasoningDecl} 与 {@link modelImageInput}(`GET /v1/models` 与配置目录同读)。
215
+ * 引擎 7.56.0([ref])起 `Model.reasoning` / `Model.input` 在型面上就是可选(缺席 = 未声明,引擎一只读法 `capabilityOf`:图的未声明照常交给模型、
216
+ * 推理的未声明不发思考档),所以本函数的返回型就是引擎的型,无断言。
221
217
  */
222
218
  export declare function mintCapabilityKeys(decl: ModelCapabilityDecl): Pick<Model, "reasoning" | "input">;
223
- /**
224
- * 带图预检:只有目录条目**明说**不收图({@link modelImageInput} 为 `"no"`)才为假 —— 提交时据此计数并告警(引擎会把这些图换成给模型的
225
- * 占位句);没声明的条目为真(不出信号,图原样交给模型)。
226
- */
227
- export declare function modelSupportsImages(model: {
228
- input?: unknown;
229
- } | undefined): boolean;
230
219
  //# sourceMappingURL=model-select.d.ts.map
@@ -137,7 +137,4 @@ export function mintCapabilityKeys(decl) {
137
137
  keys[CAPABILITY_MODEL_KEYS.input] = decl.vision ? ["text", "image"] : ["text"];
138
138
  return keys;
139
139
  }
140
- export function modelSupportsImages(model) {
141
- return modelImageInput(model) !== "no";
142
- }
143
140
  //# sourceMappingURL=model-select.js.map
@@ -42,7 +42,7 @@ export type UnmatchableRuleName = Exclude<RuleToolNameVerdict, {
42
42
  /**
43
43
  * **运维名表的态度** —— 一个常量,判官与匹配器同读(core 7.55.0 [ref])。本仓的名表消费者(env `APPROVAL_REQUIRE` / `APPROVAL_DENY` / `APPROVAL_NEVER_AUTO`、
44
44
  * 中心下发的 `approvalRequire`、请求 `settings.permissions` 的 neverAuto 座)全是**限制表**(要求审批 / 硬拦 / 禁自动答):引擎对一个名字在限制表里的读法
45
- * (`judgeRuleToolName(name, 名册, behavior)` 收不收、`isNamespacedCoveringRuleName(name, behavior)` 够着哪些工具)只分「限制 / 放行」两侧 —— 整个协议的名字
45
+ * (`judgeRuleToolName(name, 名册, behavior)` 收不收、`isCoveringRuleName(name, behavior)` 够着哪些工具)只分「限制 / 放行」两侧 —— 整个协议的名字
46
46
  * `mcp__*` / `mcp__*__*` 在 deny 与 ask 里同读成这一协议的每一只工具。受理口的判(`config.ts`)与运行期的匹配(`approval.ts`)读同一个态度,一张表不会一边收、一边什么也不拦。
47
47
  */
48
48
  export declare const NAME_TABLE_BEHAVIOR: "deny";