@sema-agent/server 1.247.0 → 1.249.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,
@@ -973,6 +997,7 @@ async function main() {
973
997
  workflowScriptStore: (() => {
974
998
  const fileStore = createFileWorkflowScriptStore(join(config.localDataRoot ?? localRoot, "workflow-scripts"));
975
999
  return {
1000
+ scopePartitioned: true,
976
1001
  persist: fileStore.persist.bind(fileStore),
977
1002
  load: fileStore.load.bind(fileStore),
978
1003
  resolveName: (name) => resolveCollabWorkflow(name) ?? fileStore.resolveName?.(name),
@@ -1098,7 +1123,7 @@ async function main() {
1098
1123
  if (sessionTitler)
1099
1124
  logger.info("session_auto_title_enabled", {});
1100
1125
  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 } : {}) });
1126
+ 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
1127
  const authorize = createAuthorizer(config, sessionStore);
1103
1128
  const runStore = backend ? backend.run() : undefined;
1104
1129
  const resumeAnchorStore = backend ? backend.resumeAnchor() : undefined;
@@ -1198,6 +1223,7 @@ async function main() {
1198
1223
  const scenarioDeps = {
1199
1224
  runner, subRunner, model: "default", skills, repoClient, requirePrincipal: config.requirePrincipal,
1200
1225
  ...(webSearch ? { webSearch } : {}), metrics, logger,
1226
+ ...(backgroundAgentStore ? { backgroundAgentStore } : {}),
1201
1227
  oaApiBaseUrl: config.oaApiBaseUrl, oaServiceToken: config.oaServiceToken, oaIssue: config.oaIssue,
1202
1228
  brandIdentity: config.configProvider === "local",
1203
1229
  ...(sendUserFileToolSpec
@@ -1228,6 +1254,27 @@ async function main() {
1228
1254
  }
1229
1255
  };
1230
1256
  let wfRunReapInFlight = false;
1257
+ let bgAgentReapInFlight = false;
1258
+ const reapBgAgents = backgroundAgentStore
1259
+ ? async () => {
1260
+ const store = backgroundAgentStore;
1261
+ const scopes = await (store.listReapScopes?.() ?? Promise.resolve(["default"]));
1262
+ let rows = 0, sessions = 0, skipped = 0;
1263
+ for (const scope of scopes) {
1264
+ const r = await defaultTaskRegistry.reapDurableAgents(scope, { store, sessions: subRunner.sessions }, {
1265
+ maxAgeMs: config.backgroundAgentRetentionMs,
1266
+ staleRunningMaxAgeMs: config.backgroundAgentStaleRunningMs,
1267
+ });
1268
+ rows += r.rowsReaped;
1269
+ sessions += r.sessionsReleased;
1270
+ skipped += r.skippedNoSessions;
1271
+ }
1272
+ if (rows > 0 || sessions > 0) {
1273
+ metrics.inc("bg_agents_reaped_total", {}, rows);
1274
+ logger.info("reaper_swept", { metric: "bg_agents_reaped_total", count: rows, sessionsReleased: sessions, skippedNoSessions: skipped });
1275
+ }
1276
+ }
1277
+ : undefined;
1231
1278
  const probeClockSkew = async () => {
1232
1279
  try {
1233
1280
  const dbMs = await backend?.dbNowMs?.();
@@ -1273,6 +1320,10 @@ async function main() {
1273
1320
  ?.reapAcked?.(Date.now() - config.workflowRunRetentionMs)
1274
1321
  .catch(() => undefined);
1275
1322
  }
1323
+ if (reapBgAgents && !bgAgentReapInFlight) {
1324
+ bgAgentReapInFlight = true;
1325
+ void reapBgAgents().catch(() => undefined).finally(() => (bgAgentReapInFlight = false));
1326
+ }
1276
1327
  if (config.scratchpadSweepTtlMs > 0) {
1277
1328
  void sweepStaleScratchpads(config.localDataRoot ?? localRoot, { olderThanMs: config.scratchpadSweepTtlMs })
1278
1329
  .then((removed) => {