@sema-agent/server 1.304.0 → 1.306.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/config.d.ts +7 -0
- package/dist/config.js +7 -0
- package/dist/http/server.js +4 -2
- package/dist/http/tar.js +4 -0
- package/dist/main.js +10 -2
- package/dist/plugins/blob-backend.js +22 -9
- package/dist/plugins/task-attachment-store.js +26 -14
- package/dist/trace/project.js +3 -3
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -164,6 +164,7 @@ export interface ServiceConfig {
|
|
|
164
164
|
};
|
|
165
165
|
snapshotBlobSqlMaxBytes?: number;
|
|
166
166
|
snapshotBlobAllowSql: boolean;
|
|
167
|
+
bindHost?: string;
|
|
167
168
|
attachmentOrphanGraceMs: number;
|
|
168
169
|
workspaceFileMaxBytes: number;
|
|
169
170
|
sendUserFile?: {
|
|
@@ -315,4 +316,10 @@ export declare function logConfigDiagnostics(logger: {
|
|
|
315
316
|
}): void;
|
|
316
317
|
export declare function applyAutoCompactWindow(m: Model, explicit?: number): void;
|
|
317
318
|
export declare function loadConfig(): ServiceConfig;
|
|
319
|
+
export declare function resolveBindHost(config: {
|
|
320
|
+
bindHost?: string;
|
|
321
|
+
allowUnauthedWrites?: boolean;
|
|
322
|
+
authToken?: string;
|
|
323
|
+
authTokens?: Record<string, string>;
|
|
324
|
+
}): string | undefined;
|
|
318
325
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -538,6 +538,7 @@ export function loadConfig() {
|
|
|
538
538
|
: undefined,
|
|
539
539
|
snapshotBlobSqlMaxBytes: optFinitePositiveEnv("SNAPSHOT_BLOB_SQL_MAX_BYTES"),
|
|
540
540
|
snapshotBlobAllowSql: process.env.SNAPSHOT_BLOB_ALLOW_SQL_BYTES === "true",
|
|
541
|
+
bindHost: process.env.BIND_HOST || process.env.HOST || undefined,
|
|
541
542
|
attachmentOrphanGraceMs: ((v) => (v !== undefined && Number.isFinite(v) && v >= 0 ? v : 3_600_000))(process.env.ATTACHMENT_ORPHAN_GRACE_MS !== undefined ? Number(process.env.ATTACHMENT_ORPHAN_GRACE_MS) : undefined),
|
|
542
543
|
workspaceFileMaxBytes: optFinitePositiveEnv("WORKSPACE_FILE_MAX_BYTES") ?? 8 * 1024 * 1024,
|
|
543
544
|
sendUserFile: (process.env.MINIO_ENDPOINT || process.env.S3_ENDPOINT) && process.env.MINIO_ACCESS_KEY && process.env.MINIO_SECRET_KEY
|
|
@@ -727,4 +728,10 @@ export function loadConfig() {
|
|
|
727
728
|
configLocalDir: process.env.CONFIG_LOCAL_DIR || undefined,
|
|
728
729
|
};
|
|
729
730
|
}
|
|
731
|
+
export function resolveBindHost(config) {
|
|
732
|
+
if (config.bindHost)
|
|
733
|
+
return config.bindHost;
|
|
734
|
+
const anyServiceAuth = Boolean(config.authToken) || Object.keys(config.authTokens ?? {}).length > 0;
|
|
735
|
+
return config.allowUnauthedWrites && !anyServiceAuth ? "127.0.0.1" : undefined;
|
|
736
|
+
}
|
|
730
737
|
//# sourceMappingURL=config.js.map
|
package/dist/http/server.js
CHANGED
|
@@ -4263,7 +4263,7 @@ export function createHttpServer(deps) {
|
|
|
4263
4263
|
sendJson(res, 413, {
|
|
4264
4264
|
code: "blob_too_large_for_sql",
|
|
4265
4265
|
errorCode: "blob_too_large_for_sql",
|
|
4266
|
-
error: `blob of ${body.byteLength} bytes exceeds this deployment's SQL snapshot-blob cap (${deps.snapshotBlobSqlCapBytes} bytes; mysql-protocol packet limit) — configure MinIO object storage (MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY) for large snapshot blobs`,
|
|
4266
|
+
error: `blob of ${body.byteLength} bytes exceeds this deployment's SQL snapshot-blob cap (${deps.snapshotBlobSqlCapBytes} bytes — TiDB's txn-entry-size-limit is the low wall at 6MiB by default; the mysql-protocol packet limit sits above it) — configure MinIO object storage (MINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEY) for large snapshot blobs, or raise SNAPSHOT_BLOB_SQL_MAX_BYTES if your deployment lifted those limits`,
|
|
4267
4267
|
});
|
|
4268
4268
|
return;
|
|
4269
4269
|
}
|
|
@@ -6821,7 +6821,9 @@ function routeLabel(_method, url) {
|
|
|
6821
6821
|
return "other";
|
|
6822
6822
|
}
|
|
6823
6823
|
function workspaceContentType(relPath) {
|
|
6824
|
-
const
|
|
6824
|
+
const base = relPath.slice(relPath.lastIndexOf("/") + 1);
|
|
6825
|
+
const dot = base.lastIndexOf(".");
|
|
6826
|
+
const ext = dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
|
|
6825
6827
|
const TABLE = {
|
|
6826
6828
|
txt: "text/plain; charset=utf-8", md: "text/plain; charset=utf-8", log: "text/plain; charset=utf-8",
|
|
6827
6829
|
json: "application/json; charset=utf-8", csv: "text/csv; charset=utf-8",
|
package/dist/http/tar.js
CHANGED
|
@@ -19,7 +19,11 @@ export function splitTarPath(relPath) {
|
|
|
19
19
|
}
|
|
20
20
|
return null;
|
|
21
21
|
}
|
|
22
|
+
const USTAR_MAX_SIZE = 8 * 1024 * 1024 * 1024 - 1;
|
|
22
23
|
export function tarHeader(relPath, sizeBytes, mtimeSec) {
|
|
24
|
+
if (!Number.isFinite(sizeBytes) || sizeBytes < 0 || sizeBytes > USTAR_MAX_SIZE) {
|
|
25
|
+
throw new Error(`tar: size ${sizeBytes} not representable in a ustar header (12-octal-byte field, max 8GiB-1): ${relPath}`);
|
|
26
|
+
}
|
|
23
27
|
const split = splitTarPath(relPath);
|
|
24
28
|
if (split === null)
|
|
25
29
|
throw new Error(`tar: path not representable in ustar (must be ≤255 bytes and splittable at "/"): ${relPath}`);
|
package/dist/main.js
CHANGED
|
@@ -24,7 +24,7 @@ import { stat as fsStat, readFile as fsReadFile } from "node:fs/promises";
|
|
|
24
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
|
-
import { loadConfig, logConfigDiagnostics } from "./config.js";
|
|
27
|
+
import { loadConfig, logConfigDiagnostics, resolveBindHost } from "./config.js";
|
|
28
28
|
import { resourceSuspendOptIn } from "./resource-suspend.js";
|
|
29
29
|
import { createSessionStore, ensureChildSessionDurableWithPromotion } from "./plugins/session-store.js";
|
|
30
30
|
import { ForkRoutingSessionStore } from "./plugins/fork-routing-session-store.js";
|
|
@@ -2340,7 +2340,15 @@ async function main() {
|
|
|
2340
2340
|
},
|
|
2341
2341
|
});
|
|
2342
2342
|
runDenySweep = server.denyExpiredApprovals;
|
|
2343
|
-
|
|
2343
|
+
const bindHost = resolveBindHost(config);
|
|
2344
|
+
await new Promise((resolve) => (bindHost ? server.listen(config.port, bindHost, resolve) : server.listen(config.port, resolve)));
|
|
2345
|
+
logger.info("listening", {
|
|
2346
|
+
port: config.port,
|
|
2347
|
+
bindHost: bindHost ?? "0.0.0.0/::(all interfaces)",
|
|
2348
|
+
...(bindHost === "127.0.0.1" && !config.bindHost
|
|
2349
|
+
? { note: "auto-narrowed to loopback: write face is unauthenticated (ALLOW_UNAUTHED_WRITES with no service token). Set BIND_HOST explicitly to override." }
|
|
2350
|
+
: {}),
|
|
2351
|
+
});
|
|
2344
2352
|
const fleetClient = startFleetClientFromEnv(config, {
|
|
2345
2353
|
instanceId,
|
|
2346
2354
|
version: serviceVersion(),
|
|
@@ -75,14 +75,24 @@ export async function sqlBlobSizes(dialect, pool, hashes) {
|
|
|
75
75
|
if (hashes.length === 0)
|
|
76
76
|
return new Map();
|
|
77
77
|
const distinct = [...new Set(hashes)];
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
const CHUNK = 1000;
|
|
79
|
+
const out = new Map();
|
|
80
|
+
for (let i = 0; i < distinct.length; i += CHUNK) {
|
|
81
|
+
const part = distinct.slice(i, i + CHUNK);
|
|
82
|
+
if (dialect === "tidb") {
|
|
83
|
+
const ph = part.map(() => "?").join(",");
|
|
84
|
+
const [rows] = await pool.query(`SELECT blob_hash, byte_len FROM snapshot_blob WHERE blob_hash IN (${ph})`, part);
|
|
85
|
+
for (const r of rows)
|
|
86
|
+
out.set(String(r.blob_hash), Number(r.byte_len));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const ph = part.map((_, j) => `$${j + 1}`).join(",");
|
|
90
|
+
const r = await pool.query(`SELECT blob_hash, byte_len FROM snapshot_blob WHERE blob_hash IN (${ph})`, part);
|
|
91
|
+
for (const row of r.rows)
|
|
92
|
+
out.set(row.blob_hash, Number(row.byte_len));
|
|
93
|
+
}
|
|
82
94
|
}
|
|
83
|
-
|
|
84
|
-
const r = await pool.query(`SELECT blob_hash, byte_len FROM snapshot_blob WHERE blob_hash IN (${ph})`, distinct);
|
|
85
|
-
return new Map(r.rows.map((row) => [row.blob_hash, Number(row.byte_len)]));
|
|
95
|
+
return out;
|
|
86
96
|
}
|
|
87
97
|
async function sqlDeleteIndexRowsPastGrace(dialect, pool, hashes) {
|
|
88
98
|
if (hashes.length === 0)
|
|
@@ -250,14 +260,17 @@ export class MinioBlobBackend {
|
|
|
250
260
|
}
|
|
251
261
|
if (toDelete.length === 0)
|
|
252
262
|
return 0;
|
|
263
|
+
let okCount = 0;
|
|
253
264
|
await mapBounded(toDelete, MINIO_OP_CONCURRENCY, async (hash) => {
|
|
254
265
|
try {
|
|
255
|
-
await fetch(this.presign(hash, "DELETE"), { method: "DELETE" });
|
|
266
|
+
const res = await (this.cfg.fetchImpl ?? fetch)(this.presign(hash, "DELETE"), { method: "DELETE" });
|
|
267
|
+
if (res.ok || res.status === 404)
|
|
268
|
+
okCount++;
|
|
256
269
|
}
|
|
257
270
|
catch {
|
|
258
271
|
}
|
|
259
272
|
});
|
|
260
|
-
return
|
|
273
|
+
return okCount;
|
|
261
274
|
}
|
|
262
275
|
}
|
|
263
276
|
//# sourceMappingURL=blob-backend.js.map
|
|
@@ -163,20 +163,26 @@ export class TiDBTaskAttachmentStore {
|
|
|
163
163
|
const lister = this.bytes;
|
|
164
164
|
if (typeof lister.listObjects !== "function")
|
|
165
165
|
return 0;
|
|
166
|
-
const candidates = [];
|
|
167
|
-
for await (const o of lister.listObjects()) {
|
|
168
|
-
if (nowMs - o.lastModifiedMs >= graceMs)
|
|
169
|
-
candidates.push(o.hash);
|
|
170
|
-
}
|
|
171
166
|
let removed = 0;
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
let batch = [];
|
|
168
|
+
const flush = async () => {
|
|
169
|
+
if (batch.length === 0)
|
|
170
|
+
return;
|
|
174
171
|
const referenced = await this.referencedShas(batch);
|
|
175
172
|
const orphans = batch.filter((h) => !referenced.has(h));
|
|
176
173
|
const safe = await this.filterStillOrphan(orphans, graceMs, nowMs);
|
|
177
174
|
if (safe.length > 0)
|
|
178
175
|
removed += await this.bytes.deleteBlobs(safe);
|
|
176
|
+
batch = [];
|
|
177
|
+
};
|
|
178
|
+
for await (const o of lister.listObjects()) {
|
|
179
|
+
if (nowMs - o.lastModifiedMs < graceMs)
|
|
180
|
+
continue;
|
|
181
|
+
batch.push(o.hash);
|
|
182
|
+
if (batch.length >= 200)
|
|
183
|
+
await flush();
|
|
179
184
|
}
|
|
185
|
+
await flush();
|
|
180
186
|
return removed;
|
|
181
187
|
}
|
|
182
188
|
async referencedShas(shas) {
|
|
@@ -269,20 +275,26 @@ export class PgTaskAttachmentStore {
|
|
|
269
275
|
const lister = this.bytes;
|
|
270
276
|
if (typeof lister.listObjects !== "function")
|
|
271
277
|
return 0;
|
|
272
|
-
const candidates = [];
|
|
273
|
-
for await (const o of lister.listObjects()) {
|
|
274
|
-
if (nowMs - o.lastModifiedMs >= graceMs)
|
|
275
|
-
candidates.push(o.hash);
|
|
276
|
-
}
|
|
277
278
|
let removed = 0;
|
|
278
|
-
|
|
279
|
-
|
|
279
|
+
let batch = [];
|
|
280
|
+
const flush = async () => {
|
|
281
|
+
if (batch.length === 0)
|
|
282
|
+
return;
|
|
280
283
|
const referenced = await this.referencedShas(batch);
|
|
281
284
|
const orphans = batch.filter((h) => !referenced.has(h));
|
|
282
285
|
const safe = await this.filterStillOrphan(orphans, graceMs, nowMs);
|
|
283
286
|
if (safe.length > 0)
|
|
284
287
|
removed += await this.bytes.deleteBlobs(safe);
|
|
288
|
+
batch = [];
|
|
289
|
+
};
|
|
290
|
+
for await (const o of lister.listObjects()) {
|
|
291
|
+
if (nowMs - o.lastModifiedMs < graceMs)
|
|
292
|
+
continue;
|
|
293
|
+
batch.push(o.hash);
|
|
294
|
+
if (batch.length >= 200)
|
|
295
|
+
await flush();
|
|
285
296
|
}
|
|
297
|
+
await flush();
|
|
286
298
|
return removed;
|
|
287
299
|
}
|
|
288
300
|
async referencedShas(shas) {
|
package/dist/trace/project.js
CHANGED
|
@@ -62,7 +62,7 @@ export function toolEndEventData(ev) {
|
|
|
62
62
|
isError: ev.isError,
|
|
63
63
|
...(ev.output !== undefined ? { output: redactDeep(ev.output) } : {}),
|
|
64
64
|
...(ev.truncated ? { truncated: true } : {}),
|
|
65
|
-
...(
|
|
65
|
+
...(Number.isFinite(ev.totalChars) ? { totalChars: ev.totalChars } : {}),
|
|
66
66
|
...(ev.structured !== undefined ? { structured: redactDeep(ev.structured) } : {}),
|
|
67
67
|
...identityFields(ev),
|
|
68
68
|
};
|
|
@@ -241,7 +241,7 @@ export function projectEvents(events, opts = {}) {
|
|
|
241
241
|
break;
|
|
242
242
|
case "tool_end": {
|
|
243
243
|
const callId = String(d.toolCallId ?? "");
|
|
244
|
-
blocks.push({ type: "tool-result", callId, ...(typeof d.label === "string" ? { label: d.label } : {}), output: d.output, ...(d.isError ? { isError: true } : {}), ...(d.truncated ? { truncated: true } : {}), ...(
|
|
244
|
+
blocks.push({ type: "tool-result", callId, ...(typeof d.label === "string" ? { label: d.label } : {}), output: d.output, ...(d.isError ? { isError: true } : {}), ...(d.truncated ? { truncated: true } : {}), ...(Number.isFinite(d.totalChars) ? { totalChars: d.totalChars } : {}), ...(d.structured !== undefined ? { structured: d.structured } : {}), ...identityFields(d) });
|
|
245
245
|
break;
|
|
246
246
|
}
|
|
247
247
|
case "prompt_assembled":
|
|
@@ -307,7 +307,7 @@ export function mapTraceEvent(type, seq, data) {
|
|
|
307
307
|
case "tool_start":
|
|
308
308
|
return { event: "tool-call", data: { seq, id: data.toolCallId, name: data.toolName, ...(typeof data.label === "string" ? { label: data.label } : {}), input: data.args, ...identityFields(data) } };
|
|
309
309
|
case "tool_end":
|
|
310
|
-
return { event: "tool-result", data: { seq, callId: data.toolCallId, ...(typeof data.label === "string" ? { label: data.label } : {}), isError: Boolean(data.isError), ...(data.output !== undefined ? { output: data.output } : {}), ...(data.truncated ? { truncated: true } : {}), ...(
|
|
310
|
+
return { event: "tool-result", data: { seq, callId: data.toolCallId, ...(typeof data.label === "string" ? { label: data.label } : {}), isError: Boolean(data.isError), ...(data.output !== undefined ? { output: data.output } : {}), ...(data.truncated ? { truncated: true } : {}), ...(Number.isFinite(data.totalChars) ? { totalChars: data.totalChars } : {}), ...(data.structured !== undefined ? { structured: data.structured } : {}), ...identityFields(data) } };
|
|
311
311
|
case "turn_end": {
|
|
312
312
|
const tokens = toContractTokens(data.usage);
|
|
313
313
|
return { event: "turn", data: { seq, ...(tokens ? { tokens } : {}) } };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.306.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",
|