@sema-agent/server 7.85.0 → 7.87.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 +19 -1
- package/dist/approval-hmac.d.ts +77 -2
- package/dist/approval-hmac.js +16 -1
- package/dist/boot/stage-01-config.js +2 -2
- package/dist/capabilities/execution-lane.d.ts +22 -0
- package/dist/capabilities/execution-lane.js +8 -0
- package/dist/capabilities/memory-notice.d.ts +4 -1
- package/dist/config-catalog.js +2 -1
- package/dist/execution-lane-caps.d.ts +13 -0
- package/dist/execution-lane-caps.js +1 -0
- package/dist/fleet/fleet-bus.d.ts +23 -3
- package/dist/fleet/fleet-reconciler.d.ts +35 -0
- package/dist/fleet/fleet-reconciler.js +52 -9
- package/dist/http/approval-sweeps.js +1 -1
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +24 -8
- package/dist/http/route-ctx.d.ts +51 -17
- package/dist/http/route-ctx.js +0 -3
- package/dist/http/routes/a2a-serve.js +1 -1
- package/dist/http/routes/approvals-assistant.d.ts +46 -23
- package/dist/http/routes/approvals-assistant.js +167 -45
- package/dist/http/routes/capabilities.js +2 -0
- package/dist/http/routes/images.js +38 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-policy.js +3 -6
- package/dist/http/routes/notify-wake.js +11 -3
- package/dist/http/routes/run-memory-capture.js +3 -5
- package/dist/http/routes/runs.js +21 -23
- package/dist/http/routes/sessions.js +10 -2
- package/dist/http/routes/shared-memory.js +5 -1
- package/dist/http/routes/tasks.js +2 -2
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/server.d.ts +2 -2
- package/dist/http/server.js +3 -3
- package/dist/leader/diffout.js +1 -1
- package/dist/leader/endpoint.js +1 -1
- package/dist/leader/fanout.js +1 -1
- package/dist/leader/leader.js +1 -1
- package/dist/leader/merge.js +1 -1
- package/dist/leader/planner.js +1 -1
- package/dist/leader/repair-oracle.js +1 -1
- package/dist/leader/repair-wire.js +1 -1
- package/dist/leader/wire.js +1 -1
- package/dist/memory-scope.d.ts +16 -0
- package/dist/observability/fail-open.d.ts +8 -0
- package/dist/observability/fail-open.js +8 -0
- package/dist/observability/metrics.d.ts +12 -0
- package/dist/observability/metrics.js +17 -0
- package/dist/observability/{run-terminal-log.d.ts → run-terminal.d.ts} +50 -10
- package/dist/observability/{run-terminal-log.js → run-terminal.js} +27 -8
- package/dist/plugins/checkpoint-store-sql.d.ts +8 -2
- package/dist/plugins/file-run-store.js +2 -2
- package/dist/plugins/memory-run-store.js +2 -2
- package/dist/plugins/remote-scratchpad.js +1 -1
- package/dist/plugins/run-store-sql.js +8 -7
- package/dist/plugins/store-contracts.d.ts +25 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/workflow-run-store-sql.js +1 -1
- package/dist/principal-jwt.d.ts +15 -7
- package/dist/principal-jwt.js +1 -1
- package/dist/runs.js +1 -1
- package/dist/session-titler.js +9 -5
- package/dist/task-settings.d.ts +35 -0
- package/dist/task-settings.js +7 -0
- package/dist/tool-approval.d.ts +22 -2
- package/dist/tool-approval.js +2 -0
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/ledger-events.d.ts +1 -1
- package/dist/trace/project.d.ts +1 -1
- package/dist/trace/project.js +1 -1
- package/dist/trace/redact.d.ts +1 -1
- package/package.json +2 -2
|
@@ -10,20 +10,38 @@ export function runTerminalLogLevel(status, errorCode) {
|
|
|
10
10
|
return undefined;
|
|
11
11
|
return errorCode === "cancelled" ? "info" : "error";
|
|
12
12
|
}
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
let logObserver;
|
|
14
|
+
const subscribers = new Set();
|
|
15
|
+
export function setRunTerminalLogObserver(fn) {
|
|
16
|
+
logObserver = fn;
|
|
17
|
+
}
|
|
18
|
+
export function subscribeRunTerminal(fn) {
|
|
19
|
+
subscribers.add(fn);
|
|
20
|
+
return () => {
|
|
21
|
+
subscribers.delete(fn);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function resetRunTerminalSubscribersForTest() {
|
|
25
|
+
subscribers.clear();
|
|
16
26
|
}
|
|
17
27
|
export function notifyRunTerminal(rec) {
|
|
28
|
+
for (const fn of [...subscribers]) {
|
|
29
|
+
try {
|
|
30
|
+
fn(rec);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
recordFailOpen("server.fleet.terminal-notify", `runId=${rec.runId} err=${errorText(err)}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
18
36
|
const level = runTerminalLogLevel(rec.status, rec.errorCode);
|
|
19
|
-
if (level === undefined || !
|
|
37
|
+
if (level === undefined || !logObserver)
|
|
20
38
|
return;
|
|
21
39
|
const raw = rec.errorMessage;
|
|
22
40
|
const message = raw === undefined ? undefined : (redactErrorMessage(raw) ?? "").slice(0, MESSAGE_CAP);
|
|
23
|
-
|
|
41
|
+
logObserver(level, {
|
|
24
42
|
runId: rec.runId,
|
|
25
|
-
sessionId: rec.sessionId,
|
|
26
|
-
...(rec.owner !== null ? { owner: rec.owner } : {}),
|
|
43
|
+
sessionId: rec.sessionId ?? "",
|
|
44
|
+
...(rec.owner !== undefined && rec.owner !== null ? { owner: rec.owner } : {}),
|
|
27
45
|
status: rec.status,
|
|
28
46
|
...(rec.resultTaskId !== undefined && rec.resultTaskId !== rec.runId ? { taskId: rec.resultTaskId } : {}),
|
|
29
47
|
...(rec.model !== undefined ? { model: rec.model } : {}),
|
|
@@ -365,6 +383,7 @@ const STATS_GATE_ROW_TREATMENT = {
|
|
|
365
383
|
decision: "verbatim",
|
|
366
384
|
toolName: "verbatim",
|
|
367
385
|
toolArg: "model-text",
|
|
386
|
+
toolCallId: "verbatim",
|
|
368
387
|
};
|
|
369
388
|
const STATS_REPETITION_EVENT_TREATMENT = {
|
|
370
389
|
turn: "verbatim",
|
|
@@ -667,4 +686,4 @@ export function resetReadRedactionMemoForTest() {
|
|
|
667
686
|
readMemoDirty.clear();
|
|
668
687
|
readMemoDirtyBytes = 0;
|
|
669
688
|
}
|
|
670
|
-
//# sourceMappingURL=run-terminal
|
|
689
|
+
//# sourceMappingURL=run-terminal.js.map
|
|
@@ -754,7 +754,9 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
754
754
|
*/
|
|
755
755
|
peekScopeByToken(token: CheckpointToken): Promise<string | null | undefined>;
|
|
756
756
|
peekPendingScope(sessionId: string, binding?: PendingRowBinding): Promise<string | null | undefined>;
|
|
757
|
-
/** Upsert the resume rebuild inputs for a session
|
|
757
|
+
/** Upsert the resume rebuild inputs for a session — written at SUBMIT (durable mode on) and, since S-433 F2,
|
|
758
|
+
* once per resume leg at its CAS win point (`DriveResumeArgs.resumeCtx`). Unconditional per `session_id`:
|
|
759
|
+
* the ordering fence lives at the CALLER's CAS win, not in a version column here. */
|
|
758
760
|
putCtx(sessionId: string, ctx: unknown): Promise<void>;
|
|
759
761
|
getCtx<T = unknown>(sessionId: string): Promise<T | null>;
|
|
760
762
|
/**
|
|
@@ -763,7 +765,11 @@ export declare class SqlCheckpointStore implements CheckpointStore {
|
|
|
763
765
|
*
|
|
764
766
|
* The extra `task_active` guard closes a multi-gate window: between a resume's CAS (pending→resolved) and
|
|
765
767
|
* the task hitting its NEXT gate (writing a new pending checkpoint), the session has no pending checkpoint —
|
|
766
|
-
* yet `putCtx`
|
|
768
|
+
* yet `putCtx` stamps `updated_at_ms` at submit and — since S-433 F2 (server 7.86.0) — once more on EVERY
|
|
769
|
+
* resume leg, at the moment that leg wins the resume CAS (`DriveResumeArgs.resumeCtx`; before that fix only
|
|
770
|
+
* the plan approval's mode write-back re-stamped it, and it did so AFTER acceptance). Both extra writes only
|
|
771
|
+
* ever REFRESH the stamp, so they lengthen a ctx's life and touch none of the three guards — the direction is
|
|
772
|
+
* "keep it longer", never "reap it sooner". So the ctx could be older than `cutoff` and was being
|
|
767
773
|
* reaped, making the next resume 409 ("resume context missing"). `task_active` holds the session lock for
|
|
768
774
|
* the WHOLE submit→last-resume-complete span (running OR suspended), so excluding sessions with an active
|
|
769
775
|
* claim keeps the ctx exactly as long as a run still needs it, while still GC'ing it once the run is terminal.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal
|
|
1
|
+
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal.js";
|
|
2
2
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
|
|
@@ -7,7 +7,7 @@ import { terminalProjection } from "@sema-agent/core";
|
|
|
7
7
|
import { AppendLog, atomicWriteFile, ensureDir, isProcessLive, processFingerprint, readJsonlRecords, sanitizePathComponent, writeThenLink } from "@sema-agent/core";
|
|
8
8
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
9
9
|
import { StoreBootRefusalError } from "./store-contracts.js";
|
|
10
|
-
import { notifyRunTerminal } from "../observability/run-terminal
|
|
10
|
+
import { notifyRunTerminal } from "../observability/run-terminal.js";
|
|
11
11
|
import { migrateRetiredAskOrigin } from "./one-time-migrations.js";
|
|
12
12
|
const ownerEq = (a, b) => (a ?? null) === (b ?? null);
|
|
13
13
|
const CLAIM_TAKEOVER_ATTEMPTS = 3;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal
|
|
1
|
+
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal.js";
|
|
2
2
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
3
3
|
import { terminalProjection } from "@sema-agent/core";
|
|
4
|
-
import { notifyRunTerminal } from "../observability/run-terminal
|
|
4
|
+
import { notifyRunTerminal } from "../observability/run-terminal.js";
|
|
5
5
|
const ownerEq = (a, b) => (a ?? null) === (b ?? null);
|
|
6
6
|
export class MemoryRunStore {
|
|
7
7
|
runs = new Map();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactHead } from "../observability/run-terminal
|
|
1
|
+
import { redactHead } from "../observability/run-terminal.js";
|
|
2
2
|
const REMOTE_SCRATCHPAD_LANES = new Set(["e2b", "k8s", "local-docker", "ssh", "device"]);
|
|
3
3
|
export function isRemoteScratchpadLane(provider) {
|
|
4
4
|
return provider !== undefined && REMOTE_SCRATCHPAD_LANES.has(provider);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal
|
|
1
|
+
import { redactErrorMessage, redactLedgerEventData, redactTerminalResult } from "../observability/run-terminal.js";
|
|
2
2
|
import { terminalProjection } from "@sema-agent/core";
|
|
3
3
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
4
4
|
import { escapeLike } from "./sql-escape.js";
|
|
5
5
|
import { pgSanitizeText } from "./pg-safe-json.js";
|
|
6
6
|
import { parseJsonLenient as parseJson, toIso as iso } from "./sql-row-helpers.js";
|
|
7
|
-
import { notifyRunTerminal, runTerminalLogLevel } from "../observability/run-terminal
|
|
7
|
+
import { notifyRunTerminal, runTerminalLogLevel } from "../observability/run-terminal.js";
|
|
8
8
|
import { mysqlDriver, pgDriver, dialectJsonEncoder } from "./sql-driver.js";
|
|
9
9
|
import { isDupKeyError } from "./sql-errors.js";
|
|
10
10
|
const RUN_ROW_COLS = "task_id, session_id, owner, status, result, error, error_code, job_id, source, instance_id, cancel_requested, objective_preview, created_at, updated_at";
|
|
@@ -121,6 +121,7 @@ export class SqlRunStore {
|
|
|
121
121
|
result = redactTerminalResult(result);
|
|
122
122
|
error = error === null ? null : (redactErrorMessage(error) ?? null);
|
|
123
123
|
const errorCode = result === null ? null : (terminalProjection(result.terminal).errorCode ?? null);
|
|
124
|
+
let won = false;
|
|
124
125
|
let observed;
|
|
125
126
|
await this.tx(async (conn) => {
|
|
126
127
|
const w = await conn.query(this.q("UPDATE task_run SET status = ?, result = ?, error = ?, error_code = ?, updated_at = ? WHERE task_id = ? AND status IN ('running','suspended','needs_review')", "UPDATE task_run SET status = $1, result = $2::jsonb, error = $3, error_code = $4, updated_at = $5 WHERE task_id = $6 AND status IN ('running','suspended','needs_review')"), [
|
|
@@ -131,7 +132,8 @@ export class SqlRunStore {
|
|
|
131
132
|
new Date(),
|
|
132
133
|
taskId,
|
|
133
134
|
]);
|
|
134
|
-
|
|
135
|
+
won = w.affected > 0;
|
|
136
|
+
if (won && runTerminalLogLevel(status, errorCode ?? undefined) !== undefined) {
|
|
135
137
|
const { rows } = await conn.query(this.q("SELECT owner, session_id, created_at FROM task_run WHERE task_id = ?", "SELECT owner, session_id, created_at FROM task_run WHERE task_id = $1"), [taskId]);
|
|
136
138
|
const row = rows[0];
|
|
137
139
|
const createdAt = row ? Date.parse(iso(row.created_at)) : NaN;
|
|
@@ -143,17 +145,16 @@ export class SqlRunStore {
|
|
|
143
145
|
}
|
|
144
146
|
await conn.query(this.q("DELETE FROM task_active WHERE task_id = ?", "DELETE FROM task_active WHERE task_id = $1"), [taskId]);
|
|
145
147
|
});
|
|
146
|
-
if (
|
|
148
|
+
if (won) {
|
|
147
149
|
notifyRunTerminal({
|
|
148
150
|
runId: taskId,
|
|
149
|
-
sessionId: observed.sessionId,
|
|
150
|
-
owner: observed.owner,
|
|
151
|
+
...(observed ? { sessionId: observed.sessionId, owner: observed.owner } : {}),
|
|
151
152
|
status,
|
|
152
153
|
resultTaskId: result?.taskId,
|
|
153
154
|
model: result?.model,
|
|
154
155
|
errorCode: errorCode ?? undefined,
|
|
155
156
|
errorMessage: (result === null ? undefined : terminalProjection(result.terminal).errorMessage) ?? error ?? undefined,
|
|
156
|
-
elapsedMs: observed
|
|
157
|
+
elapsedMs: observed?.createdAt === undefined ? undefined : Math.max(0, Date.now() - observed.createdAt),
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
160
|
}
|
|
@@ -153,7 +153,7 @@ export interface RunRecord {
|
|
|
153
153
|
* · `parked` —— 停在门上还能再动(`suspended` 审批/资源门、`needs_review` 评审门)。
|
|
154
154
|
*
|
|
155
155
|
* 🔴 为什么是**一张表**而不是三张 switch(S-213③,2026-09-11):`blocked` 这个词此前在本仓有**两个
|
|
156
|
-
* 独立写者**且答案互斥 —— `observability/run-terminal
|
|
156
|
+
* 独立写者**且答案互斥 —— `observability/run-terminal.ts` 判它是「治理判决,不是失败 ⇒ 不打行」,
|
|
157
157
|
* `fleet/fleet-bus.ts` 判它是「非成功终局(agent 放弃)⇒ failed 桶、行离场」。两处各自穷举、各自正确
|
|
158
158
|
* 地编译,而一条 `report_blocked` 的 run 在面板上离场、在引擎日志里一个字都没有。三张手抄的 switch
|
|
159
159
|
* 就是三个写者;收成一张表之后,词的语义只有这一处能改。
|
|
@@ -165,7 +165,7 @@ export interface RunRecord {
|
|
|
165
165
|
* core 已经没有的词同样红(超出键)。终局词表真变过(core 5.8.0 把 `"timeout"` 从 `TaskStatus` 删了)。
|
|
166
166
|
*
|
|
167
167
|
* 判据不许再被手抄成第二份:消费点(`approval-reconciler.ts` 判据 2、`http/routes/runs.ts` 的取消后
|
|
168
|
-
* 复读、`observability/run-terminal
|
|
168
|
+
* 复读、`observability/run-terminal.ts` 的级别判、`fleet/fleet-bus.ts` 的 failed 桶编译钉)都从这里取。
|
|
169
169
|
*/
|
|
170
170
|
export type RunStatusClass = "live" | "succeeded" | "unsuccessful" | "parked";
|
|
171
171
|
export declare const RUN_STATUS_CLASS: {
|
|
@@ -240,6 +240,29 @@ export declare function isUnsuccessfulRunStatus(status: RunRecord["status"]): bo
|
|
|
240
240
|
* 动作(cancel 的恢复把手会 CAS-expire 一张 checkpoint);对一个本进程读不懂的状态,少动一次远好过错杀。
|
|
241
241
|
*/
|
|
242
242
|
export declare function isParkedRunStatus(status: RunRecord["status"]): boolean;
|
|
243
|
+
/**
|
|
244
|
+
* 「**证得出**这条 run 活在别的副本上」——「他副本」那一句话的**唯一判据**(S-381 收编;S-430 迁居)。
|
|
245
|
+
*
|
|
246
|
+
* 成案:这个合取式此前在四处**逐字手抄**(`http/routes/runs.ts` 的 steer 臂与 interrupt 臂、同文件
|
|
247
|
+
* `sendHandleMiss`、`http/routes/run-memory-capture.ts`),`POST /v1/sessions/:id/mcp/reconnect` 是第五处、`fleet/fleet-reconciler.ts` 是第六处 ——
|
|
248
|
+
* 而它的每一个合取项都是一条**被复审逐条挣出来的**纪律,不是随手的判空:
|
|
249
|
+
* · {@link RunRecord.instanceId} 缺席(`null` / 建列之前的行 / 替身行的 `undefined`)= **不知道它在哪**,
|
|
250
|
+
* 不是「在别处」;
|
|
251
|
+
* · `thisInstanceId` 缺席 = 本副本连自己是谁都说不上,更不能断言别人;
|
|
252
|
+
* · 两者都在场且**不等**才够格说「他副本」(`markResuming` 认领后该列语义 = **当前持有副本**)。
|
|
253
|
+
* 抄一份 = 多一个写者;收成一只谓词之后,纪律改一次就处处同改。**`status` 不进本谓词**:
|
|
254
|
+
* `sendHandleMiss` 只对 `running` 行说这句话,而 steer 族在 park/终态两臂之后才走到这里 —— 各调用点
|
|
255
|
+
* 的前置臂不同族,合进来会让某一处悄悄改判。
|
|
256
|
+
*
|
|
257
|
+
* 🔴 **为什么住在这里而不是 `http/route-ctx.ts`**(S-430):`src/fleet/fleet-reconciler.ts` 是第六个手抄点,
|
|
258
|
+
* 而 `src/fleet/` 今天对 `src/http/` **零依赖**(边向恒是 http → fleet)。把消费方拉去 http 取一只纯谓词
|
|
259
|
+
* 会凭空造一条反向装载边;而本文件正是 {@link RunRecord} 与它的兄弟谓词({@link isTerminalRunStatus} /
|
|
260
|
+
* {@link isParkedRunStatus})的所在 —— 「关于 run 行的判词」本来就该在行的属主这里,http 与 fleet 都已经
|
|
261
|
+
* 依赖它。**无别名、无再导出**:旧拼法删干净,消费方的 tsc 红就是通知。
|
|
262
|
+
*/
|
|
263
|
+
export declare function runProvenElsewhere(run: {
|
|
264
|
+
instanceId?: string | null;
|
|
265
|
+
}, thisInstanceId: string | undefined): boolean;
|
|
243
266
|
/** One row of the GET /v1/sessions list (CC /resume picker): a DISTINCT session (sessionId) aggregated from its
|
|
244
267
|
* task_run rows — newest-first by last activity. The preview/status are the LATEST run's ("continue where I left
|
|
245
268
|
* off"); the counts/timestamps span the whole session. Owner included so a fleet-wide (ops) listing is attributable. */
|
|
@@ -23,6 +23,9 @@ export function isUnsuccessfulRunStatus(status) {
|
|
|
23
23
|
export function isParkedRunStatus(status) {
|
|
24
24
|
return runStatusClassOf(status) === "parked";
|
|
25
25
|
}
|
|
26
|
+
export function runProvenElsewhere(run, thisInstanceId) {
|
|
27
|
+
return typeof run.instanceId === "string" && run.instanceId.length > 0 && thisInstanceId !== undefined && run.instanceId !== thisInstanceId;
|
|
28
|
+
}
|
|
26
29
|
export function mapBakeRow(r) {
|
|
27
30
|
return {
|
|
28
31
|
bakeId: r.bake_id,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactErrorMessage, redactHead } from "../observability/run-terminal
|
|
1
|
+
import { redactErrorMessage, redactHead } from "../observability/run-terminal.js";
|
|
2
2
|
import { summarizeWorkflowRun, isTerminalWorkflowStatus, WorkflowRunStoreError } from "@sema-agent/core";
|
|
3
3
|
import { foldKeyFamily, MAX_PENDING_PER_SESSION, PURGE_FENCE_MS, SERVED_FENCE_MS, } from "../orchestration/workflow-completion-inbox.js";
|
|
4
4
|
import {} from "../orchestration/workflow-agent-session-index.js";
|
package/dist/principal-jwt.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ApprovalHmacKey, PrincipalJwtKey } from "./auth-keys.js";
|
|
2
|
+
import { type ApprovalEnvelope } from "./approval-hmac.js";
|
|
2
3
|
/**
|
|
3
4
|
* 验签允许的**时钟不一致容差**(秒)—— 本仓这条轴上的单一来源。
|
|
4
5
|
*
|
|
@@ -47,6 +48,14 @@ export declare function verifyPrincipalJwt(token: string, keys: PrincipalJwtKey[
|
|
|
47
48
|
/** 良构 Unicode(无孤立代理项)。`u` 旗下配对代理项是一个码点、不匹配 `\p{Surrogate}`;只有孤立的才命中。 */
|
|
48
49
|
export declare function isWellFormedUnicode(s: string): boolean;
|
|
49
50
|
export declare function editedPlanBinding(editedPlan: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* JWT `cnf.bnd` = **「这份身份凭据被签发去决哪一张卡」**(动作身份),故只哈希前三位。
|
|
53
|
+
*
|
|
54
|
+
* 🔴 **与 HMAC 信封的分工**(S-433 F1 立此,属主注在 `approval-hmac.ts` 顶):HMAC 绑的是**「决了什么」**
|
|
55
|
+
* —— `decision` / `reason` / `permissionModeAfter` 这些**会改变后果**的字段全在那一把里。所以「同一张卡上
|
|
56
|
+
* 把 approve 的档偷偷调宽」只由 HMAC 拦;本函数**刻意不跟着加位**:决定内容改了 `cnf.bnd` 不该变(否则
|
|
57
|
+
* 一份合法 JWT 会被绑死在一个它签发时还不知道的值上,而 `permissionModeAfter` 恰恰是决裁那一刻才定的)。
|
|
58
|
+
*/
|
|
50
59
|
export declare function approvalBnd(env: {
|
|
51
60
|
sessionId: string;
|
|
52
61
|
boundCallId?: string | null;
|
|
@@ -109,13 +118,12 @@ export declare function verifyDirectDoorProof(proof: {
|
|
|
109
118
|
jwt?: string;
|
|
110
119
|
mac?: string;
|
|
111
120
|
kid?: string;
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}, config: {
|
|
121
|
+
},
|
|
122
|
+
/** 🔴 **命名类型,不是结构等价的内联字面**(S-433 F1 [high] 的**根因**,验真后修):本位此前是一份手抄的
|
|
123
|
+
* 五字段内联形 —— 结构类型让**多带一个字段的调用方**照样编译通过,而下面那次手抄再把它**丢掉**,于是
|
|
124
|
+
* `approval-hmac.ts` 上新增的签名位在这条唯一的真实验签链上**静默失效**,tsc 一个字都不响。
|
|
125
|
+
* 用 {@link ApprovalEnvelope} 之后,信封的形只有**一个**声明点,新增一位自动到达验签器。 */
|
|
126
|
+
envelope: ApprovalEnvelope, config: {
|
|
119
127
|
principalJwtPubkeys: PrincipalJwtKey[];
|
|
120
128
|
principalJwtIss?: string;
|
|
121
129
|
principalJwtAud?: string;
|
package/dist/principal-jwt.js
CHANGED
|
@@ -101,7 +101,7 @@ export function verifyDirectDoorProof(proof, envelope, config, opts) {
|
|
|
101
101
|
return { ok: false, status: 401, errorCode: "principal_unbound", error: "principal token is not bound to this decision (cnf.bnd mismatch)" };
|
|
102
102
|
if (!proof.mac)
|
|
103
103
|
return { ok: false, status: 401, errorCode: "approval_mac_required", error: "direct door requires an approval MAC (X-Approval-Mac)" };
|
|
104
|
-
const ok = verifyApprovalHmac(
|
|
104
|
+
const ok = verifyApprovalHmac(envelope, proof.mac, proof.kid, config.approvalHmacKeys);
|
|
105
105
|
if (!ok)
|
|
106
106
|
return { ok: false, status: 401, errorCode: "approval_mac_invalid", error: "approval envelope MAC invalid" };
|
|
107
107
|
return actionBinding
|
package/dist/runs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { runWithVerification, runCascade, defaultTaskRegistry, terminalProjection, DURABLE_AGENT_HANDLE_RE } from "@sema-agent/core";
|
|
2
2
|
import { failureCodeOf, stripResumeToken } from "./terminal.js";
|
|
3
3
|
import { GOVERNANCE_HTTP_STATUS } from "./governance-http-status.js";
|
|
4
|
-
import { redactErrorMessage } from "./observability/run-terminal
|
|
4
|
+
import { redactErrorMessage } from "./observability/run-terminal.js";
|
|
5
5
|
import { withPrincipal } from "./observability/principal-context.js";
|
|
6
6
|
import { redactSecrets } from "./trace/redact.js";
|
|
7
7
|
import { taskNotificationEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "./trace/project.js";
|
package/dist/session-titler.js
CHANGED
|
@@ -26,6 +26,10 @@ export function createSessionTitler(deps) {
|
|
|
26
26
|
deps.logger?.debug?.("session_title_failed", { sessionId, error: error.slice(0, 200) });
|
|
27
27
|
recordFailOpen("server.session-titler.gateway-unreachable", error.slice(0, FAIL_CAUSE_KEY_CHARS));
|
|
28
28
|
};
|
|
29
|
+
const probeOrContinue = async (sessionId, continueWord) => deps
|
|
30
|
+
.probeTitle(sessionId)
|
|
31
|
+
.then((state) => ({ state, unreadable: false }))
|
|
32
|
+
.catch(() => ({ state: continueWord, unreadable: true }));
|
|
29
33
|
return {
|
|
30
34
|
maybeTitle(sessionId, objective, model) {
|
|
31
35
|
if (!sessionId || !objective.trim())
|
|
@@ -39,10 +43,10 @@ export function createSessionTitler(deps) {
|
|
|
39
43
|
}
|
|
40
44
|
seen.add(sessionId);
|
|
41
45
|
void (async () => {
|
|
42
|
-
let state = await
|
|
46
|
+
let state = (await probeOrContinue(sessionId, "untitled")).state;
|
|
43
47
|
if (state === "none") {
|
|
44
48
|
await new Promise((r) => setTimeout(r, NO_ROW_RETRY_MS));
|
|
45
|
-
state = await
|
|
49
|
+
state = (await probeOrContinue(sessionId, "untitled")).state;
|
|
46
50
|
if (state === "none") {
|
|
47
51
|
seen.delete(sessionId);
|
|
48
52
|
deps.metrics?.inc("session_title_total", { outcome: "row_not_yet" });
|
|
@@ -66,10 +70,10 @@ export function createSessionTitler(deps) {
|
|
|
66
70
|
}
|
|
67
71
|
const landed = await deps.setTitleIfNull(sessionId, title);
|
|
68
72
|
if (!landed) {
|
|
69
|
-
const after = await
|
|
70
|
-
if (after === "none")
|
|
73
|
+
const after = await probeOrContinue(sessionId, "none");
|
|
74
|
+
if (after.state === "none")
|
|
71
75
|
seen.delete(sessionId);
|
|
72
|
-
deps.metrics?.inc("session_title_total", { outcome: after === "none" ? "row_not_yet" : "already_titled" });
|
|
76
|
+
deps.metrics?.inc("session_title_total", { outcome: after.unreadable ? "probe_failed" : after.state === "none" ? "row_not_yet" : "already_titled" });
|
|
73
77
|
return;
|
|
74
78
|
}
|
|
75
79
|
deps.metrics?.inc("session_title_total", { outcome: "set" });
|
package/dist/task-settings.d.ts
CHANGED
|
@@ -70,6 +70,41 @@ export declare function coercePermissionMode(raw: unknown): SettingsPermissionMo
|
|
|
70
70
|
/** 五模式闭集的**严格**读法([ref] ④:`/v1/capabilities?permissionMode=` 查询串用它 —— 读面对词表外的值 400,
|
|
71
71
|
* 不走上面那条给 resume 重放留的 `default` 宽臂)。上面的宽读只是本函数外再包一层折叠,词表单点在此。 */
|
|
72
72
|
export declare function coercePermissionModeStrict(raw: unknown): SettingsPermissionMode | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* S-433 —— 一份**被批准的计划**之后,这条会话继续用的 permission mode(`plan_review` 决裁体的
|
|
75
|
+
* `permissionModeAfter`)。core 的契约句是 `present-plan-tool.js`:「If the plan is approved, the run
|
|
76
|
+
* continues (and any read-only restriction is lifted)」—— 而 core 顶层 resume 把宿主的续跑配置**整体**
|
|
77
|
+
* 展开成新一段 spec、不继承停靠点的 `handsReadOnly` / `enablePlanMode`(`runtask.ts`),所以「松开」这
|
|
78
|
+
* 件事的属主在**本仓装配续跑配置的那一处**。批准者要说的正是「松到哪一档」。
|
|
79
|
+
*
|
|
80
|
+
* 🔴 **闭集为什么只有这两个词**:它是 CC `ExitPlanMode` 三选卡上那两张 Yes 卡(「Yes, and auto-accept
|
|
81
|
+
* edits」/「Yes, and manually approve edits」)的对位;`plan` 自己(= 不松开)由 `edit`/`reject` 两个
|
|
82
|
+
* 决裁表达,`bypassPermissions` / `auto` 不在这张卡上 —— 一个批准动作不该顺带把部署的 ask 面整个关掉。
|
|
83
|
+
*
|
|
84
|
+
* 🔴 **不手抄词表**:`satisfies readonly SettingsPermissionMode[]` 让「本表的成员必须仍是本仓受理的
|
|
85
|
+
* 模式词」成为**编译期**事实 —— 五词表某天改名/删词,这里就是红的,而不是静默留一个没人认的词。
|
|
86
|
+
*/
|
|
87
|
+
export declare const PLAN_APPROVE_PERMISSION_MODES_AFTER: readonly ["default", "acceptEdits"];
|
|
88
|
+
/** {@link PLAN_APPROVE_PERMISSION_MODES_AFTER} 的类型形(值表单点,类型从值派生 —— 两处各写一份就会漂)。 */
|
|
89
|
+
export type PlanApprovePermissionModeAfter = (typeof PLAN_APPROVE_PERMISSION_MODES_AFTER)[number];
|
|
90
|
+
/** S-433 值闭集判据(wire 门用)。**宽臂一个都没有**:词表外的值 400 响亮拒 —— 这一位选的是批准之后
|
|
91
|
+
* 模型有没有手,把一个拼错的词折成任何一档都是安全轴上的静默降级([ref]「无静默 fail-open」)。 */
|
|
92
|
+
export declare function isPlanApprovePermissionModeAfter(raw: unknown): raw is PlanApprovePermissionModeAfter;
|
|
93
|
+
/**
|
|
94
|
+
* S-433 —— **一条已持久化的提交体的生效 permission mode**,单点。
|
|
95
|
+
*
|
|
96
|
+
* 它只是把 {@link effectivePermissionMode} 与「拿哪一份 settings 去问」这**一对**绑在一起:后者是
|
|
97
|
+
* `parseTaskSettings(body.settings)`(resume 重放共用的宽容解析层)。两处各写一遍这一对,就会在
|
|
98
|
+
* 「某天改成用别的 settings 去算生效模式」的那一拍静默分家 —— 而分家在这条轴上的形态是「wire 门说
|
|
99
|
+
* 这条任务不是只读起步、装配腿却按只读起步重建」,两个 4xx/行为各说各话,tsc 一声不响。
|
|
100
|
+
*
|
|
101
|
+
* ⚠️ 射程:**只管持久化体这一路**。首跑那一路的生效模式在 `boot/resolve-spec.ts` 单点算(它吃的是
|
|
102
|
+
* 场景折叠后的 settings),本函数刻意不去冒充那一处的属主。
|
|
103
|
+
*/
|
|
104
|
+
export declare function storedBodyPermissionMode(body: {
|
|
105
|
+
permissionMode?: unknown;
|
|
106
|
+
settings?: unknown;
|
|
107
|
+
}): SettingsPermissionMode | undefined;
|
|
73
108
|
/** L2 ultracode ([ref]): the effective `thinking` level given the explicit `reasoningEffort` and the ultracode
|
|
74
109
|
* preset. ultracode FLOORS at the "ultra" tier — core's single source `resolveReasoningProfile("ultra").thinking`
|
|
75
110
|
* (= "max"), never a hardcoded literal — so an explicit higher tier still wins (none exists above max today;
|
package/dist/task-settings.js
CHANGED
|
@@ -16,6 +16,13 @@ export function coercePermissionModeStrict(raw) {
|
|
|
16
16
|
return raw;
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
|
+
export const PLAN_APPROVE_PERMISSION_MODES_AFTER = ["default", "acceptEdits"];
|
|
20
|
+
export function isPlanApprovePermissionModeAfter(raw) {
|
|
21
|
+
return PLAN_APPROVE_PERMISSION_MODES_AFTER.includes(raw);
|
|
22
|
+
}
|
|
23
|
+
export function storedBodyPermissionMode(body) {
|
|
24
|
+
return effectivePermissionMode(body, parseTaskSettings(body.settings).settings);
|
|
25
|
+
}
|
|
19
26
|
export function effectiveThinking(reasoningEffort, ultracode) {
|
|
20
27
|
const explicit = isThinkingLevel(reasoningEffort) ? reasoningEffort : undefined;
|
|
21
28
|
if (!ultracode)
|
package/dist/tool-approval.d.ts
CHANGED
|
@@ -420,6 +420,22 @@ export interface LivePendingRow {
|
|
|
420
420
|
* `approval-content-kind.ts`,与 durable 两读面 / core summarize 面同词,OMIT 契约同族)。
|
|
421
421
|
* 缺席 = 普通工具 ask。展示/分诊分型用,永不参与决议路由。 */
|
|
422
422
|
contentKind?: "content_ask";
|
|
423
|
+
/**
|
|
424
|
+
* 🔴 S-454(P1;cli L-397 / 板 [ref]):这只 ask **本来会 emit 的那只活卡帧**。
|
|
425
|
+
*
|
|
426
|
+
* 值 = {@link PendingApproval.frame} 的**引用** —— `askBroadcast` 里那一处唯一构造(已过
|
|
427
|
+
* `redactDeep` / 字节帽 / [ref] 窗三键补写)的**同一个对象**,悬挂与可达两条路共用它。⇒ 这一格
|
|
428
|
+
* **不是**为列表另算的第二份卡投影:一处脱敏属主不变、零第二脱敏面,「wire 帧与列表行同一份判据」
|
|
429
|
+
* 是结构事实而不是两处各算一遍的巧合(同 `card_json` 与帧的关系)。
|
|
430
|
+
*
|
|
431
|
+
* 🔴 为什么本行不再守「input/args 不上列表」那条窄化:那条纪律的理由原文是「详情走流帧」——
|
|
432
|
+
* 而**悬挂 ask 永远没有流帧**(铸造时刻零投递目标,`suspended`),对它这条理由结构上不成立。
|
|
433
|
+
* 消费方要出卡就必须在这一行上拿到卡体,否则「列得到但渲不出」。一视同仁给**全部** live 行
|
|
434
|
+
* (规则集不因 `suspended` 分叉:有活流的 ask 多带一份它自己那张卡的副本无害)。
|
|
435
|
+
*
|
|
436
|
+
* 缺席 = 老 server(7.86.0 及以前);本服务自 7.87.0 起**恒在场**(条目上是必填格)。恒不铸 `null`。
|
|
437
|
+
*/
|
|
438
|
+
frame?: ToolApprovalFrame;
|
|
423
439
|
}
|
|
424
440
|
export interface ToolApprovalRunContext {
|
|
425
441
|
taskId: string;
|
|
@@ -1309,8 +1325,12 @@ export declare class ToolApprovalCoordinator {
|
|
|
1309
1325
|
* 方法体的逐字搬运([ref] 车2 拆分,行为零改动)。 */
|
|
1310
1326
|
private finishRespond;
|
|
1311
1327
|
/** [ref]([ref] 案):live pending 的**列表读面**——`GET /v1/approvals` 响应第二顶层键 `livePending`
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1328
|
+
* 的唯一数据源,**同时**是 `/v1/approvals/stream` 的 live 半场 diff 源(推与拉必须同源:feed 收到
|
|
1329
|
+
* `live_pending` 事件就会去 `list()`,两处各读各的会给出一条列不出来的事件)。纯读投影,零锁/零结算
|
|
1330
|
+
* 语义。
|
|
1331
|
+
* 🔴 **S-454 起行上带整只活卡帧**(`frame`,见 {@link LivePendingRow.frame}):旧文那句「input/args
|
|
1332
|
+
* 不上列表,详情走流帧」对**悬挂 ask 结构上不成立**(它永远没有流帧),而 `frame` 是 `askBroadcast`
|
|
1333
|
+
* 那一处构造的同一个对象 ⇒ 仍然只有**一个**脱敏属主、零第二投影。`scope` 与 durable 面同一表达式:`undefined` = operator 全量(含 owner null 的
|
|
1314
1334
|
* 条目),串 = 只见 `owner === scope` 的条目(null-owner 行对 principal 不可见,fail-closed——
|
|
1315
1335
|
* 宁少列不超范围;`"__none__"` 未鉴权哨兵自然恒空)。行的 `approvalId` 就是 `respond()` 收的 id
|
|
1316
1336
|
* (同源可达,[ref] 判据);`expiresAtMs` 照抄登记时单点铸定的窗死线([ref] 三键同一个数)。 */
|
package/dist/tool-approval.js
CHANGED
|
@@ -1361,6 +1361,7 @@ export class ToolApprovalCoordinator {
|
|
|
1361
1361
|
...(reachability === "unreached" ? { suspended: true } : {}),
|
|
1362
1362
|
...(child ? { originTaskId: req.sourceTaskId } : primary ? { targetCtxs: new Set(aliveCtxs), onTargetGone } : {}),
|
|
1363
1363
|
...(origin.sessionId ? { sessionId: origin.sessionId } : {}),
|
|
1364
|
+
frame,
|
|
1364
1365
|
toolName: req.toolName,
|
|
1365
1366
|
registeredAtMs: Date.now(),
|
|
1366
1367
|
expiresAtMs: persistedExpiresAtMs,
|
|
@@ -1981,6 +1982,7 @@ export class ToolApprovalCoordinator {
|
|
|
1981
1982
|
...(e.governanceForced ? { governanceForced: true } : {}),
|
|
1982
1983
|
...(e.originTaskId !== undefined ? { fromSubagent: true, originTaskId: e.originTaskId } : {}),
|
|
1983
1984
|
...(contentKind !== undefined ? { contentKind } : {}),
|
|
1985
|
+
frame: e.frame.approvalId === id ? e.frame : { ...e.frame, approvalId: id },
|
|
1984
1986
|
});
|
|
1985
1987
|
}
|
|
1986
1988
|
return rows;
|
|
@@ -21,7 +21,7 @@ import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, Ros
|
|
|
21
21
|
import type { ToolApprovalFrame } from "../tool-approval.js";
|
|
22
22
|
/** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。
|
|
23
23
|
* 🔴 **导出**([ref] U1/U2):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
|
|
24
|
-
* `observability/run-terminal
|
|
24
|
+
* `observability/run-terminal.ts` 的三张叶表 + 结果顶层键表用同一只断言,而不是各自再抄一份
|
|
25
25
|
* `type X<T extends never> = T`(抄一份就是第二个写者,两处哪天分岔谁都发现不了)。
|
|
26
26
|
* 本文件只有类型、不产 JS,所以被 `import type` 引用不新增任何运行期边。 */
|
|
27
27
|
export type AssertAllKeysHandled<T extends never> = T;
|
|
@@ -74,7 +74,7 @@ export type LedgerEventType = "reasoning" | "text" | "tool_start" | "tool_end" |
|
|
|
74
74
|
* 🔴 **park 行名的运行时闭集**(合并重扫 [4])。
|
|
75
75
|
*
|
|
76
76
|
* 此前这两个词在仓里有**三处**并列的字面量:`ledger-sink.ts` 的 `appendParked` 形参与 `onDone` 的分诊、
|
|
77
|
-
* 以及 `observability/run-terminal
|
|
77
|
+
* 以及 `observability/run-terminal.ts` 的脱敏臂。`LedgerEventType` 只是类型联合、运行期取不到,
|
|
78
78
|
* 所以脱敏臂只能自己再抄一份 —— 而抄的那一份**加词不红**:仓里/引擎加第三个 park 词并登记进
|
|
79
79
|
* `LedgerEventType` 之后,`appendParked` 与 resume 腿的动态首参照写照落,回放时那一行的
|
|
80
80
|
* `gate.riskDescriptor.summary` 明文,脱敏臂一声不吭。
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export type TraceBlock = {
|
|
|
116
116
|
* 那一案 —— 七个调用点只有三个记得拼,**漏的正是 resume 腿与 ledger-sink 落盘这两处**。
|
|
117
117
|
*
|
|
118
118
|
* ## 🔴 脱敏**不在这里**(写口不是脱敏属主)
|
|
119
|
-
* 两行的字节由模型写,必须脱 —— 但脱敏口是 `observability/run-terminal
|
|
119
|
+
* 两行的字节由模型写,必须脱 —— 但脱敏口是 `observability/run-terminal.ts` 的
|
|
120
120
|
* `redactLedgerEventData`:三孪生 store 的 `appendEvent` 落库前 + `GET /v1/runs/:id/events` 读面各过一次
|
|
121
121
|
* (幂等)。理由与 park 行逐字同源(`trace/ledger-sink.ts` 的 `appendParked` 顶注是那条规矩的属主):
|
|
122
122
|
* 写口脱 = 一个语义面上两个写者,且**盖不住存量行**(升级前落下的明文 `text` 行每次重连照样回放)。
|
package/dist/trace/project.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { redactErrorMessage, redactModelText } from "../observability/run-terminal
|
|
1
|
+
import { redactErrorMessage, redactModelText } from "../observability/run-terminal.js";
|
|
2
2
|
import { MCP_DELIVERY_VERDICTS, screenGateOutcome, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
package/dist/trace/redact.d.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* 而**模型自己写的**那一份(`TaskResult.result` / `TaskResult.salvagedOutput` / 账本 `text` 行)整条逐字
|
|
25
25
|
* 上 wire —— 工具结果送模路径给的是原文,模型把里面的凭据**逐字引用**进答复,那一份就绕过了本模块。
|
|
26
26
|
* 现在三面与 CoT(账本 `reasoning` 行)走**同一只** `redactSecrets`、同一张替换串表:零第二只脱敏器、
|
|
27
|
-
* 零 per-face 开关、零体量上限。**装载口只有一只** —— `observability/run-terminal
|
|
27
|
+
* 零 per-face 开关、零体量上限。**装载口只有一只** —— `observability/run-terminal.ts` 的
|
|
28
28
|
* `redactModelText`(四座同调:结果两叶经 `redactTerminalResult`,账本两行经 `redactLedgerEventData`);
|
|
29
29
|
* 它定的是**写回**判据(认出凭据形才改字节、抛则占位),不是第二张规则表。
|
|
30
30
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.87.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": "7.
|
|
57
|
+
"@sema-agent/core": "7.23.0",
|
|
58
58
|
"@sema-agent/settings-schema": "2.1.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|