@sema-agent/server 7.137.0 → 7.138.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 +328 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +67 -20
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/audit.js +1 -0
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +23 -12
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-04-stores.d.ts +1 -12
- package/dist/boot/stage-05-execution-env.d.ts +3 -12
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +3 -12
- package/dist/boot/stage-06-runners.js +5 -2
- package/dist/boot/stage-07-capability-layer.d.ts +3 -12
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -12
- package/dist/boot/stage-09-leader.d.ts +3 -12
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +3 -12
- package/dist/boot/stage-10-http-server.js +4 -2
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +7 -1
- package/dist/config-types.d.ts +15 -7
- package/dist/config.js +8 -5
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +1 -0
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +4 -2
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +3 -0
- package/dist/http/durable-run-leg.js +4 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/resume-legs.d.ts +5 -11
- package/dist/http/resume-legs.js +136 -91
- package/dist/http/route-ctx.d.ts +30 -51
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +6 -6
- package/dist/http/routes/capabilities.js +12 -10
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -5
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +11 -7
- package/dist/http/routes/sessions.js +6 -4
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +792 -780
- package/dist/http/server.d.ts +31 -25
- package/dist/http/wire-types.d.ts +14 -6
- package/dist/identity-source.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +5 -1
- package/dist/observability/fail-open.js +5 -1
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +14 -8
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +15 -20
- package/dist/plugins/checkpoint-store-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.js +3 -2
- package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
- package/dist/plugins/k8s-pod-reaper.js +3 -3
- package/dist/plugins/local-checkpoint-store.d.ts +1 -11
- package/dist/plugins/local-checkpoint-store.js +0 -1
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +6 -3
- package/dist/plugins/one-time-migrations.js +3 -4
- package/dist/plugins/permission-rule-store-sql.js +21 -13
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +18 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -1
- package/dist/plugins/remote-env-adb.js +1 -1
- package/dist/plugins/remote-env-device.d.ts +3 -1
- package/dist/plugins/remote-env-device.js +1 -1
- package/dist/plugins/remote-env-e2b.d.ts +2 -0
- package/dist/plugins/remote-env-e2b.js +1 -1
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +3 -1
- package/dist/plugins/remote-env-k8s.js +1 -1
- package/dist/plugins/remote-env-local-docker.d.ts +2 -0
- package/dist/plugins/remote-env-local-docker.js +1 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -1
- package/dist/plugins/remote-env-ssh.js +1 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +7 -0
- package/dist/plugins/session-ownership.js +5 -0
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/tidb-pool.js +6 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +16 -5
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/rules-consent.js +6 -4
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +6 -1
- package/dist/sandbox-git-plane.d.ts +2 -2
- package/dist/server-secret-env.d.ts +6 -3
- package/dist/server-secret-env.js +4 -2
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +1 -1
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +33 -20
- package/dist/task-mcp.js +46 -22
- package/dist/tool-approval.d.ts +32 -8
- package/dist/tool-approval.js +49 -12
- package/dist/trace/core-keyset-guard.d.ts +33 -18
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/project.d.ts +25 -7
- package/dist/trace/project.js +29 -3
- package/dist/trace/redact.js +42 -13
- package/dist/trace/self-minted-wire.d.ts +129 -10
- package/dist/trace/self-minted-wire.js +62 -3
- package/dist/trace/wire-projection-faces.d.ts +6 -6
- package/dist/trace/wire-projection-faces.js +6 -5
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/center-request.d.ts +3 -2
- package/dist/web-admin-client/center-request.js +2 -3
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +5 -0
- package/package.json +3 -3
- package/wire-changes/server@7.138.0.json +446 -0
- package/dist/http/mcp-remote-text.d.ts +0 -5
- package/dist/http/mcp-remote-text.js +0 -7
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ import type { GateSighting } from "../approval-gate-currency.js";
|
|
|
31
31
|
import type { VerifyRoundsSpec } from "./verify-rounds.js";
|
|
32
32
|
import type { RunAbort } from "../run-cancel-context.js";
|
|
33
33
|
import type { RunIdentity } from "../identity-source.js";
|
|
34
|
+
import type { PeerLease } from "../peer-seat.js";
|
|
35
|
+
import type { GateCommitment, GateSettlementEvidence } from "../gate-settlement.js";
|
|
34
36
|
/** 跨域可变状态 = lens1 §C2 实测的那 8 条「运行期登记簿」,一个对象。
|
|
35
37
|
* [ref]:`cancelledViaVerb`(按 taskId 键控的「这次是取消动词」旁表)删除 —— 中止成因改挂在每条腿自己的
|
|
36
38
|
* {@link RunAbort} 句柄上(`inflightRuns` 的值),同寿同删,不再有一张与腿不同寿的旁表。 */
|
|
@@ -148,6 +150,12 @@ export interface PreparedTaskSubmission {
|
|
|
148
150
|
* 不经提交门的内部车道(`/decide` 的宿主新 turn)铸一只不带标题器的座:不起标题。
|
|
149
151
|
*/
|
|
150
152
|
acceptance: import("../run-acceptance.js").RunAcceptance;
|
|
153
|
+
/**
|
|
154
|
+
* 这次装配的**宿主租约**:受理漏斗在装配之前开(`peerDesk.lease("fresh")`),装配在它之下登记交给引擎的对端声明;漏斗成功即把它交到这里 ——
|
|
155
|
+
* 拿到本产物的那只函数紧接着写 `try { … } finally { prepared.peerLease.release() }`,其后每个出口(早退、合流败方、建行拒、驱动返回)按构造都放。
|
|
156
|
+
* 活过那段作用域的驱动(后台腿)经 `heldFor(prepared.peerLease, () => …)` 自持一只,自己落定才放。续跑家族的内部车道交它自己漏斗开的那一只。
|
|
157
|
+
*/
|
|
158
|
+
peerLease: PeerLease;
|
|
151
159
|
}
|
|
152
160
|
/**
|
|
153
161
|
* 一条会话的**续跑重建输入**(`checkpoint_ctx` 的行体)—— 提交腿写一次,续跑腿读它重建 spec。
|
|
@@ -252,6 +260,11 @@ export interface DriveResumeArgs {
|
|
|
252
260
|
sessionId: string;
|
|
253
261
|
ctx: CheckpointCtx;
|
|
254
262
|
};
|
|
263
|
+
/**
|
|
264
|
+
* 这条续跑的**宿主租约**(续跑漏斗 `resolveResumeSpecOrBlocked` 开、装配在它之下登记对端声明;调用方作用域的 `finally` 放)。
|
|
265
|
+
* 驱动腿经 `heldFor(args.peerLease, () => driveResumeLeg(…))` 自持一只:受理早回的那一形里,腿活过调用方作用域,自己落定才放。
|
|
266
|
+
*/
|
|
267
|
+
peerLease: PeerLease;
|
|
255
268
|
/** [ref]:续跑腿的执行 Runner。resume 会用同一条 resolveSpec 重解析场景,故与首跑选同一只 —— 否则
|
|
256
269
|
* 一次续跑就把手带 band 重新 mount 回来(收窄只在首跑成立 = 没成立)。 */
|
|
257
270
|
runner: Runner;
|
|
@@ -261,6 +274,12 @@ export interface DriveResumeArgs {
|
|
|
261
274
|
taskConfig: Omit<TaskSpec, "objective" | "sessionId">;
|
|
262
275
|
resumeObjective: string;
|
|
263
276
|
outcome: ResumeOutcome;
|
|
277
|
+
/**
|
|
278
|
+
* 🔴 **这条腿到达边界时能证什么**(必填 —— 缺 = 编译错;闭集,语义属主 = `gate-settlement.ts` 的 {@link GateCommitment})。同一条驱动路径既续本请求点名的门
|
|
279
|
+
* (`/decide` 引擎臂、`/resume`、`/plan_review` ⇒ `gate_resolved`,带执行**前**从选中那一行捕获、过了信任边界的身份),也替宿主投递(wake ⇒ `delivered`)。
|
|
280
|
+
* 它只是分类:位由受理点与终局体两个边界按它铸,从不只凭这一句声明铸;缺席的取消出口(`checkpoint.resume_aborted` / 抛出臂)不铸。
|
|
281
|
+
*/
|
|
282
|
+
commitment: GateCommitment;
|
|
264
283
|
verifyRounds: VerifyRoundsSpec | undefined;
|
|
265
284
|
/**
|
|
266
285
|
* **R-1**(车CJ 收车档 §10 R-1;[ref] 批落地)—— 本条 resume 腿**装配期**铸下的用户面通告
|
|
@@ -433,10 +452,7 @@ export interface RouteLegs {
|
|
|
433
452
|
decider?: {
|
|
434
453
|
principal?: string;
|
|
435
454
|
explicitOperator: boolean;
|
|
436
|
-
}): Promise<
|
|
437
|
-
status: number;
|
|
438
|
-
body: object;
|
|
439
|
-
}>;
|
|
455
|
+
}): Promise<ResumeLegOutcome>;
|
|
440
456
|
/** notify-wake 域:唤醒一条 parked checkpoint。 */
|
|
441
457
|
resumeWake(sessionId: string, message: string | undefined, caller: string | undefined, req: IncomingMessage | undefined,
|
|
442
458
|
/** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
|
|
@@ -444,7 +460,7 @@ export interface RouteLegs {
|
|
|
444
460
|
acceptEarly?: boolean,
|
|
445
461
|
/** 透传给 {@link DriveResumeArgs.workflowDecision}。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道投递腿的专用席,
|
|
446
462
|
* 而两条腿共用这一条驱动路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿」的成文纪律。 */
|
|
447
|
-
workflowDecision?: WorkflowDecisionDelivery): Promise<
|
|
463
|
+
workflowDecision?: WorkflowDecisionDelivery): Promise<ResumeLegOutcome>;
|
|
448
464
|
/**
|
|
449
465
|
* assistant plan_review 三态腿的**纯读段**([ref],7.97.0):选卡 → 属主轻读 → 载入 → 行级 scope → 门类 → 这条决断
|
|
450
466
|
* 唯一的一次 ctx 读。任何一步拒 ⇒ `{ok:false, answer}`(不改任何状态;端点在消费一次性 nonce **之前**把它答出去);
|
|
@@ -481,10 +497,7 @@ export interface RouteLegs {
|
|
|
481
497
|
acceptEarly?: boolean,
|
|
482
498
|
/** [ref]:批准之后这条会话继续用的 permission mode(闭集 `PLAN_APPROVE_PERMISSION_MODES_AFTER`;只在把计划带出 plan 的决定
|
|
483
499
|
* —— `approve` / `edit` —— 上有意义,缺席 ⇒ `"default"`)。语义与判据的唯一属主 = `resume-legs.ts` 的同名形参顶注。 */
|
|
484
|
-
permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<
|
|
485
|
-
status: number;
|
|
486
|
-
body: object;
|
|
487
|
-
}>;
|
|
500
|
+
permissionModeAfter?: PlanApprovePermissionModeAfter): Promise<ResumeLegOutcome>;
|
|
488
501
|
}
|
|
489
502
|
/**
|
|
490
503
|
* [ref] 件 S-2 —— resume 族**受理点的断连留痕**(裁定:维持 detach,补观察面)。
|
|
@@ -673,48 +686,13 @@ export type RouteDecl = RouteDispatchDecl | RouteGateDecl;
|
|
|
673
686
|
* api-error-text-freeze 基线流程。
|
|
674
687
|
*/
|
|
675
688
|
/**
|
|
676
|
-
* resume
|
|
677
|
-
*
|
|
678
|
-
* `decisionCommitted` —— **这条腿的终局是在引擎受理了这次决定之后才结出来的**([ref] X5,7.112.0):本腿走到了「引擎交回结果」那一步
|
|
679
|
-
* (`resumeStream` / `resumeWithVerification` 解析 = core 的全部 pre-CAS 门 + checkpoint resolve CAS 都过了 —— 受理点的判据属主
|
|
680
|
-
* = {@link DriveResumeArgs.acceptEarly} 顶注),之后才收场。只由 `driveResumeLeg` 走完引擎那一步的终局出口铸;`CheckpointError` 臂、
|
|
681
|
-
* 「中止抛穿」臂、一切 4xx / 拒绝出口一律**不铸**(缺席 ⇒ 证不出提交,读者按「没提交」读 —— fail-closed)。
|
|
682
|
-
*
|
|
683
|
-
* 读者:`/decide` 的两道「这次决定提交了没有」门 —— [ref] 迟到结算留痕(`noteLateSettleIfAccepted`)与 remember 豁免落店
|
|
684
|
-
* (`routes/approvals-assistant.ts`)。它们原先只读 wire 体的 `errorCode !== "cancelled"`(「取消 = 决定没提交」),[ref] 给续跑腿补了
|
|
685
|
-
* 「引擎受理之后才被取消」的取消终局之后,`cancelled` 不再等价「没提交」⇒ 两门改读本位:`200 ∧ (errorCode≠cancelled ∨ decisionCommitted)`。
|
|
686
|
-
* 🔴 为什么不放进 `result.cancelContext`(主会话初稿的落点):那只快照的契约是「分诊材料,不是状态机输入:任何门 / CAS / resume 判定都不许
|
|
687
|
-
* 读它」(`plugins/store-contracts.ts` `RunCancelContext` 顶注)—— 这两道门正是判定;而且门读的是 `/decide` 的平面体、看不到结果对象。
|
|
688
|
-
* 受理与否是腿自己的控制流事实,在腿上说,零 wire 变更。
|
|
689
|
+
* resume 家族一条腿的结局:HTTP 应答(`status` / `body`)。「这次决定提交了没有」只有一种说法 —— 体上的结清证据 `decisionCommitted`
|
|
690
|
+
* (唯一铸点 / 唯一读法 = `gate-settlement.ts`);进程内不另带第二个提交位。
|
|
689
691
|
*/
|
|
690
|
-
export interface
|
|
692
|
+
export interface ResumeLegOutcome {
|
|
691
693
|
status: number;
|
|
692
694
|
body: object;
|
|
693
|
-
decisionCommitted?: true;
|
|
694
695
|
}
|
|
695
|
-
/**
|
|
696
|
-
* **workflow 宿主腿的结局(wake / fresh)—— 型上就没有 `decisionCommitted`**([ref] ②,7.113.0;`never` 让「这条路径不铸」成为**编译事实**,不是靠人记)。
|
|
697
|
-
*
|
|
698
|
-
* 为什么这条路径不该有该位:`/decide` 的 workflow 第三条车道(`resumeCheckpoint` 的 parked 分流,`planWorkflowParkedDecide` 之后)与 `POST /v1/sessions/:id/wake`
|
|
699
|
-
* 把决定 / 消息交给**宿主会话的下一跑**(`resumeWake` / `startFreshHostTurn`)。它们的 200 只到「已交给宿主的下一跑」—— 子代 checkpoint 的 resolve CAS 发生在
|
|
700
|
-
* workflow 引擎自己驱动那一步,server 观察不到(`resume-legs.ts` 该分流处「刻意不落 `late_settle`」同源)。「这次决定被引擎受理了」这句话在这里**没有可说的对象**,
|
|
701
|
-
* 于是 `decisionCommitted` 在这条路径上语义含混(修前:`resumeWake` 的收尾是 `driveResumeIntoRunLog` 的 `ResumeLegOutcome`,非受理点早返形(无 `acceptEarly`)下它会把
|
|
702
|
-
* 引擎腿的 `decisionCommitted:true` 原样带出去 —— 型被声明返回型 `{status, body}` 擦掉了,运行期仍在)。读者核实:两道提交门(`noteLateSettleIfAccepted` 迟到结算留痕、
|
|
703
|
-
* `/decide` 的 remember 豁免落店)在这条路径上今天**零读取**(前者该分流直接 `return`、不调;后者的 `pendingGrant` 只由引擎腿的 `onResumeCommitted` 回调置位,宿主腿不调它,且 `planWorkflowParkedDecide` 对 workflow 车道的 `remember` 本就 fail-closed 拒 —— `decide.workflow_remember_unsupported`,`parked-decide.ts`)——
|
|
704
|
-
* 无读者 ⇒ 剥掉该位,而不是留一个「铸了也没人读、读了不知道什么意思」的位。出口经 {@link buildHostLegOutcome} 只带 `status` / `body`。
|
|
705
|
-
*/
|
|
706
|
-
export interface HostLegOutcome {
|
|
707
|
-
status: number;
|
|
708
|
-
body: object;
|
|
709
|
-
decisionCommitted?: never;
|
|
710
|
-
}
|
|
711
|
-
/** resume 家族一条腿的结局:引擎腿(可带 `decisionCommitted`)∪ workflow 宿主腿(型上没有)。`out.decisionCommitted === true` 同时收窄到引擎腿。 */
|
|
712
|
-
export type ResumeLegOutcome = EngineLegOutcome | HostLegOutcome;
|
|
713
|
-
/** 把任意腿的结局折成宿主腿结局:**只带 `status` / `body`**(丢掉引擎腿的 `decisionCommitted` —— 见 {@link HostLegOutcome})。纯数据。 */
|
|
714
|
-
export declare function buildHostLegOutcome(out: {
|
|
715
|
-
status: number;
|
|
716
|
-
body: object;
|
|
717
|
-
}): HostLegOutcome;
|
|
718
696
|
/**
|
|
719
697
|
* **「决定/续跑已受理」那一枚 200 收据的单一铸点**([ref])。
|
|
720
698
|
*
|
|
@@ -724,11 +702,12 @@ export declare function buildHostLegOutcome(out: {
|
|
|
724
702
|
* 都不该加**;写成两份字面量,漂开的那天没有任何东西会说话。
|
|
725
703
|
*
|
|
726
704
|
* `bindingEnforced` 的语义不因铸点而变(「这次决定按绑定坐标受理,不是盲目放行」),故两腿同带。
|
|
705
|
+
*
|
|
706
|
+
* `evidence` = 结清证据(`gate-settlement.ts`):引擎续跑腿的受理点交 `buildSettlementEvidence({ at: "engine_accepted", … })` 铸的那一份
|
|
707
|
+
* (`gate_resolved` 腿 ⇒ 位 + 身份;wake 的 `delivered` ⇒ 空);没跨过任何边界的回执(宿主新一跑、同一决定重投)交 `NO_SETTLEMENT_EVIDENCE`。
|
|
708
|
+
* 调用方不手写证据键 —— 体上的两键只有那一只铸点。
|
|
727
709
|
*/
|
|
728
|
-
export declare function acceptedResumingReceipt(taskId: string, sessionId: string):
|
|
729
|
-
status: number;
|
|
730
|
-
body: object;
|
|
731
|
-
};
|
|
710
|
+
export declare function acceptedResumingReceipt(taskId: string, sessionId: string, evidence: GateSettlementEvidence): ResumeLegOutcome;
|
|
732
711
|
/** 一条腿的结局是不是一张「已受理」回执,是 ⇒ 回执上那一跑的 `taskId`(同一张回执的读法与 {@link acceptedResumingReceipt} 住在一起;
|
|
733
712
|
* `/decide` 的 workflow 车道据它把投递那一跑记在决定行上)。 */
|
|
734
713
|
export declare function acceptedTaskIdOf(out: {
|
package/dist/http/route-ctx.js
CHANGED
|
@@ -21,11 +21,8 @@ export function assertNever(x) {
|
|
|
21
21
|
throw new Error(`unreachable route id: ${String(x)}`);
|
|
22
22
|
}
|
|
23
23
|
export const ROUTE_METHOD_ORDER = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
24
|
-
export function
|
|
25
|
-
return { status:
|
|
26
|
-
}
|
|
27
|
-
export function acceptedResumingReceipt(taskId, sessionId) {
|
|
28
|
-
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
|
|
24
|
+
export function acceptedResumingReceipt(taskId, sessionId, evidence) {
|
|
25
|
+
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true, ...evidence } };
|
|
29
26
|
}
|
|
30
27
|
export function acceptedTaskIdOf(out) {
|
|
31
28
|
const body = out.body;
|
|
@@ -272,11 +272,17 @@ async function handleMessageSend({ req, res, ctx, params, serve, runStore }) {
|
|
|
272
272
|
const prepared = await ctx.legs.prepareSpec(req, res, body, (e) => {
|
|
273
273
|
typed = e;
|
|
274
274
|
});
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
if (!prepared) {
|
|
276
|
+
if (typed)
|
|
277
|
+
throw rpcErrorFromTypedFailure(typed, skillId);
|
|
278
278
|
return undefined;
|
|
279
|
-
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
receipt = await createDurableRun(req, res, ctx, prepared, idem);
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
prepared.peerLease.release();
|
|
285
|
+
}
|
|
280
286
|
}
|
|
281
287
|
if (!receipt)
|
|
282
288
|
return undefined;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* · **能力位同源**:`capabilities.agentRoster` 与这里的 501 谓词是同一个 `deps.backgroundAgentStore`。
|
|
26
26
|
*/
|
|
27
27
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
28
|
-
import type
|
|
28
|
+
import { type BackgroundAgentRowSummary } from "@sema-agent/core";
|
|
29
29
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
30
30
|
/** 名册窗的扫描上限(与 fleet 的终态窗同姿势:读面要有界)。窗满时回体带 `truncated:true`,
|
|
31
31
|
* `total` 于是诚实地是「窗内行数」而不是租户全量 —— 一个悄悄封顶的 total 比没有 total 更坏。 */
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { chosenAgentName } from "@sema-agent/core";
|
|
1
2
|
import { sendJson, sendError } from "../send.js";
|
|
2
3
|
import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
|
|
3
4
|
import { assertNever } from "../route-ctx.js";
|
|
4
5
|
import * as facts from "../../capability-facts.js";
|
|
6
|
+
import { backgroundAgentNameOf } from "../../background-agent-name.js";
|
|
5
7
|
export const ROSTER_SCAN_LIMIT = 500;
|
|
6
8
|
const ROSTER_STATUSES = ["running", "parked", "completed", "failed", "killed"];
|
|
7
9
|
const ROSTER_KEY_DISPOSITION = {
|
|
@@ -24,9 +26,11 @@ export function rosterAgentId(row) {
|
|
|
24
26
|
return row.handle;
|
|
25
27
|
}
|
|
26
28
|
function projectRow(r) {
|
|
29
|
+
const name = backgroundAgentNameOf(r);
|
|
27
30
|
return {
|
|
28
31
|
handle: rosterAgentId(r),
|
|
29
|
-
|
|
32
|
+
name,
|
|
33
|
+
...(chosenAgentName(r.handle, name) === undefined ? { anonymous: true } : {}),
|
|
30
34
|
...(r.agentType !== undefined ? { agentType: r.agentType } : {}),
|
|
31
35
|
status: r.status,
|
|
32
36
|
spawnedAt: r.spawnedAt,
|
|
@@ -22,7 +22,7 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCaller
|
|
|
22
22
|
import { readOwnedRun, readOwnedSession } from "../owner-access.js";
|
|
23
23
|
import { governanceOriginOf } from "../../runtime-governance.js";
|
|
24
24
|
import { deploymentListAsks } from "../../approval.js";
|
|
25
|
-
import {
|
|
25
|
+
import { grantBindingOf } from "../../standing-answer-grant.js";
|
|
26
26
|
import { sendResumeOutcome } from "../route-ctx.js";
|
|
27
27
|
import { assertNever } from "../route-ctx.js";
|
|
28
28
|
import * as facts from "../../capability-facts.js";
|
|
@@ -31,6 +31,7 @@ import { recordFailOpen } from "../../observability/fail-open.js";
|
|
|
31
31
|
import { MAX_CHECKPOINT_ID_CHARS, durableRowIdentity } from "../../checkpoint-identity.js";
|
|
32
32
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
|
|
33
33
|
import { fieldConflictFacts } from "../../field-conflict.js";
|
|
34
|
+
import { buildSettlementEvidence, decisionCommittedOf } from "../../gate-settlement.js";
|
|
34
35
|
const DECIDE_BODY_DECLARED_KEYS = [
|
|
35
36
|
"answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "feedback", "reason", "remember", "updatedInput",
|
|
36
37
|
];
|
|
@@ -259,6 +260,7 @@ async function decideIdempotentReplay(cs, args) {
|
|
|
259
260
|
decision,
|
|
260
261
|
bindingEnforced: true,
|
|
261
262
|
...(executionOutcome !== undefined ? { executionOutcome } : {}),
|
|
263
|
+
...buildSettlementEvidence({ at: "replay_matched" }),
|
|
262
264
|
},
|
|
263
265
|
};
|
|
264
266
|
}
|
|
@@ -352,8 +354,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
352
354
|
sendError(res, 404, "request.route_unsupported", "not found");
|
|
353
355
|
return;
|
|
354
356
|
}
|
|
355
|
-
|
|
356
|
-
sendJson(res, 200, { exemptions: rows.filter((r) => callGrantBindingOf({ toolName: r.toolName }).kind === "none") });
|
|
357
|
+
sendJson(res, 200, { exemptions: await deps.approvalExemptionStore.list(exSessionId) });
|
|
357
358
|
return;
|
|
358
359
|
}
|
|
359
360
|
if (exToolName === undefined) {
|
|
@@ -870,8 +871,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
870
871
|
}
|
|
871
872
|
: undefined;
|
|
872
873
|
const out = await resumeCheckpoint(sessionId, decision, body.reason ?? undefined, hostDecisionFacts(decidedBy, deciderPrincipal), req, answer, binding, grantOnCommit, true, { principal: deciderPrincipal, explicitOperator });
|
|
873
|
-
|
|
874
|
-
if (pendingGrant !== undefined && out.status === 200 && (outErrorCode !== "cancelled" || out.decisionCommitted === true) && deps.approvalExemptionStore) {
|
|
874
|
+
if (pendingGrant !== undefined && decisionCommittedOf(out) && deps.approvalExemptionStore) {
|
|
875
875
|
try {
|
|
876
876
|
await deps.approvalExemptionStore.grant(pendingGrant.sessionId, pendingGrant.toolName, deciderPrincipal ?? null);
|
|
877
877
|
rememberApplied = true;
|
|
@@ -954,7 +954,7 @@ function projectPendingForWire(row, deployment) {
|
|
|
954
954
|
governanceForced: governanceForced === true,
|
|
955
955
|
requiresRealApproval: row.requiresRealApproval === true,
|
|
956
956
|
mandated: row.mandated === true || row.ruleOffersAbsence === "mandated",
|
|
957
|
-
grantBinding:
|
|
957
|
+
grantBinding: grantBindingOf(row),
|
|
958
958
|
classes: row.classes,
|
|
959
959
|
deploymentListQuestion,
|
|
960
960
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
1
|
+
import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus, thinkingOffSpelled } from "@sema-agent/core";
|
|
2
2
|
import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableAliasNames, selectableCatalog } from "../../model-select.js";
|
|
3
3
|
import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
|
|
4
4
|
import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
|
|
@@ -12,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
|
|
|
12
12
|
import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
|
|
13
13
|
import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
|
|
14
14
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
15
|
-
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
15
|
+
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, countMcpProbeDeclarations, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
16
16
|
import { mcpForScenario } from "../../web-admin-client/facade.js";
|
|
17
17
|
import { sendScenarioNotFound } from "../scenario-read-face.js";
|
|
18
18
|
import { sendJson, sendError } from "../send.js";
|
|
@@ -87,6 +87,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
87
87
|
artifacts: facts.durableRuns(deps).available,
|
|
88
88
|
approvals: facts.checkpointPark(deps).available,
|
|
89
89
|
approvalReadRootGrant: facts.readRootGrant(deps).available,
|
|
90
|
+
modsDeploymentPackages: facts.deploymentModPackages(deps).available ? true : undefined,
|
|
90
91
|
sessions: facts.sessionAuditView(deps).available,
|
|
91
92
|
deviceExecutor: facts.deviceLane(deps).available
|
|
92
93
|
? {
|
|
@@ -249,7 +250,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
249
250
|
return;
|
|
250
251
|
}
|
|
251
252
|
const scenarioName = await deps.scenarioGate(principal, scenarioParams[0]);
|
|
252
|
-
await serveMcpProbeFace(res, ctx, principal, mcpForScenario(deps.config.mcpServers, scenarioName) ?? []
|
|
253
|
+
await serveMcpProbeFace(res, ctx, principal, { declaredBy: "deployment", specs: mcpForScenario(deps.config.mcpServers, scenarioName) ?? [] });
|
|
253
254
|
return;
|
|
254
255
|
}
|
|
255
256
|
case "capability-mcp-probe": {
|
|
@@ -267,7 +268,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
267
268
|
sendMcpProbeRefusal(res, ctx, parsed.refusal, "bad_request");
|
|
268
269
|
return;
|
|
269
270
|
}
|
|
270
|
-
await serveMcpProbeFace(res, ctx, principal,
|
|
271
|
+
await serveMcpProbeFace(res, ctx, principal, { declaredBy: "caller", drafts: parsed.drafts });
|
|
271
272
|
return;
|
|
272
273
|
}
|
|
273
274
|
case "models": {
|
|
@@ -282,6 +283,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
282
283
|
provider: m.provider,
|
|
283
284
|
...(modelReasoningDecl(m) !== undefined ? { reasoning: modelReasoningDecl(m) } : {}),
|
|
284
285
|
...(modelImageInput(m) !== "undeclared" ? { vision: modelImageInput(m) === "yes" } : {}),
|
|
286
|
+
supportsThinkingOff: thinkingOffSpelled(m),
|
|
285
287
|
...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
|
|
286
288
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
287
289
|
...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
|
|
@@ -322,18 +324,18 @@ function sendMcpProbeRefusal(res, ctx, refusal, outcome, retryAfterSec) {
|
|
|
322
324
|
...(retryAfterSec !== undefined ? { retryAfterSec } : {}),
|
|
323
325
|
});
|
|
324
326
|
}
|
|
325
|
-
async function serveMcpProbeFace(res, ctx, principal,
|
|
327
|
+
async function serveMcpProbeFace(res, ctx, principal, input) {
|
|
326
328
|
const { deps } = ctx;
|
|
327
329
|
const local = ctx.local.capabilities.mcpProbe;
|
|
328
|
-
if (
|
|
330
|
+
if (countMcpProbeDeclarations(input) === 0) {
|
|
329
331
|
deps.metrics?.inc("mcp_probe_total", { outcome: "empty" });
|
|
330
332
|
sendJson(res, 200, buildEmptyMcpProbeFace());
|
|
331
333
|
return;
|
|
332
334
|
}
|
|
333
|
-
const key = buildMcpProbeCacheKey(principal,
|
|
335
|
+
const key = buildMcpProbeCacheKey(principal, input);
|
|
334
336
|
const hit = local.cached(key, Date.now());
|
|
335
337
|
if (hit !== undefined) {
|
|
336
|
-
await answerMcpProbe(res, ctx, hit, "cached", declaredBy);
|
|
338
|
+
await answerMcpProbe(res, ctx, hit, "cached", input.declaredBy);
|
|
337
339
|
return;
|
|
338
340
|
}
|
|
339
341
|
if (local.inflight() >= MCP_PROBE_MAX_INFLIGHT) {
|
|
@@ -345,9 +347,9 @@ async function serveMcpProbeFace(res, ctx, principal, specs, declaredBy) {
|
|
|
345
347
|
sendMcpProbeRefusal(res, ctx, buildMcpProbeRateRefusal(), "rate_limited", verdict.retryAfterSec);
|
|
346
348
|
return;
|
|
347
349
|
}
|
|
348
|
-
const walk = createMcpProbeWalk(
|
|
350
|
+
const walk = createMcpProbeWalk(input, principal, deps.peerDesk);
|
|
349
351
|
local.remember(key, Date.now(), walk);
|
|
350
|
-
await answerMcpProbe(res, ctx, walk.answer, "probed", declaredBy);
|
|
352
|
+
await answerMcpProbe(res, ctx, walk.answer, "probed", input.declaredBy);
|
|
351
353
|
}
|
|
352
354
|
async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
|
|
353
355
|
const { deps } = ctx;
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
* `unsupported` 挂 409 更会把「这条 run 没有 MCP 面」谎报成一个活性问题。
|
|
26
26
|
*
|
|
27
27
|
* ── 下一步动作按 `status`,不解析 `reason`(core [ref] 键表逐字)────────────────────────────────
|
|
28
|
-
* `status.errorCode` / `status.httpStatus` 是机器面(`
|
|
29
|
-
*
|
|
28
|
+
* `status.errorCode` / `status.httpStatus` 是机器面(`unauthorized` 是一扇要用户授权的门 —— 引擎 7.59.0 起 401 与带 `insufficient_scope` 的 403 读这个词、不再是
|
|
29
|
+
* `http_status` + 状态数;`spawn_failed` 是
|
|
30
|
+
* 缺二进制);`reason` 是**人读**的一句话(它可能嵌远端文本:引擎铸点抹过请求回显与同主体词表,出门经出口座 `mcp-remote-text` 行 —— 同一个脱敏器、界 200 —— 投出),
|
|
30
31
|
* 消费端**不许**解析它。名册**按 `tools` 的在场性**投成 `toolNames`(present-iff),**不按 `outcome`**。
|
|
31
32
|
*
|
|
32
33
|
* ── 查找与拒绝形(与 steer / capture-optout **同一只**,不新造)───────────────────────────────────
|
|
@@ -7,7 +7,8 @@ import {} from "../route-ctx.js";
|
|
|
7
7
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
8
8
|
import * as facts from "../../capability-facts.js";
|
|
9
9
|
import { sessionOwnerCellOf } from "../../security.js";
|
|
10
|
-
import {
|
|
10
|
+
import { seatText } from "../../trace/exit-seat.js";
|
|
11
|
+
import { projectMcpAuthorization } from "../../mcp-authorization-face.js";
|
|
11
12
|
const BodySchema = z.object({ server: z.string().min(1).max(190) }).strict();
|
|
12
13
|
function outcomeOf(coreOutcome) {
|
|
13
14
|
switch (coreOutcome) {
|
|
@@ -24,8 +25,9 @@ function projectStatus(s) {
|
|
|
24
25
|
...(s.errorCode !== undefined ? { errorCode: s.errorCode } : {}),
|
|
25
26
|
...(s.httpStatus !== undefined ? { httpStatus: s.httpStatus } : {}),
|
|
26
27
|
...(s.delivered !== undefined ? { delivered: s.delivered } : {}),
|
|
28
|
+
...((a) => (a !== undefined ? { authorization: a } : {}))(projectMcpAuthorization(s.authorization)),
|
|
27
29
|
...(s.serverInfo !== undefined ? { serverInfo: s.serverInfo } : {}),
|
|
28
|
-
...(s.error !== undefined ? { error:
|
|
30
|
+
...(s.error !== undefined ? { error: seatText("mcp-remote-text", String(s.error)) } : {}),
|
|
29
31
|
...(s.transportClosed !== undefined ? { transportClosed: s.transportClosed } : {}),
|
|
30
32
|
};
|
|
31
33
|
}
|
|
@@ -34,7 +36,7 @@ function projectListingIncomplete(l) {
|
|
|
34
36
|
reason: l.reason,
|
|
35
37
|
pages: l.pages,
|
|
36
38
|
...(l.budgetMs !== undefined ? { budgetMs: l.budgetMs } : {}),
|
|
37
|
-
...(l.error !== undefined ? { error:
|
|
39
|
+
...(l.error !== undefined ? { error: seatText("mcp-remote-text", l.error) } : {}),
|
|
38
40
|
};
|
|
39
41
|
}
|
|
40
42
|
function projectResult(r) {
|
|
@@ -46,7 +48,7 @@ function projectResult(r) {
|
|
|
46
48
|
added: r.added,
|
|
47
49
|
removed: r.removed,
|
|
48
50
|
...(r.tools !== undefined ? { toolNames: r.tools.map((t) => t.name) } : {}),
|
|
49
|
-
...(r.reason !== undefined ? { reason:
|
|
51
|
+
...(r.reason !== undefined ? { reason: seatText("mcp-remote-text", r.reason) } : {}),
|
|
50
52
|
...(r.status !== undefined ? { status: projectStatus(r.status) } : {}),
|
|
51
53
|
...(r.listingIncomplete !== undefined ? { listingIncomplete: projectListingIncomplete(r.listingIncomplete) } : {}),
|
|
52
54
|
};
|
|
@@ -112,7 +114,7 @@ export async function handleMcpReconnect(req, res, match, ctx) {
|
|
|
112
114
|
const msg = e instanceof Error ? e.message : String(e);
|
|
113
115
|
switch (code) {
|
|
114
116
|
case "mcp.reconnect_unavailable":
|
|
115
|
-
sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason:
|
|
117
|
+
sendJson(res, 200, { taskId: activeTaskId, sessionId, server, outcome: "unsupported", reason: seatText("mcp-remote-text", msg) });
|
|
116
118
|
return;
|
|
117
119
|
case "steering.invalid_content":
|
|
118
120
|
sendError(res, 422, "steering.invalid_content", msg);
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* · 调用方显式给 `scope` ⇒ 用它 —— 哪怕它不在 `MEMORY_CONSOLIDATION_SCOPES` 里。
|
|
25
25
|
* 🔴 那张表**不是授权边界**:本仓今天没有任何授权源能对一个 operator 收窄 scope(`gateMemoryScope`
|
|
26
26
|
* 的 operator 支在查目录之前就 allow;`org-memory-admission` 明写 v1 不中央收窄 operator 声明的
|
|
27
|
-
* scope —— 全文见 `src/memory-operator-faces.ts`
|
|
27
|
+
* scope —— 全文见 `src/memory-operator-faces.ts` `MemoryComplianceFaces.erase` 的「授权座只有一只」段)。在本层拿它当
|
|
28
28
|
* 白名单就是**发明第二套授权语义**,与 `gateMemoryScope` 对同一个身份给出相反答案;
|
|
29
29
|
* · 省略 `scope` ⇒ 只有表**恰好一条**时才有缺省(那条就是这台部署的库);零条或两条以上一律 400,
|
|
30
30
|
* 并把候选列进文案 —— 让运维一眼看到「我该点哪一个」。
|
|
@@ -114,7 +114,7 @@ export declare function buildClearanceRowWire(r: OriginClearanceRow): {
|
|
|
114
114
|
baseRev: string;
|
|
115
115
|
origin: {
|
|
116
116
|
at: number;
|
|
117
|
-
cause?: "static" | "
|
|
117
|
+
cause?: "static" | "unattributed" | "observed" | "derived" | undefined;
|
|
118
118
|
taint: "external";
|
|
119
119
|
};
|
|
120
120
|
};
|
|
@@ -7,7 +7,7 @@ import { createLogger } from "../../observability/logger.js";
|
|
|
7
7
|
import { RULE_IMPORT_RETRY_AFTER_SEC, RULE_SCOPE_REFUSAL_SENTENCE, MAX_RULE_SCOPE_CHARS, buildCcImportLayerRootRefusal, parseRuleScope, serializeRuleScope } from "../../rules-consent.js";
|
|
8
8
|
import { hasControlOrBidi } from "@sema-agent/settings-schema";
|
|
9
9
|
import { IMPORTED_SETTINGS_LAYERS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, RULE_ADD_ORIGINS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
|
|
10
|
-
import {
|
|
10
|
+
import { isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
|
|
11
11
|
const logger = createLogger();
|
|
12
12
|
export const RULES_CC_IMPORT_PREPARE_PATH = "/v1/rules/cc-import/prepare";
|
|
13
13
|
export const RULES_CC_IMPORT_REDEEM_PATH = "/v1/rules/cc-import/redeem";
|
|
@@ -50,9 +50,9 @@ const LocalImportRowSchema = z
|
|
|
50
50
|
rule: z.string().min(1).max(MAX_RULE_TEXT_CHARS),
|
|
51
51
|
scope: z.string().min(1).max(MAX_RULE_SCOPE_CHARS),
|
|
52
52
|
behavior: z.enum(RULE_BEHAVIORS),
|
|
53
|
-
tool: z.string().min(1).max(190)
|
|
53
|
+
tool: z.string().min(1).max(190),
|
|
54
54
|
match: z.enum(PERSISTED_RULE_MATCHES),
|
|
55
|
-
command: z.string().
|
|
55
|
+
command: z.string().max(MAX_RULE_TEXT_CHARS),
|
|
56
56
|
adds: z.array(LocalImportAddSchema).max(64),
|
|
57
57
|
})
|
|
58
58
|
.strict();
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -222,11 +222,16 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
222
222
|
const prepared = await prepareSpec(req, res, keyedBody);
|
|
223
223
|
if (!prepared)
|
|
224
224
|
return;
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
try {
|
|
226
|
+
const resp = await createDurableRun(req, res, ctx, prepared, idem);
|
|
227
|
+
if (!resp)
|
|
228
|
+
return;
|
|
229
|
+
sendJson(res, resp.status, resp.body);
|
|
227
230
|
return;
|
|
228
|
-
|
|
229
|
-
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
prepared.peerLease.release();
|
|
234
|
+
}
|
|
230
235
|
}
|
|
231
236
|
if (match.decl.id === "run-detail" || match.decl.id === "run-events" || match.decl.id === "runs-by-idem") {
|
|
232
237
|
const runs = facts.durableRuns(deps);
|
|
@@ -433,13 +438,12 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
433
438
|
const text = body.text;
|
|
434
439
|
const priority = body.priority;
|
|
435
440
|
const steerIdemRaw = headerStr(req.headers["idempotency-key"]);
|
|
436
|
-
const
|
|
437
|
-
const messageId = steerInputId ?? uuidv7();
|
|
441
|
+
const messageId = steerIdemRaw ? `idem-${idemKeyOf(steerIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : uuidv7();
|
|
438
442
|
const trusted = explicitOperatorOk(principal, deps.config);
|
|
439
443
|
const steerInput = () => ({
|
|
440
444
|
text,
|
|
441
445
|
trusted,
|
|
442
|
-
|
|
446
|
+
inputId: messageId,
|
|
443
447
|
...(priority !== undefined ? { priority } : {}),
|
|
444
448
|
});
|
|
445
449
|
try {
|
|
@@ -3,7 +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 {
|
|
6
|
+
import { seatText } from "../../trace/exit-seat.js";
|
|
7
7
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
8
8
|
import { MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
|
|
9
9
|
import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
|
|
@@ -19,6 +19,7 @@ import { rosterAgentId } from "./agents-roster.js";
|
|
|
19
19
|
import { projectSessionListRow } from "./sessions-list.js";
|
|
20
20
|
import { readSessionRowPatch } from "../../session-row.js";
|
|
21
21
|
import { buildBoundedToolNames } from "../../panel-tool-names.js";
|
|
22
|
+
import { projectMcpAuthorization } from "../../mcp-authorization-face.js";
|
|
22
23
|
const MCP_STATUS_TTL_MS = 5_000;
|
|
23
24
|
const A2A_STATUS_TTL_MS = 5_000;
|
|
24
25
|
const A2A_MATERIALIZE_TIMEOUT_MS = 10_000;
|
|
@@ -171,7 +172,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
171
172
|
mcpStatusCache.clear();
|
|
172
173
|
const panel = (async () => {
|
|
173
174
|
const stopDial = new AbortController();
|
|
174
|
-
const matP = materializeMcpTools(specs, principal, undefined, undefined, undefined, deps.mcpRevocations, undefined, undefined, undefined, stopDial.signal);
|
|
175
|
+
const matP = materializeMcpTools(specs, principal, undefined, undefined, undefined, deps.mcpRevocations, undefined, undefined, undefined, stopDial.signal, undefined, deps.peerDesk.seat.answer);
|
|
175
176
|
const mat = await raceDeadline(matP, MCP_DIAL_DEADLINE_MS).catch(() => null);
|
|
176
177
|
if (!mat) {
|
|
177
178
|
stopDial.abort();
|
|
@@ -186,7 +187,8 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
186
187
|
status: s.status,
|
|
187
188
|
...(s.serverInfo ? { serverInfo: s.serverInfo } : {}),
|
|
188
189
|
...(s.toolNames ? { toolNames: s.toolNames } : {}),
|
|
189
|
-
...(
|
|
190
|
+
...((a) => (a !== undefined ? { authorization: a } : {}))(projectMcpAuthorization(s.authorization)),
|
|
191
|
+
...(s.error ? { error: seatText("mcp-remote-text", String(s.error)) } : {}),
|
|
190
192
|
})),
|
|
191
193
|
};
|
|
192
194
|
}
|
|
@@ -219,7 +221,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
219
221
|
if (a2aStatusCache.size > 1024)
|
|
220
222
|
a2aStatusCache.clear();
|
|
221
223
|
const panel = (async () => {
|
|
222
|
-
const matP = materializeA2aTools(specs, principal);
|
|
224
|
+
const matP = materializeA2aTools(specs, principal, undefined, undefined, deps.peerDesk.seat.answer);
|
|
223
225
|
let timer;
|
|
224
226
|
const mat = await Promise.race([matP.catch(() => null), new Promise((r) => { timer = setTimeout(() => r(null), A2A_MATERIALIZE_TIMEOUT_MS); })]);
|
|
225
227
|
if (timer)
|
|
@@ -95,9 +95,8 @@ export async function handleSideQuery(req, res, match, ctx) {
|
|
|
95
95
|
};
|
|
96
96
|
try {
|
|
97
97
|
const result = await deps.sideQuery(spec);
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
deps.sideQueryAccounting?.(principal, { model: modelId, usage: rr.usage });
|
|
98
|
+
const modelId = typeof result.model === "string" ? result.model : "unknown";
|
|
99
|
+
deps.sideQueryAccounting?.(principal, { model: modelId, usage: result.usage, account: result.account });
|
|
101
100
|
deps.metrics?.inc?.("side_query_total", { result: "ok" });
|
|
102
101
|
if (!res.writableEnded)
|
|
103
102
|
sendJson(res, 200, projectSideQueryResult(result));
|