@sema-agent/server 1.246.0 → 1.248.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/main.js CHANGED
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
5
5
  import { join } from "node:path";
6
6
  import { loadRemoteExec } from "@sema-agent/registry-core/node";
7
7
  import { skillContentHash } from "@sema-agent/registry-core";
8
- import { Runner, TtlSessionStore, uuidv7, FileRosterStore, defaultTaskRegistry, combinePolicies, createDurableQuestionPolicy, createAllowDenyPolicy, tightenTaskSpec, isThinkingLevel, QUESTION_AWAITS_RESUME, FileWorkflowRunStore, InMemoryWorkflowRunStore, workflowsCapability, NodeLspManager, createFileWorkflowScriptStore, expandTiers, NodeExecutionEnv, CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, verifyPromptArtifact } from "@sema-agent/core";
8
+ import { Runner, TtlSessionStore, uuidv7, FileRosterStore, FileBackgroundAgentStore, defaultTaskRegistry, combinePolicies, createDurableQuestionPolicy, createAllowDenyPolicy, tightenTaskSpec, isThinkingLevel, QUESTION_AWAITS_RESUME, FileWorkflowRunStore, InMemoryWorkflowRunStore, workflowsCapability, NodeLspManager, createFileWorkflowScriptStore, expandTiers, NodeExecutionEnv, CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, verifyPromptArtifact } from "@sema-agent/core";
9
9
  import { PgMemoryEngineBackend, ensurePgMemoryEngineSchema } from "./plugins/memory-engine-pg.js";
10
10
  import { TiDBMemoryEngineBackend, ensureTiDBMemoryEngineSchema } from "./plugins/memory-engine-tidb.js";
11
11
  import { PgMemoryHistoryStore, ensurePgMemoryHistorySchema, PgMemorySyncStore, ensurePgMemorySyncSchema } from "./plugins/memory-sync-store-pg.js";
@@ -78,6 +78,7 @@ import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "./conf
78
78
  import { validatePromptsDomain, centerPromptProvider, centerIdentityAssembled, applyCatalogToSource, CORE_ENGINE_VERSION, withPromptArtifactBackfill } from "./capabilities/center-prompts.js";
79
79
  import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "./config-lkg.js";
80
80
  import { TiDBRosterStore, PgRosterStore, ensureTiDBRosterSchema, ensurePgRosterSchema } from "./plugins/roster-store-sql.js";
81
+ import { TiDBBackgroundAgentStore, PgBackgroundAgentStore, ensureTiDBBackgroundAgentSchema, ensurePgBackgroundAgentSchema } from "./plugins/background-agent-store-sql.js";
81
82
  import { createPrincipalCapsClient, gateExecutionLane, scopedTokenNeedsWorker, applyObserverEnvOptIn } from "./runtime-caps-resolver.js";
82
83
  import { applyRuntimeGovernance, stripDelegationTools } from "./runtime-governance.js";
83
84
  import { parseTaskSettings, applyTaskSettings, coercePermissionMode, withPermissionMode, effectiveThinking, acceptAppendSystemPrompt, hasConstitutionAnchors, providerDropsAppend, MAX_SETTINGS_OUTPUT_STYLE_CHARS } from "./task-settings.js";
