@sema-agent/server 5.5.0 → 5.6.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.
@@ -163,7 +163,16 @@ export function createExecutionEnv(ctx) {
163
163
  // [1009]② host-signal: the spawning shell knows whether a resident daemon will honor session
164
164
  // wakeups — SCHEDULER_SESSION_WAKEUP=false flips the capability off at CONSTRUCTION (instance-
165
165
  // lifetime snapshot, core TOCTOU 契约) so core's ScheduleWakeup refuses up front.
166
- ...(config.schedulerSessionWakeup === false ? { caps: { supportsSessionWakeup: false } } : {}),
166
+ // [2436] session-lifetime 同族 host-signal(5.6.0):headless(无 daemon 收割)
167
+ // supportsSessionLifetime:false ⇒ CronCreate 前门拒收 + backend 第二道拒落盘,孤儿不产生。
168
+ ...(config.schedulerSessionWakeup === false || config.schedulerSessionLifetime === false
169
+ ? {
170
+ caps: {
171
+ ...(config.schedulerSessionWakeup === false ? { supportsSessionWakeup: false } : {}),
172
+ ...(config.schedulerSessionLifetime === false ? { supportsSessionLifetime: false } : {}),
173
+ },
174
+ }
175
+ : {}),
167
176
  })
168
177
  : undefined;
169
178
  if (hostScheduler)
