@sema-agent/server 7.70.0 → 7.72.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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +8 -4
- package/dist/approval-card.d.ts +16 -17
- package/dist/approval-card.js +0 -9
- package/dist/approval-content-kind.d.ts +13 -7
- package/dist/approval-content-kind.js +3 -1
- package/dist/approval.js +3 -2
- package/dist/bench/s1/live-deps.js +2 -0
- package/dist/boot/execution-env.js +12 -2
- package/dist/boot/memory-consolidation.d.ts +2 -1
- package/dist/boot/parked-revive-gate.d.ts +2 -0
- package/dist/boot/parked-revive-gate.js +5 -1
- package/dist/boot/resolve-spec.js +8 -3
- package/dist/boot/runner-deps.d.ts +48 -59
- package/dist/boot/runner-deps.js +10 -4
- package/dist/brain.d.ts +3 -1
- package/dist/brain.js +2 -8
- package/dist/budget.d.ts +12 -1
- package/dist/budget.js +1 -1
- package/dist/config-catalog.js +13 -11
- package/dist/config-center/apply-effective.js +2 -4
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/restart-signal.js +2 -2
- package/dist/config-center/skills-mcp.js +15 -0
- package/dist/config-types.d.ts +86 -4
- package/dist/config-types.js +19 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.js +71 -22
- package/dist/deployment-governance.d.ts +6 -3
- package/dist/deployment-governance.js +2 -1
- package/dist/execution-lane-caps.d.ts +51 -37
- package/dist/execution-lane-caps.js +23 -0
- package/dist/fleet/fleet-bus.d.ts +22 -1
- package/dist/fleet/fleet-bus.js +2 -1
- package/dist/http/durable-run-leg.d.ts +64 -0
- package/dist/http/durable-run-leg.js +63 -0
- package/dist/http/route-ctx.d.ts +14 -0
- package/dist/http/route-ctx.js +3 -0
- package/dist/http/routes/approvals-assistant.js +3 -3
- package/dist/http/routes/capabilities.js +2 -2
- package/dist/http/routes/runs.js +10 -58
- package/dist/http/routes/workflows.js +1 -0
- package/dist/http/server.js +72 -22
- package/dist/index.d.ts +1 -1
- package/dist/leader/wire.js +4 -3
- package/dist/main.js +8 -3
- package/dist/memory-operator-faces.d.ts +1 -1
- package/dist/memory-scope.d.ts +24 -0
- package/dist/memory-scope.js +12 -3
- package/dist/observability/fail-open.d.ts +1 -1
- package/dist/observability/fail-open.js +1 -1
- package/dist/observability/metrics.d.ts +4 -0
- package/dist/observability/metrics.js +3 -1
- package/dist/observability/run-terminal-log.d.ts +4 -3
- package/dist/observability/run-terminal-log.js +4 -15
- package/dist/observability/tool-trace.d.ts +18 -1
- package/dist/observability/tool-trace.js +4 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +85 -2
- package/dist/orchestration/workflow-agent-session-index.js +38 -5
- package/dist/parked-decide.d.ts +40 -1
- package/dist/parked-decide.js +22 -4
- package/dist/plugins/checkpoint-store-sql.js +5 -5
- package/dist/plugins/e2b-orphan-reclaim.d.ts +4 -4
- package/dist/plugins/e2b-orphan-reclaim.js +18 -20
- package/dist/plugins/local-checkpoint-store.js +3 -3
- package/dist/plugins/remote-env-adb.d.ts +11 -0
- package/dist/plugins/remote-env-adb.js +2 -0
- package/dist/plugins/remote-env-device.d.ts +9 -0
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +11 -0
- package/dist/plugins/remote-env-e2b.js +2 -0
- package/dist/plugins/remote-env-host.d.ts +11 -0
- package/dist/plugins/remote-env-host.js +2 -0
- package/dist/plugins/remote-env-k8s.d.ts +11 -0
- package/dist/plugins/remote-env-k8s.js +2 -0
- package/dist/plugins/remote-env-local-docker.d.ts +11 -0
- package/dist/plugins/remote-env-local-docker.js +2 -0
- package/dist/plugins/remote-env-ssh.d.ts +11 -0
- package/dist/plugins/remote-env-ssh.js +2 -0
- package/dist/plugins/store-backend.d.ts +34 -12
- package/dist/plugins/store-backend.js +12 -3
- package/dist/plugins/store-contracts.d.ts +81 -18
- package/dist/plugins/store-contracts.js +18 -30
- package/dist/plugins/workflow-run-store-sql.d.ts +31 -9
- package/dist/plugins/workflow-run-store-sql.js +28 -1
- package/dist/run-cancel-context.js +1 -1
- package/dist/run-local.js +7 -1
- package/dist/runs.d.ts +16 -2
- package/dist/runs.js +2 -1
- package/dist/runtime-caps-resolver.js +5 -3
- package/dist/task-a2a.js +2 -1
- package/dist/task-mcp.js +2 -1
- package/dist/task-settings.d.ts +21 -8
- package/dist/task-settings.js +2 -2
- package/dist/tool-approval.d.ts +26 -21
- package/dist/tool-approval.js +2 -2
- package/dist/trace/core-keyset-guard.d.ts +136 -10
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +1 -0
- package/dist/trace/ledger-events.d.ts +5 -1
- package/dist/trace/ledger-sink.js +8 -1
- package/dist/trace/project.d.ts +33 -4
- package/dist/trace/project.js +24 -6
- package/dist/trace/redact.js +10 -5
- package/dist/usage-analytics.d.ts +9 -1
- package/dist/usage-analytics.js +8 -0
- package/dist/wire-name-bound.d.ts +14 -0
- package/dist/wire-name-bound.js +13 -0
- package/package.json +3 -3
package/dist/config.js
CHANGED
|
@@ -9,7 +9,7 @@ import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
|
|
|
9
9
|
import { isV2ScopeKey } from "./memory-scope.js";
|
|
10
10
|
import { DEFAULT_QUESTION_THROTTLE } from "./question.js";
|
|
11
11
|
import { GIT_API_KINDS, isGitApiKind } from "./git-api-kind.js";
|
|
12
|
-
import { RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC } from "./config-types.js";
|
|
12
|
+
import { RETENTION_MODES, MEMORY_CONSOLIDATION_MIN_INTERVAL_SEC, RESILIENCE_DEFAULTS } from "./config-types.js";
|
|
13
13
|
import { buildWriteProtectionPosture } from "./write-protection.js";
|
|
14
14
|
import { normalizeSshFingerprint } from "./ssh-host-key.js";
|
|
15
15
|
import { readFaceForPosture } from "./read-face-posture.js";
|
|
@@ -260,16 +260,53 @@ function numEnvOr(name, fallback) {
|
|
|
260
260
|
return fallback;
|
|
261
261
|
return parseNumOrFail(name, raw);
|
|
262
262
|
}
|
|
263
|
-
function
|
|
263
|
+
function costEnv(name, emptyString) {
|
|
264
264
|
const raw = process.env[name];
|
|
265
265
|
if (raw === undefined)
|
|
266
|
-
return
|
|
266
|
+
return undefined;
|
|
267
267
|
if (raw === "") {
|
|
268
|
+
if (emptyString === "unset")
|
|
269
|
+
return undefined;
|
|
268
270
|
CONFIG_WARNINGS.push({ env: name, raw: "", used: "0", kind: "empty-preserved" });
|
|
269
271
|
return 0;
|
|
270
272
|
}
|
|
271
273
|
return parseNumOrFail(name, raw);
|
|
272
274
|
}
|
|
275
|
+
function buildCostOrAbsent(read, inherited) {
|
|
276
|
+
const declared = read.input !== undefined || read.output !== undefined || read.cacheRead !== undefined || read.cacheWrite !== undefined;
|
|
277
|
+
if (!declared && inherited === undefined)
|
|
278
|
+
return undefined;
|
|
279
|
+
return {
|
|
280
|
+
input: read.input ?? inherited?.input ?? 0,
|
|
281
|
+
output: read.output ?? inherited?.output ?? 0,
|
|
282
|
+
cacheRead: read.cacheRead ?? inherited?.cacheRead ?? 0,
|
|
283
|
+
cacheWrite: read.cacheWrite ?? inherited?.cacheWrite ?? 0,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
export function buildModelCostKey(cost) {
|
|
287
|
+
return (cost === undefined ? {} : { cost });
|
|
288
|
+
}
|
|
289
|
+
export function buildUnpricedCeilingNotice(models, limits) {
|
|
290
|
+
const ceilings = [
|
|
291
|
+
...(limits.maxTaskCostUsd > 0 ? ["MAX_TASK_COST_USD"] : []),
|
|
292
|
+
...(limits.maxPrincipalCostUsd > 0 ? ["MAX_PRINCIPAL_COST_USD"] : []),
|
|
293
|
+
];
|
|
294
|
+
const entries = Object.values(models);
|
|
295
|
+
if (ceilings.length === 0 || entries.length === 0 || entries.some((m) => m.cost !== undefined))
|
|
296
|
+
return undefined;
|
|
297
|
+
return {
|
|
298
|
+
event: "cost_ceiling_without_pricing",
|
|
299
|
+
fields: {
|
|
300
|
+
ceilings: ceilings.join(","),
|
|
301
|
+
models: [...new Set(entries.map((m) => m.id))].join(","),
|
|
302
|
+
note: `${ceilings.join(" / ")} is configured but NO model in the effective catalog declares a price table — an ` +
|
|
303
|
+
"unpriced model reports NO cost at all (core RB-368), so these $ ceilings can never fire and this deployment " +
|
|
304
|
+
"has no cost guardrail despite looking like it does. Set MODEL_COST_INPUT / MODEL_COST_OUTPUT / " +
|
|
305
|
+
"MODEL_COST_CACHE_READ / MODEL_COST_CACHE_WRITE (env lane), or a per-model `cost` on the center roster row. " +
|
|
306
|
+
"The token ceiling (MAX_TASK_TOKENS) is unaffected and still fires.",
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
|
273
310
|
function optNumEnvStrict(name) {
|
|
274
311
|
const raw = process.env[name];
|
|
275
312
|
if (!raw)
|
|
@@ -753,12 +790,12 @@ function parseModelDomain() {
|
|
|
753
790
|
baseUrl: "",
|
|
754
791
|
reasoning: boolEnv("MODEL_REASONING", true),
|
|
755
792
|
input: boolEnv("MODEL_VISION", true) ? ["text", "image"] : ["text"],
|
|
756
|
-
|
|
757
|
-
input:
|
|
758
|
-
output:
|
|
759
|
-
cacheRead:
|
|
760
|
-
cacheWrite:
|
|
761
|
-
},
|
|
793
|
+
...buildModelCostKey(buildCostOrAbsent({
|
|
794
|
+
input: costEnv("MODEL_COST_INPUT", "unset"),
|
|
795
|
+
output: costEnv("MODEL_COST_OUTPUT", "unset"),
|
|
796
|
+
cacheRead: costEnv("MODEL_COST_CACHE_READ", "unset"),
|
|
797
|
+
cacheWrite: costEnv("MODEL_COST_CACHE_WRITE", "unset"),
|
|
798
|
+
}, undefined)),
|
|
762
799
|
contextWindow: numEnv("MODEL_CONTEXT_WINDOW", "262144"),
|
|
763
800
|
maxTokens: process.env.MODEL_MAX_TOKENS !== undefined && process.env.MODEL_MAX_TOKENS !== ""
|
|
764
801
|
? parseNumOrFail("MODEL_MAX_TOKENS", process.env.MODEL_MAX_TOKENS)
|
|
@@ -776,12 +813,12 @@ function parseModelDomain() {
|
|
|
776
813
|
id: cheapId,
|
|
777
814
|
name: cheapId,
|
|
778
815
|
input: ((v) => (v === undefined ? model.input : v ? ["text", "image"] : ["text"]))(parseBoolWord("MODEL_CHEAP_VISION", process.env.MODEL_CHEAP_VISION)),
|
|
779
|
-
|
|
780
|
-
input:
|
|
781
|
-
output:
|
|
782
|
-
cacheRead:
|
|
783
|
-
cacheWrite:
|
|
784
|
-
},
|
|
816
|
+
...buildModelCostKey(buildCostOrAbsent({
|
|
817
|
+
input: costEnv("MODEL_CHEAP_COST_INPUT", "declares-zero"),
|
|
818
|
+
output: costEnv("MODEL_CHEAP_COST_OUTPUT", "declares-zero"),
|
|
819
|
+
cacheRead: costEnv("MODEL_CHEAP_COST_CACHE_READ", "declares-zero"),
|
|
820
|
+
cacheWrite: costEnv("MODEL_CHEAP_COST_CACHE_WRITE", "declares-zero"),
|
|
821
|
+
}, model.cost)),
|
|
785
822
|
contextWindow: numEnvOr("MODEL_CHEAP_CONTEXT_WINDOW", model.contextWindow),
|
|
786
823
|
maxTokens: numEnvOr("MODEL_CHEAP_MAX_TOKENS", model.maxTokens),
|
|
787
824
|
...(optFinitePositiveEnv("MODEL_CHEAP_CHARS_PER_TOKEN") !== undefined ? { charsPerToken: optFinitePositiveEnv("MODEL_CHEAP_CHARS_PER_TOKEN") } : {}),
|
|
@@ -855,12 +892,12 @@ function parseModelDomain() {
|
|
|
855
892
|
}
|
|
856
893
|
: undefined,
|
|
857
894
|
resilience: {
|
|
858
|
-
connectTimeoutMs: numEnv("MODEL_CONNECT_TIMEOUT_MS",
|
|
859
|
-
firstTokenTimeoutMs: numEnv("MODEL_FIRST_TOKEN_TIMEOUT_MS",
|
|
860
|
-
idleTimeoutMs: numEnv("MODEL_IDLE_TIMEOUT_MS",
|
|
861
|
-
circuitBreaker: boolEnv("MODEL_CIRCUIT_BREAKER",
|
|
862
|
-
failureThreshold: numEnv("MODEL_CB_FAILURE_THRESHOLD",
|
|
863
|
-
cooldownMs: numEnv("MODEL_CB_COOLDOWN_MS",
|
|
895
|
+
connectTimeoutMs: numEnv("MODEL_CONNECT_TIMEOUT_MS", String(RESILIENCE_DEFAULTS.connectTimeoutMs.value)),
|
|
896
|
+
firstTokenTimeoutMs: numEnv("MODEL_FIRST_TOKEN_TIMEOUT_MS", String(RESILIENCE_DEFAULTS.firstTokenTimeoutMs.value)),
|
|
897
|
+
idleTimeoutMs: numEnv("MODEL_IDLE_TIMEOUT_MS", String(RESILIENCE_DEFAULTS.idleTimeoutMs.value)),
|
|
898
|
+
circuitBreaker: boolEnv("MODEL_CIRCUIT_BREAKER", RESILIENCE_DEFAULTS.circuitBreaker.value),
|
|
899
|
+
failureThreshold: numEnv("MODEL_CB_FAILURE_THRESHOLD", String(RESILIENCE_DEFAULTS.failureThreshold.value)),
|
|
900
|
+
cooldownMs: numEnv("MODEL_CB_COOLDOWN_MS", String(RESILIENCE_DEFAULTS.cooldownMs.value)),
|
|
864
901
|
},
|
|
865
902
|
model,
|
|
866
903
|
envModel: model,
|
|
@@ -1551,6 +1588,18 @@ function parseOrchestrationDomain(ctx) {
|
|
|
1551
1588
|
assertReadDenyBuiltinsResolvable(tiers, exclude);
|
|
1552
1589
|
return { ...(tiers !== undefined ? { readDenyBuiltinTiers: tiers } : {}), ...(exclude !== undefined ? { readDenyBuiltinExclude: exclude } : {}) };
|
|
1553
1590
|
})(),
|
|
1591
|
+
...((h) => (h !== undefined ? { remoteExecHomeDir: h } : {}))((() => {
|
|
1592
|
+
const raw = process.env.REMOTE_EXEC_HOME_DIR;
|
|
1593
|
+
if (raw === undefined || raw === "")
|
|
1594
|
+
return undefined;
|
|
1595
|
+
if (!raw.startsWith("/")) {
|
|
1596
|
+
throw new Error(`REMOTE_EXEC_HOME_DIR="${raw}" is not an absolute path — it is the home directory of the user the EXECUTION ` +
|
|
1597
|
+
`environment runs as (the base a \`~/\` permission rule resolves against), so a relative value cannot be ` +
|
|
1598
|
+
`resolved and would silently guard nothing. Spell it absolutely (e.g. /home/user), or unset it to have ` +
|
|
1599
|
+
`\`~/\` rules refused loudly on this lane.`);
|
|
1600
|
+
}
|
|
1601
|
+
return raw;
|
|
1602
|
+
})()),
|
|
1554
1603
|
remoteExec: process.env.REMOTE_EXEC === "e2b" && process.env.E2B_API_KEY
|
|
1555
1604
|
? {
|
|
1556
1605
|
provider: "e2b",
|
|
@@ -1941,7 +1990,7 @@ const AUTH_GROUP_KEYS = [
|
|
|
1941
1990
|
"principalJwtMaxTtlSec", "bindHost", "bindHostSource",
|
|
1942
1991
|
];
|
|
1943
1992
|
const ORCHESTRATION_GROUP_KEYS = [
|
|
1944
|
-
"remoteExec", "worktreeIsolation", "leaderEnabled", "leaderFanoutEnabled", "routerEnabled", "selfOrchestrationEnabled",
|
|
1993
|
+
"remoteExec", "remoteExecHomeDir", "worktreeIsolation", "leaderEnabled", "leaderFanoutEnabled", "routerEnabled", "selfOrchestrationEnabled",
|
|
1945
1994
|
"selfOrchestrationModels", "selfOrchestrationWorkerIsolation", "forkEnabled", "experimentalObserverAgents",
|
|
1946
1995
|
"schedulerEnabled", "schedulerSessionWakeup", "schedulerSessionLifetime", "schedulerStorePath", "planModeEnabled", "hooksTimeoutMs", "workflowRunStoreBackend",
|
|
1947
1996
|
"workflowOrphanGraceMs", "workflowJournalRetentionMs", "workflowRunRetentionMs", "usageWindows", "workflowAgentsReadOnly",
|
|
@@ -59,8 +59,10 @@ export interface PathAdjudication {
|
|
|
59
59
|
* 形上是一个永不创建的哨兵目录 —— 对写门 fail-safe,对规则 fail-open。理由逐字见
|
|
60
60
|
* `task-settings.ts` 的 `FsWriteGateWiring.taskRoot`。缺席 ⇒ 需要基的规则拼法被 core 整表拒(fail-loud)。 */
|
|
61
61
|
readonly taskRoot?: string;
|
|
62
|
-
/** 🔴 S-177 / codex r2
|
|
63
|
-
*
|
|
62
|
+
/** 🔴 S-177 / codex r2 + S-213④:**执行环境的 home**(`~/…` 形规则的基)。在**本部署的执行车道
|
|
63
|
+
* 真知道自己的 home 时**在场 —— 判据的唯一属主是 `execution-lane-caps.ts` 的 `executionLaneHomeDir`
|
|
64
|
+
* (adapter 的 `ExecutionEnv.homeDir` 座读的是同一个函数)。绝不回落引擎进程自己的 home:远端车道上
|
|
65
|
+
* 那是另一个用户的目录,拿它去匹配 = 一条收紧规则静默守错地方。逐字见
|
|
64
66
|
* `task-settings.ts` 的 `FsWriteGateWiring.taskHome`。 */
|
|
65
67
|
readonly taskHome?: string;
|
|
66
68
|
}
|
|
@@ -85,7 +87,8 @@ export interface DurableApprovalSeat {
|
|
|
85
87
|
* durable resume 驱动、断连后的 detach 腿)ask——durable park 原语义逐字保留([ref] 后无活流腿放行执行
|
|
86
88
|
* 也不会产出空答:coordinator 无 ALS ctx ⇒ 冻结 `{kind:"unavailable"}`(src/question.ts),永不悬挂;
|
|
87
89
|
* park 仍是把问题送到人面前的唯一那条腿,正当性不变、只是反事实前提换了)。
|
|
88
|
-
*
|
|
90
|
+
* 工具名取 `approval-content-kind.ts` 的单一属主(它 re-export core 根导出的 `ASK_USER_QUESTION_TOOL_NAME`);
|
|
91
|
+
* server.ts 的 pre-CAS 守卫读同一枚(S-213①:此处旧注称该常量「core 未根导出」= 失实,曾据此手抄 13 处)。
|
|
89
92
|
* ⚠️ **单一属主**(复审 A2):AskUserQuestion 的 durable 判决只有这一处。任何需要「同参重建」这条判决的
|
|
90
93
|
* 地方(main.ts 的 parkedReviveInheritedGate 父约束链)必须调本工厂,不得自折 core 原形——两份拷贝里
|
|
91
94
|
* 只改一份正是本条 finding 的成因。**登记豁免一处**:leader worker 腿(src/leader/wire.ts provisionWorker)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { join, posix } from "node:path";
|
|
2
2
|
import { FileError, StubExecutionEnv, combinePolicies, createAllowDenyPolicy, createDurableQuestionPolicy, createSensitivePathPolicy, createTranscriptIntegrityPolicy, err, ok, } from "@sema-agent/core";
|
|
3
3
|
import { createDurableAskPolicy } from "./approval.js";
|
|
4
|
+
import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
|
|
4
5
|
export function createDurableQuestionGate(live) {
|
|
5
6
|
if (live === undefined)
|
|
6
7
|
return createDurableQuestionPolicy();
|
|
7
8
|
return {
|
|
8
9
|
check(req) {
|
|
9
|
-
if (req.toolName !==
|
|
10
|
+
if (req.toolName !== ASK_USER_QUESTION_TOOL_NAME)
|
|
10
11
|
return { action: "allow" };
|
|
11
12
|
return live.hasLiveContext()
|
|
12
13
|
? { action: "allow" }
|
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 执行车道**闭集**与 per-lane 能力表(design device-executor-lane-v2 §4.1 收敛件,车A-1)。
|
|
3
|
-
*
|
|
4
|
-
* ## 根本问题:lane 词表是开放字符串上的十几处独立判别式
|
|
5
|
-
*
|
|
6
|
-
* `config.remoteExec?.provider` 的静态型是 `string | undefined` 的判别联合,但消费面从来不是一处
|
|
7
|
-
* switch —— 而是散在十几个文件里的**独立等式/集合/否定**:`cwdHonored` 比 `=== "host"`、
|
|
8
|
-
* `isRemoteScratchpadLane` 查一个 `Set`、`isSandboxPathAdjudicationLane` 取 `!== "host"` 的否定、
|
|
9
|
-
* `sandboxSendLaneEnabled` 是一串 if。于是「lane 词表加一个词」的病形不是编译错,是**每一处的默认
|
|
10
|
-
* 答案静默错**:新词不在 Set 里 ⇒ 静默 false;不等于 `"host"` ⇒ 静默 true。没有一处会报,每一处都
|
|
11
|
-
* 给出一个**没有人表过态**的答案(DISEASE-SHAPES V1/V2;[ref] 执行车道轴的同族病)。
|
|
12
|
-
*
|
|
13
|
-
* ## 本模块 = 那张表的单源(三件)
|
|
14
|
-
*
|
|
15
|
-
* ① {@link ExecutionLane}:闭集联合。含 `in-process` —— `REMOTE_EXEC` 未设的进程内 stub 形**是**一条
|
|
16
|
-
* 真车道(`boot/resolve-spec.ts` 的 `?? "in-process"`、`config.ts` 的落点记账都已在用这个词),
|
|
17
|
-
* 把它排除在闭集外,普查就少一列。
|
|
18
|
-
* ② {@link executionLaneCaps}:**穷举 switch**(先例 = `capabilities/hands-lane.ts` 的
|
|
19
|
-
* `pickHandsRunner`:无 `default` 臂 ⇒ 联合加词而此处不加臂 = 编译错,而不是运行期落一个默认行)。
|
|
20
|
-
* ③ {@link ExecutionLaneCaps} 的每一位都点名它**今天的判别式坐标**,由对账测试
|
|
21
|
-
* `test/execution-lane-caps.test.ts` 逐位跑真判别式与本表对拍。
|
|
22
|
-
*
|
|
23
|
-
* ## 🔴 本模块是表,不是执法者
|
|
24
|
-
*
|
|
25
|
-
* 消费点今天仍各自判别(把判别式改成读本表 = 分批的后续车)。所以本表的全部价值押在对账测试上:
|
|
26
|
-
* 表与判别式一旦分叉,门红。**唯一**允许的分叉是 {@link PLANNED_LANE_DIVERGENCES} 里逐条登记的
|
|
27
|
-
* 「表是目标态、判别式待某车补」;登记项之外的分叉是漂移,登记项被补齐而不销行同样是红(双向)。
|
|
28
|
-
*
|
|
29
|
-
* ## 能力位的口径
|
|
30
|
-
*
|
|
31
|
-
* 每一位回答的是**车道结构上能不能**,不是「这个部署开没开」:旋钮(`LSP_ENABLED` /
|
|
32
|
-
* `SCHEDULER_ENABLED` / k8s 的 `s3Snapshot`)由消费点在表之上再合取。租户面是唯一的例外 —— 它与
|
|
33
|
-
* 车道语义绑死(host 的单用户前提),所以进了 {@link LaneCapability} 的第三个词而不是靠调用方记住。
|
|
34
|
-
*
|
|
35
|
-
* 依赖纪律:本文件是**叶**(只 type-import config-types),不引 config.ts —— config.ts 反过来引它取
|
|
36
|
-
* {@link RemoteExecProvider}([ref] 必需 env 表按同一联合键控)。
|
|
37
|
-
*/
|
|
38
1
|
import type { ServiceConfigFlat } from "./config-types.js";
|
|
39
2
|
/** 一位能力的三态。`single-user-only` = 车道支持,但只在单用户部署(`requirePrincipal !== true`)开 ——
|
|
40
3
|
* 多租户下这一位必须关(host 家族的 cwd/scheduler/backgroundShell/LSP 都是这一档,理由同源:
|
|
@@ -149,4 +112,55 @@ export interface PlannedLaneDivergence {
|
|
|
149
112
|
* 加行的门槛不变:一条分叉必须写清 today / owner / why 三件,并在补齐的**同一批**里销掉。
|
|
150
113
|
*/
|
|
151
114
|
export declare const PLANNED_LANE_DIVERGENCES: readonly PlannedLaneDivergence[];
|
|
115
|
+
/**
|
|
116
|
+
* E2B 沙箱里 agent 跑成的那个用户的 home。
|
|
117
|
+
*
|
|
118
|
+
* 这是 **E2B 平台的事实**,不是本仓的猜:E2B 的基础模板建 `user` 这个用户,每个 sandbox 的进程都以它
|
|
119
|
+
* 运行,home 恒 `/home/user`;本仓 adapter 自己的工作区根默认值(`plugins/remote-env-e2b.ts` 的
|
|
120
|
+
* `DEFAULT_MOUNT_PATH`)用的就是同一个目录。**若某个部署的自定义模板换了用户**,运维用
|
|
121
|
+
* `REMOTE_EXEC_HOME_DIR` 显式声明覆盖 —— 那条旋钮恒赢,见 {@link executionLaneHomeDir}。
|
|
122
|
+
* ⚠️ 本值**未经真机实测**(本批无 e2b 真机),按平台约定 + 仓内既有默认常量登记。
|
|
123
|
+
*/
|
|
124
|
+
export declare const E2B_SANDBOX_HOME = "/home/user";
|
|
125
|
+
/** {@link executionLaneHomeDir} 读的那两位部署配置(`ServiceConfig` 结构上满足)。 */
|
|
126
|
+
export interface LaneHomeDeployment {
|
|
127
|
+
readonly remoteExec?: {
|
|
128
|
+
readonly provider: RemoteExecProvider;
|
|
129
|
+
} | undefined;
|
|
130
|
+
/** `REMOTE_EXEC_HOME_DIR` —— 运维显式声明的执行环境 home(绝对路径;坏值在 config 层拒启)。 */
|
|
131
|
+
readonly remoteExecHomeDir?: string | undefined;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 「**这条部署的执行环境**以哪个 home 运行」—— `~/…` 形权限规则(`Edit(~/.ssh/**)`)唯一的基。
|
|
135
|
+
*
|
|
136
|
+
* ## 病(接入审计 M13 / DEBTS S-213④)
|
|
137
|
+
* core 的 `ExecutionEnv.homeDir` 是**由 adapter 声明**的座(`engine/harness/types.d.ts:511`,可选):
|
|
138
|
+
* 缺席 ⇒ core 的 `resolvePathPattern` 回 `{missingBase:"home"}` ⇒ 该规则对这条腿判 `unreadable`
|
|
139
|
+
* (fail-closed 的 ask)。四只远端 adapter(e2b/k8s/host/ssh)一个都没声明,而 server 侧的 422 前置门
|
|
140
|
+
* (`task-settings.ts` 的 `rejectUnmatchableSettingsNames`)在 home 未知时整表拒 `~/` 形 ——
|
|
141
|
+
* **于是远端部署根本写不出 `~/` 规则**,恒 422。
|
|
142
|
+
*
|
|
143
|
+
* ## 本函数 = 那个值的**单一属主**
|
|
144
|
+
* 两个消费面读同一份,不许各算各的(两处不同 = 一条规则在 422 门上被拒、却在引擎里编得出来,或反之):
|
|
145
|
+
* ① 每只 adapter 的 `homeDir` 座(`boot/execution-env.ts` 把本函数的答案递进 adapter 配置);
|
|
146
|
+
* ② 规则基 `PathRuleBases.home`(`boot/resolve-spec.ts` / `boot/parked-revive-gate.ts` 的
|
|
147
|
+
* `pathAdjudication.taskHome`)。
|
|
148
|
+
*
|
|
149
|
+
* ## 一条规则,不是七条特判
|
|
150
|
+
* **运维显式声明恒赢**(`REMOTE_EXEC_HOME_DIR`,部署级旋钮,不挂任何客户端表态);没有声明时,
|
|
151
|
+
* 只有「home 是**车道本身**的属性」的那几条车道才有答案:
|
|
152
|
+
* · `host` / `in-process` —— 命令就跑在本进程这台机器、这个用户下,`os.homedir()` 读的就是它
|
|
153
|
+
* (core 自己的 `NodeExecutionEnv` 同判);
|
|
154
|
+
* · `e2b` —— 平台固定用户,见 {@link E2B_SANDBOX_HOME};
|
|
155
|
+
* · `k8s` / `local-docker` —— home 是**镜像**的属性,boot 期无从得知;
|
|
156
|
+
* · `ssh` —— home 是**目标机上那个登录用户**的属性(root 是 `/root`、macOS 是 `/Users/<u>`),
|
|
157
|
+
* 连上之前无从得知,而 422 门要在下单那一刻回答;
|
|
158
|
+
* · `adb` —— Android 没有 POSIX 意义上的登录 home;
|
|
159
|
+
* · `device` —— 员工自己的机器,运行期才连进来。
|
|
160
|
+
* 这五条一律**缺席**(诚实:不猜一个目录去守)。缺席的后果是 `~/` 规则在下单时被 422 响亮拒,
|
|
161
|
+
* 与 core 的 `missingBase:"home"` 同向 —— 这正是负控要的那一格。
|
|
162
|
+
*
|
|
163
|
+
* 认不出的车道 ⇒ `undefined`(调用方 fail-closed)。生产链上不可达:`loadConfig` 的 [ref] 拒启门先咬。
|
|
164
|
+
*/
|
|
165
|
+
export declare function executionLaneHomeDir(deployment: LaneHomeDeployment): string | undefined;
|
|
152
166
|
//# sourceMappingURL=execution-lane-caps.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
1
2
|
const NO = "unsupported";
|
|
2
3
|
const YES = "supported";
|
|
3
4
|
const SU = "single-user-only";
|
|
@@ -163,4 +164,26 @@ export function laneCapabilityHolds(cap, deployment) {
|
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
export const PLANNED_LANE_DIVERGENCES = Object.freeze([]);
|
|
167
|
+
export const E2B_SANDBOX_HOME = "/home/user";
|
|
168
|
+
export function executionLaneHomeDir(deployment) {
|
|
169
|
+
const declared = deployment.remoteExecHomeDir;
|
|
170
|
+
if (declared !== undefined)
|
|
171
|
+
return declared;
|
|
172
|
+
const lane = executionLaneOf(deployment.remoteExec?.provider);
|
|
173
|
+
if (lane === undefined)
|
|
174
|
+
return undefined;
|
|
175
|
+
switch (lane) {
|
|
176
|
+
case "in-process":
|
|
177
|
+
case "host":
|
|
178
|
+
return homedir();
|
|
179
|
+
case "e2b":
|
|
180
|
+
return E2B_SANDBOX_HOME;
|
|
181
|
+
case "k8s":
|
|
182
|
+
case "local-docker":
|
|
183
|
+
case "ssh":
|
|
184
|
+
case "adb":
|
|
185
|
+
case "device":
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
166
189
|
//# sourceMappingURL=execution-lane-caps.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TaskNotificationPayload, TerminalCause, WorkflowRun } from "@sema-agent/core";
|
|
2
|
-
import type { RunRecord } from "../plugins/store-contracts.js";
|
|
2
|
+
import type { RunRecord, UnsuccessfulRunStatus } from "../plugins/store-contracts.js";
|
|
3
|
+
import type { AssertAllKeysHandled } from "../trace/core-keyset-guard.js";
|
|
3
4
|
/** [ref] 幽灵行案的单源判别:一条 `task_notification` 只有在 **agent 族 × 终态** 时才允许打
|
|
4
5
|
* `onChildTerminal`(fleet「subagent 树」只渲 agent 子代)。`background_bash`/`monitor`/`external`
|
|
5
6
|
* 不属 agent fleet 树——它们此前每条都打,fleet-bus 的「无 tick 无 claim」臂给 b\* 与 m\* handle 合成
|
|
@@ -618,4 +619,24 @@ export declare function isTerminalFleetStatus(status: FleetTaskStatus): boolean;
|
|
|
618
619
|
export declare function runStatusToFleet(status: RunStatusForFleet, opts?: {
|
|
619
620
|
awaitingPlanApproval?: boolean;
|
|
620
621
|
}): FleetTaskStatus;
|
|
622
|
+
/**
|
|
623
|
+
* S-213③ —— **编译期同源钉**:fleet 的 `"failed"` 桶必须恰好收下 `RUN_STATUS_CLASS` 判为「非成功终局」
|
|
624
|
+
* 的每一个 core 词。
|
|
625
|
+
*
|
|
626
|
+
* 这个词的病史:`blocked` 曾在本仓有**两个独立写者**且答案互斥 —— 本文件读它为「非成功终局(agent
|
|
627
|
+
* 放弃)⇒ 行离场」,而 `observability/run-terminal-log.ts` 读它为「治理判决,不是失败 ⇒ 不打行」。两处
|
|
628
|
+
* 各自穷举、各自正确地编译,结果是一条 `report_blocked` 的 run 在面板上离场、在引擎日志里一个字都没有。
|
|
629
|
+
* 语义收归 `plugins/store-contracts.ts` 的那张表之后,本行不再自持判断:表把某个词挪出/挪进
|
|
630
|
+
* `unsuccessful`(或 core 新增一个非成功终态)而上面的 switch 没跟上 ⇒ 下面这条收不敛到 `never` ⇒ tsc 红。
|
|
631
|
+
* (`"error"` 是 server 自有别名、不在那张表的辖域内,故不在本钉的两边出现。)
|
|
632
|
+
*/
|
|
633
|
+
type FleetUnsuccessfulBucket = "failed" | "blocked";
|
|
634
|
+
type _GuardFleetUnsuccessfulBucket = AssertAllKeysHandled<Exclude<UnsuccessfulRunStatus, FleetUnsuccessfulBucket>>;
|
|
635
|
+
/** 反向门(与 `core-keyset-guard.ts` 的 `_Guard*Reverse` 同形):桶里留了一个表**不再**判为非成功终局的
|
|
636
|
+
* 词同样红 —— 只有正向门时,把 `blocked` 挪回 `succeeded` 而 switch 照旧塞进 failed 桶,并集覆盖、
|
|
637
|
+
* 差集门一声不吭(本批实测:只加正向门时该变异 tsc rc=0)。两道钉一起加。 */
|
|
638
|
+
type _GuardFleetUnsuccessfulBucketReverse = AssertAllKeysHandled<Exclude<FleetUnsuccessfulBucket, UnsuccessfulRunStatus>>;
|
|
639
|
+
/** 占位使用(防 noUnusedLocals 形 lint;类型别名本身零运行时)。 */
|
|
640
|
+
export type FleetVocabGuards = [_GuardFleetUnsuccessfulBucket, _GuardFleetUnsuccessfulBucketReverse];
|
|
641
|
+
export {};
|
|
621
642
|
//# sourceMappingURL=fleet-bus.d.ts.map
|
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -634,9 +634,10 @@ export function runStatusToFleet(status, opts) {
|
|
|
634
634
|
case "completed":
|
|
635
635
|
return "completed";
|
|
636
636
|
case "failed":
|
|
637
|
-
case "error":
|
|
638
637
|
case "blocked":
|
|
639
638
|
return "failed";
|
|
639
|
+
case "error":
|
|
640
|
+
return "failed";
|
|
640
641
|
case "suspended":
|
|
641
642
|
return "waiting";
|
|
642
643
|
case "needs_review":
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **一条 durable run 的「建行 + 驱动」单一属主**(S-218 提取;此前整段住在 `routes/runs.ts` 的
|
|
3
|
+
* `createDurableRun` 里,只服务 HTTP/A2A 两条提交门)。
|
|
4
|
+
*
|
|
5
|
+
* 🔴 为什么提成模块:`/decide` 的 workflow 第三条车道在**宿主不在 park 上**时,同样要在宿主会话上起
|
|
6
|
+
* 一跑新 turn 把决定交给宿主的模型(S-218)。这条链上挂着 `createRun` 的会话 claim(以及它唯一诚实的
|
|
7
|
+
* 409 出路)、checkpoint ctx 落库、fleet 行发布、resume/rewind 两族锚点捕获、审批 ALS、通告投递……
|
|
8
|
+
* 手抄第二份 = 把这十来件事复制成两份会漂的实现,而漂开的那天没有任何东西会说话(`createDurableRun`
|
|
9
|
+
* 当年从路由体里提取出来时,头注写的就是同一条判词)。方向:`routes/runs.ts` 与 `http/server.ts`
|
|
10
|
+
* 都 import 本模块,本模块谁都不 import —— 与 `http/run-meta.ts` 同一条「两个域共用一件 ⇒ 单独成文件」。
|
|
11
|
+
*
|
|
12
|
+
* 边界(本腿**不**含的东西,留给各自的门):`body.taskId` 幂等重放、`Idempotency-Key` 内存去重、
|
|
13
|
+
* lease / 治理窗 pre-admission、属主门。它们是**提交面**的判据(读请求、写响应),而本腿只吃已经备好的
|
|
14
|
+
* `PreparedTaskSubmission` 并交回一份收据 —— 这正是它能被一条没有 `ServerResponse` 的内部车道复用的原因。
|
|
15
|
+
*/
|
|
16
|
+
import { type RunInternals } from "@sema-agent/core";
|
|
17
|
+
import type { RunStore } from "../plugins/store-backend.js";
|
|
18
|
+
import type { PreparedTaskSubmission, RouteCtxBase } from "./route-ctx.js";
|
|
19
|
+
/**
|
|
20
|
+
* 🔴 **TRUSTED run internals** —— 由**部署方**(不是模型、不是请求体、不是工具参数)铸给这一跑的
|
|
21
|
+
* core 内部席位。今天唯一成员 `workflowParkedResume` = 人对一条 parked workflow 子代的决定
|
|
22
|
+
* (语义属主 = core `RunInternals.workflowParkedResume` 的 d.ts 顶注:「A host that decided a workflow
|
|
23
|
+
* child's parked checkpoint launches the run that re-invokes `Workflow({resumeFromRunId})` with the
|
|
24
|
+
* decision here」)。
|
|
25
|
+
*
|
|
26
|
+
* 为什么单独命名而不是直接摊 `RunInternals`:`RunInternals` 里绝大多数席位是**执行腿自己**铸的
|
|
27
|
+
* (onForwardEvent / onTaskNotification / onActivity …),把整只类型开给调用方等于邀请第二个写者;
|
|
28
|
+
* 本类型只开「部署方可以决定的那一格」,新增一格时**必须**在这里显式点名,编译期看得见。
|
|
29
|
+
* 缺席 ⇒ 对两条腿都是完整 no-op。
|
|
30
|
+
*/
|
|
31
|
+
export type TrustedRunInternals = Pick<RunInternals, "workflowParkedResume">;
|
|
32
|
+
export interface DurableRunLegArgs {
|
|
33
|
+
/** `prepareSpec` 的产物,或内部车道按同一条 `resolveSpec` 装配出来的等价形。 */
|
|
34
|
+
prepared: PreparedTaskSubmission;
|
|
35
|
+
/** 调用方自带的 taskId(`POST /v1/runs` 的 `body.taskId` 幂等键);缺席 ⇒ 本腿铸 uuidv7。 */
|
|
36
|
+
clientTaskId?: string;
|
|
37
|
+
/** 🔒 这条 run 的 **fleet 行 scope** —— 必须与 `GET /v1/fleet/stream` 过滤用的是同一个身份,且绝不是
|
|
38
|
+
* 自报的 `x-agent-principal` 头(自报头会把行打到受害者的 scope 上,或打到 `default` 而真属主的流把它
|
|
39
|
+
* 过滤掉)。提交门传 `gatedPrincipal(req) ?? "default"`;`/decide` 的第三条车道传 resume 家族的
|
|
40
|
+
* `resumeFleetScope(req, auth)`(同一条 wire 上两条腿因此同答)。 */
|
|
41
|
+
fleetScope: string;
|
|
42
|
+
/** 🔒 这条 run 的 **elicit / question 应答方**(E23:与 respond 门读的是同一个已验身份,不是自报头)。
|
|
43
|
+
* 提交门传 `gatedPrincipal(req) ?? null` = 提交者本人;`/decide` 的第三条车道传**卡属主**(= 原提交者,
|
|
44
|
+
* 不是代为按下按钮的 operator —— 与 resume 腿那条成文口径逐字同源)。`null` = 匿名/开放部署。 */
|
|
45
|
+
elicitOwner: string | null;
|
|
46
|
+
/** run 行元数据的 `source` 列(调用方的系统身份;内部车道传自己的车道名)。 */
|
|
47
|
+
source: string | null;
|
|
48
|
+
/** 见 {@link TrustedRunInternals}。缺席 ⇒ 与本位存在之前逐字相同。 */
|
|
49
|
+
trustedInternals?: TrustedRunInternals;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 建行 + 驱动。返回 `202` = 新行已建并在跑(体带 `taskId`/`sessionId`);`409` = 会话被别的 run 占着,
|
|
53
|
+
* **没有**建行(体 = `buildActiveRunConflict` 的既有形,含 `errorCode: "conflict.session_active_run"`)。
|
|
54
|
+
* 协议渲染归调用方(HTTP `sendJson` / A2A 协议对象 / `/decide` 的受理体)。
|
|
55
|
+
*/
|
|
56
|
+
export declare function mintAndDriveDurableRun(ctx: RouteCtxBase, runStore: RunStore, args: DurableRunLegArgs): Promise<{
|
|
57
|
+
status: number;
|
|
58
|
+
body: {
|
|
59
|
+
taskId: string;
|
|
60
|
+
sessionId: string;
|
|
61
|
+
status: string;
|
|
62
|
+
} | object;
|
|
63
|
+
}>;
|
|
64
|
+
//# sourceMappingURL=durable-run-leg.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { uuidv7 } from "@sema-agent/core";
|
|
2
|
+
import { runInBackground } from "../runs.js";
|
|
3
|
+
import { fleetRunPublisher, fleetRunLabels } from "../fleet/fleet-bus.js";
|
|
4
|
+
import { cascadeConfig, runMeta } from "./run-meta.js";
|
|
5
|
+
import { resolveStreamApprovalGate } from "../tool-approval.js";
|
|
6
|
+
import { buildActiveRunConflict } from "./active-run-conflict.js";
|
|
7
|
+
import { clearTurnActivity, readTurnActivityMs } from "../turn-activity.js";
|
|
8
|
+
import { recordResourceWindow } from "../resource-window.js";
|
|
9
|
+
export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
10
|
+
const { deps } = ctx;
|
|
11
|
+
const { inflightRuns, preemptableRuns, steerableRuns } = ctx.registry;
|
|
12
|
+
const sessionId = args.prepared.spec.sessionId ?? uuidv7();
|
|
13
|
+
const taskId = args.clientTaskId ?? uuidv7();
|
|
14
|
+
const created = await runStore.createRun(taskId, sessionId, args.prepared.auth?.principal ?? null, deps.instanceId ?? "default", runMeta(args.prepared, args.source));
|
|
15
|
+
if (created.ok)
|
|
16
|
+
clearTurnActivity(taskId);
|
|
17
|
+
if (created.ok)
|
|
18
|
+
recordResourceWindow(taskId, args.prepared.spec.resourceSuspend);
|
|
19
|
+
if (created.ok)
|
|
20
|
+
deps.sessionTitler?.maybeTitle(sessionId, args.prepared.spec.objective, typeof args.prepared.spec.model === "string" ? args.prepared.spec.model : args.prepared.spec.model?.id);
|
|
21
|
+
if (!created.ok) {
|
|
22
|
+
if (args.clientTaskId && created.activeTaskId === args.clientTaskId) {
|
|
23
|
+
return { status: 202, body: { taskId: args.clientTaskId, sessionId, status: "running" } };
|
|
24
|
+
}
|
|
25
|
+
return { status: 409, body: await buildActiveRunConflict({ runStore, checkpointStore: deps.checkpointStore, governance: deps.config, runStaleSec: deps.config.runStaleSec, turnActivity: readTurnActivityMs }, sessionId, created.activeTaskId) };
|
|
26
|
+
}
|
|
27
|
+
if (deps.checkpointStore) {
|
|
28
|
+
await deps.checkpointStore.putCtx(sessionId, { body: args.prepared.body, memoryScope: args.prepared.auth?.memoryScope });
|
|
29
|
+
}
|
|
30
|
+
const anchorOwner = args.prepared.auth?.principal ?? null;
|
|
31
|
+
const getLeafId = deps.sessionStorage?.getLeafId?.bind(deps.sessionStorage);
|
|
32
|
+
const captureTurnAnchor = deps.resumeAnchorStore && getLeafId
|
|
33
|
+
? async (eventId) => {
|
|
34
|
+
const leaf = await getLeafId(sessionId);
|
|
35
|
+
if (leaf)
|
|
36
|
+
await deps.resumeAnchorStore.put(sessionId, eventId, leaf, anchorOwner);
|
|
37
|
+
}
|
|
38
|
+
: undefined;
|
|
39
|
+
const captureUserMessageAnchor = deps.resumeAnchorStore
|
|
40
|
+
? async (entryId) => { await deps.resumeAnchorStore.put(sessionId, taskId, entryId, anchorOwner); }
|
|
41
|
+
: undefined;
|
|
42
|
+
const fleetPub = fleetRunPublisher(deps.fleetBus, {
|
|
43
|
+
runId: taskId,
|
|
44
|
+
scope: args.fleetScope,
|
|
45
|
+
rootTaskId: taskId,
|
|
46
|
+
...fleetRunLabels(args.prepared.spec.objective),
|
|
47
|
+
});
|
|
48
|
+
void runInBackground(args.prepared.runner, { ...args.prepared.spec, sessionId }, runStore, taskId, deps.metrics, args.prepared.auth?.principal, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
|
|
49
|
+
? {
|
|
50
|
+
coordinator: deps.toolApproval,
|
|
51
|
+
streamApprovalOn: resolveStreamApprovalGate({
|
|
52
|
+
toolApprovalEnabled: true,
|
|
53
|
+
streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
|
|
54
|
+
backend: deps.backend,
|
|
55
|
+
parkFacility: deps.checkpointStore !== undefined,
|
|
56
|
+
}).active,
|
|
57
|
+
windowMs: deps.config.streamApproval?.windowMs,
|
|
58
|
+
windowMarginMs: deps.config.streamAskWindowMarginMs,
|
|
59
|
+
}
|
|
60
|
+
: undefined, deps.checkpointStore, args.prepared.engineNotices, args.trustedInternals);
|
|
61
|
+
return { status: 202, body: { taskId, sessionId, status: "running" } };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=durable-run-leg.js.map
|
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -438,6 +438,20 @@ export interface RouteMiss {
|
|
|
438
438
|
* 两臂逐字节同形,指路价值不丢。钉=audit-fixes-http「[ref]」格(两臂全文比对);文案变更走
|
|
439
439
|
* api-error-text-freeze 基线流程。
|
|
440
440
|
*/
|
|
441
|
+
/**
|
|
442
|
+
* **「决定/续跑已受理」那一枚 200 收据的单一铸点**(S-218)。
|
|
443
|
+
*
|
|
444
|
+
* 两条腿投同一份体:①resume 家族的受理点(`driveResumeLeg`,宿主停在 park 上时);②`/decide` 的
|
|
445
|
+
* workflow 第三条车道在宿主**不在** park 上时新铸的那一跑。契约上这两条腿说的是同一句话 ——
|
|
446
|
+
* 「决定已被受理,拿 `taskId` 去 poll `GET /v1/runs/:id` / `/events` 跟终态」——所以消费端**一条分支
|
|
447
|
+
* 都不该加**;写成两份字面量,漂开的那天没有任何东西会说话。
|
|
448
|
+
*
|
|
449
|
+
* `bindingEnforced` 的语义不因铸点而变(「这次决定按绑定坐标受理,不是盲目放行」),故两腿同带。
|
|
450
|
+
*/
|
|
451
|
+
export declare function acceptedResumingReceipt(taskId: string, sessionId: string): {
|
|
452
|
+
status: number;
|
|
453
|
+
body: object;
|
|
454
|
+
};
|
|
441
455
|
export declare const RUN_NOT_FOUND_MESSAGE = "run not found \u2014 the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
|
|
442
456
|
/** [ref] 前缀=域判别子既成契约:a\* 与 wa\* 形 id 给 TaskOutput/journal 指路;其余给 {@link RUN_NOT_FOUND_MESSAGE}。 */
|
|
443
457
|
export declare function runNotFoundMessage(id: string): string;
|
package/dist/http/route-ctx.js
CHANGED
|
@@ -17,6 +17,9 @@ export function sendResumeOutcome(res, out, logger, extraBody) {
|
|
|
17
17
|
res.setHeader("retry-after", String(Math.ceil(wait)));
|
|
18
18
|
sendJson(res, out.status, extraBody === undefined ? out.body : { ...out.body, ...extraBody });
|
|
19
19
|
}
|
|
20
|
+
export function acceptedResumingReceipt(taskId, sessionId) {
|
|
21
|
+
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
|
|
22
|
+
}
|
|
20
23
|
export const RUN_NOT_FOUND_MESSAGE = "run not found — the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
|
|
21
24
|
export function runNotFoundMessage(id) {
|
|
22
25
|
const aStar = /^(?:a|wa)[0-9a-f]{4,}$/i.test(id);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screenedStoredGate } from "../../trace/project.js";
|
|
2
2
|
import { personDecision } from "../../host-decision.js";
|
|
3
3
|
import { sameExecutionRecord } from "@sema-agent/core";
|
|
4
4
|
import { DECIDED_REPLAY_SCAN_CAP, approvalPayloadFingerprint } from "../../plugins/checkpoint-store-sql.js";
|
|
@@ -87,7 +87,7 @@ async function decideIdempotentReplay(cs, args) {
|
|
|
87
87
|
return undefined;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
return
|
|
90
|
+
return screenedStoredGate(first);
|
|
91
91
|
})();
|
|
92
92
|
return {
|
|
93
93
|
status: 200,
|
|
@@ -200,7 +200,7 @@ async function handleApprovalsAssistantBody(req, res, url, ctx, miss) {
|
|
|
200
200
|
...(s.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
201
201
|
...(s.denialLimitFallback !== undefined ? { denialLimitFallback: s.denialLimitFallback } : {}),
|
|
202
202
|
...(s.origin !== undefined ? { origin: s.origin } : {}),
|
|
203
|
-
...(s.
|
|
203
|
+
...(s.ruleStoreUnreadable !== undefined ? { ruleStoreUnreadable: s.ruleStoreUnreadable } : {}),
|
|
204
204
|
objective: ctx?.body?.objective ?? null,
|
|
205
205
|
input,
|
|
206
206
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
2
2
|
import { isModelAllowlisted } from "../../model-select.js";
|
|
3
3
|
import { resolveModelApiKey } from "../../key-resolver.js";
|
|
4
4
|
import { isSealedKeyPoison } from "../../sealed-key.js";
|
|
@@ -194,7 +194,7 @@ async function handleCapabilitiesBody(req, res, url, ctx, miss) {
|
|
|
194
194
|
vision: Array.isArray(m.input) ? m.input.includes("image") : false,
|
|
195
195
|
...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
|
|
196
196
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
197
|
-
...(
|
|
197
|
+
...((levels) => (levels !== undefined ? { supportedEffortLevels: [...levels] } : {}))(reasoningEffortLevelsOf(m)),
|
|
198
198
|
...(m.compat !== undefined ? { compat: m.compat } : {}),
|
|
199
199
|
...(atAllowlist.length > 0 ? { atMentionable: isModelAllowlisted(name, atCatalog, atAllowlist) } : {}),
|
|
200
200
|
routePairing: routePairingOf(deps, name, m),
|