@sema-agent/server 7.95.1 → 7.97.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 +10 -5
- package/deploy/sema-up/README.md +8 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +3 -0
- package/deploy/sema-up/chart/templates/server.yaml +3 -0
- package/deploy/sema-up/lib/lanes.json +56 -0
- package/deploy/sema-up/lib/lanes.py +179 -0
- package/deploy/sema-up/lib/parse-machines.py +7 -1
- package/deploy/sema-up/machines.example.yaml +5 -2
- package/deploy/sema-up/preflight.sh +7 -4
- package/deploy/sema-up/sema-up.sh +201 -24
- package/deploy/sema-up/stack/compose.yaml +4 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +2 -0
- package/dist/approval.d.ts +28 -0
- package/dist/approval.js +24 -0
- package/dist/boot/budget-tracing.d.ts +1 -0
- package/dist/boot/budget-tracing.js +3 -2
- package/dist/boot/config-center.js +2 -5
- package/dist/boot/coordinators.js +2 -2
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -2
- package/dist/boot/deferred-sandbox-path-env.js +3 -1
- package/dist/boot/memory-boundary.d.ts +17 -2
- package/dist/boot/memory-boundary.js +11 -0
- package/dist/boot/reapers.d.ts +3 -1
- package/dist/boot/reapers.js +2 -2
- package/dist/boot/resolve-spec.js +6 -6
- package/dist/boot/runner-deps.d.ts +2 -1
- package/dist/boot/session-faces.d.ts +4 -1
- package/dist/boot/session-faces.js +5 -5
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-04-stores.js +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +1 -0
- package/dist/boot/stage-07-capability-layer.d.ts +1 -0
- package/dist/boot/stage-07-capability-layer.js +10 -14
- package/dist/boot/stage-08-reapers.d.ts +2 -3
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +1 -0
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +1 -0
- package/dist/boot/stores.js +5 -11
- package/dist/capabilities/execution-lane.d.ts +5 -7
- package/dist/capabilities/execution-lane.js +2 -1
- package/dist/capabilities/memory-notice.d.ts +30 -12
- package/dist/capabilities/memory-notice.js +8 -1
- package/dist/capabilities/skills.d.ts +14 -0
- package/dist/capabilities/skills.js +4 -0
- package/dist/config-catalog.js +1 -0
- package/dist/config-types.d.ts +8 -1
- package/dist/config.d.ts +16 -0
- package/dist/config.js +13 -12
- package/dist/env-facts.js +2 -4
- package/dist/execution-lane-caps.d.ts +36 -6
- package/dist/execution-lane-caps.js +4 -0
- package/dist/file-history-capture.d.ts +65 -0
- package/dist/file-history-capture.js +21 -0
- package/dist/hosted-posture.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +14 -4
- package/dist/http/resume-legs.js +26 -17
- package/dist/http/route-ctx.d.ts +35 -9
- package/dist/http/routes/approvals-assistant.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +16 -6
- package/dist/http/routes/capabilities.js +4 -1
- package/dist/http/routes/runs.js +2 -2
- package/dist/http/routes/session-sync.js +6 -1
- package/dist/http/routes/tasks.js +2 -2
- package/dist/http/server.d.ts +4 -1
- package/dist/http/server.js +1 -1
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/memory-scope.d.ts +6 -2
- package/dist/memory-scope.js +3 -2
- package/dist/observability/fail-open.d.ts +4 -0
- package/dist/observability/fail-open.js +4 -0
- package/dist/observability/run-terminal.js +1 -0
- package/dist/run-local.js +4 -5
- package/dist/session-sync.d.ts +4 -1
- package/dist/session-sync.js +2 -2
- package/dist/task-cwd.d.ts +9 -3
- package/dist/task-cwd.js +3 -1
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +11 -0
- package/dist/trace/project.js +1 -0
- package/package.json +4 -3
package/dist/http/routes/runs.js
CHANGED
|
@@ -589,7 +589,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
589
589
|
const leafId = await Promise.resolve(deps.sessionStorage.getLeafId(run.sessionId)).catch(() => undefined);
|
|
590
590
|
if (leafId === undefined || leafId === null)
|
|
591
591
|
return;
|
|
592
|
-
const resumeRead = await readResumeCtx(
|
|
592
|
+
const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId));
|
|
593
593
|
if (resumeRead.kind === "corrupt") {
|
|
594
594
|
mintResult.corruptCtxWhere = resumeRead.where;
|
|
595
595
|
return;
|
|
@@ -612,7 +612,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
612
612
|
createdAt: Date.now(),
|
|
613
613
|
sourceTaskId: taskId,
|
|
614
614
|
});
|
|
615
|
-
const stillRead = await readResumeCtx(
|
|
615
|
+
const stillRead = await readResumeCtx(cs.getCtx(run.sessionId));
|
|
616
616
|
if (stillRead.kind === "corrupt") {
|
|
617
617
|
await cs.expire(wakeToken, cpScope).catch(() => undefined);
|
|
618
618
|
mintResult.corruptCtxWhere = stillRead.where;
|
|
@@ -41,6 +41,11 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
41
41
|
sendError(res, 501, "capability.session_store_required", "session sync requires a durable session store");
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
+
const historyStore = deps.fileHistoryStore;
|
|
45
|
+
if (historyStore === undefined) {
|
|
46
|
+
sendError(res, 501, "capability.snapshot_store_required", "session sync is not available on this deployment: file-history capture is turned off (FILE_HISTORY_CAPTURE=false), so there is no file history to export or import");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
44
49
|
const scope = sessionOwnerScopeForWrite(req);
|
|
45
50
|
if (!scope.fleetWide && scope.gateOwner === null) {
|
|
46
51
|
sendError(res, 401, "auth.unauthorized", "unauthorized");
|
|
@@ -76,7 +81,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
76
81
|
return;
|
|
77
82
|
let out;
|
|
78
83
|
try {
|
|
79
|
-
out = await exportSessionManifest(sessionId, deps.backend);
|
|
84
|
+
out = await exportSessionManifest(sessionId, deps.backend, historyStore);
|
|
80
85
|
}
|
|
81
86
|
catch (e) {
|
|
82
87
|
if (sendSessionPolicyError(res, e))
|
|
@@ -13,7 +13,7 @@ import { clearTurnActivity, readTurnActivityMs, recordTurnActivity } from "../..
|
|
|
13
13
|
import { mintCancelledResult } from "../../run-cancel-context.js";
|
|
14
14
|
import { recordResourceWindow } from "../../resource-window.js";
|
|
15
15
|
import { redactSecrets } from "../../trace/redact.js";
|
|
16
|
-
import { contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, textEndEventData, liveIdentityFields } from "../../trace/project.js";
|
|
16
|
+
import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, textEndEventData, liveIdentityFields } from "../../trace/project.js";
|
|
17
17
|
import { cascadeConfig, runMeta } from "../run-meta.js";
|
|
18
18
|
import { scopedIdempotencyKey } from "../idempotency.js";
|
|
19
19
|
import { sendJson, sendError, sseHeaders } from "../send.js";
|
|
@@ -527,7 +527,7 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
527
527
|
?
|
|
528
528
|
textEnd === null || textEnd === undefined ? null : { type: "text_end", ...textEnd }
|
|
529
529
|
: ev.type === "turn_end"
|
|
530
|
-
? { type: "turn_end", ...(
|
|
530
|
+
? { type: "turn_end", ...turnEndEventData(ev), ...ident }
|
|
531
531
|
: ev.type === "message_committed"
|
|
532
532
|
? { type: "message_committed", entryId: e.entryId, role: e.role, ...(e.toolCallId !== undefined ? { toolCallId: e.toolCallId } : {}), ...ident }
|
|
533
533
|
: { type: "context_usage", ...contextUsageEventData(ev), ...ident };
|
package/dist/http/server.d.ts
CHANGED
|
@@ -146,7 +146,10 @@ export interface ServiceStoreDeps {
|
|
|
146
146
|
toolResultStore?: ToolResultStoreFull;
|
|
147
147
|
/** [ref] per-edited-file rewind history store. Present ⇒ the rewind capabilities are advertised; core uses it
|
|
148
148
|
* via RunnerDeps.fileHistoryStore (first-touch tracking + per-turn boundaries + tracked-set restore, ANY
|
|
149
|
-
* env). Also the 2c history-transfer store (exportHistory/importHistory + blob negotiation faces).
|
|
149
|
+
* env). Also the 2c history-transfer store (exportHistory/importHistory + blob negotiation faces).
|
|
150
|
+
* 🔴 S-589:这是装配单点 `assembleFileHistory` 的**捕获脸**(后端 ∧ `FILE_HISTORY_CAPTURE`),不是「后端有没有这只店」
|
|
151
|
+
* —— 旋钮关着时它缺席,rewind 族四位、能力词 `fileHistoryCapture` 与 2c sync 路由族一起按「店不在」走。
|
|
152
|
+
* 擦除(E21 / 孤儿 blob GC)不读本键,读 boot 侧的擦除脸。 */
|
|
150
153
|
fileHistoryStore?: ServiceFileHistoryStore;
|
|
151
154
|
/** D-1 通用文件上传(clay 拍 2026-07-27:独立附件 store,不骑 snapshot blob 面):enables
|
|
152
155
|
* POST/GET/DELETE /v1/attachments*。缺席 ⇒ 501(与其他可选 store 面同姿)。绑定/物化半场在
|
package/dist/http/server.js
CHANGED
|
@@ -94,7 +94,7 @@ export function createHttpServer(rawDeps) {
|
|
|
94
94
|
}
|
|
95
95
|
const { quotaExceeded, ownerCostQuotaDenied, ownerFleetLeaseDenied, ownerLeaseDenied, ownerQuotaDenied, leaseDenied, usageWindowDenialFor, usageWindowDenied, rateLimited, safeDecode, isFleetWide, sessionOwnerScope, sessionOwnerScopeForWrite, runOwnerOk, runSessionAcceptOk, readJson, readRawBody } = createRequestGuards({ deps });
|
|
96
96
|
const { prepareSpec } = createAdmission({ deps, readJson, runnerFor });
|
|
97
|
-
const { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake
|
|
97
|
+
const { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake } = createResumeLegs({ deps, runnerFor, idemCache, inflightRuns, preemptableRuns, cancelledViaVerb, steerableRuns, wakeParkMints, counters, readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, safeDecode, isFleetWide, runOwnerOk, sessionOwnerScope, sessionOwnerScopeForWrite, runSessionAcceptOk, prepareSpec, finalizeTaskResult, ownerCostQuotaDenied, ownerFleetLeaseDenied, usageWindowDenialFor });
|
|
98
98
|
const { denyExpiredApprovals, redeemParkedAsk } = createApprovalSweeps({ deps, resumeCheckpoint, mayDiscloseRowError });
|
|
99
99
|
const { handle } = createDispatch({ deps, noteActivity, routeCtxBase, counters });
|
|
100
100
|
const server = http.createServer((req, res) => {
|
|
@@ -19,6 +19,6 @@ export declare function clampVerifyRounds(v: unknown): number;
|
|
|
19
19
|
/** `undefined` when `body.verify` is not `true` (the caller didn't opt into the gate); otherwise the clamped
|
|
20
20
|
* rounds + (if `maxCostUsd` is a positive number) the same USD→micro-USD cost ceiling the cascade lane uses.
|
|
21
21
|
* Same expression that lived inline at all four verify/resume call sites in http/server.ts (fresh-submit,
|
|
22
|
-
* resumeCheckpoint, resumePreempted, resumePlanReview) — collected here VERBATIM ([ref] R9). */
|
|
22
|
+
* resumeCheckpoint, resumePreempted, drivePlanReview — named resumePlanReview before S-609) — collected here VERBATIM ([ref] R9). */
|
|
23
23
|
export declare function verifyRoundsFromBody(body: Pick<TaskRequestBody, "verify" | "verifyRounds" | "maxCostUsd">): VerifyRoundsSpec | undefined;
|
|
24
24
|
//# sourceMappingURL=verify-rounds.d.ts.map
|
package/dist/memory-scope.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FileMemoryEngineBackend, type TaskSpec } from "@sema-agent/core";
|
|
2
2
|
import type { ServiceConfig } from "./config-types.js";
|
|
3
|
+
import { type ExecutionLane } from "./execution-lane-caps.js";
|
|
3
4
|
/** 前缀词表本体(供门/诊断读;判定一律走 {@link isV2ScopeKey},别在别处重写 startsWith 链)。 */
|
|
4
5
|
export declare const V2_SCOPE_PREFIXES: readonly string[];
|
|
5
6
|
/**
|
|
@@ -40,10 +41,13 @@ export declare function memoryScopeFor(config: ServiceConfig, principal?: string
|
|
|
40
41
|
* (`MEMORY_ENGINE_REMOTE_LANE=allow`, e.g. ssh to a host on the same NFS mount).
|
|
41
42
|
*
|
|
42
43
|
* Pure posture probe (memoryEngineBackendFor consumes it; main.ts logs it): `undefined` = no plane split
|
|
43
|
-
* (
|
|
44
|
+
* (the lane's file plane IS this worker's fs — `in-process` / `host`), `dark` = split + fail-closed, `forced` =
|
|
45
|
+
* split + operator override.
|
|
46
|
+
* S-602: the plane question reads the lane-caps table (`hostFilePlane`) — it used to be the hand-written synonym
|
|
47
|
+
* `lane === undefined || lane === "host"` (fold-ban gate D, R3); readings are unchanged lane by lane.
|
|
44
48
|
*/
|
|
45
49
|
export declare function memoryEngineRemoteLanePosture(config: ServiceConfig): {
|
|
46
|
-
lane:
|
|
50
|
+
lane: ExecutionLane;
|
|
47
51
|
posture: "dark" | "forced";
|
|
48
52
|
} | undefined;
|
|
49
53
|
/**
|
package/dist/memory-scope.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { FileMemoryEngineBackend, resolveMemoryEngineRoot, deriveControlPlaneDir, formatUserScope, formatProjScope, normalizeMemorySpec } from "@sema-agent/core";
|
|
3
|
+
import { executionLaneCaps, executionLaneOf } from "./execution-lane-caps.js";
|
|
3
4
|
import { assertMemoryScopeWidth } from "./plugins/memory-key-guards.js";
|
|
4
5
|
const V2_SCOPE_PREFIX_BY_KIND = {
|
|
5
6
|
user: "user:",
|
|
@@ -26,8 +27,8 @@ export function memoryScopeFor(config, principal, projectId) {
|
|
|
26
27
|
return config.memoryScope;
|
|
27
28
|
}
|
|
28
29
|
export function memoryEngineRemoteLanePosture(config) {
|
|
29
|
-
const lane = config.remoteExec?.provider;
|
|
30
|
-
if (lane ===
|
|
30
|
+
const lane = executionLaneOf(config.remoteExec?.provider);
|
|
31
|
+
if (executionLaneCaps(lane).hostFilePlane === "supported")
|
|
31
32
|
return undefined;
|
|
32
33
|
return { lane, posture: config.memoryEngineRemoteLaneAllowed === true ? "forced" : "dark" };
|
|
33
34
|
}
|
|
@@ -281,6 +281,10 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
281
281
|
readonly cls: "F";
|
|
282
282
|
readonly note: "S-287(`plugins/ensure-index.ts` 的 PG 臂):这口 PG **协议**面不认 `CREATE INDEX CONCURRENTLY`。今天唯一的真消费者是**仓内离线镜像的手搓 `PgQueryFn` 假件**(`pg-mem` 不是本仓依赖,`test/memory-embedder-fingerprint.test.ts` 头注已为此记过一次档,这里不重复那个错)。判据是**能力面**不是名字,且**只认阳性信号**:SQLSTATE ∈ {`0A000` feature_not_supported、`42601` syntax_error},或错误**完全不带 `code`**(= 不是驱动也不是服务端给的错误)⇒ 判「不认」,回退成普通 `CREATE INDEX IF NOT EXISTS`;**带任何其它 `code` 的一律原样抛** —— SQLSTATE 的 `55P03`/`57014`/`23505`/`42501`/`25001` 与 libuv 的 `ECONNRESET`/`EPIPE`/`ETIMEDOUT` 都在这一侧(⚠️ 不要按「5 位大写」的形状去分这两族:`EPIPE` 恰好也是 5 位大写)。放行的最坏后果 = 这一次建索引持表级 `SHARE` 锁阻塞该表的写(纯**性能/可用性**面,索引本身照样建成、语义零差别),而能走到这条臂的面**按定义**不是生产 PG。计数非零 = 有一口本以为是真 PG 的部署其实不认 CONCURRENTLY,运维要去看它到底是什么。detail = `<表>.<索引名>`。";
|
|
283
283
|
};
|
|
284
|
+
readonly "server.assistant-inbox.objective-ctx-corrupt": {
|
|
285
|
+
readonly cls: "F";
|
|
286
|
+
readonly note: "S-609(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):某一行的续跑上下文(checkpoint_ctx)读出来是**坏体**(店的拒绝契约 `StoreCorruptError`;local = 档不是 JSON / 信封不合形,SQL = 列是合法 JSON 但不是一只对象)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡不显示它属于哪个任务(纯展示位;这一格不参与任何决裁、续跑或门判 —— 续跑腿与 plan_review 门对同一行各自走读口、坏体一律响亮 500)。不放行的代价是整只 `summaries.map` 抛出 ⇒ 一行坏体打掉整个用户的 inbox。故 F 类;必须留痕,因为修前那句 `.catch(() => null)` 让「坏体」与「本来就没有」同形无痕(detail = 读口转述的 `where`,人拿它去修那一行)。缺席(行不在 / 店抖动)**不**记本 tag:那是读口的刻意保守,不是失败开放。";
|
|
287
|
+
};
|
|
284
288
|
};
|
|
285
289
|
/** 词表键推导的闭集类型——未登记的 tag 传不进 {@link recordFailOpen}(编译期拒)。 */
|
|
286
290
|
export type FailOpenTag = keyof typeof FAIL_OPEN_TAGS;
|
|
@@ -254,6 +254,10 @@ export const FAIL_OPEN_TAGS = {
|
|
|
254
254
|
cls: "F",
|
|
255
255
|
note: "S-287(`plugins/ensure-index.ts` 的 PG 臂):这口 PG **协议**面不认 `CREATE INDEX CONCURRENTLY`。今天唯一的真消费者是**仓内离线镜像的手搓 `PgQueryFn` 假件**(`pg-mem` 不是本仓依赖,`test/memory-embedder-fingerprint.test.ts` 头注已为此记过一次档,这里不重复那个错)。判据是**能力面**不是名字,且**只认阳性信号**:SQLSTATE ∈ {`0A000` feature_not_supported、`42601` syntax_error},或错误**完全不带 `code`**(= 不是驱动也不是服务端给的错误)⇒ 判「不认」,回退成普通 `CREATE INDEX IF NOT EXISTS`;**带任何其它 `code` 的一律原样抛** —— SQLSTATE 的 `55P03`/`57014`/`23505`/`42501`/`25001` 与 libuv 的 `ECONNRESET`/`EPIPE`/`ETIMEDOUT` 都在这一侧(⚠️ 不要按「5 位大写」的形状去分这两族:`EPIPE` 恰好也是 5 位大写)。放行的最坏后果 = 这一次建索引持表级 `SHARE` 锁阻塞该表的写(纯**性能/可用性**面,索引本身照样建成、语义零差别),而能走到这条臂的面**按定义**不是生产 PG。计数非零 = 有一口本以为是真 PG 的部署其实不认 CONCURRENTLY,运维要去看它到底是什么。detail = `<表>.<索引名>`。"
|
|
256
256
|
},
|
|
257
|
+
"server.assistant-inbox.objective-ctx-corrupt": {
|
|
258
|
+
cls: "F",
|
|
259
|
+
note: "S-609(`routes/approvals-assistant.ts` 的 `GET /v1/assistant/inbox`):某一行的续跑上下文(checkpoint_ctx)读出来是**坏体**(店的拒绝契约 `StoreCorruptError`;local = 档不是 JSON / 信封不合形,SQL = 列是合法 JSON 但不是一只对象)⇒ **这一行**的 `objective` 落 `null`,列表其余照常。放行的最坏后果 = inbox 上这一张卡不显示它属于哪个任务(纯展示位;这一格不参与任何决裁、续跑或门判 —— 续跑腿与 plan_review 门对同一行各自走读口、坏体一律响亮 500)。不放行的代价是整只 `summaries.map` 抛出 ⇒ 一行坏体打掉整个用户的 inbox。故 F 类;必须留痕,因为修前那句 `.catch(() => null)` 让「坏体」与「本来就没有」同形无痕(detail = 读口转述的 `where`,人拿它去修那一行)。缺席(行不在 / 店抖动)**不**记本 tag:那是读口的刻意保守,不是失败开放。",
|
|
260
|
+
},
|
|
257
261
|
};
|
|
258
262
|
export function failOpenTagForDroppedFrame(frameType) {
|
|
259
263
|
switch (frameType) {
|
package/dist/run-local.js
CHANGED
|
@@ -24,10 +24,9 @@ import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
|
|
|
24
24
|
import { createConfigProvider } from "./config-provider.js";
|
|
25
25
|
import { applyEffective, applyCenterReadFace, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./config-center/facade.js";
|
|
26
26
|
import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
|
|
27
|
-
import { executionLaneHomeDir } from "./execution-lane-caps.js";
|
|
27
|
+
import { executionLaneHomeDir, executionLaneOf } from "./execution-lane-caps.js";
|
|
28
28
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "./project-memory.js";
|
|
29
|
-
import {
|
|
30
|
-
import { toolsRunOnThisHost } from "./task-cwd.js";
|
|
29
|
+
import { loadDeploymentSkills } from "./capabilities/skills.js";
|
|
31
30
|
import { createRepoClient } from "./capabilities/repo-tools.js";
|
|
32
31
|
import { webSearchConfigFromEnv, createWebSearchBackend } from "./plugins/web-search.js";
|
|
33
32
|
import { buildScenarios, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
|
|
@@ -424,7 +423,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
424
423
|
const subRunner = new Runner(subRunnerDeps);
|
|
425
424
|
const handslessRunner = new Runner(withoutExecutionEnv(runnerDeps));
|
|
426
425
|
const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
|
|
427
|
-
const skills =
|
|
426
|
+
const skills = loadDeploymentSkills(config);
|
|
428
427
|
const repoClient = config.gitApiBaseUrl ? createRepoClient(config.gitApiKind, config.gitApiBaseUrl, config.gitApiToken) : undefined;
|
|
429
428
|
const webSearchCfg = webSearchConfigFromEnv();
|
|
430
429
|
const webSearch = webSearchCfg ? createWebSearchBackend(webSearchCfg) : undefined;
|
|
@@ -489,7 +488,7 @@ export async function runLocal(argv, deps = {}) {
|
|
|
489
488
|
...(a2a ? { a2a } : {}),
|
|
490
489
|
...(Object.keys(limits).length > 0 ? { limits } : {}),
|
|
491
490
|
}, config, workspaceDir, memoryEngine?.root);
|
|
492
|
-
logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: config.remoteExec?.provider
|
|
491
|
+
logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: executionLaneOf(config.remoteExec?.provider) });
|
|
493
492
|
const settleSessionBackground = async () => {
|
|
494
493
|
const reaped = defaultTaskRegistry.reapSessionBackground(sessionId, scope);
|
|
495
494
|
if (reaped === 0)
|
package/dist/session-sync.d.ts
CHANGED
|
@@ -140,7 +140,10 @@ export interface SessionManifest {
|
|
|
140
140
|
* `null` ONLY for "session does not exist". (Named exportSessionManifest, NOT exportManifest, to avoid the collision
|
|
141
141
|
* with the history store's own export verb.)
|
|
142
142
|
*/
|
|
143
|
-
export declare function exportSessionManifest(sessionId: string, srcBackend: StoreBackend
|
|
143
|
+
export declare function exportSessionManifest(sessionId: string, srcBackend: StoreBackend,
|
|
144
|
+
/** S-589:文件历史读**装配结果**(捕获脸),不直取 `srcBackend.fileHistory()` —— 「这台部署有没有文件历史店」
|
|
145
|
+
* 只在 `assembleFileHistory` 判一次。同一个后端铸的同一只店,四店同源的不变式不变。 */
|
|
146
|
+
historyStore: ServiceFileHistoryStore): Promise<{
|
|
144
147
|
manifest: SessionManifest;
|
|
145
148
|
getBlob: BlobGetter;
|
|
146
149
|
} | null>;
|
package/dist/session-sync.js
CHANGED
|
@@ -21,7 +21,7 @@ export async function replayFileHistory(store, scope, envelope, srcGetBlob, opts
|
|
|
21
21
|
function ownerAware(backend) {
|
|
22
22
|
return backend.session();
|
|
23
23
|
}
|
|
24
|
-
export async function exportSessionManifest(sessionId, srcBackend) {
|
|
24
|
+
export async function exportSessionManifest(sessionId, srcBackend, historyStore) {
|
|
25
25
|
const session = ownerAware(srcBackend);
|
|
26
26
|
const listEntryIds = session.listEntryIds?.bind(session);
|
|
27
27
|
if (!listEntryIds)
|
|
@@ -31,7 +31,7 @@ export async function exportSessionManifest(sessionId, srcBackend) {
|
|
|
31
31
|
return null;
|
|
32
32
|
const getLeafId = session.getLeafId?.bind(session);
|
|
33
33
|
const leafId = getLeafId ? await getLeafId(sessionId) : null;
|
|
34
|
-
const fs =
|
|
34
|
+
const fs = historyStore;
|
|
35
35
|
const fileHistory = typeof fs.exportHistory === "function" ? await fs.exportHistory(sessionId) : null;
|
|
36
36
|
const policyStore = srcBackend.sessionPolicy();
|
|
37
37
|
const policy = typeof policyStore.listBySession === "function"
|
package/dist/task-cwd.d.ts
CHANGED
|
@@ -56,12 +56,18 @@ export declare function cwdHonored(config: {
|
|
|
56
56
|
* S-377 —— 「**工具跑的那台机器**就是本进程这台吗」。回答的是一个**文件系统同一性**问题,不是权限问题:
|
|
57
57
|
* server 盘上的一条绝对路径(出厂 `SKILLS_DIR` 下某个技能自己的目录)对模型的工具**有没有意义**。
|
|
58
58
|
*
|
|
59
|
+
* 判据 = 能力表两位的合取 {@link handsOnWorkerFilePlane}(`coreRemoteExecutionEnv ∧ hostFilePlane`,都读表,
|
|
60
|
+
* 本函数不手写任何车道词):
|
|
59
61
|
* · `host`(run-on-this-machine,无容器)⇒ 真;
|
|
60
|
-
* · `
|
|
61
|
-
*
|
|
62
|
+
* · `in-process`(`REMOTE_EXEC` 未设)⇒ **假**(S-602,clay 裁 [ref] A 翻面;改前判真)—— 该 lane 根本
|
|
63
|
+
* 没挂手(core 落 `StubExecutionEnv`),「工具的盘」这句话在这里没有指称对象。改前的理由「文件系统同一性
|
|
64
|
+
* 这条轴上确实是同一台机器,判真让规则只剩一条」把**缺席折成了邻居**:wire 上的 `toolsOnThisHost` 因此
|
|
65
|
+
* 对无手部署说真,消费端的 doctor 据此说「工具在本机」。代价如实记:出厂目录形技能在 in-process 上不再带
|
|
66
|
+
* `baseDir` —— core 律:缺席 ⇒ 结果逐字节同 baseDir 到货之前,而那条 lane 上本来也没有能读它的工具;
|
|
62
67
|
* · 其余每一条(`k8s` / `e2b` / `ssh` / `adb` / `device` / `local-docker`)⇒ 假:工具的盘在别处,
|
|
63
68
|
* server 自己的路径在那边**不存在**,声明它等于给模型一条指向不存在文件的线索,还顺带把本机目录
|
|
64
|
-
*
|
|
69
|
+
* 布局说了出去;
|
|
70
|
+
* · 认不出的词 ⇒ 假(fail-closed:没认出来的车道不许被当成「本机」)。
|
|
65
71
|
*
|
|
66
72
|
* 🔴 **为什么不复用 {@link cwdHonored}**:那一只是**权限**判据(单用户 ∧ host),它的 `requirePrincipal`
|
|
67
73
|
* 那一半防的是「一个租户的输入把 agent 指向另一个租户的文件」。本谓词判的路径不是调用方给的,是**运维
|
package/dist/task-cwd.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { executionLaneOf, handsOnWorkerFilePlane } from "./execution-lane-caps.js";
|
|
2
3
|
export const MAX_CWD_CHARS = 4_096;
|
|
3
4
|
export function isValidCwd(cwd) {
|
|
4
5
|
return (typeof cwd === "string" &&
|
|
@@ -21,7 +22,8 @@ export function cwdHonored(config) {
|
|
|
21
22
|
return config.remoteExec?.provider === "host" && config.requirePrincipal !== true;
|
|
22
23
|
}
|
|
23
24
|
export function toolsRunOnThisHost(config) {
|
|
24
|
-
|
|
25
|
+
const lane = executionLaneOf(config.remoteExec?.provider);
|
|
26
|
+
return lane !== undefined && handsOnWorkerFilePlane(lane);
|
|
25
27
|
}
|
|
26
28
|
export function deviceCwdHonored(config) {
|
|
27
29
|
return config.remoteExec?.provider === "device";
|
|
@@ -138,7 +138,7 @@ type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requi
|
|
|
138
138
|
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
139
139
|
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
140
140
|
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
141
|
-
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles";
|
|
141
|
+
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles" | "responseModel";
|
|
142
142
|
type TaskResultStripped = never;
|
|
143
143
|
type _GuardTaskResult = AssertAllKeysHandled<Exclude<keyof TaskResult, TaskResultForwarded | TaskResultStripped>>;
|
|
144
144
|
type _GuardTaskResultReverse = AssertAllKeysHandled<Exclude<TaskResultForwarded | TaskResultStripped, keyof TaskResult>>;
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -904,11 +904,22 @@ export declare function contextUsageEventData(ev: {
|
|
|
904
904
|
* 而不是"未知";这正是那种"回放后看起来一切正常"的丢失。
|
|
905
905
|
* 两者**在 live 腿看得见、durable 腿回放后永久消失** —— 与 [ref] 的 `label`、[ref] 的 workflowRunId 同一族
|
|
906
906
|
* (白名单没跟上 core 新增字段)。补 builder 的同时也就把它纳入了 `wire-whitelist-exhaustiveness` 的编译期差集门。
|
|
907
|
+
*
|
|
908
|
+
* 🔴 **本构造器是 `turn_end` 帧载荷的唯一铸点**(core 7.29.0 提货批,车LY):三条腿同调 —— live SSE
|
|
909
|
+
* (`http/routes/tasks.ts` 的 `/v1/tasks/stream` 臂,身份键另由 `liveIdentityFields` 补四键)、durable 账本
|
|
910
|
+
* (`ledger-sink.ts`)、resume 腿(`resume-legs.ts`)。live 臂此前是一份**手抄**的键集,于是 core 7.29.0 加的
|
|
911
|
+
* `responseModel` 在 durable 面由这里补上以后,live 面仍会被那份手抄静默剥掉 —— 同一帧两条腿两套键集。
|
|
912
|
+
*
|
|
913
|
+
* `responseModel`(core 7.29.0 #1029):**供应商自己**报的、回答这一 turn 的模型名,**只在**它 ≠ 请求所带 id
|
|
914
|
+
* 时在场。缺席 = 「报了同名」或「没报」,**一个读法**(请求 id 读 `TaskResult.model`)。值是供应商铸的名字
|
|
915
|
+
* (与 `apiFailure.requestId` 同类:不是模型写的自由文本)⇒ 逐字;非串 / 空串 ⇒ 缺席(core 的读律
|
|
916
|
+
* `providerReportedModel` 对空串答「没报」,本仓不铸一个看起来合法的空名)。
|
|
907
917
|
*/
|
|
908
918
|
export declare function turnEndEventData(ev: {
|
|
909
919
|
usage?: unknown;
|
|
910
920
|
usageMissing?: true;
|
|
911
921
|
stopReason?: string;
|
|
922
|
+
responseModel?: unknown;
|
|
912
923
|
eventId?: unknown;
|
|
913
924
|
parentToolCallId?: unknown;
|
|
914
925
|
}): Record<string, unknown>;
|
package/dist/trace/project.js
CHANGED
|
@@ -717,6 +717,7 @@ export function turnEndEventData(ev) {
|
|
|
717
717
|
...(ev.usage ? { usage: ev.usage } : {}),
|
|
718
718
|
...(ev.usageMissing === true ? { usageMissing: true } : {}),
|
|
719
719
|
...(typeof ev.stopReason === "string" ? { stopReason: ev.stopReason } : {}),
|
|
720
|
+
...(typeof ev.responseModel === "string" && ev.responseModel !== "" ? { responseModel: ev.responseModel } : {}),
|
|
720
721
|
...identityFields(ev),
|
|
721
722
|
};
|
|
722
723
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.97.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",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"types": "./dist/device-protocol.d.ts",
|
|
19
19
|
"default": "./dist/device-protocol.js"
|
|
20
20
|
},
|
|
21
|
-
"./package.json": "./package.json"
|
|
21
|
+
"./package.json": "./package.json",
|
|
22
|
+
"./deploy/sema-up/lanes.json": "./deploy/sema-up/lib/lanes.json"
|
|
22
23
|
},
|
|
23
24
|
"files": [
|
|
24
25
|
"dist",
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
|
|
60
61
|
},
|
|
61
62
|
"dependencies": {
|
|
62
|
-
"@sema-agent/core": "7.
|
|
63
|
+
"@sema-agent/core": "7.29.0",
|
|
63
64
|
"@sema-agent/settings-schema": "3.0.0",
|
|
64
65
|
"e2b": "^2.28.0",
|
|
65
66
|
"libsodium-wrappers": "^0.8.4",
|