@@ -615,6 +615,12 @@ export interface ServiceConfigFlat {
615
615
  * of parking a wakeup that would never fire (TB background-reap族 [991]②b). Default ON (the co-resident
616
616
  * TOC daemon does honor its own sessions' wakeups); opt-out only — SCHEDULER_ENABLED 同门. */
617
617
  schedulerSessionWakeup: boolean;
618
+ /** [2425]/[2436] session-lifetime 同族 host-signal(5.6.0):headless 部署(spawn 时已知无常驻 daemon
619
+ * 收割 session-lifetime 记录)设 `SCHEDULER_SESSION_LIFETIME=false` ⇒ capability 面
620
+ * `supportsSessionLifetime:false` ⇒ core 的 CronCreate 前门拒收 durable:false(fail-closed 于工具层),
621
+ * backend.schedule 第二道同拒——session 记录不落盘=孤儿不产生。Default ON(co-resident TOC daemon
622
+ * 真会收割);opt-out only,WAKEUP 同形。 */
623
+ schedulerSessionLifetime: boolean;
618
624
  /** R-survey/EnterPlanMode (core 1.167): MODEL-DRIVEN plan mode. When true, runs start with
619
625
  * `TaskSpec.enablePlanMode:true` but NOT `handsReadOnly` (writable-start) → core auto-mounts `enter_plan_mode`
620
626
  * (+ `present_plan`) so the model can self-call `enter_plan_mode` at ANY time it judges a task needs planning
@@ -879,7 +885,7 @@ export type ServiceMemoryConfig = Pick<ServiceConfigFlat, "memoryEngineEnabled"
879
885
  * 函数不产出它,但它与 `autonomy` 是同一根治理棒的两半,归本组。 */
880
886
  export type ServiceAuthConfig = Pick<ServiceConfigFlat, "authToken" | "authTokens" | "allowUnauthedWrites" | "corsOrigins" | "principalHeader" | "requirePrincipal" | "autonomy" | "commandPolicy" | "operatorPrincipals" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "principalJwtMaxTtlSec" | "bindHost" | "bindHostSource">;
881
887
  /** 组:orchestration(编排 + 执行车道 + 沙箱面 + workflow/后台 agent 存留)。 */
882
- export type ServiceOrchestrationConfig = Pick<ServiceConfigFlat, "remoteExec" | "worktreeIsolation" | "leaderEnabled" | "leaderFanoutEnabled" | "routerEnabled" | "selfOrchestrationEnabled" | "selfOrchestrationModels" | "selfOrchestrationWorkerIsolation" | "forkEnabled" | "experimentalObserverAgents" | "schedulerEnabled" | "schedulerSessionWakeup" | "schedulerStorePath" | "planModeEnabled" | "workflowRunStoreBackend" | "workflowOrphanGraceMs" | "workflowJournalRetentionMs" | "workflowRunRetentionMs" | "workflowAgentsReadOnly" | "workflowSizeGuideline" | "backgroundAgentRetentionMs" | "backgroundAgentStaleRunningMs" | "backgroundAgentParkClaimStaleMs" | "rosterRetentionMs" | "scratchpadSweepTtlMs" | "sandboxPkgSource" | "sessionAutoTitle" | "selectEnvironmentTool" | "envFactsEnabled" | "toolDeferLongtail" | "lspEnabled" | "lspHostEnabled" | "imageBakes">;
888
+ export type ServiceOrchestrationConfig = Pick<ServiceConfigFlat, "remoteExec" | "worktreeIsolation" | "leaderEnabled" | "leaderFanoutEnabled" | "routerEnabled" | "selfOrchestrationEnabled" | "selfOrchestrationModels" | "selfOrchestrationWorkerIsolation" | "forkEnabled" | "experimentalObserverAgents" | "schedulerEnabled" | "schedulerSessionWakeup" | "schedulerSessionLifetime" | "schedulerStorePath" | "planModeEnabled" | "workflowRunStoreBackend" | "workflowOrphanGraceMs" | "workflowJournalRetentionMs" | "workflowRunRetentionMs" | "workflowAgentsReadOnly" | "workflowSizeGuideline" | "backgroundAgentRetentionMs" | "backgroundAgentStaleRunningMs" | "backgroundAgentParkClaimStaleMs" | "rosterRetentionMs" | "scratchpadSweepTtlMs" | "sandboxPkgSource" | "sessionAutoTitle" | "selectEnvironmentTool" | "envFactsEnabled" | "toolDeferLongtail" | "lspEnabled" | "lspHostEnabled" | "imageBakes">;
883
889
  /** 组:limitsHttp(HTTP 面 + 各类上限/配额/回收窗)。 */
884
890
  export type ServiceLimitsHttpConfig = Pick<ServiceConfigFlat, "port" | "attachmentOrphanGraceMs" | "workspaceFileMaxBytes" | "attachmentMaxBytes" | "attachmentMimeAllowlist" | "attachmentUnboundTtlMs" | "infraCostRates" | "drainGraceMs" | "sighupIdleGraceMs" | "rateLimitPerMin" | "maxTaskCostUsd" | "maxTaskTokens" | "maxPrincipalCostUsd" | "costQuotaWindowSec" | "reapIntervalSec" | "runStaleSec" | "toolResultTtlSec">;
885
891
  /** 组:observability(可观测)。 */
package/dist/config.js CHANGED
@@ -1179,6 +1179,7 @@ function parseOrchestrationDomain(ctx) {
1179
1179
  planModeEnabled: boolEnv("PLAN_MODE_ENABLED", true), // EnterPlanMode (core 1.167) model-driven plan; 🆕 default ON (resident — clay), PLAN_MODE_ENABLED=false opts out
1180
1180
  ...(process.env.SCHEDULER_STORE_PATH ? { schedulerStorePath: process.env.SCHEDULER_STORE_PATH } : {}),
1181
1181
  schedulerSessionWakeup: boolEnv("SCHEDULER_SESSION_WAKEUP", true), // [1009]② host-signal: default ON, the spawning shell opts a daemon-less engine out (PLAN_MODE_ENABLED 同形解析)
1182
+ schedulerSessionLifetime: boolEnv("SCHEDULER_SESSION_LIFETIME", true), // [2436] 同族 host-signal(5.6.0):headless=false ⇒ CronCreate 前门拒 session-lifetime,孤儿不落盘
1182
1183
  selfOrchestrationModels: csv("SELF_ORCHESTRATION_MODELS"),
1183
1184
  selfOrchestrationWorkerIsolation: boolEnv("SELF_ORCHESTRATION_WORKER_ISOLATION", false),
1184
1185
  ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}),
@@ -1326,7 +1327,7 @@ const AUTH_GROUP_KEYS = [
1326
1327
  const ORCHESTRATION_GROUP_KEYS = [
1327
1328
  "remoteExec", "worktreeIsolation", "leaderEnabled", "leaderFanoutEnabled", "routerEnabled", "selfOrchestrationEnabled",
1328
1329
  "selfOrchestrationModels", "selfOrchestrationWorkerIsolation", "forkEnabled", "experimentalObserverAgents",
1329
- "schedulerEnabled", "schedulerSessionWakeup", "schedulerStorePath", "planModeEnabled", "workflowRunStoreBackend",
1330
+ "schedulerEnabled", "schedulerSessionWakeup", "schedulerSessionLifetime", "schedulerStorePath", "planModeEnabled", "workflowRunStoreBackend",
1330
1331
  "workflowOrphanGraceMs", "workflowJournalRetentionMs", "workflowRunRetentionMs", "workflowAgentsReadOnly",
1331
1332
  "workflowSizeGuideline", "backgroundAgentRetentionMs", "backgroundAgentStaleRunningMs",
1332
1333
  "backgroundAgentParkClaimStaleMs", "rosterRetentionMs", "scratchpadSweepTtlMs", "sandboxPkgSource",
@@ -145,6 +145,12 @@ export class FileSchedulerBackend {
145
145
  if (intent.lifetime === "session" && !ctx.sessionId) {
146
146
  return err(new SchedulerError("invalid_schedule", 'lifetime:"session" requires a session to bind to (ctx.sessionId missing)'));
147
147
  }
148
+ // [2436] 纵深(5.6.0):能力面已声明无 daemon 收割 session-lifetime(headless 部署形,
149
+ // SCHEDULER_SESSION_LIFETIME=false)⇒ 落盘一条即必然孤儿([2425] 外溢病)。core 的 CronCreate 读
150
+ // 能力面在工具层前门拒是第一道;这里是第二道——错装配宿主绕过工具层直调也不许落盘。
151
+ if (intent.lifetime === "session" && this.schedulerCapabilities.supportsSessionLifetime === false) {
152
+ return err(new SchedulerError("invalid_schedule", 'lifetime:"session" is not supported on this deployment (no resident daemon reaps session-lifetime records — the row would be an orphan)'));
153
+ }
148
154
  const records = this.load();
149
155
  const key = dedupKey(ctx.scope, intent, ctx.sessionId);
150
156
  const existingIdx = records.findIndex((r) => {
@@ -194,9 +200,12 @@ export class FileSchedulerBackend {
194
200
  async cancel(id, ctx) {
195
201
  const records = this.load();
196
202
  const idx = records.findIndex((r) => r.id === id);
197
- // 🔴 scope isolation: a non-own-scope id is `not_found` (don't leak existence). Idempotent: missing = ok.
198
- if (idx < 0 || records[idx].scope !== ctx.scope)
199
- return ok(undefined);
203
+ // 🔴 scope isolation + 假肯定病修([2425]/[2209],5.6.0):missing non-own-scope **同折**
204
+ // err(not_found)——存在性仍不泄露(错 id/别人的任务/已删的重试三条到达路径一个答案),但不再
205
+ // ok(undefined) 谎报「删掉了」。旧形的代价是真实的:模型删错 id 得到成功回执,真任务继续按点起跑。
206
+ if (idx < 0 || records[idx].scope !== ctx.scope) {
207
+ return err(new SchedulerError("not_found", `no scheduled task ${id} in your scope (wrong id, already cancelled, or not yours)`));
208
+ }
200
209
  records.splice(idx, 1);
201
210
  try {
202
211
  this.save(records);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "5.5.0",
3
+ "version": "5.6.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",