@@ -514,6 +515,28 @@ async function main() {
514
515
  if (rosterStore)
515
516
  logger.info("roster_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
516
517
  }
518
+ let backgroundAgentStore;
519
+ {
520
+ const mysqlPool = backend?.mysqlPool?.();
521
+ const pgPool = backend?.pgPool?.();
522
+ if (pgPool) {
523
+ const q = async (text, params) => { const r = await pgPool.query(text, params); return { rows: r.rows }; };
524
+ await ensurePgBackgroundAgentSchema(q);
525
+ backgroundAgentStore = new PgBackgroundAgentStore(q);
526
+ }
527
+ else if (mysqlPool) {
528
+ await ensureTiDBBackgroundAgentSchema(mysqlPool);
529
+ backgroundAgentStore = new TiDBBackgroundAgentStore(mysqlPool);
530
+ }
531
+ else if (backend?.kind === "local") {
532
+ backgroundAgentStore = new FileBackgroundAgentStore(config.localDataRoot ?? localRoot);
533
+ if (config.requirePrincipal === true) {
534
+ logger.warn("background_agent_store_local_multitenant", { note: "file-store reap only sweeps scope 'default'; principal-scoped durable rows are never reaped on the local backend (scope enumeration = core ask)" });
535
+ }
536
+ }
537
+ if (backgroundAgentStore)
538
+ logger.info("background_agent_store_enabled", { backend: pgPool ? "pg" : mysqlPool ? "tidb" : "file" });
539
+ }
517
540
  const memoryExportBackend = config.memoryEngineBackend !== "file" ? memoryEngine?.backend : undefined;
518
541
  const memoryLane = memoryEngineRemoteLanePosture(config);
519
542
  if (config.memoryEngineBackend === "file" || !config.memoryEngineEnabled) {
@@ -910,6 +933,7 @@ async function main() {
910
933
  const runnerDeps = {
911
934
  promptSource,
912
935
  ...(rosterStore ? { rosterStore } : {}),
936
+ ...(backgroundAgentStore ? { backgroundAgentStore } : {}),
913
937
  brain,
914
938
  models: config.models,
915
939
  roles: config.roles,
@@ -1098,7 +1122,7 @@ async function main() {
1098
1122
  if (sessionTitler)
1099
1123
  logger.info("session_auto_title_enabled", {});
1100
1124
  const workflowsCapable = workflowsCapability(runnerDeps);
1101
- const subRunner = new Runner({ brain, models: config.models, roles: config.roles, pricing, tracer, promptSource, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}) });
1125
+ const subRunner = new Runner({ brain, models: config.models, roles: config.roles, pricing, tracer, promptSource, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}), ...(backgroundAgentStore ? { backgroundAgentStore } : {}) });
1102
1126
  const authorize = createAuthorizer(config, sessionStore);
1103
1127
  const runStore = backend ? backend.run() : undefined;
1104
1128
  const resumeAnchorStore = backend ? backend.resumeAnchor() : undefined;
@@ -1198,6 +1222,7 @@ async function main() {
1198
1222
  const scenarioDeps = {
1199
1223
  runner, subRunner, model: "default", skills, repoClient, requirePrincipal: config.requirePrincipal,
1200
1224
  ...(webSearch ? { webSearch } : {}), metrics, logger,
1225
+ ...(backgroundAgentStore ? { backgroundAgentStore } : {}),
1201
1226
  oaApiBaseUrl: config.oaApiBaseUrl, oaServiceToken: config.oaServiceToken, oaIssue: config.oaIssue,
1202
1227
  brandIdentity: config.configProvider === "local",
1203
1228
  ...(sendUserFileToolSpec
@@ -1228,6 +1253,27 @@ async function main() {
1228
1253
  }
1229
1254
  };
1230
1255
  let wfRunReapInFlight = false;
1256
+ let bgAgentReapInFlight = false;
1257
+ const reapBgAgents = backgroundAgentStore
1258
+ ? async () => {
1259
+ const store = backgroundAgentStore;
1260
+ const scopes = await (store.listReapScopes?.() ?? Promise.resolve(["default"]));
1261
+ let rows = 0, sessions = 0, skipped = 0;
1262
+ for (const scope of scopes) {
1263
+ const r = await defaultTaskRegistry.reapDurableAgents(scope, { store, sessions: subRunner.sessions }, {
1264
+ maxAgeMs: config.backgroundAgentRetentionMs,
1265
+ staleRunningMaxAgeMs: config.backgroundAgentStaleRunningMs,
1266
+ });
1267
+ rows += r.rowsReaped;
1268
+ sessions += r.sessionsReleased;
1269
+ skipped += r.skippedNoSessions;
1270
+ }
1271
+ if (rows > 0 || sessions > 0) {
1272
+ metrics.inc("bg_agents_reaped_total", {}, rows);
1273
+ logger.info("reaper_swept", { metric: "bg_agents_reaped_total", count: rows, sessionsReleased: sessions, skippedNoSessions: skipped });
1274
+ }
1275
+ }
1276
+ : undefined;
1231
1277
  const probeClockSkew = async () => {
1232
1278
  try {
1233
1279
  const dbMs = await backend?.dbNowMs?.();
@@ -1273,6 +1319,10 @@ async function main() {
1273
1319
  ?.reapAcked?.(Date.now() - config.workflowRunRetentionMs)
1274
1320
  .catch(() => undefined);
1275
1321
  }
1322
+ if (reapBgAgents && !bgAgentReapInFlight) {
1323
+ bgAgentReapInFlight = true;
1324
+ void reapBgAgents().catch(() => undefined).finally(() => (bgAgentReapInFlight = false));
1325
+ }
1276
1326
  if (config.scratchpadSweepTtlMs > 0) {
1277
1327
  void sweepStaleScratchpads(config.localDataRoot ?? localRoot, { olderThanMs: config.scratchpadSweepTtlMs })
1278
1328
  .then((removed) => {