@sema-agent/server 7.107.0 → 7.109.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 +72 -1
- package/USAGE.md +51 -25
- package/dist/approval-ask-audit-store.d.ts +62 -4
- package/dist/approval-ask-audit-store.js +67 -11
- package/dist/approval-ask-machine.d.ts +9 -25
- package/dist/approval-ask-machine.js +5 -2
- package/dist/approval-card.d.ts +32 -3
- package/dist/approval-card.js +29 -2
- package/dist/approval.js +16 -13
- package/dist/bench/s1/live-deps.d.ts +4 -5
- package/dist/bench/s1/live-deps.js +9 -10
- package/dist/boot/coordinators.d.ts +4 -0
- package/dist/boot/coordinators.js +3 -2
- package/dist/boot/leader.js +0 -2
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +3 -8
- package/dist/boot/shutdown.d.ts +8 -0
- package/dist/boot/shutdown.js +31 -8
- package/dist/boot/stage-06-runners.d.ts +1 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-08-reapers.d.ts +1 -0
- package/dist/boot/stage-09-leader.d.ts +1 -0
- package/dist/boot/stage-10-http-server.d.ts +1 -0
- package/dist/boot/stage-10-http-server.js +3 -1
- package/dist/brain.js +2 -1
- package/dist/capabilities/scenarios.d.ts +3 -2
- package/dist/config-catalog.js +1 -3
- package/dist/config-center/apply-effective.js +2 -0
- package/dist/config-center/types.d.ts +7 -0
- package/dist/config-provider.js +1 -0
- package/dist/config-types.d.ts +2 -9
- package/dist/config.js +2 -5
- package/dist/deployment-governance.js +2 -1
- package/dist/fleet-client.d.ts +10 -2
- package/dist/fleet-client.js +14 -8
- package/dist/http/admission.js +8 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +41 -0
- package/dist/http/memory-compliance-failure-reply.js +73 -0
- package/dist/http/memory-store-refusal-reply.d.ts +2 -2
- package/dist/http/resume-legs.js +3 -2
- package/dist/http/route-ctx.d.ts +3 -3
- package/dist/http/routes/capabilities.js +1 -0
- package/dist/http/routes/diagnostics.js +2 -0
- package/dist/http/routes/memory-compliance.js +2 -34
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/sessions.js +3 -11
- package/dist/http/routes/side-query.js +7 -2
- package/dist/http/routes/tasks.js +2 -1
- package/dist/http/server.d.ts +2 -2
- package/dist/http/wire-types.d.ts +8 -0
- package/dist/leader/diffup.d.ts +53 -0
- package/dist/leader/diffup.js +95 -1
- package/dist/leader/leader.d.ts +0 -6
- package/dist/leader/leader.js +1 -1
- package/dist/leader/repair-wire.js +1 -1
- package/dist/leader/wire.d.ts +3 -10
- package/dist/leader/wire.js +39 -13
- package/dist/memory-store-refusal.d.ts +2 -1
- package/dist/model-entry-headers.d.ts +41 -0
- package/dist/model-entry-headers.js +61 -0
- package/dist/model-entry-refusal.d.ts +6 -0
- package/dist/model-entry-refusal.js +4 -0
- package/dist/model-reach-scope.d.ts +55 -0
- package/dist/model-reach-scope.js +16 -0
- package/dist/model-unreachable-notice.d.ts +38 -0
- package/dist/model-unreachable-notice.js +72 -0
- package/dist/observability/fail-open.d.ts +5 -5
- package/dist/observability/fail-open.js +5 -5
- package/dist/observability/run-terminal.d.ts +2 -1
- package/dist/outbound-dispatcher.d.ts +69 -0
- package/dist/outbound-dispatcher.js +123 -3
- package/dist/plugins/approval-ask-store-file.d.ts +2 -1
- package/dist/plugins/approval-ask-store-file.js +3 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +7 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +18 -0
- package/dist/plugins/approval-ask-store-sql.js +7 -0
- package/dist/plugins/park-commit-watch.d.ts +48 -0
- package/dist/plugins/park-commit-watch.js +87 -0
- package/dist/request-key-closure.js +1 -1
- package/dist/router/route-orchestration.js +7 -2
- package/dist/run-local.js +2 -3
- package/dist/runs.js +3 -2
- package/dist/runtime-governance.d.ts +3 -3
- package/dist/runtime-governance.js +3 -2
- package/dist/task-settings.js +4 -2
- package/dist/tool-approval.d.ts +99 -15
- package/dist/tool-approval.js +75 -10
- package/dist/tool-rule-names.d.ts +25 -0
- package/dist/tool-rule-names.js +5 -0
- package/dist/trace/core-keyset-guard.d.ts +14 -2
- package/dist/trace/engine-notice-wire.d.ts +3 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/project.d.ts +3 -1
- package/dist/trace/project.js +2 -3
- package/dist/trace/self-minted-wire.d.ts +71 -0
- package/dist/trace/self-minted-wire.js +28 -0
- package/dist/unattended-permission-mode.d.ts +54 -93
- package/dist/unattended-permission-mode.js +8 -61
- package/package.json +3 -3
package/dist/approval-card.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* 没有方法、没有捕获的行为。
|
|
22
22
|
*/
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { READ_ROOT_CANDIDATE_DIR_MAX, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
|
|
24
|
+
import { READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer } from "@sema-agent/core";
|
|
25
25
|
import type { AskRow } from "./plugins/approval-ask-store-sql.js";
|
|
26
26
|
/** 模型自由文本(`sourceAgentName` / `delegation.agentName`)的限长(设计稿 §6.2)。设计 §3.1 把
|
|
27
27
|
* 「限长 + 脱敏」写成 **server 新增责任**(引擎无此层):spawning model 挑的名字是自由文本,
|
|
@@ -429,6 +429,25 @@ export declare function readClosedWordSeat<S extends ClosedWordSeat>(carrier: ob
|
|
|
429
429
|
type ClosedWordSeat = "mandate" | "origin";
|
|
430
430
|
/** 一座的值型 = core 寄存行上那一座的型(去掉可选位的 `undefined`)。 */
|
|
431
431
|
type ClosedWordOf<S extends ClosedWordSeat> = NonNullable<ToolApprovalPark[S]>;
|
|
432
|
+
/**
|
|
433
|
+
* 🔴 **S-934 ②(core 7.37.0 #1214)—— ask 类对的唯一窄读**:`askClass`(一问的类 = `classes` 的首员)与 `classes`(这一问属于的全部类,core
|
|
434
|
+
* `ASK_CLASSES` 序)。三个载体上同名:`AskRequest`(活卡帧 / 呈卡帧的卡读它)、寄存行 `PendingAction.tool_approval`(运维队列行经
|
|
435
|
+
* {@link parkRowFacts} 读它);`CheckpointSummary` 不回显(core 原句「read the row」)⇒ inbox 行不带。
|
|
436
|
+
*
|
|
437
|
+
* 判据(display,不是裁决输入 —— 裁决在 core 的仲裁点,本仓无人值守腿的按类作答读的是 core 交来的 `AskRequest.classes` 本身,不经本函数):
|
|
438
|
+
* · **两键都缺席 ⇒ 缺席**(不计数):老引擎(core 7.37.0 之前)、老行(续跑不补,KL-1214-b)、不盖 `origin` 的站(KL-1214-a)。缺席从不编默认类;
|
|
439
|
+
* · **在场 ⇒ 必须是一整只好对**:`askClass` 过 core `isAskClass`;`classes` 是非空数组、每员过 `isAskClass`、首员 === `askClass`(core d.ts
|
|
440
|
+
* 「`classes[0] === askClass`」「Present exactly when askClass is」)。半对 / 集外词 / 首员不符 ⇒ **两键都不投**(卡上少一行类 ≪ 卡上出现生词
|
|
441
|
+
* 或半只对)+ 计一次 `server.approval-card.closed-word-out-of-set`(S-249 族,detail 前缀 `askClass=` / `classes=` 判别是哪一格读不出)。
|
|
442
|
+
* · 不自造:本仓不重算类、不排序、不去重(core 的屏 `screenAskClassMembers` 在写停车行前已经筛过;它不在包根导出面上 —— 转 core 请求导出,
|
|
443
|
+
* 收车档 ⑤)。投出去的 `classes` 是新数组(帧不与载体共享可变引用)。
|
|
444
|
+
*/
|
|
445
|
+
export declare function readAskClassPair(carrier: object): AskClassPair | undefined;
|
|
446
|
+
/** 类对的投影形(帧 / 卡 / 队列行同一形):两键同在同缺。值型取 core 寄存行上的座(core 改型 ⇒ 下面的围栏编译红)。 */
|
|
447
|
+
export interface AskClassPair {
|
|
448
|
+
askClass: NonNullable<ToolApprovalPark["askClass"]>;
|
|
449
|
+
classes: Array<NonNullable<ToolApprovalPark["classes"]>[number]>;
|
|
450
|
+
}
|
|
432
451
|
/**
|
|
433
452
|
* 🔴 S-700 P1(client-core CC-180 / cli L-652 的根子;板 [ref] 订正 → [ref] 立案)—— **park 行事实**:
|
|
434
453
|
* 运维队列行(`GET /v1/approvals` + `/stream`)顶层展开的那几位。型**从 core 寄存行派生,不手抄**(S-249 同一条
|
|
@@ -446,8 +465,10 @@ type ClosedWordOf<S extends ClosedWordSeat> = NonNullable<ToolApprovalPark[S]>;
|
|
|
446
465
|
* S-755(cli L-695 / [ref],client-core [ref])第五位 `origin`:谁提的这一问(core `ASK_ORIGINS` 闭集一词,经 {@link readClosedWordSeat};
|
|
447
466
|
* 与活卡帧 `origin` / inbox 行 `origin` 同名同义同值)。此前只有活卡帧与 inbox 行带它 ⇒ 耐久重开 / 重连时壳从队列行读不到出身词,
|
|
448
467
|
* bypass 姿态下按 `ask_rule` / `hook` 照问的那条壳规则无从落地。缺席 = 老行(core 7.5.0 之前 park 的)/ 集外词(计 S-249 tag)。
|
|
468
|
+
* S-934 ②(core 7.37.0 #1214)第六 / 七位 `askClass` / `classes`:这一问的类对(经 {@link readAskClassPair};两位同在同缺,与活卡帧 / 呈卡帧的卡
|
|
469
|
+
* 同名同义同值)—— durable 审批席按类答的依据。缺席 = 老行(core 7.37.0 之前 park 的,续跑不补)/ 读不出(计 S-249 tag)。
|
|
449
470
|
*/
|
|
450
|
-
export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin">;
|
|
471
|
+
export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes">;
|
|
451
472
|
/**
|
|
452
473
|
* S-700 —— park 行事实的**唯一投影**(`pendingAction` 是寄存行上 core 铸的那一只,读自持久层 ⇒ `unknown`)。
|
|
453
474
|
*
|
|
@@ -629,6 +650,8 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
629
650
|
}, z.core.$strict>>>;
|
|
630
651
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
631
652
|
}, z.core.$strict>>;
|
|
653
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary">>;
|
|
654
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary">>>;
|
|
632
655
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
633
656
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
634
657
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -742,6 +765,8 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
742
765
|
}, z.core.$strict>>>;
|
|
743
766
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
744
767
|
}, z.core.$strict>>;
|
|
768
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary">>;
|
|
769
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "operator_forced" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "ordinary">>>;
|
|
745
770
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
746
771
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
747
772
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -787,6 +812,10 @@ export interface ApprovalCardSource {
|
|
|
787
812
|
* `ApprovalCardSchema.ruleOffers`)。与 wire 帧**同一份素材** ⇒ live 帧 / `card_json` / 重放帧
|
|
788
813
|
* 三面同源。 */
|
|
789
814
|
ruleOffers?: readonly RuleOffer[];
|
|
815
|
+
/** S-934 ②:类对 —— 与 wire 帧**同一份素材**(发帧点经 `readAskClassPair` 窄读定;`ToolApprovalFrame` 结构上满足本接口)⇒ live 帧 /
|
|
816
|
+
* `approval_request` / `card_json` / 重放帧四面同源。两键同在同缺。 */
|
|
817
|
+
askClass?: AskClass;
|
|
818
|
+
classes?: readonly AskClass[];
|
|
790
819
|
fromSubagent?: true;
|
|
791
820
|
sourceTaskId?: string;
|
|
792
821
|
/** 已 redactSecrets。 */
|
|
@@ -838,7 +867,7 @@ export interface ApprovalRequestFrame {
|
|
|
838
867
|
/** = SSE 具名事件名(与 `tool_approval` 同约定)。 */
|
|
839
868
|
type: "approval_request";
|
|
840
869
|
schemaVersion: 1;
|
|
841
|
-
/** `deriveAskId` 派生(
|
|
870
|
+
/** `deriveAskId` 派生(持久层主键;六元身份元组 —— S-944 / 7.109.0 起含这一问的类集 —— 见 approval-ask-machine.ts)。 */
|
|
842
871
|
askId: string;
|
|
843
872
|
/** wire run id(= 协调器 ctx 的 taskId)。 */
|
|
844
873
|
taskId: string;
|
package/dist/approval-card.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, isAskOrigin, isPersistedRuleMandate } from "@sema-agent/core";
|
|
2
|
+
import { ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, isAskClass, isAskOrigin, isPersistedRuleMandate } from "@sema-agent/core";
|
|
3
3
|
import { redactSecrets } from "./trace/redact.js";
|
|
4
4
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
5
|
import { PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS } from "./permission-rule-vocab.js";
|
|
@@ -284,18 +284,31 @@ const CLOSED_WORD_SEAT_GUARDS = {
|
|
|
284
284
|
mandate: isPersistedRuleMandate,
|
|
285
285
|
origin: isAskOrigin,
|
|
286
286
|
};
|
|
287
|
+
export function readAskClassPair(carrier) {
|
|
288
|
+
const askClass = "askClass" in carrier ? carrier.askClass : undefined;
|
|
289
|
+
const classes = "classes" in carrier ? carrier.classes : undefined;
|
|
290
|
+
if (askClass === undefined && classes === undefined)
|
|
291
|
+
return undefined;
|
|
292
|
+
if (isAskClass(askClass) && Array.isArray(classes) && classes.length > 0 && classes.every(isAskClass) && classes[0] === askClass) {
|
|
293
|
+
return { askClass, classes: [...classes] };
|
|
294
|
+
}
|
|
295
|
+
recordFailOpen("server.approval-card.closed-word-out-of-set", isAskClass(askClass) ? `classes=${outOfSetDetail(classes)}` : `askClass=${outOfSetDetail(askClass)}`);
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
287
298
|
export function parkRowFacts(pendingAction) {
|
|
288
299
|
if (typeof pendingAction !== "object" || pendingAction === null || !("kind" in pendingAction) || pendingAction.kind !== "tool_approval")
|
|
289
300
|
return {};
|
|
290
301
|
const ruleOffersAbsence = readRuleOffersAbsence(pendingAction);
|
|
291
302
|
const mandate = readClosedWordSeat(pendingAction, "mandate");
|
|
292
303
|
const origin = readClosedWordSeat(pendingAction, "origin");
|
|
304
|
+
const askClassPair = readAskClassPair(pendingAction);
|
|
293
305
|
return {
|
|
294
306
|
...(readParkRowTrueSeat(pendingAction, "requiresRealApproval") ? { requiresRealApproval: true } : {}),
|
|
295
307
|
...(readParkRowTrueSeat(pendingAction, "mandated") ? { mandated: true } : {}),
|
|
296
308
|
...(mandate !== undefined ? { mandate } : {}),
|
|
297
309
|
...(origin !== undefined ? { origin } : {}),
|
|
298
310
|
...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
|
|
311
|
+
...(askClassPair ?? {}),
|
|
299
312
|
};
|
|
300
313
|
}
|
|
301
314
|
const DenialLimitFallbackSchema = z
|
|
@@ -337,6 +350,8 @@ export const ApprovalCardSchema = z
|
|
|
337
350
|
classifierUnavailable: ClassifierUnavailableSchema.optional(),
|
|
338
351
|
probeCause: ProbeCauseSchema.optional(),
|
|
339
352
|
ruleEvidence: RuleEvidenceSchema.optional(),
|
|
353
|
+
askClass: z.custom((v) => isAskClass(v)).optional(),
|
|
354
|
+
classes: z.array(z.custom((v) => isAskClass(v))).min(1).optional(),
|
|
340
355
|
fromSubagent: z.literal(true).optional(),
|
|
341
356
|
sourceTaskId: z.string().max(MAX_IDENT).optional(),
|
|
342
357
|
sourceAgentName: z.string().max(MAX_AGENT_NAME).optional(),
|
|
@@ -348,7 +363,17 @@ export const ApprovalCardSchema = z
|
|
|
348
363
|
})
|
|
349
364
|
.optional(),
|
|
350
365
|
})
|
|
351
|
-
.strict()
|
|
366
|
+
.strict()
|
|
367
|
+
.superRefine((card, ctx) => {
|
|
368
|
+
const hasClass = card.askClass !== undefined;
|
|
369
|
+
const hasClasses = card.classes !== undefined;
|
|
370
|
+
if (hasClass !== hasClasses) {
|
|
371
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [hasClass ? "classes" : "askClass"], message: "askClass and classes must be present together" });
|
|
372
|
+
}
|
|
373
|
+
else if (hasClass && card.classes[0] !== card.askClass) {
|
|
374
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["classes"], message: "classes[0] must equal askClass" });
|
|
375
|
+
}
|
|
376
|
+
});
|
|
352
377
|
export const ApprovalCardEnvelopeSchema = z
|
|
353
378
|
.object({
|
|
354
379
|
schemaVersion: z.literal(1),
|
|
@@ -377,6 +402,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
|
|
|
377
402
|
const ruleEvidence = readRuleEvidence(req);
|
|
378
403
|
const ruleOffersAbsence = readRuleOffersAbsence(req);
|
|
379
404
|
const denialLimitFallback = readDenialLimitFallback(req);
|
|
405
|
+
const askClassPair = readAskClassPair(source);
|
|
380
406
|
const toolCallId = clip(source.toolCallId, MAX_IDENT);
|
|
381
407
|
const sourceTaskId = clip(source.sourceTaskId, MAX_IDENT);
|
|
382
408
|
const sourceAgentName = clip(source.sourceAgentName, MAX_AGENT_NAME);
|
|
@@ -399,6 +425,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
|
|
|
399
425
|
...(source.ruleOffers !== undefined && source.ruleOffers.length > 0 ? { ruleOffers: source.ruleOffers.map(copyRuleOffer) } : {}),
|
|
400
426
|
...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
|
|
401
427
|
...(denialLimitFallback !== undefined ? { denialLimitFallback } : {}),
|
|
428
|
+
...(askClassPair !== undefined ? { askClass: askClassPair.askClass, classes: askClassPair.classes } : {}),
|
|
402
429
|
...(source.fromSubagent === true ? { fromSubagent: true } : {}),
|
|
403
430
|
...(sourceTaskId !== undefined ? { sourceTaskId } : {}),
|
|
404
431
|
...(sourceAgentName !== undefined ? { sourceAgentName } : {}),
|
package/dist/approval.js
CHANGED
|
@@ -3,6 +3,7 @@ import { operatorAlwaysHumanAsk, operatorAsk } from "./operator-ask.js";
|
|
|
3
3
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
|
|
4
4
|
import { isExplicitPosture } from "./posture-source.js";
|
|
5
5
|
import { handsOnWorkerFilePlane } from "./execution-lane-caps.js";
|
|
6
|
+
import { heldRuleName } from "./tool-rule-names.js";
|
|
6
7
|
export function hasApprovalListIntent(config) {
|
|
7
8
|
return (config.approvalRequire.length > 0 ||
|
|
8
9
|
config.approvalDeny.length > 0 ||
|
|
@@ -79,49 +80,51 @@ export function createDurableAskPolicy(opts) {
|
|
|
79
80
|
const neverAuto = createNameSetMatcher(opts.neverAuto ?? []);
|
|
80
81
|
const budget = Math.max(0, Math.floor(opts.autoBudget ?? 0));
|
|
81
82
|
let autoApproved = 0;
|
|
83
|
+
const isQuestionTool = (name) => name === ASK_USER_QUESTION_TOOL_NAME;
|
|
82
84
|
return {
|
|
83
85
|
check: (req) => {
|
|
84
|
-
|
|
85
|
-
if (deny(toolName))
|
|
86
|
+
if (heldRuleName(req, deny) !== undefined)
|
|
86
87
|
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
const neverAutoHit = heldRuleName(req, neverAuto);
|
|
89
|
+
if (neverAutoHit !== undefined)
|
|
90
|
+
return operatorAlwaysHumanAsk(`APPROVAL_NEVER_AUTO(${neverAutoHit})`, `human approval required to run "${req.toolName}"`);
|
|
91
|
+
const requireHit = heldRuleName(req, require);
|
|
92
|
+
if (requireHit !== undefined) {
|
|
90
93
|
const remEarly = req.budget?.resourceRemainingMicroUsd;
|
|
91
94
|
if (remEarly !== undefined && remEarly <= 0) {
|
|
92
95
|
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
93
96
|
}
|
|
94
|
-
if (opts.exempt &&
|
|
97
|
+
if (opts.exempt && heldRuleName(req, isQuestionTool) === undefined) {
|
|
95
98
|
return (async () => {
|
|
96
99
|
let exempted = false;
|
|
97
100
|
try {
|
|
98
|
-
exempted = (await opts.exempt(toolName)) === true;
|
|
101
|
+
exempted = (await opts.exempt(req.toolName)) === true;
|
|
99
102
|
}
|
|
100
103
|
catch {
|
|
101
104
|
exempted = false;
|
|
102
105
|
}
|
|
103
106
|
if (exempted) {
|
|
104
|
-
opts.onExempted?.(toolName, req.toolName);
|
|
107
|
+
opts.onExempted?.(req.toolName, req.toolName);
|
|
105
108
|
return { action: "allow" };
|
|
106
109
|
}
|
|
107
|
-
return decideRequired(req,
|
|
110
|
+
return decideRequired(req, requireHit);
|
|
108
111
|
})();
|
|
109
112
|
}
|
|
110
|
-
return decideRequired(req,
|
|
113
|
+
return decideRequired(req, requireHit);
|
|
111
114
|
}
|
|
112
115
|
return { action: "allow" };
|
|
113
116
|
},
|
|
114
117
|
};
|
|
115
|
-
function decideRequired(req,
|
|
118
|
+
function decideRequired(req, requireHit) {
|
|
116
119
|
const rem = req.budget?.resourceRemainingMicroUsd;
|
|
117
120
|
if (rem !== undefined && rem <= 0) {
|
|
118
121
|
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
119
122
|
}
|
|
120
|
-
if (
|
|
123
|
+
if (heldRuleName(req, isQuestionTool) === undefined && budget > 0 && autoApproved < budget) {
|
|
121
124
|
autoApproved++;
|
|
122
125
|
return { action: "allow" };
|
|
123
126
|
}
|
|
124
|
-
return operatorAsk(`APPROVAL_REQUIRE(${
|
|
127
|
+
return operatorAsk(`APPROVAL_REQUIRE(${requireHit})`, `approval required to run "${req.toolName}"`);
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
//# sourceMappingURL=approval.js.map
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
* `infraFailed` (EXCLUDED) — NEVER a fabricated uniform delivered=false loss for the whole TEAM column.
|
|
36
36
|
*/
|
|
37
37
|
import { type TaskSpec } from "@sema-agent/core";
|
|
38
|
-
import { type UnattendedLeg } from "../../unattended-permission-mode.js";
|
|
39
38
|
import type { ProfileDeps, SoloImplSpec, SupImplSpec } from "./arms.js";
|
|
40
39
|
import type { TrapSpec } from "./tasks.js";
|
|
41
40
|
/** Live runtime config — the SAME base model + budget every arm runs on (the §3.2 fairness root). */
|
|
@@ -96,11 +95,11 @@ export declare function benchBaseSpec(rt: LiveRuntimeConfig, cellId: string): (o
|
|
|
96
95
|
/**
|
|
97
96
|
* Project a `SoloImplSpec` (budget already stamped by the harness, all keys in `limits`) onto the bench base TaskSpec.
|
|
98
97
|
* 🔴 7.106.0 合并复审 X3:SOLO 是**无人值守腿**(verify→fix 跑在一只不接 `onAsk` 的 Runner 上,没有审批席)⇒ 经 `withUnattendedLeg` 接
|
|
99
|
-
* 与 TEAM 的 leader worker
|
|
100
|
-
* default
|
|
101
|
-
* (checkpoint suspend)
|
|
98
|
+
* 与 TEAM 的 leader worker 同一只合并口(S-934 ①:`default` + 按类作答的 onAsk,无席)。修前裸 spec ⇒ core 7.34.0「缺席 =
|
|
99
|
+
* default」且无席 ⇒ 写与非只读命令 headless 拒、终态照旧 completed —— SOLO 与 TEAM 的比较混进了权限差异。SUP 不走这里:它有耐久审批席
|
|
100
|
+
* (checkpoint suspend),它的问要人答。
|
|
102
101
|
*/
|
|
103
|
-
export declare function toTaskSpec(base: (objective: string) => TaskSpec, impl: SoloImplSpec
|
|
102
|
+
export declare function toTaskSpec(base: (objective: string) => TaskSpec, impl: SoloImplSpec): TaskSpec;
|
|
104
103
|
/** Project a `SupImplSpec` onto the bench base TaskSpec PLUS the durable wiring (checkpointStore + ask policy). */
|
|
105
104
|
export declare function toSupTaskSpec(base: (objective: string) => TaskSpec, impl: SupImplSpec, trap: TrapSpec): TaskSpec;
|
|
106
105
|
//# sourceMappingURL=live-deps.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { outwardPlane } from "../../terminal.js";
|
|
2
2
|
import { Runner, runWithVerification, resumeWithVerification, runRepairLoop, combinePolicies, createDurableQuestionPolicy, QUESTION_AWAITS_RESUME, } from "@sema-agent/core";
|
|
3
3
|
import { loadConfig } from "../../config.js";
|
|
4
|
-
import {
|
|
4
|
+
import { withUnattendedLeg } from "../../unattended-permission-mode.js";
|
|
5
5
|
import { createBrain } from "../../brain.js";
|
|
6
6
|
import { buildPricing } from "../../budget.js";
|
|
7
7
|
import { RemoteContainerExecutionEnv } from "../../plugins/remote-env-e2b.js";
|
|
@@ -58,7 +58,7 @@ function buildBrainIngredients(rt) {
|
|
|
58
58
|
if (!p || ((p.inputPer1M ?? 0) === 0 && (p.outputPer1M ?? 0) === 0)) {
|
|
59
59
|
throw new Error(`s1 live: zero pricing for ${rt.modelId} — C1 cost axis would be a fabricated $0 (set MODEL_COST_INPUT/OUTPUT)`);
|
|
60
60
|
}
|
|
61
|
-
return { brain, models: config.models, roles: config.roles, pricing
|
|
61
|
+
return { brain, models: config.models, roles: config.roles, pricing };
|
|
62
62
|
}
|
|
63
63
|
const sh = (env) => async (cmd) => {
|
|
64
64
|
const r = await env.exec(`bash -lc ${JSON.stringify(cmd)}`);
|
|
@@ -168,9 +168,8 @@ function graderTransport(grader) {
|
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
170
|
export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
171
|
-
const { brain, models, roles, pricing
|
|
171
|
+
const { brain, models, roles, pricing } = buildBrainIngredients(rt);
|
|
172
172
|
const baseSpec = benchBaseSpec(rt, cellId);
|
|
173
|
-
const soloLeg = createUnattendedLeg(leaderMode, {});
|
|
174
173
|
const state = {};
|
|
175
174
|
const ensureWorker = async () => {
|
|
176
175
|
if (!state.worker) {
|
|
@@ -208,7 +207,7 @@ export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
|
208
207
|
const deps = {
|
|
209
208
|
runWithVerification: async (implSpec) => {
|
|
210
209
|
const { runner } = await ensureWorker();
|
|
211
|
-
return runWithVerification(runner, toTaskSpec(baseSpec, implSpec
|
|
210
|
+
return runWithVerification(runner, toTaskSpec(baseSpec, implSpec), { maxRounds: rt.maxRounds ?? 2 });
|
|
212
211
|
},
|
|
213
212
|
runWithVerificationSup: async (implSpec) => {
|
|
214
213
|
const { runner } = await ensureWorker();
|
|
@@ -284,7 +283,7 @@ export function buildLiveDeps(rt, trap, seed, cellId) {
|
|
|
284
283
|
rmSync(tmp, { recursive: true, force: true });
|
|
285
284
|
}
|
|
286
285
|
};
|
|
287
|
-
return runLeaderForTrap(rt, brain, models, roles, pricing,
|
|
286
|
+
return runLeaderForTrap(rt, brain, models, roles, pricing, trap, cellId, captureIntegratedTreeToBundle);
|
|
288
287
|
},
|
|
289
288
|
runOracle: () => runOracle(false),
|
|
290
289
|
};
|
|
@@ -303,8 +302,8 @@ export function benchBaseSpec(rt, cellId) {
|
|
|
303
302
|
function projectImplBudget(base, impl) {
|
|
304
303
|
return { ...base(impl.objective), limits: { ...impl.limits } };
|
|
305
304
|
}
|
|
306
|
-
export function toTaskSpec(base, impl
|
|
307
|
-
return withUnattendedLeg(projectImplBudget(base, impl)
|
|
305
|
+
export function toTaskSpec(base, impl) {
|
|
306
|
+
return withUnattendedLeg(projectImplBudget(base, impl));
|
|
308
307
|
}
|
|
309
308
|
export function toSupTaskSpec(base, impl, trap) {
|
|
310
309
|
const requireApproval = trap.gatedTools ?? ["Bash"];
|
|
@@ -317,7 +316,7 @@ export function toSupTaskSpec(base, impl, trap) {
|
|
|
317
316
|
onQuestion: QUESTION_AWAITS_RESUME,
|
|
318
317
|
};
|
|
319
318
|
}
|
|
320
|
-
async function runLeaderForTrap(rt, brain, models, roles, pricing,
|
|
319
|
+
async function runLeaderForTrap(rt, brain, models, roles, pricing, trap, cellId, importIntegratedTreeToWorker) {
|
|
321
320
|
const { mkdtempSync, rmSync, writeFileSync, mkdirSync } = await import("node:fs");
|
|
322
321
|
const { execFileSync, spawn } = await import("node:child_process");
|
|
323
322
|
const { tmpdir } = await import("node:os");
|
|
@@ -370,7 +369,7 @@ async function runLeaderForTrap(rt, brain, models, roles, pricing, leaderMode, t
|
|
|
370
369
|
process.env.LEADER_ENABLED = "true";
|
|
371
370
|
process.env.LEADER_WORKER_BUDGET_USD = String((rt.maxCostUsd ?? 1.0) / 2);
|
|
372
371
|
const run = createLeaderRunner({
|
|
373
|
-
brain, models, roles, pricing,
|
|
372
|
+
brain, models, roles, pricing, e2bApiKey: rt.e2bApiKey, workspace: W,
|
|
374
373
|
...(s1DebugGit() ? { logger: { warn: (m, x) => console.error(`[S1_DEBUG_LEADER warn] ${m}`, x ? JSON.stringify(x).slice(0, 300) : ""), info: (m, x) => console.error(`[S1_DEBUG_LEADER info] ${m}`, x ? JSON.stringify(x).slice(0, 200) : "") } } : {}),
|
|
375
374
|
});
|
|
376
375
|
const teamSeedWrite = (trap.seedFiles ?? [])
|
|
@@ -13,6 +13,7 @@ import type { Logger } from "../observability/logger.js";
|
|
|
13
13
|
import { QuestionCoordinator } from "../question.js";
|
|
14
14
|
import { ToolApprovalCoordinator, type ParkedAskRedeem } from "../tool-approval.js";
|
|
15
15
|
import { FileApprovalAskAuditStore } from "../approval-ask-audit-store.js";
|
|
16
|
+
import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
16
17
|
import { SendUserFileEmitter } from "../capabilities/send-user-file-tool.js";
|
|
17
18
|
import { TaskEnvRegistry } from "../capabilities/sandbox-file-send.js";
|
|
18
19
|
import type { StoreBackend } from "../plugins/store-backend.js";
|
|
@@ -32,6 +33,9 @@ export interface LiveCoordinatorsCtx {
|
|
|
32
33
|
* 必须排在它之前;同款 holder 先例 = reaper 的 `getRunDenySweep`)。取到 undefined ⇒ 那条臂逐字回落
|
|
33
34
|
* 修前 404(partial 部署安全)。缺席(不传本键)⇒ 协调器整条迟到腿的 PARKED 臂恒 404。 */
|
|
34
35
|
getParkedRedeem?: () => ParkedAskRedeem | undefined;
|
|
36
|
+
/** S-929 F1:checkpoint 店的 park 提交观察层(stage-06 与店同一处铸;在场 ⇔ 有 checkpoint 店)。协调器据它判「有序关停下的 park 路由
|
|
37
|
+
* 提交了没有」—— 审计 settle 行等 park 提交落定才写。缺席 = 没有 park 设施(core 在 ask 回调处就收场,没有提交这一步)。 */
|
|
38
|
+
parkCommits?: ParkCommitWatch;
|
|
35
39
|
}
|
|
36
40
|
export declare function createLiveCoordinators(ctx: LiveCoordinatorsCtx): {
|
|
37
41
|
elicitation: ElicitationCoordinator | undefined;
|
|
@@ -10,7 +10,7 @@ import { basename, resolve } from "node:path";
|
|
|
10
10
|
import { toolsRunOnThisHost } from "../task-cwd.js";
|
|
11
11
|
import { stat as fsStat, readFile as fsReadFile } from "node:fs/promises";
|
|
12
12
|
export function createLiveCoordinators(ctx) {
|
|
13
|
-
const { config, logger, backend, sendUserFileTaskEnvs, ruleConsent, ruleScopeRootFor, getParkedRedeem } = ctx;
|
|
13
|
+
const { config, logger, backend, sendUserFileTaskEnvs, ruleConsent, ruleScopeRootFor, getParkedRedeem, parkCommits } = ctx;
|
|
14
14
|
const elicitation = config.mcpElicitation.enabled ? new ElicitationCoordinator(config.mcpElicitation.throttle) : undefined;
|
|
15
15
|
const question = config.askQuestionEnabled ? new QuestionCoordinator(config.questionThrottle) : undefined;
|
|
16
16
|
const durableEnabled = backend?.checkpoint !== undefined && config.durableApproval === true;
|
|
@@ -51,7 +51,7 @@ export function createLiveCoordinators(ctx) {
|
|
|
51
51
|
decided: converged.decided,
|
|
52
52
|
inconsistent: converged.inconsistent,
|
|
53
53
|
corruptLines: converged.corruptLines,
|
|
54
|
-
note: "orphan approval asks from
|
|
54
|
+
note: "orphan approval asks from the previous process were converged (cause crashed_before_park = it crashed; cause shutdown_before_park = an orderly shutdown cut the leg off before it closed or before its park committed); see GET /v1/approvals crashConverged",
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -71,6 +71,7 @@ export function createLiveCoordinators(ctx) {
|
|
|
71
71
|
...(getParkedRedeem !== undefined ? { parkedRedeem: getParkedRedeem } : {}),
|
|
72
72
|
...(approvalAskAudit !== undefined ? { askAudit: approvalAskAudit } : {}),
|
|
73
73
|
...(approvalExemptionStore !== undefined ? { sessionGrants: approvalExemptionStore } : {}),
|
|
74
|
+
...(parkCommits !== undefined ? { parkCommits } : {}),
|
|
74
75
|
})
|
|
75
76
|
: undefined;
|
|
76
77
|
const sendUserFileEmitter = (() => {
|
package/dist/boot/leader.js
CHANGED
|
@@ -2,7 +2,6 @@ import { createLeaderEndpoint } from "../leader/endpoint.js";
|
|
|
2
2
|
import { createLeaderRunner } from "../leader/wire.js";
|
|
3
3
|
import { buildDeploymentPostureSeats } from "./runner-deps.js";
|
|
4
4
|
import { hasApprovalListIntent } from "../approval.js";
|
|
5
|
-
import { unattendedPermissionMode } from "../unattended-permission-mode.js";
|
|
6
5
|
export function leaderK8sMinioGap(leaderEnabled, leaderProvider, hasS3) {
|
|
7
6
|
if (!(leaderEnabled && leaderProvider === "k8s" && !hasS3))
|
|
8
7
|
return null;
|
|
@@ -59,7 +58,6 @@ export function createLeaderFace(ctx) {
|
|
|
59
58
|
: {}),
|
|
60
59
|
...(ctx.promptSource ? { promptSource: ctx.promptSource } : {}),
|
|
61
60
|
...(ctx.onError ? { onError: ctx.onError } : {}),
|
|
62
|
-
unattendedPermissionMode: unattendedPermissionMode(config),
|
|
63
61
|
fanoutEnabled: config.leaderFanoutEnabled,
|
|
64
62
|
...((process.env.MODEL_ROUTER_ID || process.env.MODEL_CHEAP_ID)
|
|
65
63
|
? { routerModel: (process.env.MODEL_ROUTER_ID || process.env.MODEL_CHEAP_ID) }
|
|
@@ -17,7 +17,7 @@ import type { StoreBackend } from "../plugins/store-backend.js";
|
|
|
17
17
|
import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
18
18
|
import { type createPrincipalEntitlementsClient } from "../runtime-caps-resolver.js";
|
|
19
19
|
import { type OwnerAwareSessionStore } from "../security.js";
|
|
20
|
-
import {
|
|
20
|
+
import type { RunnerDepsOnAsk } from "./runner-deps.js";
|
|
21
21
|
type PrincipalCaps = ReturnType<typeof createPrincipalEntitlementsClient>;
|
|
22
22
|
/** `resolveSpec` 原先从 `main()` 闭包里拿到的全部 boot 局部量。 */
|
|
23
23
|
export interface ResolveSpecCtx {
|
|
@@ -40,8 +40,7 @@ import { redactSecrets } from "../trace/redact.js";
|
|
|
40
40
|
import { DeferredSandboxPathEnv, isSandboxPathAdjudicationLane, sandboxPathEnvSlots } from "./deferred-sandbox-path-env.js";
|
|
41
41
|
import { executionLaneCaps, executionLaneHomeDir, executionLaneOf } from "../execution-lane-caps.js";
|
|
42
42
|
import { effectiveMemoryPersistenceCapable } from "./memory-boundary.js";
|
|
43
|
-
import {
|
|
44
|
-
import { createUnattendedLeg, unattendedPermissionMode, withUnattendedLeg } from "../unattended-permission-mode.js";
|
|
43
|
+
import { withUnattendedLeg } from "../unattended-permission-mode.js";
|
|
45
44
|
import { memoryFaceMounted } from "../memory-scope.js";
|
|
46
45
|
import { createAssemblyIncarnationRead, sessionFaceReaderOf } from "./session-incarnation-seat.js";
|
|
47
46
|
export function createResolveSpec(ctx) {
|
|
@@ -440,7 +439,7 @@ export function createResolveSpec(ctx) {
|
|
|
440
439
|
const merged = extra.length > 0 ? [...(base ?? []), ...extra] : base;
|
|
441
440
|
return merged && config.toolDeferLongtail ? applyLongtailDefer(merged, true) : merged;
|
|
442
441
|
})(cap.tools),
|
|
443
|
-
skills: mergeUserSkills(cap.skills, body.skills, logger),
|
|
442
|
+
skills: body.disableSkills === true ? [] : mergeUserSkills(cap.skills, body.skills, logger),
|
|
444
443
|
...(parsedSettings.settings?.skillListingBudgetFraction !== undefined ? { skillListingBudgetFraction: parsedSettings.settings.skillListingBudgetFraction } : {}),
|
|
445
444
|
...(parsedSettings.settings?.skillListingMaxDescChars !== undefined ? { skillListingMaxDescChars: parsedSettings.settings.skillListingMaxDescChars } : {}),
|
|
446
445
|
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, logger, opts?.onNotice !== undefined ? { sessionId: auth?.sessionId, emit: opts.onNotice } : undefined),
|
|
@@ -670,15 +669,11 @@ export function createResolveSpec(ctx) {
|
|
|
670
669
|
}
|
|
671
670
|
return governed;
|
|
672
671
|
};
|
|
673
|
-
const resumeRunnerSeats = () => ({
|
|
674
|
-
...buildDeploymentPostureSeats(config),
|
|
675
|
-
...(memoryEngine !== undefined ? { memoryEngineDir: memoryEngine.root } : {}),
|
|
676
|
-
});
|
|
677
672
|
const resolveSpecForLeg = async (body, req, auth, opts) => {
|
|
678
673
|
const spec = await resolveSpec(body, req, auth, opts);
|
|
679
674
|
if (opts?.unattendedLeg !== true)
|
|
680
675
|
return spec;
|
|
681
|
-
return withUnattendedLeg(spec
|
|
676
|
+
return withUnattendedLeg(spec);
|
|
682
677
|
};
|
|
683
678
|
return resolveSpecForLeg;
|
|
684
679
|
}
|
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ import type { RateLimiter } from "../observability/rate-limit.js";
|
|
|
29
29
|
import type { startFleetClientFromEnv } from "../fleet-client.js";
|
|
30
30
|
import type { BreakerStateStore, CostQuotaStore, RateLimiterStore, StoreBackend } from "../plugins/store-backend.js";
|
|
31
31
|
import type { WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
|
|
32
|
+
import type { ToolApprovalCoordinator } from "../tool-approval.js";
|
|
33
|
+
import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
32
34
|
export interface ShutdownCtx {
|
|
33
35
|
config: ServiceConfig;
|
|
34
36
|
/** [ref]①:崩溃遗言的 version 键(与 /v1/capabilities.version 同源=main 的 serviceVersion())。 */
|
|
@@ -87,6 +89,12 @@ export interface ShutdownCtx {
|
|
|
87
89
|
configCenter: {
|
|
88
90
|
stopRefreshLoop(): void;
|
|
89
91
|
} | undefined;
|
|
92
|
+
/** S-929:活体审批协调器(`TOOL_APPROVAL_ENABLED` 关 ⇒ 缺席)。hardShutdown 起点调它的 `drainForShutdown`:本进程握着的活卡
|
|
93
|
+
* 按断连同路收场、审计留有序关停记号 —— 否则下一次 boot 把有序重启读成崩溃(`crashed_before_park`)。 */
|
|
94
|
+
toolApproval: ToolApprovalCoordinator | undefined;
|
|
95
|
+
/** S-929 F1:checkpoint 店的 park 提交观察层(`plugins/park-commit-watch.ts`;在场 ⇔ 本部署有 checkpoint 店)。hardShutdown 在
|
|
96
|
+
* `backend.close()` 之前等它 quiesce —— 在飞的 `put`(审批 park / 资源挂起…,与审批协调器在不在场无关)不许被抽掉连接池。 */
|
|
97
|
+
parkCommits: ParkCommitWatch | undefined;
|
|
90
98
|
}
|
|
91
99
|
/**
|
|
92
100
|
* `installShutdownHandlers` 的**摘除把手**([ref] 二轮重扫件4)。
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -6,8 +6,9 @@ import { installProcessExitBoundary } from "./exit-boundary.js";
|
|
|
6
6
|
import { createEngineLeaseTracker } from "./engine-lease.js";
|
|
7
7
|
import { writeExitLast, readExitLast, clearExitLast } from "./exit-last.js";
|
|
8
8
|
import { isScriptRealmRejection, describeRejectionReason } from "../orchestration/hardened-vm-runner.js";
|
|
9
|
+
const HARD_STOP_GRACE_MS = 10_000;
|
|
9
10
|
export function installShutdownHandlers(ctx) {
|
|
10
|
-
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, } = ctx;
|
|
11
|
+
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, toolApproval, parkCommits, } = ctx;
|
|
11
12
|
const dataRoot = config.localDataRoot;
|
|
12
13
|
if (dataRoot) {
|
|
13
14
|
const prior = readCrashLast(dataRoot);
|
|
@@ -69,6 +70,16 @@ export function installShutdownHandlers(ctx) {
|
|
|
69
70
|
closing = true;
|
|
70
71
|
if (dataRoot)
|
|
71
72
|
clearCrashLast(dataRoot);
|
|
73
|
+
const graceDeadlineMs = Date.now() + HARD_STOP_GRACE_MS;
|
|
74
|
+
const approvalDrain = toolApproval === undefined
|
|
75
|
+
? Promise.resolve()
|
|
76
|
+
: toolApproval
|
|
77
|
+
.drainForShutdown(graceDeadlineMs)
|
|
78
|
+
.then(({ uncommittedParks }) => {
|
|
79
|
+
for (const p of uncommittedParks)
|
|
80
|
+
logger.warn("approval_park_uncommitted_at_shutdown", { approvalId: p.approvalId, taskId: p.taskId });
|
|
81
|
+
})
|
|
82
|
+
.catch((err) => logger.warn("approval_drain_for_shutdown_failed", { err: String(err) }));
|
|
72
83
|
clearInterval(reaper);
|
|
73
84
|
clearInterval(fleetReconcile.timer);
|
|
74
85
|
const retentionTeardown = retentionLane === undefined
|
|
@@ -79,6 +90,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
79
90
|
.then(() => undefined)
|
|
80
91
|
.catch(() => undefined);
|
|
81
92
|
fleetReconcile.reconciler.stop();
|
|
93
|
+
const routingStopped = fleetClient?.stopRouting() ?? Promise.resolve();
|
|
82
94
|
parentWatch?.stop();
|
|
83
95
|
engineLease?.stop();
|
|
84
96
|
storeLiveProbe?.stop();
|
|
@@ -86,23 +98,34 @@ export function installShutdownHandlers(ctx) {
|
|
|
86
98
|
configCenter?.stopRefreshLoop();
|
|
87
99
|
otelExporter?.stop();
|
|
88
100
|
breakerState?.stop();
|
|
89
|
-
if (costQuota && "stop" in costQuota)
|
|
90
|
-
costQuota.stop();
|
|
91
|
-
if (rateLimiter && "stop" in rateLimiter)
|
|
92
|
-
rateLimiter.stop();
|
|
93
101
|
runner.sessions.dispose();
|
|
94
102
|
subRunner.sessions.dispose();
|
|
95
103
|
void lspManager?.dispose?.();
|
|
96
104
|
void workflowNotifyJournal?.close?.();
|
|
97
105
|
exitBoundary.reapChildProcessesEarly();
|
|
98
|
-
|
|
106
|
+
const drained = approvalDrain
|
|
107
|
+
.then(() => parkCommits?.quiesce(graceDeadlineMs))
|
|
108
|
+
.then((q) => {
|
|
109
|
+
if (q !== undefined && q.inFlight > 0)
|
|
110
|
+
logger.warn("checkpoint_puts_inflight_at_backend_close", { inFlight: q.inFlight });
|
|
111
|
+
});
|
|
112
|
+
const ledgerStopped = drained.then(async () => {
|
|
113
|
+
if (costQuota && "stop" in costQuota)
|
|
114
|
+
costQuota.stop();
|
|
115
|
+
if (rateLimiter && "stop" in rateLimiter)
|
|
116
|
+
rateLimiter.stop();
|
|
117
|
+
await fleetClient?.flushFinalUsage();
|
|
118
|
+
});
|
|
99
119
|
server.close(() => {
|
|
100
|
-
void
|
|
120
|
+
void Promise.all([retentionTeardown, ledgerStopped])
|
|
121
|
+
.then(() => (backend ? backend.close() : Promise.resolve()))
|
|
122
|
+
.then(() => routingStopped)
|
|
123
|
+
.finally(() => process.exit(0));
|
|
101
124
|
});
|
|
102
125
|
const finalExit = setTimeout(() => { logger.warn("hard_shutdown_final_deadline", { afterMs: 15_000 }); process.exit(0); }, 15_000);
|
|
103
126
|
finalExit.unref?.();
|
|
104
127
|
server.closeIdleConnections?.();
|
|
105
|
-
const forceClose = setTimeout(() => server.closeAllConnections?.(),
|
|
128
|
+
const forceClose = setTimeout(() => server.closeAllConnections?.(), HARD_STOP_GRACE_MS);
|
|
106
129
|
forceClose.unref?.();
|
|
107
130
|
};
|
|
108
131
|
let draining = false;
|
|
@@ -14,6 +14,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
|
|
|
14
14
|
approvalExemptionStore: import("../plugins/approval-exemption-store.js").ApprovalExemptionStore | undefined;
|
|
15
15
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
16
16
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
17
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
17
18
|
durableEnabled: boolean;
|
|
18
19
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
19
20
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|
|
@@ -13,6 +13,7 @@ import { buildConsolidationValveAudit, createMemoryConsolidationFaces, resolveCo
|
|
|
13
13
|
import { createPerModelAuthSeat } from "./side-query-lane.js";
|
|
14
14
|
import { createWorkflowOrchestration } from "./workflow-orchestration.js";
|
|
15
15
|
import { createLiveCoordinators } from "./coordinators.js";
|
|
16
|
+
import { createParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
16
17
|
import { createRuntimeCaps } from "./runtime-caps.js";
|
|
17
18
|
import { createRunnerDeps, createSharedRunnerDeps } from "./runner-deps.js";
|
|
18
19
|
import { createOrgMemoryAdmissionWiring } from "./org-memory.js";
|
|
@@ -22,8 +23,11 @@ import { parkedAskRedeem, runStore } from "./late-binds.js";
|
|
|
22
23
|
export function runStage06(ctx) {
|
|
23
24
|
const { backend, backgroundAgentStore, brain, sessionIncarnationOf, config, configCenter, consolidationValve, deploymentHooks, executionEnvFactory, fileHistoryStore, localRoot, logger, lspManager, mailboxRecipientLifecycle, mailboxStore, memoryEngine, memorySyncRunner, metrics, perSessionCwd, permissionRuleProvider, pricing, rosterStore, ruleConsent, sendUserFileTaskEnvs, sessionCaptureRecordStore, sessionCaptureRecords, sessionPolicyStore, sessionStore, taskAttachmentStore, taskListLane, toolResultStore, tracer, usageWindowStore } = ctx;
|
|
24
25
|
const { sqlWorkflowRunStore, workflowNotifyJournal, workflowCompletionInbox, deliverWorkflowCompletion, workflowNotifyGate, fleetBus, workflowRunStore, workflowJournalStore, outcomeSink, workflowRecoverOpts, workflowAgentRegistry, subagentSteerRegistry, workflowAgentSessionIndex, } = createWorkflowOrchestration({ config, logger, metrics, localRoot, backend, getRunStore: () => runStore });
|
|
26
|
+
const parkCommitted = backend?.checkpoint && config.durableApproval ? createParkCommitWatch(backend.checkpoint(logger)) : undefined;
|
|
27
|
+
const checkpointStore = parkCommitted?.store;
|
|
28
|
+
const parkCommits = parkCommitted?.watch;
|
|
25
29
|
const { elicitation, question, toolApproval, durableEnabled, streamApprovalGate, approvalAskAudit, approvalExemptionStore, sendUserFileEmitter, sendFileLedger, sendUserFileToolSpec } = createLiveCoordinators({
|
|
26
|
-
config, logger, backend, sendUserFileTaskEnvs, ruleConsent,
|
|
30
|
+
config, logger, backend, sendUserFileTaskEnvs, ruleConsent, parkCommits,
|
|
27
31
|
getParkedRedeem: () => parkedAskRedeem,
|
|
28
32
|
ruleScopeRootFor: (sessionId) => cardRuleScopeRoot(sessionId !== undefined ? perSessionCwd.get(sessionId) : undefined, config),
|
|
29
33
|
});
|
|
@@ -40,7 +44,6 @@ export function runStage06(ctx) {
|
|
|
40
44
|
logger.info("shared_memory_stores_enabled", { backend: backend?.kind });
|
|
41
45
|
const runnerOffloadStore = toolResultStore ?? new InMemoryToolResultStore({ maxTotalChars: 64_000_000 });
|
|
42
46
|
const commitHands = config.configProvider === "local" ? { commitCoAuthor: "Sema <noreply@vivi-ai.com>" } : undefined;
|
|
43
|
-
const checkpointStore = backend?.checkpoint && config.durableApproval ? backend.checkpoint(logger) : undefined;
|
|
44
47
|
const retentionExecutor = backend?.retention?.({ taskAttachmentTable: taskAttachmentStore !== undefined, taskListTables: taskListLane.backend !== "memory", logger });
|
|
45
48
|
const retentionLaneStore = backend?.retentionLane?.();
|
|
46
49
|
assertRetentionLaneWirable({
|
|
@@ -202,6 +205,6 @@ export function runStage06(ctx) {
|
|
|
202
205
|
};
|
|
203
206
|
const subRunner = new Runner(subRunnerDeps);
|
|
204
207
|
const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
|
|
205
|
-
return { ...ctx, approvalAskAudit, approvalExemptionStore, centerRuntimeCapsResolver, checkpointStore, durableEnabled, elicitation, fleetBus, governanceSeams, handslessRunner, handslessSubRunner, hookAgent, hookAgentRunner, hookLlm, mcpRevocations, memoryConsolidationFaces, memoryOptOutGrantStore, orgMemoryAdmission, outcomeSink, principalCaps, question, retentionExecutor, retentionLaneStore, runner, runnerDeps, runtimeCapsPeekResolver, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionTitler, sharedMemoryStore, sqlWorkflowRunStore, streamApprovalGate, subRunner, subRunnerSessions, subagentSteerRegistry, toolApproval, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable };
|
|
208
|
+
return { ...ctx, approvalAskAudit, approvalExemptionStore, centerRuntimeCapsResolver, checkpointStore, parkCommits, durableEnabled, elicitation, fleetBus, governanceSeams, handslessRunner, handslessSubRunner, hookAgent, hookAgentRunner, hookLlm, mcpRevocations, memoryConsolidationFaces, memoryOptOutGrantStore, orgMemoryAdmission, outcomeSink, principalCaps, question, retentionExecutor, retentionLaneStore, runner, runnerDeps, runtimeCapsPeekResolver, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionTitler, sharedMemoryStore, sqlWorkflowRunStore, streamApprovalGate, subRunner, subRunnerSessions, subagentSteerRegistry, toolApproval, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable };
|
|
206
209
|
}
|
|
207
210
|
//# sourceMappingURL=stage-06-runners.js.map
|
|
@@ -27,6 +27,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
|
|
|
27
27
|
approvalAskAudit: import("../approval-ask-audit-store.js").FileApprovalAskAuditStore | undefined;
|
|
28
28
|
centerRuntimeCapsResolver: ((principal: string | undefined) => Promise<import("@sema-agent/core").RuntimeCaps | undefined>) | undefined;
|
|
29
29
|
checkpointStore: import("../plugins/store-backend.js").CheckpointStoreFull | undefined;
|
|
30
|
+
parkCommits: import("../plugins/park-commit-watch.js").ParkCommitWatch | undefined;
|
|
30
31
|
durableEnabled: boolean;
|
|
31
32
|
elicitation: import("../elicitation.js").ElicitationCoordinator | undefined;
|
|
32
33
|
fleetBus: import("../fleet/fleet-bus.js").FleetEventBus;
|