@sema-agent/server 7.78.0 → 7.78.2
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 +6 -0
- package/USAGE.md +4 -0
- package/dist/approval-card.d.ts +37 -4
- package/dist/approval-card.js +22 -2
- package/dist/boot/resolve-spec.js +6 -3
- package/dist/config-catalog.d.ts +18 -1
- package/dist/config-catalog.js +3 -3
- package/dist/governance-http-status.d.ts +27 -0
- package/dist/governance-http-status.js +11 -0
- package/dist/http/routes/approvals-assistant.d.ts +35 -0
- package/dist/http/routes/approvals-assistant.js +39 -1
- package/dist/http/routes/tasks.js +4 -9
- package/dist/http/server.d.ts +28 -4
- package/dist/http/server.js +33 -13
- package/dist/observability/fail-open.d.ts +4 -0
- package/dist/observability/fail-open.js +4 -0
- package/dist/parked-decide.d.ts +7 -2
- package/dist/plugins/host-workspace-registry.d.ts +27 -0
- package/dist/plugins/host-workspace-registry.js +27 -0
- package/dist/plugins/one-time-migrations.d.ts +3 -0
- package/dist/plugins/one-time-migrations.js +18 -11
- package/dist/plugins/remote-env-host.d.ts +15 -0
- package/dist/plugins/remote-env-host.js +41 -1
- package/dist/request-key-closure.d.ts +30 -0
- package/dist/request-key-closure.js +56 -0
- package/dist/runs.d.ts +51 -0
- package/dist/runs.js +4 -11
- package/dist/runtime-governance.d.ts +18 -4
- package/dist/runtime-governance.js +2 -2
- package/dist/spec-fields.d.ts +4 -2
- package/dist/spec-fields.js +4 -5
- package/dist/task-a2a.js +8 -6
- package/dist/task-mcp.js +5 -3
- package/dist/task-settings.d.ts +49 -17
- package/dist/task-settings.js +37 -38
- package/dist/tool-approval.d.ts +35 -3
- package/dist/tool-approval.js +41 -19
- package/dist/tool-axis-words.d.ts +30 -0
- package/dist/tool-axis-words.js +9 -0
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/ledger-sink.js +12 -5
- package/dist/trace/model-segment.d.ts +32 -2
- package/dist/trace/model-segment.js +15 -5
- package/dist/trace/project.d.ts +37 -3
- package/dist/trace/project.js +14 -10
- package/package.json +3 -3
|
@@ -2,7 +2,7 @@ import { terminalProjection } from "@sema-agent/core";
|
|
|
2
2
|
import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
3
3
|
import { NotifiedKeys, taskNotificationStreamKey } from "../orchestration/workflow-completion-inbox.js";
|
|
4
4
|
import { isParkLedgerEventType } from "./ledger-events.js";
|
|
5
|
-
import { isModelSegmentBoundary } from "./model-segment.js";
|
|
5
|
+
import { isModelSegmentBoundary, reasoningDeltaBytes, reasoningSegmentEventId } from "./model-segment.js";
|
|
6
6
|
export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
7
7
|
let seq = startSeq;
|
|
8
8
|
let chain = Promise.resolve();
|
|
@@ -19,6 +19,7 @@ export function createLedgerSink(opts) {
|
|
|
19
19
|
let text = "";
|
|
20
20
|
let reasoning = "";
|
|
21
21
|
let textEventId;
|
|
22
|
+
let reasoningEventId;
|
|
22
23
|
const beat = (kind, statusData) => {
|
|
23
24
|
try {
|
|
24
25
|
opts.onActivity?.(kind, statusData);
|
|
@@ -34,8 +35,9 @@ export function createLedgerSink(opts) {
|
|
|
34
35
|
};
|
|
35
36
|
const flush = async () => {
|
|
36
37
|
if (reasoning) {
|
|
37
|
-
await append("reasoning", modelTextEventData({ text: reasoning }));
|
|
38
|
+
await append("reasoning", modelTextEventData({ text: reasoning, eventId: reasoningEventId }));
|
|
38
39
|
reasoning = "";
|
|
40
|
+
reasoningEventId = undefined;
|
|
39
41
|
}
|
|
40
42
|
if (text) {
|
|
41
43
|
await append("text", modelTextEventData({ text, eventId: textEventId }));
|
|
@@ -53,10 +55,15 @@ export function createLedgerSink(opts) {
|
|
|
53
55
|
textEventId ??= td.eventId;
|
|
54
56
|
break;
|
|
55
57
|
}
|
|
56
|
-
case "reasoning_delta":
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
case "reasoning_delta": {
|
|
59
|
+
const rd = ev;
|
|
60
|
+
const bytes = reasoningDeltaBytes(rd);
|
|
61
|
+
if (opts.persistThinking && bytes !== undefined) {
|
|
62
|
+
reasoning += bytes;
|
|
63
|
+
reasoningEventId ??= reasoningSegmentEventId(rd.eventId);
|
|
64
|
+
}
|
|
59
65
|
break;
|
|
66
|
+
}
|
|
60
67
|
case "tool_start":
|
|
61
68
|
await append("tool_start", toolStartEventData(ev));
|
|
62
69
|
break;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SegmentEndFields } from "./project.js";
|
|
1
2
|
/**
|
|
2
3
|
* 本帧是不是模型文本的段界。**四条消费腿共用这一只**:账本投影 switch(`trace/ledger-sink.ts`)、
|
|
3
4
|
* 顶层 live 流与转发子代腿(`http/routes/tasks.ts`)、子代 tail 面(`fleet/subagent-tail-bus.ts`)。
|
|
@@ -5,8 +6,10 @@
|
|
|
5
6
|
* (第三方 Runner 塞进来的野帧不该切走宿主的权威段)。
|
|
6
7
|
*/
|
|
7
8
|
export declare function isModelSegmentBoundary(type: string): boolean;
|
|
8
|
-
/** live 面的段末帧(`type` 即事件名;其余键由 `reasoningEndEventData` 白名单铸出)。
|
|
9
|
-
|
|
9
|
+
/** live 面的段末帧(`type` 即事件名;其余键由 `reasoningEndEventData` 白名单铸出)。
|
|
10
|
+
* 形是**声明**出来的、不是 `Record<string, unknown>`(S-334 门①):`eventId` 是本帧的续流游标,
|
|
11
|
+
* 型必须说得出口 —— live 腿的 `id:` 行取的正是它。 */
|
|
12
|
+
export type ReasoningEndFrame = SegmentEndFields & {
|
|
10
13
|
type: "reasoning_end";
|
|
11
14
|
};
|
|
12
15
|
/** 登记册**读到的全部字段**,逐个写出来(不是 `Record<string, unknown>`):`TaskEvent` 与转发腿的原始帧
|
|
@@ -48,6 +51,33 @@ export interface ReasoningSegments {
|
|
|
48
51
|
* 与账本腿 `LedgerSink.onDone → flush()` 同位同义 —— 段界表里没有终局词,终局走这扇门。 */
|
|
49
52
|
cut(match?: (ident: ReasoningStreamIdent) => boolean): ReasoningEndFrame[];
|
|
50
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* 一段推理的**段末事件 id** —— 唯一铸点,live 段末帧与账本 `reasoning` 行共用这一只。
|
|
56
|
+
*
|
|
57
|
+
* 🔴 **为什么段末帧不能沿用任何一块 delta 的 `eventId`**(S-334):SSE 的 `id:` 行是**续流游标**,
|
|
58
|
+
* 「每帧唯一」就是它的定义(消费端据它做**整帧幂等**:见过的 id 整帧丢);而本仓 live 腿的 `id:` 行
|
|
59
|
+
* 恰恰取自载荷的 `eventId`(`http/routes/tasks.ts` 的 `sseData`)。沿用段内某一块的锚 ⇒ 段末帧与那一块
|
|
60
|
+
* delta 顶着同一枚游标,消费端把**权威段**当重放帧丢弃 —— 本帧存在的唯一理由(整段脱敏后的权威副本)
|
|
61
|
+
* 当场结构性失效。「这段是从哪一帧开始攒的」不是游标要回答的问题,而「整段替换」这条消费律本来就
|
|
62
|
+
* 不需要段首锚:重连从**帧**续,不从段续。
|
|
63
|
+
*
|
|
64
|
+
* 形 = 那一枚锚 + 一个派生记号,**确定性**是它的全部要点:live 腿与账本腿各自看着同一条流、在同一个
|
|
65
|
+
* 段界上算出**同一枚**字符串,于是「同一份权威副本」在身份面也成立,而两条腿之间不需要任何传值通道
|
|
66
|
+
* ——bg / resume 两条账本腿上根本没有 live 登记册可问,靠传值就只能做成「detach 车道有、别的腿没有」
|
|
67
|
+
* 的两种账本行形。
|
|
68
|
+
*
|
|
69
|
+
* 输入 = 本段**第一块带锚**的 delta 的 `eventId`(不是「第一块」的:首块无锚不等于整段无锚,三条腿
|
|
70
|
+
* 统一用 `??=` 闩第一枚**有定义**的锚 —— 与 E18 的 `textEventId ??=` 逐字同律)。整段一块带锚的都没有
|
|
71
|
+
* ⇒ 段末 id 缺席(诚实的「无锚」,绝不合成占位 —— 与 `sseData` 的既有纪律同源:不可锚的位置不许
|
|
72
|
+
* 伪装成可锚)。
|
|
73
|
+
*/
|
|
74
|
+
export declare function reasoningSegmentEventId(anchor: unknown): string | undefined;
|
|
75
|
+
/** 一块 `reasoning_delta` 对段的**贡献字节** —— 非空串才算。账本腿与三条 live 腿共用这一只:空/坏形
|
|
76
|
+
* 增量一个字节都不贡献,既不开段也不参与闩锚 ⇒ 两面结构上不可能把锚闩在不同的帧上(`reasoning_end`
|
|
77
|
+
* 与账本 `reasoning` 行的正文早就逐字节相等,身份面随 S-334 收进同一条规则)。 */
|
|
78
|
+
export declare function reasoningDeltaBytes(ev: {
|
|
79
|
+
delta?: unknown;
|
|
80
|
+
}): string | undefined;
|
|
51
81
|
/** 「这条流属于这些子代 id 之一」—— 子代终态收段的匹配器(`task_id` 与 `sessionId` 是同一个子代的两个
|
|
52
82
|
* id 域,取并集;`undefined` 成员自动忽略)。腿上共用这一只,免得各写一遍 id 域的并集。 */
|
|
53
83
|
export declare function reasoningStreamOfTask(...ids: ReadonlyArray<string | undefined>): (ident: ReasoningStreamIdent) => boolean;
|
|
@@ -7,6 +7,13 @@ const BOUNDARY = new Set([
|
|
|
7
7
|
export function isModelSegmentBoundary(type) {
|
|
8
8
|
return BOUNDARY.has(type);
|
|
9
9
|
}
|
|
10
|
+
const REASONING_SEGMENT_ID_MARK = "~reasoning_end";
|
|
11
|
+
export function reasoningSegmentEventId(anchor) {
|
|
12
|
+
return typeof anchor === "string" && anchor.length > 0 ? `${anchor}${REASONING_SEGMENT_ID_MARK}` : undefined;
|
|
13
|
+
}
|
|
14
|
+
export function reasoningDeltaBytes(ev) {
|
|
15
|
+
return typeof ev.delta === "string" && ev.delta !== "" ? ev.delta : undefined;
|
|
16
|
+
}
|
|
10
17
|
export function reasoningStreamOfTask(...ids) {
|
|
11
18
|
const set = new Set(ids.filter((v) => typeof v === "string" && v !== ""));
|
|
12
19
|
return (ident) => (ident.sourceTaskId !== undefined && set.has(ident.sourceTaskId)) || (ident.bgAgentId !== undefined && set.has(ident.bgAgentId));
|
|
@@ -25,21 +32,24 @@ export function createReasoningSegments() {
|
|
|
25
32
|
if (seg === undefined)
|
|
26
33
|
return [];
|
|
27
34
|
open.delete(key);
|
|
28
|
-
const data = reasoningEndEventData({ ...seg.ident, eventId: seg.
|
|
35
|
+
const data = reasoningEndEventData({ ...seg.ident, eventId: seg.segmentEventId, content: seg.buf });
|
|
29
36
|
return data === null ? [] : [{ type: "reasoning_end", ...data }];
|
|
30
37
|
};
|
|
31
38
|
return {
|
|
32
39
|
onEvent: (ev) => {
|
|
33
40
|
if (ev.type === "reasoning_delta") {
|
|
34
|
-
|
|
41
|
+
const bytes = reasoningDeltaBytes(ev);
|
|
42
|
+
if (bytes === undefined)
|
|
35
43
|
return [];
|
|
36
44
|
const ident = identOf(ev);
|
|
37
45
|
const key = streamKeyOf(ident);
|
|
38
46
|
const seg = open.get(key);
|
|
39
47
|
if (seg === undefined)
|
|
40
|
-
open.set(key, { ident,
|
|
41
|
-
else
|
|
42
|
-
seg.buf +=
|
|
48
|
+
open.set(key, { ident, segmentEventId: reasoningSegmentEventId(ev.eventId), buf: bytes });
|
|
49
|
+
else {
|
|
50
|
+
seg.buf += bytes;
|
|
51
|
+
seg.segmentEventId ??= reasoningSegmentEventId(ev.eventId);
|
|
52
|
+
}
|
|
43
53
|
return [];
|
|
44
54
|
}
|
|
45
55
|
return isModelSegmentBoundary(ev.type ?? "") ? cutKey(streamKeyOf(identOf(ev))) : [];
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -192,8 +192,42 @@ export declare function screenedStoredEventData(type: string, data: unknown): un
|
|
|
192
192
|
* 此前三处各自逐字透传 —— 同一份文本毫秒后在 `done.result.result` 上已脱,live 面却在凭据生成瞬间明文(B-114)。
|
|
193
193
|
* `text_delta` 仍逐字:跨 chunk 的凭据无法就地判,流式脱敏是独立设计件(S-270)。
|
|
194
194
|
* 坏形(content 非串/空串)⇒ null(丢帧,不铸「权威空段」:core 契约明言空段不发本帧,消费端收到空段会清掉已攒 delta)。
|
|
195
|
-
*
|
|
196
|
-
|
|
195
|
+
* 身份**四键**随行(live 现状带全四键,消费端可能已依赖);值经 {@link identityKey} —— 非空 string 才上 wire
|
|
196
|
+
* (S-334 起不再逐字透传:坏形身份键会在 live 写口上铸出假游标)。 */
|
|
197
|
+
export declare function textEndEventData(ev: Record<string, unknown>): SegmentEndFields | null;
|
|
198
|
+
/**
|
|
199
|
+
* live 面的**身份四键**(core `TaskEventIdentity` 全集)—— 一个属主,两处共用({@link segmentEndFields}
|
|
200
|
+
* 与 sync 腿白名单 catch-all 的 `ident`;此前是两份手抄)。与 durable 面的 {@link identityFields} 的差别
|
|
201
|
+
* **只剩键集**:那边两键(durable builder 对另两键的既定排除),这边四键(live 现状,消费端已依赖);
|
|
202
|
+
* **值判据是同一条** —— 两只都问 {@link identityKey}(非空 `string` 才上 wire,绝不强转)。
|
|
203
|
+
*
|
|
204
|
+
* 🔴 **型必须说得出口**(S-334):`eventId` 是 live 腿 SSE `id:` 行的**唯一**来源,而 `id:` 行是续流游标
|
|
205
|
+
* ——一个连值的型都说不出的键不许铸成游标。非串/空串 ⇒ 键缺席(与「无锚不发 `id:` 行」同一条纪律:
|
|
206
|
+
* 不可锚的位置绝不伪装成可锚)。转发子代腿的帧是 UNTRUSTED RAW(§E1),这一道同时是它的形判门。
|
|
207
|
+
*
|
|
208
|
+
* 🔴 **`type` 而不是 `interface`**(它与 {@link SegmentEndFields} 两处都是,别改回去):TS 只给**类型别名**
|
|
209
|
+
* 隐式索引签名,interface 没有 ⇒ 写成 interface 的话,每一个把本形交给 `Record<string, unknown>` 形参
|
|
210
|
+
* (tail 总线帧、live 帧写口)的调用点都得手抄一次 `{ ...frame }` 展开。别名让「声明出来的形」原样流经
|
|
211
|
+
* 既有写口,零调用点噪声。
|
|
212
|
+
*/
|
|
213
|
+
export type LiveEventIdentity = {
|
|
214
|
+
eventId?: string;
|
|
215
|
+
parentToolCallId?: string;
|
|
216
|
+
sourceTaskId?: string;
|
|
217
|
+
bgAgentId?: string;
|
|
218
|
+
};
|
|
219
|
+
/** 段末帧(`text_end` / `reasoning_end`)的载荷**形**(两只帧一个字节不差 —— 一个 wire 概念一份形,
|
|
220
|
+
* 消费端的读法只学一次;差别只有各自铸点的空段判据)。 */
|
|
221
|
+
export type SegmentEndFields = LiveEventIdentity & {
|
|
222
|
+
content: string;
|
|
223
|
+
};
|
|
224
|
+
/** {@link LiveEventIdentity} 的铸点。[ref] 门①:条件展开的臂逐条是直写字面量(键名对扫描器可见)。 */
|
|
225
|
+
export declare function liveIdentityFields(ev: {
|
|
226
|
+
eventId?: unknown;
|
|
227
|
+
parentToolCallId?: unknown;
|
|
228
|
+
sourceTaskId?: unknown;
|
|
229
|
+
bgAgentId?: unknown;
|
|
230
|
+
}): LiveEventIdentity;
|
|
197
231
|
/**
|
|
198
232
|
* `reasoning_end` 段末帧的**唯一**铸点(三条 live 腿共用:top stream / 转发子代腿 / 子代 tail 面)——
|
|
199
233
|
* `text_end` 的推理面孪生({@link textEndEventData}),形逐字同(共用 {@link segmentEndFields})。
|
|
@@ -210,7 +244,7 @@ export declare function textEndEventData(ev: Record<string, unknown>): Record<st
|
|
|
210
244
|
* 「整段替换已攒的 delta」—— 发一枚空白权威段 = 让消费端把已渲染的思考清成空白。坏形(`content` 非串)
|
|
211
245
|
* 同样丢帧,理由与 `text_end` 逐字同源。
|
|
212
246
|
*/
|
|
213
|
-
export declare function reasoningEndEventData(ev: Record<string, unknown>):
|
|
247
|
+
export declare function reasoningEndEventData(ev: Record<string, unknown>): SegmentEndFields | null;
|
|
214
248
|
/** The durable `tool_end` payload (shared by both append sites). E1: the model-facing `output` is UNTRUSTED RAW
|
|
215
249
|
* from core (file/shell/API bodies) — core only SIZE-bounds it (`truncated`), REDACTION is ours (same contract as
|
|
216
250
|
* `tool_start.args`); never re-fed to a model. E2: identity. Absent `output` ⇒ the tool produced no content body.
|
package/dist/trace/project.js
CHANGED
|
@@ -78,10 +78,13 @@ export function aggregateModelUsage(events) {
|
|
|
78
78
|
}
|
|
79
79
|
function identityFields(src) {
|
|
80
80
|
return {
|
|
81
|
-
...(src.eventId ? { eventId:
|
|
82
|
-
...(src.parentToolCallId ? { parentToolCallId:
|
|
81
|
+
...(identityKey(src.eventId) !== undefined ? { eventId: identityKey(src.eventId) } : {}),
|
|
82
|
+
...(identityKey(src.parentToolCallId) !== undefined ? { parentToolCallId: identityKey(src.parentToolCallId) } : {}),
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
+
function identityKey(v) {
|
|
86
|
+
return typeof v === "string" && v !== "" ? v : undefined;
|
|
87
|
+
}
|
|
85
88
|
export function modelTextEventData(ev) {
|
|
86
89
|
return { text: ev.text, ...(ev.eventId ? { eventId: ev.eventId } : {}) };
|
|
87
90
|
}
|
|
@@ -192,15 +195,17 @@ export function textEndEventData(ev) {
|
|
|
192
195
|
return null;
|
|
193
196
|
return segmentEndFields(ev.content, ev);
|
|
194
197
|
}
|
|
195
|
-
function
|
|
198
|
+
export function liveIdentityFields(ev) {
|
|
196
199
|
return {
|
|
197
|
-
|
|
198
|
-
...(ev.
|
|
199
|
-
...(ev.
|
|
200
|
-
...(ev.
|
|
201
|
-
...(ev.bgAgentId !== undefined ? { bgAgentId: ev.bgAgentId } : {}),
|
|
200
|
+
...(identityKey(ev.eventId) !== undefined ? { eventId: identityKey(ev.eventId) } : {}),
|
|
201
|
+
...(identityKey(ev.parentToolCallId) !== undefined ? { parentToolCallId: identityKey(ev.parentToolCallId) } : {}),
|
|
202
|
+
...(identityKey(ev.sourceTaskId) !== undefined ? { sourceTaskId: identityKey(ev.sourceTaskId) } : {}),
|
|
203
|
+
...(identityKey(ev.bgAgentId) !== undefined ? { bgAgentId: identityKey(ev.bgAgentId) } : {}),
|
|
202
204
|
};
|
|
203
205
|
}
|
|
206
|
+
function segmentEndFields(content, ev) {
|
|
207
|
+
return { content: redactModelText(content), ...liveIdentityFields(ev) };
|
|
208
|
+
}
|
|
204
209
|
export function reasoningEndEventData(ev) {
|
|
205
210
|
if (typeof ev.content !== "string" || ev.content.trim().length === 0)
|
|
206
211
|
return null;
|
|
@@ -593,8 +598,7 @@ export function compactedEventData(ev) {
|
|
|
593
598
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
594
599
|
})();
|
|
595
600
|
return {
|
|
596
|
-
...(ev
|
|
597
|
-
...(ev.parentToolCallId !== undefined ? { parentToolCallId: ev.parentToolCallId } : {}),
|
|
601
|
+
...identityFields(ev),
|
|
598
602
|
...(typeof ev.trigger === "string" ? { trigger: ev.trigger } : {}),
|
|
599
603
|
...(num(ev.tokensBefore) !== undefined ? { tokensBefore: num(ev.tokensBefore) } : {}),
|
|
600
604
|
...(ev.preserved_segment?.firstKeptEntryId ? { preserved_segment: { firstKeptEntryId: ev.preserved_segment.firstKeptEntryId } } : {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.78.
|
|
3
|
+
"version": "7.78.2",
|
|
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.19.0",
|
|
58
58
|
"@sema-agent/settings-schema": "2.1.0",
|
|
59
59
|
"e2b": "^2.28.0",
|
|
60
60
|
"libsodium-wrappers": "^0.8.4",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"sharp": "^0.35.3"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@sema-agent/sdk": "9.
|
|
72
|
+
"@sema-agent/sdk": "9.5.0",
|
|
73
73
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
74
74
|
"@types/node": "22.10.2",
|
|
75
75
|
"@types/pg": "^8.20.0",
|