@sema-agent/server 7.47.0-rc.1 → 7.47.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/dist/approval.js +14 -7
- package/dist/config.d.ts +15 -0
- package/dist/config.js +1 -1
- package/dist/http/server.js +13 -1
- package/dist/task-settings.js +11 -10
- package/package.json +2 -2
package/dist/approval.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {} from "@sema-agent/core";
|
|
1
|
+
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "@sema-agent/core";
|
|
2
2
|
export function hasOperatorGateIntent(config) {
|
|
3
3
|
return (config.approvalRequire.length > 0 ||
|
|
4
4
|
config.approvalDeny.length > 0 ||
|
|
@@ -13,20 +13,27 @@ export function assertGateIntentServiceable(config, checkpointStorePresent) {
|
|
|
13
13
|
}
|
|
14
14
|
throw new Error("DURABLE_APPROVAL=true but no checkpoint store is available — the configured DB backend has no checkpoint face (or no backend is configured). Wire a MySQL-protocol/PostgreSQL/file backend, or unset DURABLE_APPROVAL.");
|
|
15
15
|
}
|
|
16
|
+
function createNameSetMatcher(names) {
|
|
17
|
+
const exact = new Set(names);
|
|
18
|
+
const covering = names.filter(isNamespacedCoveringRuleName);
|
|
19
|
+
if (covering.length === 0)
|
|
20
|
+
return (toolName) => exact.has(toolName);
|
|
21
|
+
return (toolName) => exact.has(toolName) || covering.some((rule) => namespacedRuleNameCovers(rule, toolName));
|
|
22
|
+
}
|
|
16
23
|
export function createDurableAskPolicy(opts) {
|
|
17
|
-
const require =
|
|
18
|
-
const deny =
|
|
19
|
-
const neverAuto =
|
|
24
|
+
const require = createNameSetMatcher(opts.requireApproval);
|
|
25
|
+
const deny = createNameSetMatcher(opts.deny ?? []);
|
|
26
|
+
const neverAuto = createNameSetMatcher(opts.neverAuto ?? []);
|
|
20
27
|
const budget = Math.max(0, Math.floor(opts.autoBudget ?? 0));
|
|
21
28
|
let autoApproved = 0;
|
|
22
29
|
return {
|
|
23
30
|
check: (req) => {
|
|
24
31
|
const toolName = req.toolName;
|
|
25
|
-
if (deny
|
|
32
|
+
if (deny(toolName))
|
|
26
33
|
return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
|
|
27
|
-
if (neverAuto
|
|
34
|
+
if (neverAuto(toolName))
|
|
28
35
|
return { action: "ask", message: `human approval required to run "${req.toolName}"` };
|
|
29
|
-
if (require
|
|
36
|
+
if (require(toolName)) {
|
|
30
37
|
const remEarly = req.budget?.resourceRemainingMicroUsd;
|
|
31
38
|
if (remEarly !== undefined && remEarly <= 0) {
|
|
32
39
|
return { action: "ask", message: `durable resource budget exhausted — human approval required to run "${req.toolName}"` };
|
package/dist/config.d.ts
CHANGED
|
@@ -185,6 +185,21 @@ export declare function applyAutoCompactWindow(m: Model, explicit?: number): "ex
|
|
|
185
185
|
*
|
|
186
186
|
* 已接受的权衡(与退役表墓碑同一条):部署自有工具真叫 `figma__x` 的极端形会被误拒——boot 期无 roster 可
|
|
187
187
|
* 豁免,且失败响亮、指引明确,好过静默失守。
|
|
188
|
+
*
|
|
189
|
+
* 🔴 **三条腿的消费者现已全部认 covering**(#450 孪生修,[5246];此前本段记的「分家」已作废):
|
|
190
|
+
* core 的每一只 name-keyed policy(`createAllowDenyPolicy` / `createPermissionRulePolicy` /
|
|
191
|
+
* `createApprovalPolicy`)都解 covering 拼法,而 operator 腿的消费者 `createDurableAskPolicy`
|
|
192
|
+
* (`src/approval.ts`)自 core 5.60.1 的谓词根导出到货后,deny/neverAuto/require 三集合也改成
|
|
193
|
+
* 「精确 ∪ covering」(同一只 `namespacedRuleNameCovers`)。于是本函数放行的
|
|
194
|
+
* `<ns>__<server>__*` / `<ns>__<server>__<glob>` 在**每一条**腿上都是**真判**,不再是
|
|
195
|
+
* 「放行进 no-op」—— 而那正是 #450 病形(`APPROVAL_DENY=mcp__figma__*` 判 allow)的根。
|
|
196
|
+
*
|
|
197
|
+
* ⚠️ 仍然拒的那一格,理由**换了**(别再照旧引「approval.ts 还不认」):`<ns>__<peer>` **两段形**
|
|
198
|
+
* (`mcp__figma`)core 全家解成 covering,本函数判它「缺段」拒。挡它的不再是消费腿的能力,而是
|
|
199
|
+
* **一名两义**:同一个 `mcp__figma` 既可能是运维想写的「整台服务器」,也可能是他把三段名写漏了一段
|
|
200
|
+
* (`mcp__figma__get_file` 少打一截),两者在 boot 期无 roster 可判——所以三条腿一律响亮拒,并在
|
|
201
|
+
* 指引里直接给出**无歧义**的等价写法 `mcp__figma__*`(见下方 guidance)。放宽两段形是一次
|
|
202
|
+
* behavior-facing 的放宽(三条腿同时变宽,且方向是「更少拒绝」),要走独立批的三问,不是本函数的补丁。
|
|
188
203
|
*/
|
|
189
204
|
export interface UnmatchableToolName {
|
|
190
205
|
name: string;
|
package/dist/config.js
CHANGED
|
@@ -773,7 +773,7 @@ export function findUnmatchableToolNames(names) {
|
|
|
773
773
|
continue;
|
|
774
774
|
}
|
|
775
775
|
if (ns.parse(name) === undefined) {
|
|
776
|
-
out.push({ name, guidance: `incomplete ${ns.id} name — the live form is ${ns.prefix}<server>__<tool
|
|
776
|
+
out.push({ name, guidance: `incomplete ${ns.id} name — the live form is ${ns.prefix}<server>__<tool>, or ${ns.prefix}<server>__* to cover every tool on that server` });
|
|
777
777
|
}
|
|
778
778
|
}
|
|
779
779
|
return out;
|
package/dist/http/server.js
CHANGED
|
@@ -1583,10 +1583,19 @@ export function createHttpServer(rawDeps) {
|
|
|
1583
1583
|
e.code === "resume.parent_constraint_mismatch" ||
|
|
1584
1584
|
e.code === "resume.constraint_rejected" ||
|
|
1585
1585
|
e.code === "resume.constraint_unprojectable" ||
|
|
1586
|
+
e.code === "resume.usage_window_exhausted" ||
|
|
1587
|
+
e.code === "resume.principal_mismatch" ||
|
|
1586
1588
|
e.code.startsWith("wake.") ||
|
|
1587
1589
|
(e.code === "checkpoint.unsupported_version" && checkpointRowRedeemableElsewhere(e.detail?.reason));
|
|
1588
1590
|
if (claimedRow && taskId && deps.runStore) {
|
|
1589
|
-
if (retriable) {
|
|
1591
|
+
if (retriable && freshRunClaimed) {
|
|
1592
|
+
const c = { taskId, sessionId, status: "failed", errorCode: e.code, errorMessage: e.message, stats: { turns: 0, tokens: 0 } };
|
|
1593
|
+
await deps.runStore.setTerminal(taskId, "failed", c, c.errorMessage ?? null).catch((err) => {
|
|
1594
|
+
deps.logger?.warn?.("wake_synthetic_run_release_failed", { taskId, sessionId, errorCode: e.code, error: err instanceof Error ? err.message : String(err), note: "the synthetic run row for this refused fresh-run resume could not be settled — its task_active claim is still held and the next attempt on this session will 409 conflict.session_active_run until reapStale collects it (runStaleSec)" });
|
|
1595
|
+
});
|
|
1596
|
+
settleFleet("failed");
|
|
1597
|
+
}
|
|
1598
|
+
else if (retriable) {
|
|
1590
1599
|
await (outcome.gate === "plan_review" ? deps.runStore.setNeedsReview(taskId) : deps.runStore.setSuspended(taskId)).catch(() => undefined);
|
|
1591
1600
|
settleFleet(outcome.gate === "plan_review" ? "needs_review" : "suspended");
|
|
1592
1601
|
}
|
|
@@ -1604,6 +1613,9 @@ export function createHttpServer(rawDeps) {
|
|
|
1604
1613
|
? (outcome.gate === "policy_ask" ? "approval_binding_mismatch" : "resume_outcome_invalid")
|
|
1605
1614
|
: e.code,
|
|
1606
1615
|
...(e.detail?.field ? { field: e.detail.field } : {}),
|
|
1616
|
+
...(e.code === "resume.usage_window_exhausted" && typeof e.detail?.retryAfterMs === "number" && Number.isFinite(e.detail.retryAfterMs) && e.detail.retryAfterMs > 0
|
|
1617
|
+
? { retryAfterSec: Math.max(1, Math.ceil(e.detail.retryAfterMs / 1000)) }
|
|
1618
|
+
: {}),
|
|
1607
1619
|
...(retriable ? { retriable: true } : {}),
|
|
1608
1620
|
},
|
|
1609
1621
|
};
|
package/dist/task-settings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { combinePolicies, createAllowDenyPolicy, createFsWriteGatePolicy, tightenTaskSpec, resolveReasoningProfile, rankOf, isThinkingLevel, CYBER_RISK, URL_SAFETY, HARNESS_SECTION_ANCHOR, RUN_WORKFLOW_TOOL_NAME, } from "@sema-agent/core";
|
|
1
|
+
import { combinePolicies, createAllowDenyPolicy, createFsWriteGatePolicy, createPermissionRulePolicy, tightenTaskSpec, resolveReasoningProfile, rankOf, isThinkingLevel, CYBER_RISK, URL_SAFETY, HARNESS_SECTION_ANCHOR, RUN_WORKFLOW_TOOL_NAME, } from "@sema-agent/core";
|
|
2
2
|
import { findCcRuleFormNames, findUnmatchableToolNames, formatUnmatchableToolNames } from "./config.js";
|
|
3
3
|
import { parseHooksConfig } from "./hooks/hook-runner.js";
|
|
4
4
|
export function coercePermissionMode(raw) {
|
|
@@ -151,16 +151,17 @@ export function acceptAppendSystemPrompt(v, warn, packDropsAppend) {
|
|
|
151
151
|
}
|
|
152
152
|
return v;
|
|
153
153
|
}
|
|
154
|
+
const ASK_RULE_SOURCE = "settings.permissions.ask";
|
|
154
155
|
function createAskListPolicy(askNames) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
156
|
+
try {
|
|
157
|
+
return createPermissionRulePolicy(askNames.map((name) => ({ rule: name, behavior: "ask", source: ASK_RULE_SOURCE })), {
|
|
158
|
+
defaultAction: "allow",
|
|
159
|
+
caps: { maxRules: MAX_SETTINGS_PERMISSION_RULES },
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
throw new Error(`permissions.ask has rule(s) core cannot compile — ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
164
|
+
}
|
|
164
165
|
}
|
|
165
166
|
const WORKFLOW_ASK_NAMES = [RUN_WORKFLOW_TOOL_NAME];
|
|
166
167
|
function createWorkflowAskPolicy(isExempt) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.47.0
|
|
3
|
+
"version": "7.47.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@sema-agent/core": "^5.60.
|
|
57
|
+
"@sema-agent/core": "^5.60.1",
|
|
58
58
|
"@sema-agent/registry-core": "^0.19.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|