@sema-agent/server 4.3.0 → 5.0.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/USAGE.md +5 -3
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.d.ts +5 -37
- package/dist/approval.js +12 -112
- package/dist/auth-bridge.d.ts +0 -1
- package/dist/auth-bridge.js +0 -1
- package/dist/auth-keys.d.ts +1 -1
- package/dist/auth-keys.js +1 -1
- package/dist/bench/s1/run-firm.js +1 -1
- package/dist/boot/config-center.d.ts +1 -1
- package/dist/boot/config-center.js +3 -2
- package/dist/boot/reapers.d.ts +1 -2
- package/dist/boot/reapers.js +4 -5
- package/dist/boot/resolve-spec.d.ts +1 -3
- package/dist/boot/resolve-spec.js +21 -35
- package/dist/boot/stores.js +1 -1
- package/dist/brain.js +3 -1
- package/dist/capabilities/center-prompts.d.ts +2 -3
- package/dist/capabilities/center-prompts.js +2 -3
- package/dist/capabilities/sandbox-file-send.d.ts +0 -2
- package/dist/capabilities/sandbox-file-send.js +2 -5
- package/dist/capabilities/scenarios.d.ts +0 -9
- package/dist/capabilities/scenarios.js +1 -20
- package/dist/capabilities/send-user-file-tool.js +3 -3
- package/dist/config-center/apply-effective.js +8 -8
- package/dist/config-center/types.d.ts +10 -3
- package/dist/config-provider.js +6 -11
- package/dist/config-types.d.ts +12 -26
- package/dist/config.js +95 -68
- package/dist/fleet/fleet-bus.js +25 -33
- package/dist/fleet-client.js +1 -1
- package/dist/http/active-run-conflict.d.ts +2 -0
- package/dist/http/active-run-conflict.js +1 -0
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +10 -96
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/fleet.js +4 -1
- package/dist/http/routes/images.js +10 -4
- package/dist/http/routes/runs.js +34 -49
- package/dist/http/routes/session-sync.d.ts +1 -1
- package/dist/http/routes/session-sync.js +2 -1
- package/dist/http/routes/tasks.js +7 -7
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/server.d.ts +1 -6
- package/dist/http/server.js +15 -10
- package/dist/http/verify-rounds.d.ts +2 -2
- package/dist/http/wire-types.d.ts +1 -1
- package/dist/images/bake-validate.d.ts +0 -22
- package/dist/images/bake-validate.js +0 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -5
- package/dist/main.js +5 -9
- package/dist/memory-scope.js +2 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +6 -4
- package/dist/orchestration/workflow-completion-inbox.js +6 -4
- package/dist/plugins/breaker-state-sql.d.ts +2 -3
- package/dist/plugins/image-index-sql.d.ts +0 -1
- package/dist/plugins/image-index-sql.js +0 -1
- package/dist/plugins/local-checkpoint-store.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.js +1 -1
- package/dist/plugins/memory-engine-pg.js +2 -1
- package/dist/plugins/memory-engine-tidb.js +1 -1
- package/dist/plugins/memory-engine-vector-util.d.ts +2 -3
- package/dist/plugins/memory-engine-vector-util.js +2 -3
- package/dist/plugins/memory-run-store.d.ts +1 -1
- package/dist/plugins/memory-session-policy-store.d.ts +1 -1
- package/dist/plugins/memory-session-policy-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +1 -1
- package/dist/plugins/pg-pool.js +8 -10
- package/dist/plugins/pg-rate-limiter.d.ts +1 -4
- package/dist/plugins/pg-rate-limiter.js +0 -1
- package/dist/plugins/roster-store-sql.d.ts +1 -3
- package/dist/plugins/roster-store-sql.js +3 -5
- package/dist/plugins/store-backend.d.ts +7 -17
- package/dist/plugins/store-backend.js +14 -30
- package/dist/plugins/tidb-pool.js +4 -28
- package/dist/plugins/workflow-journal-store-sql.d.ts +1 -1
- package/dist/plugins/workflow-journal-store-sql.js +1 -1
- package/dist/principal-jwt.js +2 -2
- package/dist/prompts-domain-validate.d.ts +4 -3
- package/dist/prompts-domain-validate.js +7 -8
- package/dist/router/route-orchestration.js +3 -3
- package/dist/run-local.js +5 -4
- package/dist/runs.js +8 -6
- package/dist/runtime-caps-resolver.d.ts +3 -2
- package/dist/runtime-caps-resolver.js +4 -4
- package/dist/runtime-governance.d.ts +4 -7
- package/dist/runtime-governance.js +12 -17
- package/dist/sealed-key.d.ts +1 -1
- package/dist/sealed-key.js +1 -1
- package/dist/security.d.ts +0 -5
- package/dist/security.js +8 -12
- package/dist/session-sync.d.ts +0 -2
- package/dist/session-sync.js +10 -17
- package/dist/spec-fields.js +6 -6
- package/dist/task-settings.js +7 -7
- package/dist/tool-approval.d.ts +3 -3
- package/dist/tool-approval.js +10 -10
- package/dist/trace/artifacts.d.ts +11 -0
- package/dist/trace/artifacts.js +8 -19
- package/dist/trace/ledger-sink.js +7 -1
- package/dist/trace/project.d.ts +17 -0
- package/dist/trace/project.js +55 -5
- package/package.json +2 -2
- package/dist/capabilities/oa-tools.d.ts +0 -15
- package/dist/capabilities/oa-tools.js +0 -54
- package/dist/plugins/approval-store-sql.d.ts +0 -116
- package/dist/plugins/approval-store-sql.js +0 -150
- package/dist/plugins/file-workflow-journal-store.d.ts +0 -12
- package/dist/plugins/file-workflow-journal-store.js +0 -12
- package/dist/plugins/pg-approval-store.d.ts +0 -9
- package/dist/plugins/pg-approval-store.js +0 -9
- package/dist/plugins/pg-breaker-state.d.ts +0 -8
- package/dist/plugins/pg-breaker-state.js +0 -8
- package/dist/plugins/pg-checkpoint-store.d.ts +0 -10
- package/dist/plugins/pg-checkpoint-store.js +0 -10
- package/dist/plugins/pg-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/pg-file-snapshot-store.js +0 -8
- package/dist/plugins/pg-image-bake.d.ts +0 -12
- package/dist/plugins/pg-image-bake.js +0 -11
- package/dist/plugins/pg-image-index.d.ts +0 -12
- package/dist/plugins/pg-image-index.js +0 -11
- package/dist/plugins/pg-outcome-ledger.d.ts +0 -12
- package/dist/plugins/pg-outcome-ledger.js +0 -11
- package/dist/plugins/pg-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/pg-resume-anchor-store.js +0 -7
- package/dist/plugins/pg-run-store.d.ts +0 -9
- package/dist/plugins/pg-run-store.js +0 -9
- package/dist/plugins/pg-session-policy-store.d.ts +0 -7
- package/dist/plugins/pg-session-policy-store.js +0 -7
- package/dist/plugins/pg-session-store.d.ts +0 -12
- package/dist/plugins/pg-session-store.js +0 -12
- package/dist/plugins/pg-tool-result-store.d.ts +0 -9
- package/dist/plugins/pg-tool-result-store.js +0 -9
- package/dist/plugins/pg-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-journal-store.js +0 -9
- package/dist/plugins/pg-workflow-run-store.d.ts +0 -9
- package/dist/plugins/pg-workflow-run-store.js +0 -9
- package/dist/plugins/tidb-approval-store.d.ts +0 -8
- package/dist/plugins/tidb-approval-store.js +0 -8
- package/dist/plugins/tidb-breaker-state.d.ts +0 -7
- package/dist/plugins/tidb-breaker-state.js +0 -7
- package/dist/plugins/tidb-checkpoint-store.d.ts +0 -9
- package/dist/plugins/tidb-checkpoint-store.js +0 -9
- package/dist/plugins/tidb-file-snapshot-store.d.ts +0 -8
- package/dist/plugins/tidb-file-snapshot-store.js +0 -8
- package/dist/plugins/tidb-image-bake.d.ts +0 -12
- package/dist/plugins/tidb-image-bake.js +0 -11
- package/dist/plugins/tidb-image-index.d.ts +0 -12
- package/dist/plugins/tidb-image-index.js +0 -11
- package/dist/plugins/tidb-outcome-ledger.d.ts +0 -12
- package/dist/plugins/tidb-outcome-ledger.js +0 -12
- package/dist/plugins/tidb-resume-anchor-store.d.ts +0 -7
- package/dist/plugins/tidb-resume-anchor-store.js +0 -7
- package/dist/plugins/tidb-run-store.d.ts +0 -10
- package/dist/plugins/tidb-run-store.js +0 -9
- package/dist/plugins/tidb-session-policy-store.d.ts +0 -7
- package/dist/plugins/tidb-session-policy-store.js +0 -7
- package/dist/plugins/tidb-tool-result-store.d.ts +0 -8
- package/dist/plugins/tidb-tool-result-store.js +0 -10
- package/dist/plugins/tidb-workflow-journal-store.d.ts +0 -9
- package/dist/plugins/tidb-workflow-journal-store.js +0 -9
- package/dist/plugins/tidb-workflow-run-store.d.ts +0 -10
- package/dist/plugins/tidb-workflow-run-store.js +0 -10
- package/dist/plugins/workflow-journal-limits.d.ts +0 -12
- package/dist/plugins/workflow-journal-limits.js +0 -12
package/USAGE.md
CHANGED
|
@@ -97,7 +97,9 @@ MAX_PRINCIPAL_COST_USD=5.00 COST_QUOTA_WINDOW_SEC=86400 # 0/不设 = 不限;
|
|
|
97
97
|
MODEL_DEGRADE_TO=deepseek-v4-flash
|
|
98
98
|
MODEL_DEGRADE_AT_COST_FRACTION=0.7 # ① 近预算(1.40):累计成本到 0.7×maxCostUsd 切(需任务有 cost ceiling)
|
|
99
99
|
MODEL_DEGRADE_REACTIVE=true # ② 反应式(1.39):主模型 rate_limit/breaker-open 时切(brain 级,最外层)
|
|
100
|
-
MODEL_DEGRADE_ON=rate_limit,breaker_open #
|
|
100
|
+
MODEL_DEGRADE_ON=rate_limit,breaker_open # 可选,反应式触发器子集;词表=breaker_open|rate_limit|budget|server_error|last_resort
|
|
101
|
+
# ⚠️ core 5.1.0 起,不设 MODEL_DEGRADE_ON 时引擎默认**含 server_error**(主模型 5xx 也切便宜模型)。
|
|
102
|
+
# 不想要 5xx 触发就显式设回 rate_limit,breaker_open。拼错词 boot 拒启(不静默忽略)。
|
|
101
103
|
```
|
|
102
104
|
- 反应式降级 brain 包在**最外层**(core council #8);fallback brain 用自己的凭据(decorator 清掉主模型的 per-call key 防泄漏给别的 provider)。**坑**:`MODEL_DEGRADE_TO` 最好别和被限流的是同一网关/账号,否则反应式切过去照样撞同一个 rate_limit。
|
|
103
105
|
- **定价怎么设**:`model.cost` 来自 `MODEL_COST_INPUT/OUTPUT/CACHE_READ/CACHE_WRITE`(**USD per 1M tokens**,默认 0 = `costUsd` 读 0)。云模型(如 review-gw 的 deepseek-v4-pro)必须设,否则 spend 恒为 $0;本地自托管(qwen)留 0 即对(无 per-token 外部花费)。字段名是 `costUsd`,**非美元计价的网关要先折算**(如 DeepSeek 官方 CNY ÷ 汇率)。配置控制面管的模型走 `CenterModel.cost`(中心存价、不存 secret)。
|
|
@@ -373,8 +375,8 @@ curl -N http://<host>:8090/v1/tasks/stream -H 'content-type: application/json' \
|
|
|
373
375
|
| 端点 | 用途 |
|
|
374
376
|
|---|---|
|
|
375
377
|
| `GET /v1/sessions/<id>` | 审计回溯:当前上下文 + 摘要(owner 校验) |
|
|
376
|
-
| `GET /v1/approvals?owner=user:42` |
|
|
377
|
-
| `POST /v1/approvals/<
|
|
378
|
+
| `GET /v1/approvals?owner=user:42` | 高危写审批(durable,需 `DURABLE_APPROVAL=true`):**operator** 看待办队列(可按 owner 过滤);非 operator 只看自己的 |
|
|
379
|
+
| `POST /v1/approvals/<sessionId>/decide` `{"decision":"approve"|"deny","reason":"…"}` | 批/否并恢复挂起任务(CAS,重复决议 409);**仅 operator**(非 operator → 403)。5.0.0 起旧轮询腿 `POST /v1/approvals/<id>` 已退役 |
|
|
378
380
|
| `GET /health` | 健康(无需鉴权) |
|
|
379
381
|
| `GET /metrics` | Prometheus 指标(有 token 时需带) |
|
|
380
382
|
|
package/dist/approval-hmac.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* design/80 D-G: approval-envelope HMAC (INTEGRITY, not identity). Split out of `security.ts` (design/158
|
|
3
|
-
* A13
|
|
3
|
+
* A13; consumers import from HERE — [2354] cleared the security.ts compat re-exports; verifyDirectDoorProof in
|
|
4
4
|
* ./principal-jwt.ts imports {@link verifyApprovalHmac} from here for the combined proof).
|
|
5
5
|
*
|
|
6
6
|
* ✅ WIRED into the resolve path (was "🔴 SCAFFOLD — NOT YET WIRED" — that claim went STALE; a 2026-07-25 doc-rot
|
package/dist/approval.d.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Built on core's `createApprovalPolicy` (which routes requireApproval/deny and races the wait against
|
|
6
|
-
* the task's AbortSignal). Our `approve` records a pending row and polls it for a decision; it also
|
|
7
|
-
* honors the signal directly (marks the request expired and releases) so a never-answered approval is
|
|
8
|
-
* dropped at the task deadline instead of holding the worker — design/06 F4 self-protection.
|
|
2
|
+
* Human-in-the-loop approval gate (F4) — durable-only since 5.0.0 ([2354]/[2356] A-5:OA 轮询车道
|
|
3
|
+
* (createOaApprovalPolicy + ApprovalStore pending 行轮询)整体退役;唯一门形 = durable checkpoint
|
|
4
|
+
* suspend/resume,见 createDurableAskPolicy 与 /v1/approvals 的 checkpointStore 腿)。
|
|
9
5
|
*/
|
|
10
6
|
import { type ToolPolicy } from "@sema-agent/core";
|
|
11
|
-
import type { ApprovalStore } from "./plugins/store-backend.js";
|
|
12
7
|
/**
|
|
13
8
|
* 运维**是否表达了门意图** —— boot 的单用户 allow-all 基线只在"零门意图"时才允许铺开,
|
|
14
9
|
* 所以这个谓词漏一格 = 那一格的意图被 allow-all 静默吞掉。
|
|
@@ -33,7 +28,8 @@ export declare function hasOperatorGateIntent(config: {
|
|
|
33
28
|
* Durable approval policy (core 1.67 / design/45): returns three-state **`ask`** for gated tools instead of
|
|
34
29
|
* polling. With `TaskSpec.durableApproval` set + a `checkpointStore` on the Runner, core turns that `ask` into
|
|
35
30
|
* a **suspend** (persists a checkpoint, ends `status:"suspended"`) — no held connection, resumable on any
|
|
36
|
-
* replica. (
|
|
31
|
+
* replica. (The former poll-lane
|
|
32
|
+
* twin, createOaApprovalPolicy, was retired in 5.0.0 — durable is the only gate.)
|
|
37
33
|
*/
|
|
38
34
|
export interface DurableAskOptions {
|
|
39
35
|
requireApproval: string[];
|
|
@@ -48,32 +44,4 @@ export interface DurableAskOptions {
|
|
|
48
44
|
onExempted?: (canonicalToolName: string, rawToolName: string) => void;
|
|
49
45
|
}
|
|
50
46
|
export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
|
|
51
|
-
export interface OaApprovalOptions {
|
|
52
|
-
store: ApprovalStore;
|
|
53
|
-
/** Tool names that require an operator decision before they run. */
|
|
54
|
-
requireApproval: string[];
|
|
55
|
-
/** Safety tools that must ALWAYS reach a human — checked BEFORE the exemption probe (workflow audit
|
|
56
|
-
* 2026-07-13: the OA leg consumed exemptions without the neverAuto guard, so a grant made in durable mode
|
|
57
|
-
* could silently auto-approve a NEVER_AUTO tool after an ops switch back to the poll gate). */
|
|
58
|
-
neverAuto?: string[];
|
|
59
|
-
/** Session exemption probe — same contract as createDurableAskPolicy.exempt (fail-closed). */
|
|
60
|
-
exempt?: (sessionId: string, canonicalToolName: string) => Promise<boolean>;
|
|
61
|
-
/** Audit hook for an exemption short-circuit. */
|
|
62
|
-
onExempted?: (sessionId: string, canonicalToolName: string) => void;
|
|
63
|
-
/** Per-run context captured for the approval row (operator UI shows session/tool/args). */
|
|
64
|
-
context: () => {
|
|
65
|
-
taskId?: string | null;
|
|
66
|
-
sessionId?: string | null;
|
|
67
|
-
owner?: string | null;
|
|
68
|
-
};
|
|
69
|
-
/** Always-denied tools. */
|
|
70
|
-
deny?: string[];
|
|
71
|
-
/** Poll interval for the decision. Default 1500ms. */
|
|
72
|
-
pollMs?: number;
|
|
73
|
-
}
|
|
74
|
-
export declare function createOaApprovalPolicy(opts: OaApprovalOptions): ToolPolicy;
|
|
75
|
-
/** Poll the approval row until decided, or release (deny) when the task aborts. Exported for unit tests.
|
|
76
|
-
* `scope` is the run's tenant identity (owner-sourced) — carried on every read/decide so a run only ever
|
|
77
|
-
* observes/aborts its OWN pending row (single-DB fleet read guard; defense-in-depth). */
|
|
78
|
-
export declare function waitForDecision(store: ApprovalStore, id: string, scope: string | null, signal: AbortSignal | undefined, pollMs: number): Promise<boolean>;
|
|
79
47
|
//# sourceMappingURL=approval.d.ts.map
|
package/dist/approval.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Built on core's `createApprovalPolicy` (which routes requireApproval/deny and races the wait against
|
|
6
|
-
* the task's AbortSignal). Our `approve` records a pending row and polls it for a decision; it also
|
|
7
|
-
* honors the signal directly (marks the request expired and releases) so a never-answered approval is
|
|
8
|
-
* dropped at the task deadline instead of holding the worker — design/06 F4 self-protection.
|
|
2
|
+
* Human-in-the-loop approval gate (F4) — durable-only since 5.0.0 ([2354]/[2356] A-5:OA 轮询车道
|
|
3
|
+
* (createOaApprovalPolicy + ApprovalStore pending 行轮询)整体退役;唯一门形 = durable checkpoint
|
|
4
|
+
* suspend/resume,见 createDurableAskPolicy 与 /v1/approvals 的 checkpointStore 腿)。
|
|
9
5
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import { createLogger } from "./observability/logger.js";
|
|
12
|
-
const logger = createLogger();
|
|
6
|
+
import {} from "@sema-agent/core";
|
|
13
7
|
/**
|
|
14
8
|
* 运维**是否表达了门意图** —— boot 的单用户 allow-all 基线只在"零门意图"时才允许铺开,
|
|
15
9
|
* 所以这个谓词漏一格 = 那一格的意图被 allow-all 静默吞掉。
|
|
@@ -31,14 +25,13 @@ export function hasOperatorGateIntent(config) {
|
|
|
31
25
|
config.durableApproval);
|
|
32
26
|
}
|
|
33
27
|
export function createDurableAskPolicy(opts) {
|
|
34
|
-
// 🔒
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const neverAuto = new Set((opts.neverAuto ?? []).map(canonicalToolName));
|
|
28
|
+
// 🔒 RAW-name matching(core 5.0.0 RB-476:canonicalToolName 折叠面整体退役)。安全前提没有变松,
|
|
29
|
+
// 只是换了执行者:live 请求名恒为 CC canonical(旧名在 core roster 层响亮 miss,永远到不了本 policy);
|
|
30
|
+
// 配置侧写了退役名 = core prepare 硬失败 `config.legacy_tool_name`(+ 本仓 config 装配墓碑先一步拒启)。
|
|
31
|
+
// 旧的双侧归一防的「旧名滑过新名规则」在 5.0.0 下无成立路径——折叠臂留着才是静默兼容层。
|
|
32
|
+
const require = new Set(opts.requireApproval);
|
|
33
|
+
const deny = new Set(opts.deny ?? []);
|
|
34
|
+
const neverAuto = new Set(opts.neverAuto ?? []);
|
|
42
35
|
const budget = Math.max(0, Math.floor(opts.autoBudget ?? 0));
|
|
43
36
|
// design/80 D-E (upgrade-budget): a per-run-leg counter of NORMAL gated calls auto-approved so far. The policy
|
|
44
37
|
// is rebuilt per resolveSpec call (= per submit AND per resume — server.ts), so this closure is per-leg —
|
|
@@ -47,7 +40,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
47
40
|
let autoApproved = 0;
|
|
48
41
|
return {
|
|
49
42
|
check: (req) => {
|
|
50
|
-
const toolName =
|
|
43
|
+
const toolName = req.toolName; // RAW(5.0.0):live 名恒 canonical,折叠面已随 core RB-476 退役
|
|
51
44
|
if (deny.has(toolName))
|
|
52
45
|
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
53
46
|
// inv#2: a never-auto (irreversible / safety) tool ALWAYS asks a human — UNCONDITIONALLY, even if it was not
|
|
@@ -120,97 +113,4 @@ export function createDurableAskPolicy(opts) {
|
|
|
120
113
|
return { action: "ask", message: `approval required to run "${req.toolName}"` };
|
|
121
114
|
}
|
|
122
115
|
}
|
|
123
|
-
export function createOaApprovalPolicy(opts) {
|
|
124
|
-
const pollMs = opts.pollMs ?? 1500;
|
|
125
|
-
const neverAuto = new Set((opts.neverAuto ?? []).map(canonicalToolName));
|
|
126
|
-
return createApprovalPolicy({
|
|
127
|
-
requireApproval: opts.requireApproval,
|
|
128
|
-
deny: opts.deny,
|
|
129
|
-
approve: async (req, signal) => {
|
|
130
|
-
const ctx = opts.context();
|
|
131
|
-
// Session exemption — core already routed deny (deny wins before approve is ever called);
|
|
132
|
-
// a remembered (sessionId, toolName) auto-approves without a pending row. Fail-closed on a store error.
|
|
133
|
-
// neverAuto ALWAYS wins the exemption (same ordering lock as the durable policy — the OA leg previously
|
|
134
|
-
// lacked this guard, workflow audit 2026-07-13).
|
|
135
|
-
if (opts.exempt && ctx.sessionId) {
|
|
136
|
-
const toolName = canonicalToolName(req.toolName);
|
|
137
|
-
if (toolName !== "AskUserQuestion" && !neverAuto.has(toolName)) {
|
|
138
|
-
let exempted = false;
|
|
139
|
-
try {
|
|
140
|
-
exempted = (await opts.exempt(ctx.sessionId, toolName)) === true; // strict boolean, same as the durable twin
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
exempted = false;
|
|
144
|
-
}
|
|
145
|
-
if (exempted) {
|
|
146
|
-
opts.onExempted?.(ctx.sessionId, toolName);
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
const id = uuidv7();
|
|
152
|
-
// scope = the run's tenant identity, owner-sourced (single-DB fleet read guard; defense-in-depth). The
|
|
153
|
-
// poll/abort paths below carry the SAME scope so this run only ever reads/aborts its own pending row.
|
|
154
|
-
const scope = ctx.owner ?? null;
|
|
155
|
-
await opts.store.createPending(id, scope, { ...ctx, toolName: req.toolName, args: req.args });
|
|
156
|
-
return waitForDecision(opts.store, id, scope, signal, pollMs);
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
/** Consecutive poll errors tolerated before giving up (a persistent outage still fail-closes to deny). */
|
|
161
|
-
const MAX_POLL_ERRORS = 5;
|
|
162
|
-
/** Poll the approval row until decided, or release (deny) when the task aborts. Exported for unit tests.
|
|
163
|
-
* `scope` is the run's tenant identity (owner-sourced) — carried on every read/decide so a run only ever
|
|
164
|
-
* observes/aborts its OWN pending row (single-DB fleet read guard; defense-in-depth). */
|
|
165
|
-
export async function waitForDecision(store, id, scope, signal, pollMs) {
|
|
166
|
-
let consecutiveErrors = 0;
|
|
167
|
-
for (;;) {
|
|
168
|
-
if (signal?.aborted) {
|
|
169
|
-
// C1(failloud):最小对症=失败留痕,不必重试——这是最后一次尝试把行标 expired,任务本身已经在
|
|
170
|
-
// abort 路径上收尾,重试没有下一个时机。裸吞会让一次真实的店写故障(TiDB blip)在观测面上
|
|
171
|
-
// 与"成功标了 expired"毫无区别;补 error 留痕,行为(deny)不变。
|
|
172
|
-
await store.decide(id, scope, "expired", "task aborted before decision", null).catch((e) => {
|
|
173
|
-
logger.error("approval_expire_write_failed", { id, scope, err: e instanceof Error ? e.message : String(e) });
|
|
174
|
-
});
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
let s;
|
|
178
|
-
try {
|
|
179
|
-
s = await store.getStatus(id, scope);
|
|
180
|
-
consecutiveErrors = 0;
|
|
181
|
-
}
|
|
182
|
-
catch (e) {
|
|
183
|
-
// A single transient TiDB blip must NOT throw out of the poll loop — core fail-closes a thrown
|
|
184
|
-
// approval policy to DENY, so one hiccup would deny an already-approved high-risk call after the
|
|
185
|
-
// operator clicked approve. Tolerate a few consecutive errors (keep polling); only give up (re-throw →
|
|
186
|
-
// deny) on a persistent outage.
|
|
187
|
-
if (++consecutiveErrors >= MAX_POLL_ERRORS)
|
|
188
|
-
throw e;
|
|
189
|
-
await sleepAbortable(pollMs, signal);
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
if (s?.status === "approved")
|
|
193
|
-
return true;
|
|
194
|
-
if (s?.status === "denied" || s?.status === "expired")
|
|
195
|
-
return false;
|
|
196
|
-
await sleepAbortable(pollMs, signal);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
function sleepAbortable(ms, signal) {
|
|
200
|
-
return new Promise((resolve) => {
|
|
201
|
-
if (signal?.aborted) {
|
|
202
|
-
resolve();
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
const onAbort = () => {
|
|
206
|
-
clearTimeout(timer);
|
|
207
|
-
resolve();
|
|
208
|
-
};
|
|
209
|
-
const timer = setTimeout(() => {
|
|
210
|
-
signal?.removeEventListener("abort", onAbort);
|
|
211
|
-
resolve();
|
|
212
|
-
}, ms);
|
|
213
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
116
|
//# sourceMappingURL=approval.js.map
|
package/dist/auth-bridge.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { type AuthBridgeErrorCode, type VerifiedIdentity } from "@sema-agent/reg
|
|
|
2
2
|
import type { Logger } from "./observability/logger.js";
|
|
3
3
|
import type { Metrics } from "./observability/metrics.js";
|
|
4
4
|
export type { VerifiedIdentity } from "@sema-agent/registry-core/api/auth-bridge";
|
|
5
|
-
export { looksLikeJwt } from "@sema-agent/registry-core/api/auth-bridge";
|
|
6
5
|
export interface RegistryJwtVerifierOptions {
|
|
7
6
|
/** R4 — 期望 iss(registry 的 SSO_ISSUER;默认=SEMA_REGISTRY_URL,双侧去尾斜杠比较)。 */
|
|
8
7
|
issuer: string;
|
package/dist/auth-bridge.js
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
13
13
|
import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, REGISTRY_JWKS_PATH, RegistryJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/registry-core/api/auth-bridge";
|
|
14
|
-
export { looksLikeJwt } from "@sema-agent/registry-core/api/auth-bridge";
|
|
15
14
|
const DEFAULT_JWKS_TTL_SEC = 15 * 60;
|
|
16
15
|
/** JWKS 响应体字节上限(一个配错或超大响应的端点不应让 worker 无界缓冲;正常 JWKS 千字节级)。 */
|
|
17
16
|
const MAX_JWKS_BYTES = 256 * 1024;
|
package/dist/auth-keys.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
|
|
6
6
|
* security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
|
|
7
7
|
* leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
|
|
8
|
-
* (verifyApprovalHmac / verifyPrincipalJwt) stay in
|
|
8
|
+
* (verifyApprovalHmac / verifyPrincipalJwt) stay in ./approval-hmac.ts and ./principal-jwt.ts; consumers import these four names from HERE ([2354] 兼容面全清).
|
|
9
9
|
*/
|
|
10
10
|
/** One key in the rotating HMAC key-set. `kid` lets the verifier pick the signing key (or fall back to trying the
|
|
11
11
|
* whole set); `status` lets sema-registry rotate without breaking in-flight approvals: `active` = sign + verify,
|
package/dist/auth-keys.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* IDENTITY). config.ts consumes ONLY these two functions + their row types at env-load time, and importing them from
|
|
6
6
|
* security.ts made the base config layer value-depend on the whole 55KiB auth module (lens2 §F). This file is a pure
|
|
7
7
|
* leaf (JSON.parse + shape filters, zero repo imports); the VERIFIERS that consume the parsed key-sets
|
|
8
|
-
* (verifyApprovalHmac / verifyPrincipalJwt) stay in
|
|
8
|
+
* (verifyApprovalHmac / verifyPrincipalJwt) stay in ./approval-hmac.ts and ./principal-jwt.ts; consumers import these four names from HERE ([2354] 兼容面全清).
|
|
9
9
|
*/
|
|
10
10
|
/** Parse APPROVAL_HMAC_KEYS — a sema-registry-managed, rotating key-SET, as a JSON array of {kid,key,status}.
|
|
11
11
|
* Empty / unset / unparseable ⇒ `[]` ⇒ HMAC verification is OFF (D-G inactive; back-compat, BFF-only door). */
|
|
@@ -278,7 +278,7 @@ function dryRunMockFactory() {
|
|
|
278
278
|
sessionId: `dry-${String(seed)}`,
|
|
279
279
|
status: "completed",
|
|
280
280
|
result: "DONE",
|
|
281
|
-
stats: { turns: 3, tokens: 1200, costMicroUsd: 50_000,
|
|
281
|
+
stats: { turns: 3, tokens: 1200, costMicroUsd: 50_000, nested: { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0 }, ...stats },
|
|
282
282
|
verification: { verdict: green ? "PASS" : "FAIL", rounds: 1, findings: [] },
|
|
283
283
|
};
|
|
284
284
|
const deps = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CenterPromptSource } from "@sema-agent/core";
|
|
2
2
|
import { buildPricing } from "../budget.js";
|
|
3
|
-
import { type PromptsDomainFaces } from "../
|
|
3
|
+
import { type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
4
4
|
import { type Scenario, type ScenarioDeps, type ScenarioDetail } from "../capabilities/scenarios.js";
|
|
5
5
|
import type { LoadedSkill } from "../capabilities/skills.js";
|
|
6
6
|
import { type ServiceConfig } from "../config.js";
|
|
@@ -38,7 +38,8 @@ import { skillContentHash } from "@sema-agent/registry-core";
|
|
|
38
38
|
import { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, } from "@sema-agent/core";
|
|
39
39
|
import { buildPricing } from "../budget.js";
|
|
40
40
|
import { applyCenterPlugins } from "../capabilities/center-plugins.js";
|
|
41
|
-
import {
|
|
41
|
+
import { applyCatalogToSource, withPromptArtifactBackfill } from "../capabilities/center-prompts.js";
|
|
42
|
+
import { validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
42
43
|
import { centerScenarios, centerScenarioDetails } from "../capabilities/scenarios.js";
|
|
43
44
|
import { configLkgEnabled } from "../config.js";
|
|
44
45
|
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "../config-lkg.js";
|
|
@@ -104,7 +105,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
104
105
|
sealedKeys = await ensureSealedKeyStore(join(config.localDataRoot ?? localRoot, "sealed-key"), logger);
|
|
105
106
|
void reportExecutionPublicKey({
|
|
106
107
|
baseUrl: cc?.baseUrl,
|
|
107
|
-
adminToken: process.env.SEMA_REGISTRY_ADMIN_TOKEN
|
|
108
|
+
adminToken: process.env.SEMA_REGISTRY_ADMIN_TOKEN, // [2373]B-1:REGISTRY_ADMIN_TOKEN 双读已墓碑(在场即拒启)
|
|
108
109
|
key: sealedKeys.latest,
|
|
109
110
|
...(cc?.worker ? { notes: `worker ${cc.worker}` } : {}),
|
|
110
111
|
logger,
|
package/dist/boot/reapers.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ import type { Logger } from "../observability/logger.js";
|
|
|
20
20
|
import type { Metrics } from "../observability/metrics.js";
|
|
21
21
|
import type { WorkflowNotifyGate, WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
|
|
22
22
|
import type { TaskAttachmentStore } from "../plugins/task-attachment-store.js";
|
|
23
|
-
import type {
|
|
23
|
+
import type { CheckpointStoreFull, CostQuotaStore, ImageBake, RateLimiterStore, ServiceWorkflowJournalStore, StoreBackend, ToolResultStoreFull } from "../plugins/store-backend.js";
|
|
24
24
|
export interface ReapersCtx {
|
|
25
25
|
config: ServiceConfig;
|
|
26
26
|
logger: Logger;
|
|
@@ -30,7 +30,6 @@ export interface ReapersCtx {
|
|
|
30
30
|
subRunner: Runner;
|
|
31
31
|
runStore: ReturnType<StoreBackend["run"]> | undefined;
|
|
32
32
|
checkpointStore: CheckpointStoreFull | undefined;
|
|
33
|
-
approvalStore: ApprovalStore | undefined;
|
|
34
33
|
rateLimiter: RateLimiter | RateLimiterStore | undefined;
|
|
35
34
|
costQuota: CostQuota | CostQuotaStore | undefined;
|
|
36
35
|
toolResultStore: ToolResultStoreFull | undefined;
|
package/dist/boot/reapers.js
CHANGED
|
@@ -17,7 +17,7 @@ import { sweepStaleScratchpads } from "../env-facts.js";
|
|
|
17
17
|
import { CostQuota } from "../observability/cost-quota.js";
|
|
18
18
|
/** 起后台维护 tick,返回定时器 handle(收尾段 clearInterval 用)。 */
|
|
19
19
|
export function startReapers(ctx) {
|
|
20
|
-
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore,
|
|
20
|
+
const { config, logger, metrics, localRoot, backend, subRunner, runStore, checkpointStore, rateLimiter, costQuota, toolResultStore, fileSnapshotStore, taskAttachmentStore, imageBakes, worktreeReap, workflowNotifyGate, workflowJournalStore, sqlWorkflowRunStore, workflowNotifyJournal, rosterStore, backgroundAgentStore, mailboxStore, getRunDenySweep, } = ctx;
|
|
21
21
|
// S7 (SILENT-FALLBACK P0-d): the sweeps' return counts were discarded — an instance death that batch-fails
|
|
22
22
|
// N orphans was indistinguishable from organic failures. Count + log ONLY when a sweep flipped rows (>0),
|
|
23
23
|
// so healthy ticks stay silent. Tolerant of void-returning stores (typeof guard).
|
|
@@ -137,11 +137,10 @@ export function startReapers(ctx) {
|
|
|
137
137
|
// continues with the denial), vs the abort reapExpired gives the other kinds. Bounded per tick.
|
|
138
138
|
void getRunDenySweep()?.(Date.now()).catch(() => undefined); // A10 搬运改写:晚绑取值(原 `runDenySweep?.`)
|
|
139
139
|
}
|
|
140
|
-
// The finer, OPT-IN
|
|
141
|
-
//
|
|
142
|
-
//
|
|
140
|
+
// The finer, OPT-IN time-based suspended-run reaper (APPROVAL_TIMEOUT_SEC). Stays gated — reapSuspended
|
|
141
|
+
// with a 0 TTL would nuke ALL suspended rows (cutoff = now). The absolute backstop above is the safety
|
|
142
|
+
// floor; this is the operator-chosen deadline. ([2354] A-5:F4 轮询店的 expireStale 腿随车道退役。)
|
|
143
143
|
if (config.approvalTimeoutSec > 0) {
|
|
144
|
-
void approvalStore?.expireStale(config.approvalTimeoutSec * 1000).catch(() => undefined);
|
|
145
144
|
void runStore?.reapSuspended(config.approvalTimeoutSec * 1000).then(reapCount("runs_reaped_total", { kind: "suspended" })).catch(() => undefined);
|
|
146
145
|
}
|
|
147
146
|
// GC checkpoint_ctx rows whose checkpoint is gone (bound to the checkpoint lifecycle).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MemoryBackend, type RunnerDeps } from "@sema-agent/core";
|
|
2
|
-
import {
|
|
2
|
+
import type { PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
3
3
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
4
4
|
import { sendUserFileTool } from "../capabilities/send-user-file-tool.js";
|
|
5
5
|
import { selectScenario } from "../capabilities/scenarios.js";
|
|
@@ -56,8 +56,6 @@ export interface ResolveSpecCtx {
|
|
|
56
56
|
} | undefined;
|
|
57
57
|
durableEnabled: boolean;
|
|
58
58
|
approvalExemptionStore: ReturnType<StoreBackend["approvalExemption"]> | undefined;
|
|
59
|
-
approvalEnabled: boolean | undefined;
|
|
60
|
-
approvalStore: ReturnType<NonNullable<StoreBackend["approval"]>> | undefined;
|
|
61
59
|
singleUserAutoAcceptBaseline: boolean;
|
|
62
60
|
checkpointStore: ReturnType<NonNullable<StoreBackend["checkpoint"]>> | undefined;
|
|
63
61
|
deploymentHooks: NonNullable<RunnerDeps["hooks"]>;
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import { realpathSync } from "node:fs";
|
|
21
21
|
import { join } from "node:path";
|
|
22
22
|
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, combinePolicies, createAllowDenyPolicy, createDurableQuestionPolicy, expandTiers, tightenTaskSpec } from "@sema-agent/core";
|
|
23
|
-
import {
|
|
23
|
+
import { createDurableAskPolicy } from "../approval.js";
|
|
24
24
|
import { cappedCeiling } from "../budget.js";
|
|
25
25
|
import { centerPromptProvider, centerIdentityAssembled } from "../capabilities/center-prompts.js";
|
|
26
26
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
@@ -39,7 +39,8 @@ import { resourceSuspendOptIn } from "../resource-suspend.js";
|
|
|
39
39
|
import { isIsolatedExecEnv, routeServiceTask, supPostureOverrides } from "../router/route-orchestration.js";
|
|
40
40
|
import { gateExecutionLane } from "../runtime-caps-resolver.js";
|
|
41
41
|
import { applyRuntimeGovernance, stripDelegationTools } from "../runtime-governance.js";
|
|
42
|
-
import { HttpError,
|
|
42
|
+
import { HttpError, encodeCheckpointScope } from "../security.js";
|
|
43
|
+
import { memorySpecForRequest } from "../memory-scope.js";
|
|
43
44
|
import { mcpForScenario } from "../config-center/facade.js";
|
|
44
45
|
import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, normalizeSuggestNextPrompts, promptProfileFromBody, resolveTaskLimits, retainBackgroundProcessesFromBody, taskAgentsSpecFragment, toolNameListFromBody } from "../spec-fields.js";
|
|
45
46
|
import { cwdHonored, effectiveHostWorkspace, inProcessSingleUserLane, isValidCwd, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
|
|
@@ -48,7 +49,7 @@ import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, acceptAppendSystemPrompt, applyTaskSet
|
|
|
48
49
|
import { enableForkFromBody, normalizeRetainSubagentSessions, selfOrchestrationFromBody } from "../task-workflow.js";
|
|
49
50
|
import { redactSecrets } from "../trace/redact.js";
|
|
50
51
|
export function createResolveSpec(ctx) {
|
|
51
|
-
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore,
|
|
52
|
+
const { config, logger, metrics, localRoot, scenarios, principalCaps, centerRuntimeCapsResolver, getCenterPrompts, getKeyResolver, taskAttachmentStore, perSessionCwd, setSessionCwd, setSessionShellEnv, hookLlm, hookAgent, fleetBus, hookWakeBus, resumeAnchorStore, ownerAware, taskLimitCaps, taskTimeoutSec, selectEnvTool, sendUserFileToolSpec, memoryEngine, durableEnabled, approvalExemptionStore, singleUserAutoAcceptBaseline, checkpointStore, deploymentHooks, imageIndex, perTaskImage, sessionEnvSelection, } = ctx;
|
|
52
53
|
// Deployment-owned mapping. Tools/prompt/skills come from the selected scenario (assembled once,
|
|
53
54
|
// bound per request); identity/session/policy stay server-side. Never taken from the request body.
|
|
54
55
|
// design/158 A8:从 createHttpServer 实参里提出来(原地占该字面量 1,093 行中的 967 行)——
|
|
@@ -692,8 +693,9 @@ export function createResolveSpec(ctx) {
|
|
|
692
693
|
// provider 才不会各看一版(TOCTOU:门判安全、pick 到已组装包=core 侧静默丢 rider 复活)。
|
|
693
694
|
promptProvider: centerDecls ? centerPromptProvider(centerDecls, scenarioName) : cap.promptProvider,
|
|
694
695
|
// F4: high-risk write approval gate. DURABLE (design/45, opt-in): the gated `ask` SUSPENDS the task
|
|
695
|
-
// (durable checkpoint, resumable on any replica).
|
|
696
|
-
//
|
|
696
|
+
// (durable checkpoint, resumable on any replica). [2354]/[2356] A-5(5.0.0): the legacy POLL gate
|
|
697
|
+
// (createOaApprovalPolicy over ApprovalStore pending rows) is retired — durable is the ONLY gate; an
|
|
698
|
+
// operator with approval intent but no checkpointStore falls to `undefined` (core's UNGATED warning).
|
|
697
699
|
// Durable ask (TC-5.4, core 1.95): in durable mode an AskUserQuestion call suspends like an F4 gate —
|
|
698
700
|
// the question policy adjudicates it `ask`, the operator answers out-of-band, and the resume carries
|
|
699
701
|
// the QuestionAnswer (server.ts `body.answer` → onQuestion closure). Suspend side mounts the tool with
|
|
@@ -711,36 +713,20 @@ export function createResolveSpec(ctx) {
|
|
|
711
713
|
}
|
|
712
714
|
: {}),
|
|
713
715
|
}))
|
|
714
|
-
:
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
: {}),
|
|
729
|
-
})
|
|
730
|
-
: singleUserAutoAcceptBaseline
|
|
731
|
-
// 🔴 (live finding: single-user host-lane Bash ran UNGATED, no adjudication): a
|
|
732
|
-
// single-user turnkey worker with NO expressed gate intent previously left `toolPolicy` UNDEFINED →
|
|
733
|
-
// core's write-capable hand tools mount UNADJUDICATED (core error-logs it every task; host lane has NO
|
|
734
|
-
// sandbox to fall back on). CC's trust model is auto-accept, but the GATE MECHANISM must be PRESENT
|
|
735
|
-
// (core 原则: "机制留、默认可更宽 auto-accept"). So wire an adjudicated auto-accept BASELINE
|
|
736
|
-
// (`createAllowDenyPolicy({})` = a present, effect-aware policy that allows all): satisfies core's
|
|
737
|
-
// `hasEffectAwareGate`, restores observability + a hook/tighten point, and the operator STILL tightens
|
|
738
|
-
// irreversible ops via `AUTONOMY` / `commandPolicy` (layered TIGHTEN-ONLY by applyRuntimeGovernance).
|
|
739
|
-
// Interactive approval routed to the shell HITL = follow-on. 🔴 `singleUserAutoAcceptBaseline` requires
|
|
740
|
-
// ZERO gate intent — a single-user op who SET approval flags but wired no store falls to `undefined`
|
|
741
|
-
// (core warns = real misconfig, not masked); multi-tenant likewise stays `undefined` (approval required).
|
|
742
|
-
? createAllowDenyPolicy({})
|
|
743
|
-
: undefined,
|
|
716
|
+
: singleUserAutoAcceptBaseline
|
|
717
|
+
// 🔴 (live finding: single-user host-lane Bash ran UNGATED, no adjudication): a
|
|
718
|
+
// single-user turnkey worker with NO expressed gate intent previously left `toolPolicy` UNDEFINED →
|
|
719
|
+
// core's write-capable hand tools mount UNADJUDICATED (core error-logs it every task; host lane has NO
|
|
720
|
+
// sandbox to fall back on). CC's trust model is auto-accept, but the GATE MECHANISM must be PRESENT
|
|
721
|
+
// (core 原则: "机制留、默认可更宽 auto-accept"). So wire an adjudicated auto-accept BASELINE
|
|
722
|
+
// (`createAllowDenyPolicy({})` = a present, effect-aware policy that allows all): satisfies core's
|
|
723
|
+
// `hasEffectAwareGate`, restores observability + a hook/tighten point, and the operator STILL tightens
|
|
724
|
+
// irreversible ops via `AUTONOMY` / `commandPolicy` (layered TIGHTEN-ONLY by applyRuntimeGovernance).
|
|
725
|
+
// Interactive approval routed to the shell HITL = follow-on. 🔴 `singleUserAutoAcceptBaseline` requires
|
|
726
|
+
// ZERO gate intent — a single-user op who SET approval flags but wired no store falls to `undefined`
|
|
727
|
+
// (core warns = real misconfig, not masked); multi-tenant likewise stays `undefined` (approval required).
|
|
728
|
+
? createAllowDenyPolicy({})
|
|
729
|
+
: undefined,
|
|
744
730
|
// Durable suspend needs both the store (here, per-task) and the opt-in scope key (multi-tenant =
|
|
745
731
|
// principal; "_" when auth is off). core suspends on a policy `ask` only when these are present.
|
|
746
732
|
...(durableEnabled
|
package/dist/boot/stores.js
CHANGED
|
@@ -27,7 +27,7 @@ import { LocalTaskAttachmentStore } from "../plugins/local-task-attachment-store
|
|
|
27
27
|
import { PgTaskAttachmentStore, TiDBTaskAttachmentStore, ensurePgTaskAttachmentSchema, ensureTiDBTaskAttachmentSchema } from "../plugins/task-attachment-store.js";
|
|
28
28
|
import { createSessionStore } from "../plugins/session-store.js";
|
|
29
29
|
import { assertCloudSnapshotBlobPosture, openStoreBackendWithFallback } from "../plugins/store-backend.js";
|
|
30
|
-
import { memoryEngineBackendFor, memoryEngineRemoteLanePosture } from "../
|
|
30
|
+
import { memoryEngineBackendFor, memoryEngineRemoteLanePosture } from "../memory-scope.js";
|
|
31
31
|
export async function openStores(ctx) {
|
|
32
32
|
const { config, logger, metrics, localRoot } = ctx;
|
|
33
33
|
// One shared SQL store backend for L1 + L2 (TiDB/MySQL or PostgreSQL per DB_BACKEND). Owned here.
|
package/dist/brain.js
CHANGED
|
@@ -183,7 +183,9 @@ export function createBrain(config, deps = {}) {
|
|
|
183
183
|
fetchImpl,
|
|
184
184
|
...timeouts,
|
|
185
185
|
});
|
|
186
|
-
|
|
186
|
+
// core 5.1.0([2390]②):chain-of-one 链形;downgradeOn 缺席时 core 默认含 server_error(默认门
|
|
187
|
+
// 变宽)——MODEL_DEGRADE_ON 是运维收窄旋钮,词表验门在 config.ts parseDegradeOn。
|
|
188
|
+
brain = createDegradingBrain({ primary: brain, fallbacks: [{ brain: fallback, model: fallbackModel }], downgradeOn: config.degrade.downgradeOn });
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
return brain;
|
|
@@ -22,9 +22,8 @@
|
|
|
22
22
|
import { type PromptProvider, type PublishedPromptArtifactEnvelope } from "@sema-agent/core";
|
|
23
23
|
import { type EffectiveCenterPrompts, type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
24
24
|
/** 判形半场(validateCenterPrompts/validatePromptsDomain/CORE_ENGINE_VERSION 及两 interface)已下沉到
|
|
25
|
-
* 中立叶子 `src/prompts-domain-validate.ts`(design/158 S6
|
|
26
|
-
*
|
|
27
|
-
export { validateCenterPrompts, validatePromptsDomain, CORE_ENGINE_VERSION, type EffectiveCenterPrompts, type PromptsDomainFaces } from "../prompts-domain-validate.js";
|
|
25
|
+
* 中立叶子 `src/prompts-domain-validate.ts`(design/158 S6);消费者直引真源([2354] 兼容面全清,
|
|
26
|
+
* 此处兼容 re-export 已删)。 */
|
|
28
27
|
/** [985]b / [1285] — §9.4 by-digest 补拉组合店:local miss ⇒ fetchRaw(digest) 从 center 拉 envelope ⇒
|
|
29
28
|
* core verifyPromptArtifact 全管线 + **回验「拿到的=要的」digest 逐位**(center 答非所问=丢弃)⇒
|
|
30
29
|
* best-effort 回写 inner(下次直命中)。任何失败=undefined(诚实缺席,fail-loud 归 core 的
|
|
@@ -23,9 +23,8 @@ import { verifyPromptArtifact } from "@sema-agent/core";
|
|
|
23
23
|
import { CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
24
24
|
import { SHA256_HEX_RE } from "../digest-form.js";
|
|
25
25
|
/** 判形半场(validateCenterPrompts/validatePromptsDomain/CORE_ENGINE_VERSION 及两 interface)已下沉到
|
|
26
|
-
* 中立叶子 `src/prompts-domain-validate.ts`(design/158 S6
|
|
27
|
-
*
|
|
28
|
-
export { validateCenterPrompts, validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-validate.js";
|
|
26
|
+
* 中立叶子 `src/prompts-domain-validate.ts`(design/158 S6);消费者直引真源([2354] 兼容面全清,
|
|
27
|
+
* 此处兼容 re-export 已删)。 */
|
|
29
28
|
/** [985]b / [1285] — §9.4 by-digest 补拉组合店:local miss ⇒ fetchRaw(digest) 从 center 拉 envelope ⇒
|
|
30
29
|
* core verifyPromptArtifact 全管线 + **回验「拿到的=要的」digest 逐位**(center 答非所问=丢弃)⇒
|
|
31
30
|
* best-effort 回写 inner(下次直命中)。任何失败=undefined(诚实缺席,fail-loud 归 core 的
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
*/
|
|
36
36
|
import type { ExecutionEnv, ExecutionEnvFactory } from "@sema-agent/core";
|
|
37
37
|
import type { IssuedFileLink, PreparedDirectUpload } from "../plugins/send-user-file.js";
|
|
38
|
-
import { shellQuote as shq } from "../plugins/remote-shell.js";
|
|
39
38
|
/** Leak backstop (codex review HIGH): core skips destroy on suspend/review paths and a crash may skip it
|
|
40
39
|
* entirely — the suspendVM wrap covers the common case, this bound covers the rest. Far above any real
|
|
41
40
|
* per-replica concurrency. 修6: at the cap the registry REFUSES the new registration instead of FIFO-evicting
|
|
@@ -92,7 +91,6 @@ export declare class TaskEnvRegistry {
|
|
|
92
91
|
* adb/local-docker remain a follow-on).
|
|
93
92
|
*/
|
|
94
93
|
export declare function sandboxSendLaneEnabled(provider: string | undefined, requirePrincipal: boolean): boolean;
|
|
95
|
-
export { shq };
|
|
96
94
|
/** Strip the capability URL (and any SigV4 signature) from text before it reaches an error/log — including
|
|
97
95
|
* the percent-encoded forms an adapter may echo (the k8s exec transport carries the command in a request
|
|
98
96
|
* URI, so an error can quote the URL re-encoded; codex review MED). */
|
|
@@ -139,11 +139,8 @@ export function sandboxSendLaneEnabled(provider, requirePrincipal) {
|
|
|
139
139
|
return requirePrincipal !== true;
|
|
140
140
|
return false;
|
|
141
141
|
}
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
// re-exported alias — not a plain call-through rename — because two test files import `shq` by name from
|
|
145
|
-
// this module.
|
|
146
|
-
export { shq };
|
|
142
|
+
// [2354] clay 令兼容面全清:R10 曾留的 `export { shq }` 兼容转口已删——quoting 唯一真源=
|
|
143
|
+
// remote-shell.ts 的 shellQuote(原先仅有的两个消费者是测试文件,已改从真源导入)。
|
|
147
144
|
/** Strip the capability URL (and any SigV4 signature) from text before it reaches an error/log — including
|
|
148
145
|
* the percent-encoded forms an adapter may echo (the k8s exec transport carries the command in a request
|
|
149
146
|
* URI, so an error can quote the URL re-encoded; codex review MED). */
|
|
@@ -46,16 +46,7 @@ export interface ScenarioDeps {
|
|
|
46
46
|
metrics?: Metrics;
|
|
47
47
|
logger?: Logger;
|
|
48
48
|
/** OA backend coordinates for the `oa` scenario (read /api/v1, write /api/assets). */
|
|
49
|
-
oaApiBaseUrl?: string;
|
|
50
|
-
oaServiceToken?: string;
|
|
51
49
|
/** 可选:`oa` 场景注入"开 Gitea issue"工具(OA AI 请求#5);repo/token/labels 固定,模型只填 title/body。 */
|
|
52
|
-
oaIssue?: {
|
|
53
|
-
baseUrl: string;
|
|
54
|
-
owner: string;
|
|
55
|
-
repo: string;
|
|
56
|
-
token: string;
|
|
57
|
-
defaultLabels?: number[];
|
|
58
|
-
};
|
|
59
50
|
/**
|
|
60
51
|
* When true, the `default` scenario carries the Sema product identity (see {@link semaIdentityProvider}).
|
|
61
52
|
* Set by the local/TOC deployment (CONFIG_PROVIDER=local / run-local) so the local engine answers "who
|