@sema-agent/server 1.289.0 → 1.291.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/env-facts.d.ts +5 -0
- package/dist/env-facts.js +35 -1
- package/dist/fleet/fleet-bus.d.ts +34 -1
- package/dist/fleet/fleet-bus.js +53 -4
- package/dist/http/server.d.ts +1 -0
- package/dist/http/server.js +49 -11
- package/dist/main.js +14 -4
- package/dist/runs.d.ts +1 -1
- package/dist/runs.js +6 -2
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/package.json +1 -1
package/dist/env-facts.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export declare function resumeFactsForLane(provider: "e2b" | "k8s" | "ssh" | "ad
|
|
|
25
25
|
export declare function scratchpadSessionSegment(sessionId: string): string;
|
|
26
26
|
export declare function scratchpadDirFor(localDataRoot: string, sessionId: string): string;
|
|
27
27
|
export declare function ensureScratchpadDir(localDataRoot: string, sessionId: string): Promise<string | undefined>;
|
|
28
|
+
export declare function acceptShellScratchpadDir(raw: unknown, opts: {
|
|
29
|
+
requirePrincipal: boolean;
|
|
30
|
+
hostSemanticsLane: boolean;
|
|
31
|
+
warn: (msg: string, meta?: object) => void;
|
|
32
|
+
}): Promise<string | undefined>;
|
|
28
33
|
export declare function purgeScratchpadDir(localDataRoot: string, sessionId: string): Promise<void>;
|
|
29
34
|
export declare function sweepStaleScratchpads(localDataRoot: string, opts: {
|
|
30
35
|
olderThanMs: number;
|
package/dist/env-facts.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
1
|
+
import { isAbsolute, join, resolve, sep } from "node:path";
|
|
2
2
|
import { mkdir, readdir, rm, stat } from "node:fs/promises";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
const MAX_STR = 64;
|
|
@@ -59,6 +59,40 @@ export async function ensureScratchpadDir(localDataRoot, sessionId) {
|
|
|
59
59
|
return undefined;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
export async function acceptShellScratchpadDir(raw, opts) {
|
|
63
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (opts.requirePrincipal) {
|
|
66
|
+
opts.warn("shell_scratchpad_ignored", { reason: "multi_tenant", note: "tenant-supplied exempt dir on a shared worker disk — server-computed scratchpad used instead" });
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
if (!opts.hostSemanticsLane) {
|
|
70
|
+
opts.warn("shell_scratchpad_ignored", { reason: "remote_lane", note: "worker-local path is not real to remote-sandbox hands — in-sandbox scratchpad used instead" });
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
if (!isAbsolute(raw)) {
|
|
74
|
+
opts.warn("shell_scratchpad_ignored", { reason: "not_absolute" });
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
if (raw.length > MAX_PATH) {
|
|
78
|
+
opts.warn("shell_scratchpad_ignored", { reason: "too_long", length: raw.length, max: MAX_PATH });
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const canonical = resolve(raw);
|
|
82
|
+
const depth = canonical.split(sep).filter((s) => s.length > 0).length;
|
|
83
|
+
if (depth < 3) {
|
|
84
|
+
opts.warn("shell_scratchpad_ignored", { reason: "too_shallow", canonical });
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await mkdir(canonical, { recursive: true });
|
|
89
|
+
return canonical;
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
opts.warn("shell_scratchpad_ignored", { reason: "mkdir_failed", error: err instanceof Error ? err.message : String(err) });
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
62
96
|
export async function purgeScratchpadDir(localDataRoot, sessionId) {
|
|
63
97
|
const dir = scratchpadDirFor(localDataRoot, sessionId);
|
|
64
98
|
try {
|
|
@@ -8,6 +8,7 @@ export interface FleetTaskRow {
|
|
|
8
8
|
scope?: string;
|
|
9
9
|
sessionId?: string;
|
|
10
10
|
parentId?: string;
|
|
11
|
+
parentToolCallId?: string;
|
|
11
12
|
workflowRunId?: string;
|
|
12
13
|
status: FleetTaskStatus;
|
|
13
14
|
startedAt?: number;
|
|
@@ -22,6 +23,20 @@ export interface FleetTaskRow {
|
|
|
22
23
|
};
|
|
23
24
|
toolUses?: number;
|
|
24
25
|
transcriptId?: string;
|
|
26
|
+
stoppedBy?: string;
|
|
27
|
+
usage?: {
|
|
28
|
+
totalTokens?: number;
|
|
29
|
+
toolUses?: number;
|
|
30
|
+
durationMs?: number;
|
|
31
|
+
tokens?: number;
|
|
32
|
+
turns?: number;
|
|
33
|
+
costMicroUsd?: number;
|
|
34
|
+
};
|
|
35
|
+
resumable?: boolean;
|
|
36
|
+
editedFiles?: Array<{
|
|
37
|
+
path: string;
|
|
38
|
+
edits: number;
|
|
39
|
+
}>;
|
|
25
40
|
}
|
|
26
41
|
export interface FleetWorkflowRow {
|
|
27
42
|
id: string;
|
|
@@ -160,9 +175,27 @@ export declare function fleetRunPublisher(bus: FleetEventBus | undefined, run: {
|
|
|
160
175
|
status?: string;
|
|
161
176
|
}) => void;
|
|
162
177
|
onChildTerminal: (taskId: string, status: string, altId?: string, toolUseId?: string) => boolean;
|
|
163
|
-
onTerminal: (status: string
|
|
178
|
+
onTerminal: (status: string, residuals?: {
|
|
179
|
+
usage?: FleetTaskRow["usage"];
|
|
180
|
+
stoppedBy?: string;
|
|
181
|
+
transcriptId?: string;
|
|
182
|
+
}) => void;
|
|
164
183
|
};
|
|
165
184
|
export type FleetRunPublisher = ReturnType<typeof fleetRunPublisher>;
|
|
185
|
+
export declare function fleetRunResiduals(result: {
|
|
186
|
+
sessionId?: string;
|
|
187
|
+
errorCode?: string;
|
|
188
|
+
stats?: {
|
|
189
|
+
turns?: number;
|
|
190
|
+
tokens?: number;
|
|
191
|
+
toolCalls?: number;
|
|
192
|
+
costMicroUsd?: number;
|
|
193
|
+
};
|
|
194
|
+
} | null | undefined): {
|
|
195
|
+
usage?: FleetTaskRow["usage"];
|
|
196
|
+
stoppedBy?: string;
|
|
197
|
+
transcriptId?: string;
|
|
198
|
+
};
|
|
166
199
|
export declare function fleetBackgroundChildPublisher(bus?: FleetEventBus, log?: (msg: string, fields: Record<string, unknown>) => void): (e: import("@sema-agent/core").BackgroundChildEvent) => void;
|
|
167
200
|
export declare function fleetRunLabels(objective: string | undefined): {
|
|
168
201
|
name: string;
|
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -136,21 +136,47 @@ export function fleetRunPublisher(bus, run) {
|
|
|
136
136
|
}
|
|
137
137
|
return hadRow;
|
|
138
138
|
},
|
|
139
|
-
onTerminal(status) {
|
|
139
|
+
onTerminal(status, residuals) {
|
|
140
140
|
settledLeg = true;
|
|
141
141
|
const fleetStatus = runStatusToFleet(status);
|
|
142
|
-
|
|
142
|
+
const terminal = fleetStatus === "completed" || fleetStatus === "failed" || fleetStatus === "killed";
|
|
143
|
+
const res = terminal && residuals
|
|
144
|
+
? {
|
|
145
|
+
...(residuals.usage ? { usage: residuals.usage } : {}),
|
|
146
|
+
...(residuals.stoppedBy ? { stoppedBy: residuals.stoppedBy } : {}),
|
|
147
|
+
...(residuals.transcriptId ? { transcriptId: residuals.transcriptId } : {}),
|
|
148
|
+
}
|
|
149
|
+
: {};
|
|
150
|
+
bus.publishTask({ id: run.runId, status: fleetStatus, tokens, elapsedMs: Date.now() - startedAt, ...res });
|
|
143
151
|
for (const cid of children)
|
|
144
152
|
bus.removeTask(cid);
|
|
145
153
|
children.clear();
|
|
146
154
|
childStartedAt.clear();
|
|
147
155
|
childByToolCall.clear();
|
|
148
|
-
if (
|
|
156
|
+
if (terminal) {
|
|
149
157
|
bus.removeTask(run.runId);
|
|
150
158
|
}
|
|
151
159
|
},
|
|
152
160
|
};
|
|
153
161
|
}
|
|
162
|
+
export function fleetRunResiduals(result) {
|
|
163
|
+
if (!result)
|
|
164
|
+
return {};
|
|
165
|
+
const s = result.stats;
|
|
166
|
+
const usage = s
|
|
167
|
+
? {
|
|
168
|
+
...(typeof s.tokens === "number" ? { totalTokens: s.tokens } : {}),
|
|
169
|
+
...(typeof s.turns === "number" ? { turns: s.turns } : {}),
|
|
170
|
+
...(typeof s.toolCalls === "number" ? { toolUses: s.toolCalls } : {}),
|
|
171
|
+
...(typeof s.costMicroUsd === "number" ? { costMicroUsd: s.costMicroUsd } : {}),
|
|
172
|
+
}
|
|
173
|
+
: {};
|
|
174
|
+
return {
|
|
175
|
+
...(Object.keys(usage).length > 0 ? { usage } : {}),
|
|
176
|
+
...(result.errorCode === "cancelled" ? { stoppedBy: "user" } : {}),
|
|
177
|
+
...(result.sessionId ? { transcriptId: result.sessionId } : {}),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
154
180
|
export function fleetBackgroundChildPublisher(bus, log) {
|
|
155
181
|
if (!bus)
|
|
156
182
|
return () => undefined;
|
|
@@ -223,6 +249,7 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
223
249
|
...(m.hostSessionId ? { sessionId: m.hostSessionId } : {}),
|
|
224
250
|
...(parentId !== undefined ? { parentId } : {}),
|
|
225
251
|
...(m.workflowRunId !== undefined ? { workflowRunId: m.workflowRunId } : {}),
|
|
252
|
+
...(m.parentToolCallId !== undefined ? { parentToolCallId: m.parentToolCallId } : {}),
|
|
226
253
|
...(m.spawnedAt !== undefined ? { startedAt: m.spawnedAt, elapsedMs: Date.now() - m.spawnedAt } : {}),
|
|
227
254
|
};
|
|
228
255
|
};
|
|
@@ -250,6 +277,7 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
250
277
|
sessionScoped: e.sessionScoped,
|
|
251
278
|
spawnedAt: e.startedAt ?? Date.now(),
|
|
252
279
|
...(e.rootSessionId ? { rootSessionId: e.rootSessionId } : {}),
|
|
280
|
+
...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}),
|
|
253
281
|
...(e.sessionId ? { aliasUuid: e.sessionId } : {}),
|
|
254
282
|
...(e.workflowRunId ? { workflowRunId: e.workflowRunId } : {}),
|
|
255
283
|
...(e.workflowRunId && !(e.sessionScoped && e.owner)
|
|
@@ -293,6 +321,8 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
293
321
|
dlog("bg_child_event", { kind: `${e.kind}-after-terminal-ignored`, taskId: e.taskId });
|
|
294
322
|
return;
|
|
295
323
|
}
|
|
324
|
+
if (m.parentToolCallId === undefined && e.parentToolCallId)
|
|
325
|
+
m.parentToolCallId = e.parentToolCallId;
|
|
296
326
|
if (e.kind === "tick") {
|
|
297
327
|
if (!m.suppressedTwin && e.progressTaskId && (!e.progressParentTaskId || e.progressParentTaskId === (m.parentTaskId ?? m.parentSessionLink))) {
|
|
298
328
|
const tail = ` ${e.progressTaskId}`;
|
|
@@ -321,7 +351,25 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
321
351
|
return;
|
|
322
352
|
}
|
|
323
353
|
const status = e.status === "completed" ? "completed" : e.status === "killed" ? "killed" : "failed";
|
|
324
|
-
bus.publishTask({
|
|
354
|
+
bus.publishTask({
|
|
355
|
+
id: e.taskId, ...rowTags(m), status,
|
|
356
|
+
...(e.stoppedBy ? { stoppedBy: e.stoppedBy } : {}),
|
|
357
|
+
...(e.resumable !== undefined ? { resumable: e.resumable } : {}),
|
|
358
|
+
...(e.transcriptId ? { transcriptId: e.transcriptId } : {}),
|
|
359
|
+
...(e.editedFiles !== undefined ? { editedFiles: e.editedFiles.slice(0, 100).map((f) => ({ path: redactSecrets(f.path), edits: f.edits })) } : {}),
|
|
360
|
+
...(e.usage
|
|
361
|
+
? {
|
|
362
|
+
usage: {
|
|
363
|
+
...(e.usage.totalTokens !== undefined ? { totalTokens: e.usage.totalTokens } : {}),
|
|
364
|
+
...(e.usage.toolUses !== undefined ? { toolUses: e.usage.toolUses } : {}),
|
|
365
|
+
...(e.usage.durationMs !== undefined ? { durationMs: e.usage.durationMs } : {}),
|
|
366
|
+
...(e.usage.tokens !== undefined ? { tokens: e.usage.tokens } : {}),
|
|
367
|
+
...(e.usage.turns !== undefined ? { turns: e.usage.turns } : {}),
|
|
368
|
+
...(e.usage.costMicroUsd !== undefined ? { costMicroUsd: e.usage.costMicroUsd } : {}),
|
|
369
|
+
},
|
|
370
|
+
}
|
|
371
|
+
: {}),
|
|
372
|
+
});
|
|
325
373
|
bus.removeTask(e.taskId);
|
|
326
374
|
if (m.aliasUuid) {
|
|
327
375
|
const tail = ` ${m.aliasUuid}`;
|
|
@@ -362,6 +410,7 @@ export function fleetBackgroundChildPublisher(bus, log) {
|
|
|
362
410
|
}
|
|
363
411
|
: {}),
|
|
364
412
|
...(e.transcriptId ? { transcriptId: e.transcriptId } : {}),
|
|
413
|
+
...(e.parentToolCallId ? { parentToolCallId: e.parentToolCallId } : {}),
|
|
365
414
|
...(m.tenantScope ? { ownerScope: m.tenantScope } : {}),
|
|
366
415
|
...(m.hostSessionId ? { ownerSessionId: m.hostSessionId } : {}),
|
|
367
416
|
...(m.rootSessionId ? { rootSessionId: m.rootSessionId } : {}),
|
package/dist/http/server.d.ts
CHANGED
package/dist/http/server.js
CHANGED
|
@@ -21,7 +21,7 @@ import { runInBackground, evictIfConflict, stripCheckpointToken, resumeAtHttpSta
|
|
|
21
21
|
import { looksLikeJwt } from "../auth-bridge.js";
|
|
22
22
|
import { redactSteerIn, STEER_IN_MAX_CHARS, STEER_IN_MAX_REQUEST_CHARS } from "../orchestration/workflow-agent-steer.js";
|
|
23
23
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationFoldKey, taskNotificationStreamKey, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
24
|
-
import { fleetRunPublisher, fleetRunLabels } from "../fleet/fleet-bus.js";
|
|
24
|
+
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals } from "../fleet/fleet-bus.js";
|
|
25
25
|
import { defaultSubagentTailBus, projectTailFrame } from "../fleet/subagent-tail-bus.js";
|
|
26
26
|
import { RateLimiter } from "../observability/rate-limit.js";
|
|
27
27
|
import { withPrincipal } from "../observability/principal-context.js";
|
|
@@ -679,6 +679,7 @@ export function createHttpServer(deps) {
|
|
|
679
679
|
toolOutput: true,
|
|
680
680
|
messageIdentity: true,
|
|
681
681
|
forwardSubagentEvents: true,
|
|
682
|
+
scratchpadDir: true,
|
|
682
683
|
subagentSteer: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
|
|
683
684
|
subagentResume: Boolean(deps.subagentSteerRegistry) && Boolean(deps.runStore),
|
|
684
685
|
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: false, hooks: deps.config.requirePrincipal !== true },
|
|
@@ -853,8 +854,12 @@ export function createHttpServer(deps) {
|
|
|
853
854
|
return;
|
|
854
855
|
}
|
|
855
856
|
streamTaskId = earlyDurableTid;
|
|
857
|
+
let usageKey;
|
|
856
858
|
streamDetached = detachOnDisconnect;
|
|
857
859
|
sseHeaders(res, earlyDurableTid ? { "x-task-id": earlyDurableTid } : undefined);
|
|
860
|
+
if (earlyDurableTid) {
|
|
861
|
+
res.write(`event: meta\ndata: ${JSON.stringify({ type: "meta", taskId: earlyDurableTid, ...(prepared.spec.sessionId ? { sessionId: prepared.spec.sessionId } : {}) })}\n\n`);
|
|
862
|
+
}
|
|
858
863
|
const ac = new AbortController();
|
|
859
864
|
if (prepared.spec.sessionId)
|
|
860
865
|
markChildrenStoppedByUserOnAbort(ac.signal, prepared.spec.sessionId, prepared.auth?.principal);
|
|
@@ -921,6 +926,9 @@ export function createHttpServer(deps) {
|
|
|
921
926
|
const rs = deps.runStore;
|
|
922
927
|
const tid = durableTaskId;
|
|
923
928
|
ledgerSink = createLedgerSink({ appendEvent: (seq, type, data) => rs.appendEvent(tid, seq, type, data), persistThinking: deps.config.traceThinking });
|
|
929
|
+
usageKey = prepared.spec.sessionId;
|
|
930
|
+
if (usageKey)
|
|
931
|
+
deps.modelUsage?.register(usageKey);
|
|
924
932
|
}
|
|
925
933
|
if (deps.checkpointStore && prepared.spec.sessionId) {
|
|
926
934
|
await deps.checkpointStore.putCtx(prepared.spec.sessionId, { body: prepared.body, memoryScope: prepared.auth?.memoryScope });
|
|
@@ -961,11 +969,11 @@ export function createHttpServer(deps) {
|
|
|
961
969
|
throw e;
|
|
962
970
|
}
|
|
963
971
|
let fleetSettled = false;
|
|
964
|
-
const settleFleet = (status) => {
|
|
972
|
+
const settleFleet = (status, residuals) => {
|
|
965
973
|
if (fleetSettled)
|
|
966
974
|
return;
|
|
967
975
|
fleetSettled = true;
|
|
968
|
-
fleetPub?.onTerminal(status);
|
|
976
|
+
fleetPub?.onTerminal(status, residuals);
|
|
969
977
|
};
|
|
970
978
|
let liveStreamRef;
|
|
971
979
|
const subagentHandleEvictions = [];
|
|
@@ -1069,16 +1077,25 @@ export function createHttpServer(deps) {
|
|
|
1069
1077
|
}
|
|
1070
1078
|
finalizeTaskResult(ev.result, principal, prepared.spec.objective, prepared.spec.sessionId);
|
|
1071
1079
|
putRewindAnchor();
|
|
1072
|
-
settleFleet(finalResult?.status ?? "completed");
|
|
1080
|
+
settleFleet(finalResult?.status ?? "completed", fleetRunResiduals(finalResult));
|
|
1073
1081
|
if (ledgerSink && finalResult) {
|
|
1082
|
+
if (usageKey && deps.modelUsage && deps.runStore && durableTaskId) {
|
|
1083
|
+
const rs2 = deps.runStore;
|
|
1084
|
+
const tid2 = durableTaskId;
|
|
1085
|
+
const fr = finalResult;
|
|
1086
|
+
finalResult = await attachModelUsage(fr, { append: ledgerSink.append, getEvents: (_id, after) => rs2.getEvents(tid2, after), modelUsage: deps.modelUsage, taskId: usageKey }).catch(() => fr);
|
|
1087
|
+
}
|
|
1074
1088
|
await ledgerSink.onDone(finalResult);
|
|
1075
1089
|
ledgerTerminal = true;
|
|
1076
1090
|
}
|
|
1077
1091
|
res.write(`data: ${JSON.stringify({ ...ev, result: finalResult })}\n\n`);
|
|
1078
1092
|
continue;
|
|
1079
1093
|
}
|
|
1080
|
-
if (ledgerSink)
|
|
1094
|
+
if (ledgerSink) {
|
|
1081
1095
|
await ledgerSink.onEvent(ev);
|
|
1096
|
+
if (ev.type === "turn_end" && usageKey)
|
|
1097
|
+
await appendModelUsageDelta(ledgerSink.append, deps.modelUsage, usageKey);
|
|
1098
|
+
}
|
|
1082
1099
|
fleetPub?.onEvent(ev);
|
|
1083
1100
|
if (ev.type === "status")
|
|
1084
1101
|
deps.metrics?.inc("brain_retry_total", { phase: String(ev.phase) });
|
|
@@ -1164,7 +1181,16 @@ export function createHttpServer(deps) {
|
|
|
1164
1181
|
}
|
|
1165
1182
|
const withApproval = () => approvalCtx && deps.toolApproval ? deps.toolApproval.runWithContext(approvalCtx, withQuestion) : withQuestion();
|
|
1166
1183
|
await (deps.sendUserFile
|
|
1167
|
-
? deps.sendUserFile.runWithContext({
|
|
1184
|
+
? deps.sendUserFile.runWithContext({
|
|
1185
|
+
taskId: askTaskId,
|
|
1186
|
+
emit: async (f) => {
|
|
1187
|
+
void (await emitAsk(f));
|
|
1188
|
+
if (ledgerSink) {
|
|
1189
|
+
const { type, ...rest } = f;
|
|
1190
|
+
await ledgerSink.append(type, rest).catch(() => undefined);
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
}, withApproval)
|
|
1168
1194
|
: withApproval());
|
|
1169
1195
|
if (durableTaskId && deps.runStore) {
|
|
1170
1196
|
if (finalResult?.status === "suspended" && deps.checkpointStore)
|
|
@@ -1232,7 +1258,7 @@ export function createHttpServer(deps) {
|
|
|
1232
1258
|
await ledgerSink.onDone(finalResult).catch(() => undefined);
|
|
1233
1259
|
}
|
|
1234
1260
|
await deps.runStore.setTerminal(durableTaskId, finalResult.status, finalResult, finalResult.errorMessage ?? null);
|
|
1235
|
-
settleFleet(finalResult.status);
|
|
1261
|
+
settleFleet(finalResult.status, fleetRunResiduals(finalResult));
|
|
1236
1262
|
}
|
|
1237
1263
|
else if (ac.signal.aborted) {
|
|
1238
1264
|
const err = "stream aborted before completion (run cancelled)";
|
|
@@ -1271,6 +1297,8 @@ export function createHttpServer(deps) {
|
|
|
1271
1297
|
finally {
|
|
1272
1298
|
uncountedBillableInflight--;
|
|
1273
1299
|
clearInterval(hb);
|
|
1300
|
+
if (usageKey)
|
|
1301
|
+
deps.modelUsage?.clear(usageKey);
|
|
1274
1302
|
}
|
|
1275
1303
|
if (!ranLive && resp && !res.writableEnded) {
|
|
1276
1304
|
res.write(`data: ${JSON.stringify({ type: "done", result: resp.body, replay: true })}\n\n`);
|
|
@@ -2163,7 +2191,17 @@ export function createHttpServer(deps) {
|
|
|
2163
2191
|
});
|
|
2164
2192
|
return;
|
|
2165
2193
|
}
|
|
2166
|
-
|
|
2194
|
+
const g14 = (() => {
|
|
2195
|
+
const d = out.details;
|
|
2196
|
+
if (!d || d.error !== undefined || d.retrieval_status === "not_ready")
|
|
2197
|
+
return {};
|
|
2198
|
+
if (d.type === "background_bash")
|
|
2199
|
+
return { cursorSemantics: d.details && "bytesDroppedBeforeCursor" in d.details ? "cursor" : "full" };
|
|
2200
|
+
if (d.type === "monitor" || d.type === "background_agent")
|
|
2201
|
+
return { cursorSemantics: "full" };
|
|
2202
|
+
return {};
|
|
2203
|
+
})();
|
|
2204
|
+
sendJson(res, 200, { taskId: runId, target, content: out.content, output: out.details, ...g14 });
|
|
2167
2205
|
return;
|
|
2168
2206
|
}
|
|
2169
2207
|
const subVerbMatch = req.method === "POST" ? (RUN_SUBAGENT_STEER_RE.exec(url) ?? RUN_SUBAGENT_RESUME_RE.exec(url)) : null;
|
|
@@ -5078,11 +5116,11 @@ export function createHttpServer(deps) {
|
|
|
5078
5116
|
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: sessionId, ...fleetRunLabels(resumeObjective) })
|
|
5079
5117
|
: undefined;
|
|
5080
5118
|
let fleetSettled = false;
|
|
5081
|
-
const settleFleet = (status) => {
|
|
5119
|
+
const settleFleet = (status, residuals) => {
|
|
5082
5120
|
if (fleetSettled)
|
|
5083
5121
|
return;
|
|
5084
5122
|
fleetSettled = true;
|
|
5085
|
-
fleetPub?.onTerminal(status);
|
|
5123
|
+
fleetPub?.onTerminal(status, residuals);
|
|
5086
5124
|
};
|
|
5087
5125
|
let result;
|
|
5088
5126
|
let reopenConfirmedPark = false;
|
|
@@ -5445,7 +5483,7 @@ export function createHttpServer(deps) {
|
|
|
5445
5483
|
else
|
|
5446
5484
|
await deps.runStore.setTerminal(taskId, result.status, stripCheckpointToken(result), result.errorMessage ?? null);
|
|
5447
5485
|
}
|
|
5448
|
-
settleFleet(checkpointReopened ? "suspended" : result.status);
|
|
5486
|
+
settleFleet(checkpointReopened ? "suspended" : result.status, fleetRunResiduals(result));
|
|
5449
5487
|
return {
|
|
5450
5488
|
status: 200,
|
|
5451
5489
|
body: {
|
package/dist/main.js
CHANGED
|
@@ -21,7 +21,7 @@ import { createSendUserFileIssuer } from "./plugins/send-user-file.js";
|
|
|
21
21
|
import { withLedgerRecording } from "./plugins/send-file-ledger.js";
|
|
22
22
|
import { basename, resolve } from "node:path";
|
|
23
23
|
import { stat as fsStat, readFile as fsReadFile } from "node:fs/promises";
|
|
24
|
-
import { buildEnvFacts, egressForRemoteExec, ensureScratchpadDir, purgeScratchpadDir, sweepStaleScratchpads, resumeFactsForLane } from "./env-facts.js";
|
|
24
|
+
import { acceptShellScratchpadDir, buildEnvFacts, egressForRemoteExec, ensureScratchpadDir, purgeScratchpadDir, sweepStaleScratchpads, resumeFactsForLane } from "./env-facts.js";
|
|
25
25
|
import { normalizeSuggestNextPrompts, normalizeResilience, normalizeAttachments, normalizeResumeAtMode, resolveTaskLimits, taskAgentsSpecFragment, retainBackgroundProcessesFromBody, toolNameListFromBody, promptProfileFromBody } from "./spec-fields.js";
|
|
26
26
|
import { createBrain, brainSummary } from "./brain.js";
|
|
27
27
|
import { loadConfig, logConfigDiagnostics } from "./config.js";
|
|
@@ -499,6 +499,12 @@ async function main() {
|
|
|
499
499
|
}
|
|
500
500
|
else {
|
|
501
501
|
memoryEngine = memoryEngineBackendFor(config);
|
|
502
|
+
if (memoryEngine && process.env.LOCAL_DATA_ROOT && !config.memoryEngineDir) {
|
|
503
|
+
logger.warn("memory_engine_dir_defaulted", {
|
|
504
|
+
root: memoryEngine.root,
|
|
505
|
+
hint: "LOCAL_DATA_ROOT is set but MEMORY_ENGINE_DIR is not — the memory engine is sharing the machine-wide default; set MEMORY_ENGINE_DIR to isolate it under your data root",
|
|
506
|
+
});
|
|
507
|
+
}
|
|
502
508
|
}
|
|
503
509
|
let rosterStore;
|
|
504
510
|
{
|
|
@@ -2181,9 +2187,13 @@ async function main() {
|
|
|
2181
2187
|
effectiveSettings = Object.keys(rest2).length > 0 ? rest2 : undefined;
|
|
2182
2188
|
}
|
|
2183
2189
|
const hostSemanticsLane = config.remoteExec === undefined || config.remoteExec.provider === "host";
|
|
2184
|
-
const
|
|
2185
|
-
|
|
2186
|
-
|
|
2190
|
+
const shellScratchpad = await acceptShellScratchpadDir(body.scratchpadDir, {
|
|
2191
|
+
requirePrincipal: config.requirePrincipal,
|
|
2192
|
+
hostSemanticsLane,
|
|
2193
|
+
warn: (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: auth?.sessionId ?? null }),
|
|
2194
|
+
});
|
|
2195
|
+
const scratchpadDir = shellScratchpad ??
|
|
2196
|
+
(hostSemanticsLane && auth?.sessionId ? await ensureScratchpadDir(config.localDataRoot ?? localRoot, auth.sessionId) : undefined);
|
|
2187
2197
|
if (effectiveSettings) {
|
|
2188
2198
|
const fsWriteGate = hostSemanticsLane
|
|
2189
2199
|
? (() => {
|
package/dist/runs.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Metrics } from "./observability/metrics.js";
|
|
|
5
5
|
import type { ModelUsageTracker, PromptManifestTracker } from "./budget.js";
|
|
6
6
|
import type { ElicitationCoordinator } from "./elicitation.js";
|
|
7
7
|
import type { QuestionCoordinator } from "./question.js";
|
|
8
|
-
import type
|
|
8
|
+
import { type FleetRunPublisher } from "./fleet/fleet-bus.js";
|
|
9
9
|
import { type WorkflowCompletionInbox } from "./orchestration/workflow-completion-inbox.js";
|
|
10
10
|
export declare function backgroundAgentOutput(registry: typeof defaultTaskRegistry, handle: string, access: {
|
|
11
11
|
owner: string;
|
package/dist/runs.js
CHANGED
|
@@ -3,6 +3,7 @@ import { withPrincipal } from "./observability/principal-context.js";
|
|
|
3
3
|
import { redactSecrets } from "./trace/redact.js";
|
|
4
4
|
import { taskNotificationEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "./trace/project.js";
|
|
5
5
|
import { createLedgerSink } from "./trace/ledger-sink.js";
|
|
6
|
+
import { fleetRunResiduals } from "./fleet/fleet-bus.js";
|
|
6
7
|
import { defaultSubagentTailBus, projectTailFrame } from "./fleet/subagent-tail-bus.js";
|
|
7
8
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKey, NotifiedKeys } from "./orchestration/workflow-completion-inbox.js";
|
|
8
9
|
export async function backgroundAgentOutput(registry, handle, access, agentStore) {
|
|
@@ -365,13 +366,16 @@ export async function runInBackground(runner, spec, runStore, taskId, metrics, p
|
|
|
365
366
|
legLive = false;
|
|
366
367
|
if (fleetPublisher) {
|
|
367
368
|
if (reached?.kind === "done")
|
|
368
|
-
fleetPublisher.onTerminal(reached.result.errorCode === "cancelled" ? "cancelled" : reached.result.status);
|
|
369
|
+
fleetPublisher.onTerminal(reached.result.errorCode === "cancelled" ? "cancelled" : reached.result.status, fleetRunResiduals(reached.result));
|
|
369
370
|
else if (reached?.kind === "suspended")
|
|
370
371
|
fleetPublisher.onTerminal("suspended");
|
|
371
372
|
else if (reached?.kind === "needs_review")
|
|
372
373
|
fleetPublisher.onTerminal("needs_review");
|
|
373
374
|
else
|
|
374
|
-
fleetPublisher.onTerminal(cancelCtrl.signal.aborted ? "cancelled" : "failed"
|
|
375
|
+
fleetPublisher.onTerminal(cancelCtrl.signal.aborted ? "cancelled" : "failed", {
|
|
376
|
+
...(cancelCtrl.signal.aborted ? { stoppedBy: "user" } : {}),
|
|
377
|
+
...(spec.sessionId ? { transcriptId: spec.sessionId } : {}),
|
|
378
|
+
});
|
|
375
379
|
}
|
|
376
380
|
if (inflight?.get(taskId) === cancelCtrl)
|
|
377
381
|
inflight.delete(taskId);
|
|
@@ -2,7 +2,7 @@ import type { TaskNotificationPayload, BackgroundChildEvent, RosterEntry, AskReq
|
|
|
2
2
|
type AssertAllKeysHandled<T extends never> = T;
|
|
3
3
|
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable";
|
|
4
4
|
type _GuardNotification = AssertAllKeysHandled<Exclude<keyof TaskNotificationPayload, NotificationProjected>>;
|
|
5
|
-
type BgNotifProjected = "taskId" | "sessionId" | "seq" | "status" | "summary" | "stoppedBy" | "resumable" | "recentSteps" | "editedFiles" | "usage" | "transcriptId" | "rootSessionId" | "parentTaskId";
|
|
5
|
+
type BgNotifProjected = "taskId" | "sessionId" | "seq" | "status" | "summary" | "stoppedBy" | "resumable" | "recentSteps" | "editedFiles" | "usage" | "transcriptId" | "rootSessionId" | "parentTaskId" | "parentToolCallId";
|
|
6
6
|
type BgNotifExcluded = "kind" | "sessionScoped" | "owner" | "scope" | "description" | "agentType" | "name" | "currentAction" | "currentTool" | "parentSessionId" | "startedAt" | "workflowRunId" | "progressTaskId" | "progressParentTaskId";
|
|
7
7
|
type _GuardBgNotif = AssertAllKeysHandled<Exclude<keyof BackgroundChildEvent, BgNotifProjected | BgNotifExcluded>>;
|
|
8
8
|
type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "createdAt";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.291.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",
|