@sema-agent/server 7.117.0 → 7.119.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 +182 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +58 -28
- package/deploy/sema-up/README.md +2 -0
- package/deploy/sema-up/chart/templates/minio.yaml +2 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +1 -0
- package/deploy/sema-up/chart/templates/server.yaml +1 -0
- package/deploy/sema-up/chart/values.yaml +7 -1
- package/deploy/sema-up/cluster-up.sh +20 -8
- package/deploy/sema-up/kube-up.sh +29 -16
- package/deploy/sema-up/lib/buckets.sh +21 -0
- package/deploy/sema-up/lib/health.sh +33 -0
- package/deploy/sema-up/sema-up.sh +14 -9
- package/deploy/sema-up/smoke.sh +16 -6
- package/deploy/sema-up/stack/compose.yaml +1 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -1
- package/dist/approval-ask-audit-store.js +2 -7
- package/dist/approval-card.d.ts +40 -10
- package/dist/approval-card.js +11 -1
- package/dist/approval.d.ts +55 -17
- package/dist/approval.js +74 -33
- package/dist/audit.d.ts +12 -1
- package/dist/audit.js +62 -2
- package/dist/auto-mode-face.d.ts +2 -3
- package/dist/bake-runner/main.js +1 -6
- package/dist/bake-runner/protocol.d.ts +18 -0
- package/dist/bake-runner/protocol.js +22 -2
- package/dist/bake-runner/runner.d.ts +12 -8
- package/dist/bake-runner/runner.js +5 -9
- package/dist/boot/config-center.js +1 -1
- package/dist/boot/coordinators.js +4 -1
- package/dist/boot/device-lane.d.ts +3 -3
- package/dist/boot/device-lane.js +1 -2
- package/dist/boot/leader.d.ts +4 -4
- package/dist/boot/leader.js +1 -2
- package/dist/boot/parked-revive-gate.d.ts +4 -6
- package/dist/boot/parked-revive-gate.js +2 -6
- package/dist/boot/resolve-spec.js +9 -11
- package/dist/boot/runner-deps.js +2 -2
- package/dist/boot/stage-07-capability-layer.js +7 -3
- package/dist/boot/stage-10-http-server.js +3 -2
- package/dist/boot/stores.js +12 -7
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +24 -6
- package/dist/capabilities/code-review-council.js +8 -11
- package/dist/capabilities/hands-lane.d.ts +25 -0
- package/dist/capabilities/hands-lane.js +1 -1
- package/dist/capabilities/mcp-probe.d.ts +2 -2
- package/dist/capabilities/scenarios.d.ts +34 -7
- package/dist/capabilities/scenarios.js +33 -6
- package/dist/config-catalog.js +3 -3
- package/dist/config.d.ts +14 -18
- package/dist/config.js +15 -26
- package/dist/deployment-governance.d.ts +5 -7
- package/dist/deployment-governance.js +4 -5
- package/dist/host-decision.d.ts +114 -31
- package/dist/host-decision.js +39 -2
- package/dist/http/admission.js +12 -6
- package/dist/http/approval-sweeps.js +1 -1
- package/dist/http/mcp-dial-deadline.d.ts +35 -0
- package/dist/http/mcp-dial-deadline.js +21 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +11 -5
- package/dist/http/memory-compliance-failure-reply.js +17 -8
- package/dist/http/memory-store-refusal-reply.d.ts +14 -11
- package/dist/http/memory-store-refusal-reply.js +16 -5
- package/dist/http/resume-legs.js +8 -3
- package/dist/http/routes/approvals-assistant.d.ts +25 -3
- package/dist/http/routes/approvals-assistant.js +27 -26
- package/dist/http/routes/capabilities.js +6 -3
- package/dist/http/routes/mcp-reconnect.d.ts +17 -0
- package/dist/http/routes/mcp-reconnect.js +6 -1
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/runs.js +47 -33
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +23 -22
- package/dist/http/routes/workflows.js +2 -0
- package/dist/http/wire-types.d.ts +17 -13
- package/dist/images/manifest.d.ts +7 -1
- package/dist/images/manifest.js +18 -16
- package/dist/memory-store-refusal.d.ts +38 -18
- package/dist/memory-store-refusal.js +25 -7
- package/dist/model-unreachable-notice.d.ts +1 -1
- package/dist/namespaced-rule-name.d.ts +46 -41
- package/dist/namespaced-rule-name.js +36 -22
- package/dist/observability/corrupt-read-seat.d.ts +4 -0
- package/dist/observability/corrupt-read-seat.js +1 -0
- package/dist/observability/fail-open.d.ts +19 -3
- package/dist/observability/fail-open.js +19 -3
- package/dist/operator-ask.d.ts +6 -2
- package/dist/orchestration/workflow-agent-session-index.d.ts +82 -59
- package/dist/orchestration/workflow-agent-session-index.js +80 -14
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -0
- package/dist/orchestration/workflow-completion-inbox.js +39 -17
- package/dist/orchestration/workflow-notify-journal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.js +7 -2
- package/dist/outbound-dispatcher.d.ts +29 -20
- package/dist/outbound-dispatcher.js +105 -16
- package/dist/parked-decide.d.ts +43 -48
- package/dist/parked-decide.js +54 -16
- package/dist/permission-rule-vocab.d.ts +4 -3
- package/dist/permission-rule-vocab.js +1 -1
- package/dist/plugins/approval-ask-store-sql.d.ts +17 -20
- package/dist/plugins/approval-ask-store-sql.js +0 -3
- package/dist/plugins/approval-exemption-store.d.ts +4 -0
- package/dist/plugins/approval-exemption-store.js +1 -0
- package/dist/plugins/blob-backend.d.ts +13 -0
- package/dist/plugins/blob-backend.js +26 -0
- package/dist/plugins/local-session-store.d.ts +78 -47
- package/dist/plugins/local-session-store.js +152 -122
- package/dist/plugins/one-time-migrations.d.ts +11 -0
- package/dist/plugins/one-time-migrations.js +128 -4
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/snapshot-bucket-presence.d.ts +36 -0
- package/dist/plugins/snapshot-bucket-presence.js +40 -0
- package/dist/plugins/store-backend.d.ts +17 -6
- package/dist/plugins/store-backend.js +46 -16
- package/dist/plugins/store-open-wait.d.ts +33 -0
- package/dist/plugins/store-open-wait.js +73 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/web-search.d.ts +20 -1
- package/dist/plugins/web-search.js +39 -10
- package/dist/plugins/workflow-run-store-sql.d.ts +7 -6
- package/dist/plugins/workflow-run-store-sql.js +5 -7
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +1 -1
- package/dist/rule-entry-list.d.ts +35 -46
- package/dist/rule-entry-list.js +18 -26
- package/dist/rules-consent.js +3 -0
- package/dist/run-local.js +5 -3
- package/dist/runs.d.ts +1 -1
- package/dist/security.d.ts +5 -3
- package/dist/security.js +4 -0
- package/dist/session-policy-wire.d.ts +13 -12
- package/dist/session-policy-wire.js +11 -11
- package/dist/spec-fields.d.ts +13 -11
- package/dist/spec-fields.js +4 -7
- package/dist/standing-answer-grant.d.ts +14 -2
- package/dist/standing-answer-grant.js +8 -1
- package/dist/store-posture.d.ts +14 -6
- package/dist/store-posture.js +7 -4
- package/dist/task-settings.d.ts +27 -55
- package/dist/task-settings.js +13 -21
- package/dist/tool-approval.d.ts +133 -138
- package/dist/tool-approval.js +175 -66
- package/dist/trace/core-keyset-guard.d.ts +5 -5
- package/dist/trace/redact.d.ts +6 -0
- package/dist/trace/redact.js +9 -9
- package/dist/trace/self-minted-wire.d.ts +16 -2
- package/dist/trace/self-minted-wire.js +7 -0
- package/dist/user-input-ledger.d.ts +30 -14
- package/dist/user-input-ledger.js +25 -14
- package/package.json +2 -2
- package/scripts/drain-check-local.mjs +74 -3
- package/scripts/drain-check.mysql.sql +43 -17
- package/scripts/drain-check.pg.sql +46 -20
package/dist/approval-card.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* 没有方法、没有捕获的行为。
|
|
22
22
|
*/
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { ALLOW_RULE_MEMBERS, 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";
|
|
24
|
+
import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer, type SteerReplayFacet } 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 挑的名字是自由文本,
|
|
@@ -81,11 +81,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
81
81
|
kind: z.ZodLiteral<"single">;
|
|
82
82
|
rule: z.ZodString;
|
|
83
83
|
match: z.ZodEnum<{
|
|
84
|
+
name: "name";
|
|
84
85
|
path: "path";
|
|
85
86
|
exact: "exact";
|
|
86
87
|
prefix: "prefix";
|
|
87
88
|
wildcard: "wildcard";
|
|
88
89
|
subpath: "subpath";
|
|
90
|
+
name_prefix: "name_prefix";
|
|
89
91
|
}>;
|
|
90
92
|
command: z.ZodString;
|
|
91
93
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -94,11 +96,13 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
94
96
|
kind: z.ZodLiteral<"command">;
|
|
95
97
|
rule: z.ZodString;
|
|
96
98
|
match: z.ZodEnum<{
|
|
99
|
+
name: "name";
|
|
97
100
|
path: "path";
|
|
98
101
|
exact: "exact";
|
|
99
102
|
prefix: "prefix";
|
|
100
103
|
wildcard: "wildcard";
|
|
101
104
|
subpath: "subpath";
|
|
105
|
+
name_prefix: "name_prefix";
|
|
102
106
|
}>;
|
|
103
107
|
command: z.ZodString;
|
|
104
108
|
segment: z.ZodString;
|
|
@@ -158,11 +162,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
158
162
|
kind: z.ZodLiteral<"single">;
|
|
159
163
|
rule: z.ZodString;
|
|
160
164
|
match: z.ZodEnum<{
|
|
165
|
+
name: "name";
|
|
161
166
|
path: "path";
|
|
162
167
|
exact: "exact";
|
|
163
168
|
prefix: "prefix";
|
|
164
169
|
wildcard: "wildcard";
|
|
165
170
|
subpath: "subpath";
|
|
171
|
+
name_prefix: "name_prefix";
|
|
166
172
|
}>;
|
|
167
173
|
command: z.ZodString;
|
|
168
174
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -171,11 +177,13 @@ export declare const RuleOfferRawSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
171
177
|
kind: z.ZodLiteral<"command">;
|
|
172
178
|
rule: z.ZodString;
|
|
173
179
|
match: z.ZodEnum<{
|
|
180
|
+
name: "name";
|
|
174
181
|
path: "path";
|
|
175
182
|
exact: "exact";
|
|
176
183
|
prefix: "prefix";
|
|
177
184
|
wildcard: "wildcard";
|
|
178
185
|
subpath: "subpath";
|
|
186
|
+
name_prefix: "name_prefix";
|
|
179
187
|
}>;
|
|
180
188
|
command: z.ZodString;
|
|
181
189
|
segment: z.ZodString;
|
|
@@ -437,7 +445,7 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
437
445
|
kind: "tool_approval";
|
|
438
446
|
}>;
|
|
439
447
|
/**
|
|
440
|
-
* 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`)——
|
|
448
|
+
* 🔴 **闭集词座的唯一窄读**(S-721 起 `mandate`;S-755 起 `origin`;S-1170 起 `classifierNoRuling` / `differs`)—— 一座一只成员筛,**名字是参数**(与
|
|
441
449
|
* {@link readParkRowTrueSeat} 同一条:一处解析,不是两只各写一遍的函数)。
|
|
442
450
|
* · `mandate`(core 7.32.0 #1092)—— 一问**站在哪一个 mandate 词上**(`mandated` 说「站在强制上」,本座说是 core
|
|
443
451
|
* `PERSISTED_RULE_MANDATES` 六词里的哪一个;core 只在强制位的**整因**是那一个词时铸 —— 治理 / hook / 祖先,或不止一个理由
|
|
@@ -446,6 +454,11 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
446
454
|
* · `origin`(core 7.5.0 [ref] 的 park 孪生座;S-755)—— **谁提的这一问**,core `ASK_ORIGINS` 闭集一词。读者:运维队列行读寄存行
|
|
447
455
|
* 孪生座 `PendingAction.tool_approval.origin`({@link parkRowFacts})。活卡帧**不经**本函数:它读引擎在门上刚盖好的
|
|
448
456
|
* `AskRequest.origin`(盖章点即 core 的筛点),照旧只过「非空串」形门(`tool-approval.ts` 帧键 `origin` 顶注)。
|
|
457
|
+
* · `classifierNoRuling`(core 7.43.0 #1353)—— 分类器没给判词的成因词,core `AUTO_MODE_FALLBACK_CAUSES` 闭集一词(筛 = `isAutoModeFallbackCause`)。
|
|
458
|
+
* 读者:活卡帧读 `AskRequest.classifierNoRuling`(`tool-approval.ts`);inbox 行读 core `CheckpointSummary` 已筛过的同名位、直投不经本函数。
|
|
459
|
+
* · `differs`(core 7.44.0 #1374)—— **载体是引擎拒 steer 重放那只错的 `detail`**(不是 ask 的三个载体之一),值是 core `STEER_REPLAY_FACETS` 的**非空子集**
|
|
460
|
+
* (core:「恒非空」;筛 = 本文件 {@link isSteerReplayDiffers},成员表取 core 常量)。读者:`runs.ts` 的 409 `steering.duplicate_input_id` 体(`detail.differs`)。
|
|
461
|
+
* 集外成员 / 空数组 / 非数组 ⇒ 按缺席(不铸 `detail`,码仍是契约)+ 计一次;detail 只报形名(`differs=<array>` —— 数组从不展开成员,见 {@link outOfSetDetail})。
|
|
449
462
|
*
|
|
450
463
|
* 什么时候经本函数 —— 一句话:**筛点在 core;server 只在「读的是持久层原字节、中间没有 core 投影」的地方亲手调 core 的那一只筛**。
|
|
451
464
|
* inbox 行读 core `CheckpointSummary.{mandate,origin}`(core `summarizeCheckpoint` 已用同一只 `isPersistedRuleMandate` / `isAskOrigin`
|
|
@@ -459,10 +472,12 @@ type ToolApprovalPark = Extract<CorePendingAction, {
|
|
|
459
472
|
* 只读值不调用值)。
|
|
460
473
|
*/
|
|
461
474
|
export declare function readClosedWordSeat<S extends ClosedWordSeat>(carrier: object, seat: S): ClosedWordOf<S> | undefined;
|
|
462
|
-
/**
|
|
463
|
-
type
|
|
464
|
-
/**
|
|
465
|
-
type
|
|
475
|
+
/** ask 载体上的闭集词座名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。 */
|
|
476
|
+
type AskClosedWordSeat = "mandate" | "origin" | "classifierNoRuling";
|
|
477
|
+
/** 闭集词座的名 = ask 载体上的三座 + 引擎拒 steer 重放那只错的 `detail.differs`(载体不同、读法同一只)。 */
|
|
478
|
+
type ClosedWordSeat = AskClosedWordSeat | "differs";
|
|
479
|
+
/** 一座的值型:ask 三座 = core 寄存行上那一座的型(去掉可选位的 `undefined`);`differs` = core 闭集 `SteerReplayFacet` 的数组(core `detail.differs` 的型)。 */
|
|
480
|
+
type ClosedWordOf<S extends ClosedWordSeat> = S extends AskClosedWordSeat ? NonNullable<ToolApprovalPark[S]> : readonly SteerReplayFacet[];
|
|
466
481
|
/**
|
|
467
482
|
* 🔴 **S-934 ②(core 7.37.0 #1214)—— ask 类对的唯一窄读**:`askClass`(一问的类 = `classes` 的首员)与 `classes`(这一问属于的全部类,core
|
|
468
483
|
* `ASK_CLASSES` 序)。三个载体上同名:`AskRequest`(活卡帧 / 呈卡帧的卡读它)、寄存行 `PendingAction.tool_approval`(运维队列行经
|
|
@@ -600,11 +615,13 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
600
615
|
kind: z.ZodLiteral<"single">;
|
|
601
616
|
rule: z.ZodString;
|
|
602
617
|
match: z.ZodEnum<{
|
|
618
|
+
name: "name";
|
|
603
619
|
path: "path";
|
|
604
620
|
exact: "exact";
|
|
605
621
|
prefix: "prefix";
|
|
606
622
|
wildcard: "wildcard";
|
|
607
623
|
subpath: "subpath";
|
|
624
|
+
name_prefix: "name_prefix";
|
|
608
625
|
}>;
|
|
609
626
|
command: z.ZodString;
|
|
610
627
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -613,11 +630,13 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
613
630
|
kind: z.ZodLiteral<"command">;
|
|
614
631
|
rule: z.ZodString;
|
|
615
632
|
match: z.ZodEnum<{
|
|
633
|
+
name: "name";
|
|
616
634
|
path: "path";
|
|
617
635
|
exact: "exact";
|
|
618
636
|
prefix: "prefix";
|
|
619
637
|
wildcard: "wildcard";
|
|
620
638
|
subpath: "subpath";
|
|
639
|
+
name_prefix: "name_prefix";
|
|
621
640
|
}>;
|
|
622
641
|
command: z.ZodString;
|
|
623
642
|
segment: z.ZodString;
|
|
@@ -676,8 +695,8 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
676
695
|
}, z.core.$strict>>>;
|
|
677
696
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
678
697
|
}, z.core.$strict>>;
|
|
679
|
-
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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
680
|
-
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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
698
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
699
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
681
700
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
682
701
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
683
702
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -726,11 +745,13 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
726
745
|
kind: z.ZodLiteral<"single">;
|
|
727
746
|
rule: z.ZodString;
|
|
728
747
|
match: z.ZodEnum<{
|
|
748
|
+
name: "name";
|
|
729
749
|
path: "path";
|
|
730
750
|
exact: "exact";
|
|
731
751
|
prefix: "prefix";
|
|
732
752
|
wildcard: "wildcard";
|
|
733
753
|
subpath: "subpath";
|
|
754
|
+
name_prefix: "name_prefix";
|
|
734
755
|
}>;
|
|
735
756
|
command: z.ZodString;
|
|
736
757
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -739,11 +760,13 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
739
760
|
kind: z.ZodLiteral<"command">;
|
|
740
761
|
rule: z.ZodString;
|
|
741
762
|
match: z.ZodEnum<{
|
|
763
|
+
name: "name";
|
|
742
764
|
path: "path";
|
|
743
765
|
exact: "exact";
|
|
744
766
|
prefix: "prefix";
|
|
745
767
|
wildcard: "wildcard";
|
|
746
768
|
subpath: "subpath";
|
|
769
|
+
name_prefix: "name_prefix";
|
|
747
770
|
}>;
|
|
748
771
|
command: z.ZodString;
|
|
749
772
|
segment: z.ZodString;
|
|
@@ -802,8 +825,8 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
802
825
|
}, z.core.$strict>>>;
|
|
803
826
|
personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
|
|
804
827
|
}, z.core.$strict>>;
|
|
805
|
-
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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
806
|
-
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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "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" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
828
|
+
askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
|
|
829
|
+
classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "write_protection_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
|
|
807
830
|
fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
|
|
808
831
|
sourceTaskId: z.ZodOptional<z.ZodString>;
|
|
809
832
|
sourceAgentName: z.ZodOptional<z.ZodString>;
|
|
@@ -976,6 +999,13 @@ export declare function buildRevokeFrame(batchId: string, askIds: readonly strin
|
|
|
976
999
|
* 竞争者;收敛是车2 的窗到期竞争者与车5 恢复扫描的职责)。
|
|
977
1000
|
*/
|
|
978
1001
|
export declare function buildReplayFrame(row: AskRow, nowMs: number): ApprovalRequestFrame | undefined;
|
|
1002
|
+
/**
|
|
1003
|
+
* S-1154 —— 持久行上那张卡**要不要人**:卡面 `risk.requiresRealApproval`(铸卡时取自引擎在 `AskRequest` 上盖的同一位,
|
|
1004
|
+
* {@link buildApprovalCard} 第三参)。读者 = 耐久 ask 回决口在裁决之前交给引擎判官 `policyCannotAnswer` 的那一问(`host-decision.ts` 的 `heldAskOf`)。
|
|
1005
|
+
* 🔴 读不出卡(`card_json` 形不合)⇒ **按要人读**(fail-closed):这一位只用来**拒**策略的放行,读坏的行上拒一次可以改成人答 / 策略拒
|
|
1006
|
+
* 再来;反方向(读坏当不要人)会让一次引擎终将拒掉的放行先落成一条宣称 approve 的行。
|
|
1007
|
+
*/
|
|
1008
|
+
export declare function storedCardDemandsAPerson(cardJson: unknown): boolean;
|
|
979
1009
|
/** {@link buildApprovalPreamble} 的返回形——帧 + 两个**计数**(调用方按自己的 logger 记 warn;本模块
|
|
980
1010
|
* 保持纯函数,不吃 logger:那会让一个 `build*` 捕获行为)。 */
|
|
981
1011
|
export interface ApprovalPreamble {
|
package/dist/approval-card.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, isAskClass, isAskOrigin, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
|
|
2
|
+
import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, STEER_REPLAY_FACETS, isAskClass, isAskOrigin, isAutoModeFallbackCause, isPersistedRuleMandate, screenAskClassMembers } 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";
|
|
@@ -314,9 +314,15 @@ export function readClosedWordSeat(carrier, seat) {
|
|
|
314
314
|
recordFailOpen("server.approval-card.closed-word-out-of-set", `${seat}=${outOfSetDetail(raw)}`);
|
|
315
315
|
return undefined;
|
|
316
316
|
}
|
|
317
|
+
function isSteerReplayDiffers(v) {
|
|
318
|
+
const facets = STEER_REPLAY_FACETS;
|
|
319
|
+
return Array.isArray(v) && v.length > 0 && v.every((f) => facets.includes(f));
|
|
320
|
+
}
|
|
317
321
|
const CLOSED_WORD_SEAT_GUARDS = {
|
|
318
322
|
mandate: isPersistedRuleMandate,
|
|
319
323
|
origin: isAskOrigin,
|
|
324
|
+
classifierNoRuling: isAutoModeFallbackCause,
|
|
325
|
+
differs: isSteerReplayDiffers,
|
|
320
326
|
};
|
|
321
327
|
export function readAskClassPair(carrier) {
|
|
322
328
|
const askClass = "askClass" in carrier ? carrier.askClass : undefined;
|
|
@@ -520,6 +526,10 @@ export function buildReplayFrame(row, nowMs) {
|
|
|
520
526
|
approvalId: parsed.data.approvalId,
|
|
521
527
|
};
|
|
522
528
|
}
|
|
529
|
+
export function storedCardDemandsAPerson(cardJson) {
|
|
530
|
+
const parsed = ApprovalCardEnvelopeSchema.safeParse(cardJson);
|
|
531
|
+
return !parsed.success || parsed.data.card.risk.requiresRealApproval;
|
|
532
|
+
}
|
|
523
533
|
export function buildApprovalPreamble(rows, nowMs, replayMax) {
|
|
524
534
|
const frames = [];
|
|
525
535
|
let skipped = 0;
|
package/dist/approval.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* (createOaApprovalPolicy + ApprovalStore pending 行轮询)整体退役;唯一门形 = durable checkpoint
|
|
4
4
|
* suspend/resume,见 createDurableAskPolicy 与 /v1/approvals 的 checkpointStore 腿)。
|
|
5
5
|
*/
|
|
6
|
-
import { type ToolPolicy } from "@sema-agent/core";
|
|
6
|
+
import { type ToolCallRequest, type ToolPolicy } from "@sema-agent/core";
|
|
7
7
|
import { type PostureSource } from "./posture-source.js";
|
|
8
8
|
import { type ExecutionLane } from "./execution-lane-caps.js";
|
|
9
|
+
import { type ApprovalExemptionStore } from "./plugins/approval-exemption-store.js";
|
|
9
10
|
/**
|
|
10
11
|
* 门意图判据读的五个量(`ServiceConfig` 结构满足)。单独成型是为了让**热路径**能拿「候选视图」来判
|
|
11
12
|
* (S-668 波 2:`{ ...config, approvalRequire: 候选名单 }`)—— 判据只有一份,输入可以是活配置也可以是候选。
|
|
@@ -52,7 +53,7 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
|
|
|
52
53
|
readonly requirePrincipal: boolean;
|
|
53
54
|
}): boolean;
|
|
54
55
|
/**
|
|
55
|
-
* 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)
|
|
56
|
+
* 门意图**不可服务**的判据 —— 返回拒因(可服务 ⇒ `undefined`)。**全仓唯一一份**,三处调用、处置不同:
|
|
56
57
|
* · **boot**(`boot/stage-07-capability-layer.ts`):对装配完的整份 config 判,拒因 ⇒ **拒启**(全窗复审 D3-F1,
|
|
57
58
|
* HIGH;与 env 墓碑族同谱系)。v4.3.0 的轮询门形(APPROVAL_REQUIRE + DB backend + DURABLE_APPROVAL 未设)在
|
|
58
59
|
* 5.0.0 只剩 core 每任务 warn——**原先拦、现在放**(方向反转)。「留 undefined 让 core warn」对新配置是
|
|
@@ -60,6 +61,9 @@ export declare function singleUserAutoAcceptBaselineApplies(config: GateIntentVi
|
|
|
60
61
|
* · **热路径**(S-668 波 2 ④,`config-center/apply-effective.ts` 的审批组 stage):对**候选视图**
|
|
61
62
|
* (活配置 + 候选名单)判,拒因 ⇒ 审批组**整组拒**、活配置零变化、世代账停旧代。进程在跑,拒启不是选项;
|
|
62
63
|
* 而放行一份「没有 checkpoint 店可停车」的名单 = 单用户 auto-accept 基线仍在、名单静默不生效。
|
|
64
|
+
* · **每个任务的装配**(S-1144,`boot/resolve-spec.ts` 的 `resolveSpec` 头一道):对**活配置**判,拒因 ⇒ 请求 501
|
|
65
|
+
* `capability.checkpoint_store_required`。部署形到不了(boot 已拒启);可达的是嵌入方装配 / 直调 `resolveSpec`(自己递 ctx、没经 stage-07)。
|
|
66
|
+
* 修前这一形把审批基线静默铸成 `undefined`,请求的 allow 清「普通问」后任务零卡落盘 —— 同一条规则在起服层拒、在装配层静默 = 一事两读。
|
|
63
67
|
* `checkpointStorePresent` 是**部署事实**(本进程建没建出 checkpoint 店),不在 `ServiceConfig` 里 ⇒ 调用方显式递。
|
|
64
68
|
* 放这文件与 hasOperatorGateIntent/inv#2 同源(意图判据再漂要同时改两段)。
|
|
65
69
|
*/
|
|
@@ -129,22 +133,56 @@ export declare function buildForceDurableGateInertNotice(input: {
|
|
|
129
133
|
* replica. (The former poll-lane
|
|
130
134
|
* twin, createOaApprovalPolicy, was retired in 5.0.0 — durable is the only gate.)
|
|
131
135
|
*/
|
|
132
|
-
export interface DurableAskOptions {
|
|
133
|
-
requireApproval: string[];
|
|
134
|
-
deny?: string[];
|
|
136
|
+
export interface DurableAskOptions extends ApprovalListsView {
|
|
135
137
|
autoBudget?: number;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* tools, AFTER deny/neverAuto (both always win) and BEFORE the budget path. Canonical-space toolName.
|
|
139
|
-
* A rejected promise is treated as NOT exempt (fail-closed → ask) at the call site below.
|
|
140
|
-
* 🔴 S-877 候裁 16:会话授权**两个读位、一只店、按问句的作者分**(收车档 ⑩ 16):本探针兑现**本仓自己的问**(名单门)
|
|
141
|
-
* —— 在它自己的层上「不问」,于是委派子代经父约束链继承到的同一问也不问;引擎自装的问(模式写门 / 形状层)由审批席
|
|
142
|
-
* (`ToolApprovalCoordinator.standingGrantSettles`)兑现。本探针**不能**退役:子代的继承问到达祖先审批席时 core 盖
|
|
143
|
-
* `mandated`(`ruleClearanceOf` 的 inheritedUnresolved / ancestorResolved 门),席的判据依约不退役它 —— 只有本层的
|
|
144
|
-
* 「不问」够得着继承链(钉 test/parked-decide-leg.test.ts「[候裁② 修]remember 全链行为」)。 */
|
|
145
|
-
exempt?: (canonicalToolName: string) => Promise<boolean>;
|
|
146
|
-
/** Audit hook — fired when an exemption short-circuits the ask (the `approval_exempted` log line). */
|
|
147
|
-
onExempted?: (canonicalToolName: string, rawToolName: string) => void;
|
|
138
|
+
/** 本会话的「本会话放行」读面(server 的会话豁免店,键 = 会话 × wire 工具名)。缺席 = 这条腿没有会话 / 没有店 ⇒ 名单门照问。 */
|
|
139
|
+
exemption?: DeploymentListExemption;
|
|
148
140
|
}
|
|
141
|
+
/** 三张运维名单(一只调用由哪一张说话)的入参 —— 名单门与「问的属主」读法同读这一份。 */
|
|
142
|
+
export interface ApprovalListsView {
|
|
143
|
+
readonly requireApproval: readonly string[];
|
|
144
|
+
readonly deny?: readonly string[];
|
|
145
|
+
readonly neverAuto?: readonly string[];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 三张运维名单对**一只调用**的判词(deny 先于 never-auto 先于 require),`hit` = 命中的那个名(规则归因写运维名单里的那个)。
|
|
149
|
+
* 名单门按它出 deny / 恒问人 / 名单的问;「这张卡上有没有名单自己的问」也按它读(见 {@link deploymentListAsks})—— 一份读法,两个读者。
|
|
150
|
+
*/
|
|
151
|
+
export type ApprovalListVerdict = {
|
|
152
|
+
readonly list: "deny";
|
|
153
|
+
} | {
|
|
154
|
+
readonly list: "never_auto" | "require";
|
|
155
|
+
readonly hit: string;
|
|
156
|
+
} | {
|
|
157
|
+
readonly list: "none";
|
|
158
|
+
};
|
|
159
|
+
/** 铸一只判词函数(名单的命中集与 covering 规则只解一次)。名字读法 = {@link heldRuleName}(收紧臂读调用答得上的全部名字)。 */
|
|
160
|
+
export declare function createApprovalListVerdict(lists: ApprovalListsView): (call: Pick<ToolCallRequest, "toolName" | "face">) => ApprovalListVerdict;
|
|
161
|
+
/**
|
|
162
|
+
* **「问的属主」的读法**:部署名单门对这只调用出不出它**自己的**那一问(`APPROVAL_REQUIRE` 臂)—— 读的是铸点本身(同一只判词),
|
|
163
|
+
* 不另造一张表。读者:审批席(活卡的提示位 / 回决写侧)、耐久 `/decide` 腿与运维队列行(停驻行上只有工具名,按 wire 名读)。
|
|
164
|
+
* 名单是热换的(中心下发),读者每次现读活配置。答 `true` 只说「名单门问这只调用」;这张卡是不是名单的那一问,还要看卡上的类
|
|
165
|
+
* (`tool-approval.ts` 的 `StandingAnswerFacts.deploymentListQuestion`)。
|
|
166
|
+
*/
|
|
167
|
+
export declare function deploymentListAsks(config: Pick<GateIntentView, "approvalRequire" | "approvalDeny" | "approvalNeverAuto">, call: Pick<ToolCallRequest, "toolName" | "face">): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* 名单门的「本会话放行」读面:本会话的豁免店读一次 + server 自己的审计行。名单的问是 server 铸的,它的站着的答案记在 server 的
|
|
170
|
+
* 会话豁免店(活卡的 `allow_session` 与耐久 `/decide` 的 `remember:"session"` 写同一只店),名单门在出问**之前**读它。
|
|
171
|
+
*/
|
|
172
|
+
export interface DeploymentListExemption {
|
|
173
|
+
/** 这只工具(wire 名)在本会话有没有豁免行。有界、fail-closed:读抛 / 超时 ⇒ `false`(照问,人多看一张卡)。 */
|
|
174
|
+
readonly has: (toolName: string) => Promise<boolean>;
|
|
175
|
+
/** 名单门因为豁免行没出问 —— server 自己的审计行(宿主豁免;不是人答的、不是策略代答的、没有记住任何东西)。 */
|
|
176
|
+
readonly onExempted: (toolName: string) => void;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* 名单门豁免读面的**唯一**铸点(HTTP 腿 `resolve-spec` 与 park 赎回腿 `parked-revive-gate` 两处装配都经它):键 = 会话 × wire 工具名
|
|
180
|
+
* (与活卡 `allow_session` / `/decide` remember 写下的键同形)。审计事件名 {@link APPROVAL_EXEMPTED_EVENT},字段只有会话、工具与读位
|
|
181
|
+
* `seat: "deployment_list"`(审批席自己那一行是 `seat: "approval_seat"`)。读的期限与审批席读同一只店的期限同值。
|
|
182
|
+
*/
|
|
183
|
+
export declare function createDeploymentListExemption(store: Pick<ApprovalExemptionStore, "has">, sessionId: string, logger: {
|
|
184
|
+
info(event: string, fields?: Record<string, unknown>): void;
|
|
185
|
+
warn(event: string, fields?: Record<string, unknown>): void;
|
|
186
|
+
}, leg?: "parked_revive"): DeploymentListExemption;
|
|
149
187
|
export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
|
|
150
188
|
//# sourceMappingURL=approval.d.ts.map
|
package/dist/approval.js
CHANGED
|
@@ -4,7 +4,8 @@ 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
6
|
import { heldRuleName } from "./tool-rule-names.js";
|
|
7
|
-
import {
|
|
7
|
+
import { DURABLE_CONVERGE_READ_TIMEOUT_MS, policyAskStandingAnswerFacts, standingAnswerDurablyRecordable } from "./tool-approval.js";
|
|
8
|
+
import { APPROVAL_EXEMPTED_EVENT } from "./plugins/approval-exemption-store.js";
|
|
8
9
|
export function hasApprovalListIntent(config) {
|
|
9
10
|
return (config.approvalRequire.length > 0 ||
|
|
10
11
|
config.approvalDeny.length > 0 ||
|
|
@@ -68,6 +69,49 @@ export function buildForceDurableGateInertNotice(input) {
|
|
|
68
69
|
},
|
|
69
70
|
};
|
|
70
71
|
}
|
|
72
|
+
export function createApprovalListVerdict(lists) {
|
|
73
|
+
const require = createNameSetMatcher(lists.requireApproval);
|
|
74
|
+
const deny = createNameSetMatcher(lists.deny ?? []);
|
|
75
|
+
const neverAuto = createNameSetMatcher(lists.neverAuto ?? []);
|
|
76
|
+
return (call) => {
|
|
77
|
+
if (heldRuleName(call, deny) !== undefined)
|
|
78
|
+
return { list: "deny" };
|
|
79
|
+
const neverAutoHit = heldRuleName(call, neverAuto);
|
|
80
|
+
if (neverAutoHit !== undefined)
|
|
81
|
+
return { list: "never_auto", hit: neverAutoHit };
|
|
82
|
+
const requireHit = heldRuleName(call, require);
|
|
83
|
+
if (requireHit !== undefined)
|
|
84
|
+
return { list: "require", hit: requireHit };
|
|
85
|
+
return { list: "none" };
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function deploymentListAsks(config, call) {
|
|
89
|
+
return createApprovalListVerdict({ requireApproval: config.approvalRequire, deny: config.approvalDeny, neverAuto: config.approvalNeverAuto })(call).list === "require";
|
|
90
|
+
}
|
|
91
|
+
export function createDeploymentListExemption(store, sessionId, logger, leg) {
|
|
92
|
+
const where = { sessionId, ...(leg !== undefined ? { leg } : {}) };
|
|
93
|
+
return {
|
|
94
|
+
has: async (toolName) => {
|
|
95
|
+
let timer;
|
|
96
|
+
try {
|
|
97
|
+
const deadline = new Promise((_, reject) => {
|
|
98
|
+
timer = setTimeout(() => reject(new Error(`exemption read timed out after ${DURABLE_CONVERGE_READ_TIMEOUT_MS}ms`)), DURABLE_CONVERGE_READ_TIMEOUT_MS);
|
|
99
|
+
timer.unref?.();
|
|
100
|
+
});
|
|
101
|
+
return (await Promise.race([store.has(sessionId, toolName), deadline])) === true;
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
logger.warn("session_grant_read_failed", { ...where, toolName, seat: "deployment_list", error: String(err).slice(0, 200) });
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
if (timer !== undefined)
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
onExempted: (toolName) => logger.info(APPROVAL_EXEMPTED_EVENT, { ...where, toolName, seat: "deployment_list" }),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
71
115
|
function createNameSetMatcher(names) {
|
|
72
116
|
const exact = new Set(names);
|
|
73
117
|
const covering = names.filter(isNamespacedCoveringRuleName);
|
|
@@ -79,44 +123,27 @@ function grantedByRule() {
|
|
|
79
123
|
return { action: "allow", decisionReason: "rule" };
|
|
80
124
|
}
|
|
81
125
|
export function createDurableAskPolicy(opts) {
|
|
82
|
-
const
|
|
83
|
-
const deny = createNameSetMatcher(opts.deny ?? []);
|
|
84
|
-
const neverAuto = createNameSetMatcher(opts.neverAuto ?? []);
|
|
126
|
+
const verdictOf = createApprovalListVerdict(opts);
|
|
85
127
|
const budget = Math.max(0, Math.floor(opts.autoBudget ?? 0));
|
|
86
128
|
let autoApproved = 0;
|
|
87
129
|
const isQuestionTool = (name) => name === ASK_USER_QUESTION_TOOL_NAME;
|
|
88
130
|
return {
|
|
89
131
|
check: (req) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
let exempted = false;
|
|
104
|
-
try {
|
|
105
|
-
exempted = (await opts.exempt(req.toolName)) === true;
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
exempted = false;
|
|
109
|
-
}
|
|
110
|
-
if (exempted) {
|
|
111
|
-
opts.onExempted?.(req.toolName, req.toolName);
|
|
112
|
-
return grantedByRule();
|
|
113
|
-
}
|
|
114
|
-
return decideRequired(req, requireHit);
|
|
115
|
-
})();
|
|
132
|
+
const verdict = verdictOf(req);
|
|
133
|
+
switch (verdict.list) {
|
|
134
|
+
case "deny":
|
|
135
|
+
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
136
|
+
case "never_auto":
|
|
137
|
+
return operatorAlwaysHumanAsk(`APPROVAL_NEVER_AUTO(${verdict.hit})`, `human approval required to run "${req.toolName}"`);
|
|
138
|
+
case "require":
|
|
139
|
+
return decideRequired(req, verdict.hit);
|
|
140
|
+
case "none":
|
|
141
|
+
return { action: "allow" };
|
|
142
|
+
default: {
|
|
143
|
+
const unreachable = verdict;
|
|
144
|
+
throw new Error(`unhandled approval-list verdict: ${JSON.stringify(unreachable)}`);
|
|
116
145
|
}
|
|
117
|
-
return decideRequired(req, requireHit);
|
|
118
146
|
}
|
|
119
|
-
return { action: "allow" };
|
|
120
147
|
},
|
|
121
148
|
};
|
|
122
149
|
function decideRequired(req, requireHit) {
|
|
@@ -124,11 +151,25 @@ export function createDurableAskPolicy(opts) {
|
|
|
124
151
|
if (rem !== undefined && rem <= 0) {
|
|
125
152
|
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
126
153
|
}
|
|
154
|
+
const ask = operatorAsk(`APPROVAL_REQUIRE(${requireHit})`, `approval required to run "${req.toolName}"`);
|
|
155
|
+
if (opts.exemption !== undefined && standingAnswerDurablyRecordable(policyAskStandingAnswerFacts(req, ask, true))) {
|
|
156
|
+
const exemption = opts.exemption;
|
|
157
|
+
return (async () => {
|
|
158
|
+
if (await exemption.has(req.toolName)) {
|
|
159
|
+
exemption.onExempted(req.toolName);
|
|
160
|
+
return { action: "allow" };
|
|
161
|
+
}
|
|
162
|
+
return budgetOrAsk(req, ask);
|
|
163
|
+
})();
|
|
164
|
+
}
|
|
165
|
+
return budgetOrAsk(req, ask);
|
|
166
|
+
}
|
|
167
|
+
function budgetOrAsk(req, ask) {
|
|
127
168
|
if (heldRuleName(req, isQuestionTool) === undefined && budget > 0 && autoApproved < budget) {
|
|
128
169
|
autoApproved++;
|
|
129
170
|
return grantedByRule();
|
|
130
171
|
}
|
|
131
|
-
return
|
|
172
|
+
return ask;
|
|
132
173
|
}
|
|
133
174
|
}
|
|
134
175
|
//# sourceMappingURL=approval.js.map
|
package/dist/audit.d.ts
CHANGED
|
@@ -16,7 +16,9 @@ export interface SessionAudit {
|
|
|
16
16
|
provider: string;
|
|
17
17
|
modelId: string;
|
|
18
18
|
} | null;
|
|
19
|
-
/** Current model context: prior messages with older history collapsed into a summary message.
|
|
19
|
+
/** Current model context: prior messages with older history collapsed into a summary message.
|
|
20
|
+
* 🔴 **存档原形**(store 里怎么写就怎么回)—— 不是 wire 形。HTTP 读面一律过 {@link redactSessionViewForRead}(次序 = 选窗 → 脱敏 → 截断)
|
|
21
|
+
* 再回给调用方;直接消费本视图的宿主(`buildSessionAudit` 是包根导出)自己负责同一道脱敏。 */
|
|
20
22
|
messages: unknown[];
|
|
21
23
|
/** [ref]① web 观测切片 B: the session's prompt-epoch pin, core contract verbatim (core 1.304
|
|
22
24
|
* `session.getPromptEpoch()` — first-class `prompt_epoch` entry, compaction restatement, [ref] anchor
|
|
@@ -36,10 +38,19 @@ export declare function buildSessionAudit(pool: Pool, sessionId: string): Promis
|
|
|
36
38
|
* (its storage seam has no wake-equivalent yet — may turn out to be a core gap). */
|
|
37
39
|
export declare function buildSessionAuditPg(pool: PgPool, sessionId: string): Promise<SessionAudit | undefined>;
|
|
38
40
|
/** The LOCAL (File) leg — web session area on DB_BACKEND=local.
|
|
41
|
+
* repo 取自 `createLocalSessionRepo`(与 `LocalSessionStore` 同一只工厂):坏记录的披露座(F 类 `server.session-repo.corrupt-record-skipped`)
|
|
42
|
+
* 因此在视图口同样在场 —— 视图照常返回、跳过的记录有计数 + 探针行(修前自建一只不带座的 repo,零披露)。
|
|
39
43
|
* 实现姿势:`FileSessionRepo.exportEntries`(纯读、torn-tail 恢复、missing→not_found)→
|
|
40
44
|
* `boundedTail`(纯函数切 floor)→ InMemorySessionStorage → 同一 auditFromStorage 内核。零写面、
|
|
41
45
|
* 零新 seam;createdAt 从 repo.list() 的 metadata 取(File 形态 meta 与 entries 分储)。 */
|
|
42
46
|
export declare function buildSessionAuditLocal(root: string, sessionId: string): Promise<SessionAudit | undefined>;
|
|
47
|
+
/**
|
|
48
|
+
* 🔴 **会话视图的读面口 —— `GET /v1/sessions/:id` 的全部取法(整读 / `?tail` / `?before` / `?blobCap` / `?message=N`)共用这一只**。
|
|
49
|
+
* 次序 = **选 → 脱 → 截**(路由 `http/routes/sessions.ts`):整条消息的选窗不切字符串,先选窗不改任何一条的脱敏读数、只把脱敏的量降到选中的那几条;
|
|
50
|
+
* `blobCap` 的截断会切字符串(预览切在密钥中间,半截密钥认不出来)⇒ 截断恒在脱敏之后。
|
|
51
|
+
* `messages` 缺席 ⇒ 不铸键;非数组 ⇒ 深扫;其余键(`owner` / `promptEpoch` / `model` …)逐字。字节没变 ⇒ **同一引用**。
|
|
52
|
+
*/
|
|
53
|
+
export declare function redactSessionViewForRead<V extends object>(view: V): V;
|
|
43
54
|
/** Window `messages` — `tail=N` (last N) or `before=<offset>&limit=N` ([max(0,before-N), before)).
|
|
44
55
|
* Returns the window + its {offset,total} so the web can page upward. */
|
|
45
56
|
export declare function windowMessages(messages: unknown[], opts: {
|
package/dist/audit.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { StoredSession,
|
|
1
|
+
import { StoredSession, InMemorySessionStorage, boundedTail } from "@sema-agent/core";
|
|
2
2
|
import { TiDBSessionStorage } from "./plugins/tidb-session-storage.js";
|
|
3
3
|
import { PgSessionStorage } from "./plugins/pg-session-storage.js";
|
|
4
|
+
import { createLocalSessionRepo } from "./plugins/local-session-store.js";
|
|
5
|
+
import { redactModelText } from "./observability/run-terminal.js";
|
|
6
|
+
import { redactDeepWith } from "./trace/redact.js";
|
|
4
7
|
export async function buildSessionAudit(pool, sessionId) {
|
|
5
8
|
return auditFromStorage(await TiDBSessionStorage.wake(pool, sessionId), sessionId);
|
|
6
9
|
}
|
|
@@ -8,7 +11,7 @@ export async function buildSessionAuditPg(pool, sessionId) {
|
|
|
8
11
|
return auditFromStorage(await PgSessionStorage.wake(pool, sessionId), sessionId);
|
|
9
12
|
}
|
|
10
13
|
export async function buildSessionAuditLocal(root, sessionId) {
|
|
11
|
-
const repo =
|
|
14
|
+
const repo = createLocalSessionRepo(root);
|
|
12
15
|
let entries;
|
|
13
16
|
try {
|
|
14
17
|
entries = await repo.exportEntries(sessionId);
|
|
@@ -40,6 +43,63 @@ async function auditFromStorage(storage, sessionId) {
|
|
|
40
43
|
...(promptEpoch ? { promptEpoch } : {}),
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
const deepScrub = (v) => redactDeepWith(v, redactModelText);
|
|
47
|
+
const textSlot = (v) => (typeof v === "string" ? redactModelText(v) : deepScrub(v));
|
|
48
|
+
function scrubSlot(p, key, scan) {
|
|
49
|
+
const v = p[key];
|
|
50
|
+
if (v === undefined)
|
|
51
|
+
return p;
|
|
52
|
+
const next = scan(v);
|
|
53
|
+
return next === v ? p : { ...p, [key]: next };
|
|
54
|
+
}
|
|
55
|
+
const PART_READ_TREATMENT = {
|
|
56
|
+
text: (p) => scrubSlot(p, "text", textSlot),
|
|
57
|
+
thinking: (p) => scrubSlot(p, "thinking", textSlot),
|
|
58
|
+
toolCall: (p) => scrubSlot(p, "arguments", deepScrub),
|
|
59
|
+
image: (p) => p,
|
|
60
|
+
document: (p) => p,
|
|
61
|
+
};
|
|
62
|
+
function readParts(content) {
|
|
63
|
+
if (!Array.isArray(content))
|
|
64
|
+
return textSlot(content);
|
|
65
|
+
const next = content.map((part) => {
|
|
66
|
+
if (part !== null && typeof part === "object" && !Array.isArray(part)) {
|
|
67
|
+
const type = part.type;
|
|
68
|
+
if (typeof type === "string" && Object.hasOwn(PART_READ_TREATMENT, type)) {
|
|
69
|
+
return PART_READ_TREATMENT[type](part);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return deepScrub(part);
|
|
73
|
+
});
|
|
74
|
+
return next.every((x, i) => x === content[i]) ? content : next;
|
|
75
|
+
}
|
|
76
|
+
const readContent = (m) => scrubSlot(m, "content", readParts);
|
|
77
|
+
const MESSAGE_READ_TREATMENT = {
|
|
78
|
+
user: (m) => m,
|
|
79
|
+
custom: (m) => m,
|
|
80
|
+
assistant: (m) => readContent(m),
|
|
81
|
+
toolResult: (m) => scrubSlot(readContent(m), "details", deepScrub),
|
|
82
|
+
bashExecution: (m) => scrubSlot(scrubSlot(m, "command", textSlot), "output", textSlot),
|
|
83
|
+
compactionSummary: (m) => scrubSlot(m, "summary", textSlot),
|
|
84
|
+
};
|
|
85
|
+
function readMessage(m) {
|
|
86
|
+
if (m !== null && typeof m === "object" && !Array.isArray(m)) {
|
|
87
|
+
const role = m.role;
|
|
88
|
+
if (typeof role === "string" && Object.hasOwn(MESSAGE_READ_TREATMENT, role)) {
|
|
89
|
+
return MESSAGE_READ_TREATMENT[role](m);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return deepScrub(m);
|
|
93
|
+
}
|
|
94
|
+
export function redactSessionViewForRead(view) {
|
|
95
|
+
const { messages } = view;
|
|
96
|
+
if (messages === undefined)
|
|
97
|
+
return view;
|
|
98
|
+
const next = Array.isArray(messages)
|
|
99
|
+
? (() => { const out = messages.map(readMessage); return out.every((x, i) => x === messages[i]) ? messages : out; })()
|
|
100
|
+
: deepScrub(messages);
|
|
101
|
+
return next === messages ? view : { ...view, messages: next };
|
|
102
|
+
}
|
|
43
103
|
export function windowMessages(messages, opts) {
|
|
44
104
|
const total = messages.length;
|
|
45
105
|
if (opts.before !== undefined) {
|
package/dist/auto-mode-face.d.ts
CHANGED
|
@@ -42,8 +42,7 @@
|
|
|
42
42
|
* `entitlementSource`(既有位)说的是「center 源在不在」;`armed` 说的是「按三态谓词此刻会不会武装」。
|
|
43
43
|
* 两者刻意并存:前者告诉壳有没有组织面,后者告诉壳这台机器上 auto 到底是不是 default 的别名。
|
|
44
44
|
*/
|
|
45
|
-
import { type RunnerDeps, type RuntimeCaps } from "@sema-agent/core";
|
|
46
|
-
import type { SettingsPermissionMode } from "./task-settings.js";
|
|
45
|
+
import { type PermissionMode, type RunnerDeps, type RuntimeCaps } from "@sema-agent/core";
|
|
47
46
|
/**
|
|
48
47
|
* 分类器席的模型 —— **调 core 的单一解析器** `classifierSeatModel({deps, main})`(core 7.20.0 / [ref],
|
|
49
48
|
* 本仓 [ref] 的跨仓诉求兑现;契约句 `classifier.seat.one_resolver` 逐字:引擎的武装点与**显示这个席**
|
|
@@ -123,7 +122,7 @@ export type AutoModeVerdict = {
|
|
|
123
122
|
* 走到这里还在抛 = 装配缺陷,读面 500 比一句编出来的 reason 诚实。
|
|
124
123
|
*/
|
|
125
124
|
export declare function judgeAutoModeArming(face: AutoModeFaceDeps | undefined, input: {
|
|
126
|
-
readonly requestedMode:
|
|
125
|
+
readonly requestedMode: PermissionMode | undefined;
|
|
127
126
|
readonly principal: string | undefined;
|
|
128
127
|
/** 本地 `PERMISSIONS_DISABLE_AUTO_MODE`(= catalog/settings 键 `permissions.disableAutoMode`)是否置 true —— caps false 时分词
|
|
129
128
|
* `local_denied` / `org_denied`(seam ⑤;两者对壳的指路不同:改本机 env vs 找组织)。 */
|