@sema-agent/server 1.305.0 → 1.307.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/README.md CHANGED
@@ -130,6 +130,7 @@ The server is configured entirely through environment variables. The most import
130
130
  | Variable | Default | What it does |
131
131
  |----------|---------|--------------|
132
132
  | `PORT` | `8090` | HTTP listen port |
133
+ | `BIND_HOST` (alias `HOST`) | see note | Listen address. An explicit value **always wins**. Default: `127.0.0.1` when the write face is unauthenticated (`ALLOW_UNAUTHED_WRITES=true` **and** no service token configured), otherwise all interfaces — deployments with a token are unaffected. |
133
134
  | `MODEL_GATEWAY_BASEURL` | `http://127.0.0.1:8000/v1` | OpenAI-compatible gateway base URL (without `/chat/completions`) |
134
135
  | `MODEL_ID` | `Qwen3.5-35B` | Default model id |
135
136
  | `MODEL_API_KEY` | — | Gateway API key (optional) |
package/README.zh-CN.md CHANGED
@@ -123,6 +123,7 @@ curl -s localhost:8090/v1/tasks -H "Authorization: Bearer <SERVICE_AUTH_TOKEN>"
123
123
  | 变量 | 默认 | 说明 |
124
124
  |------|------|------|
125
125
  | `PORT` | `8090` | HTTP 监听端口 |
126
+ | `BIND_HOST`(兼容 `HOST`) | 见说明 | 监听地址。显式值**恒生效**。缺省:写面无鉴权时(`ALLOW_UNAUTHED_WRITES=true` **且**未配任何 service token)= `127.0.0.1`,否则全接口——配了 token 的部署不受影响。 |
126
127
  | `MODEL_GATEWAY_BASEURL` | `http://127.0.0.1:8000/v1` | OpenAI 兼容网关地址(不带 `/chat/completions`) |
127
128
  | `MODEL_ID` | `Qwen3.5-35B` | 缺省模型 id |
128
129
  | `MODEL_API_KEY` | — | 网关 key(可选) |
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/main.js CHANGED
@@ -24,11 +24,11 @@ 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";
31
- import { createStoreBackend, assertCloudSnapshotBlobPosture } from "./plugins/store-backend.js";
31
+ import { createStoreBackend, openStoreBackendWithFallback, assertCloudSnapshotBlobPosture } from "./plugins/store-backend.js";
32
32
  import { e2bExecutionEnvFactory } from "./plugins/remote-env-e2b.js";
33
33
  import { k8sExecutionEnvFactory } from "./plugins/remote-env-k8s.js";
34
34
  import { sshExecutionEnvFactory } from "./plugins/remote-env-ssh.js";
@@ -428,22 +428,9 @@ async function main() {
428
428
  config.dbBackend === "local" ||
429
429
  (config.sessionBackend === "auto" && !!(config.tidb || config.pg));
430
430
  if (wantDb) {
431
- backend = createStoreBackend(config);
432
- if (backend) {
433
- try {
434
- await backend.ensureSchema();
435
- }
436
- catch (err) {
437
- if (config.sessionBackend === "auto" || (config.dbBackend === "local" && !config.dbBackendExplicit)) {
438
- logger.warn("store_db_unreachable_fallback_memory", { backend: backend.kind, error: err instanceof Error ? err.message : String(err) });
439
- storeBackendDegraded = true;
440
- await backend.close().catch(() => undefined);
441
- backend = undefined;
442
- }
443
- else
444
- throw err;
445
- }
446
- }
431
+ const opened = await openStoreBackendWithFallback(config, logger);
432
+ backend = opened.backend;
433
+ storeBackendDegraded = opened.degraded;
447
434
  }
448
435
  metrics.setGauge("store_backend_degraded", storeBackendDegraded ? 1 : 0);
449
436
  {
@@ -2340,7 +2327,15 @@ async function main() {
2340
2327
  },
2341
2328
  });
2342
2329
  runDenySweep = server.denyExpiredApprovals;
2343
- await new Promise((resolve) => server.listen(config.port, resolve));
2330
+ const bindHost = resolveBindHost(config);
2331
+ await new Promise((resolve) => (bindHost ? server.listen(config.port, bindHost, resolve) : server.listen(config.port, resolve)));
2332
+ logger.info("listening", {
2333
+ port: config.port,
2334
+ bindHost: bindHost ?? "0.0.0.0/::(all interfaces)",
2335
+ ...(bindHost === "127.0.0.1" && !config.bindHost
2336
+ ? { note: "auto-narrowed to loopback: write face is unauthenticated (ALLOW_UNAUTHED_WRITES with no service token). Set BIND_HOST explicitly to override." }
2337
+ : {}),
2338
+ });
2344
2339
  const fleetClient = startFleetClientFromEnv(config, {
2345
2340
  instanceId,
2346
2341
  version: serviceVersion(),
@@ -96,4 +96,10 @@ export interface StoreBackend {
96
96
  export declare function assertCloudSnapshotBlobPosture(kind: "mysql" | "pg" | "local", config: Pick<ServiceConfig, "snapshotBlobStore" | "snapshotBlobAllowSql">): void;
97
97
  export declare function snapshotBoundsFromConfig(config: ServiceConfig): FileSnapshotBounds;
98
98
  export declare function createStoreBackend(config: ServiceConfig): StoreBackend | undefined;
99
+ export declare function openStoreBackendWithFallback(config: ServiceConfig, logger: {
100
+ warn: (msg: string, meta?: Record<string, unknown>) => void;
101
+ }): Promise<{
102
+ backend: StoreBackend | undefined;
103
+ degraded: boolean;
104
+ }>;
99
105
  //# sourceMappingURL=store-backend.d.ts.map
@@ -217,4 +217,24 @@ export function createStoreBackend(config) {
217
217
  return undefined;
218
218
  return new TiDBBackend(createTidbPool(config), config);
219
219
  }
220
+ export async function openStoreBackendWithFallback(config, logger) {
221
+ const mayFallback = config.dbBackend === "local" ? !config.dbBackendExplicit : config.sessionBackend === "auto";
222
+ let backend;
223
+ try {
224
+ backend = createStoreBackend(config);
225
+ if (backend)
226
+ await backend.ensureSchema();
227
+ }
228
+ catch (err) {
229
+ if (!mayFallback)
230
+ throw err;
231
+ logger.warn("store_db_unreachable_fallback_memory", {
232
+ backend: backend?.kind ?? config.dbBackend,
233
+ error: err instanceof Error ? err.message : String(err),
234
+ });
235
+ await backend?.close().catch(() => undefined);
236
+ return { backend: undefined, degraded: true };
237
+ }
238
+ return { backend, degraded: false };
239
+ }
220
240
  //# sourceMappingURL=store-backend.js.map
@@ -3,6 +3,7 @@ export interface ToolApprovalFrame {
3
3
  type: "tool_approval" | "tool_approval_complete";
4
4
  approvalId: string;
5
5
  toolName?: string;
6
+ toolCallId?: string;
6
7
  sourceTaskId?: string;
7
8
  fromSubagent?: true;
8
9
  sourceAgentName?: string;
@@ -160,6 +160,7 @@ export class ToolApprovalCoordinator {
160
160
  type: "tool_approval",
161
161
  approvalId: id,
162
162
  toolName: req.toolName,
163
+ ...(typeof req.toolCallId === "string" && req.toolCallId !== "" ? { toolCallId: req.toolCallId } : {}),
163
164
  ...(child
164
165
  ? {
165
166
  sourceTaskId: req.sourceTaskId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "1.305.0",
3
+ "version": "1.307.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",