@sema-agent/server 7.96.0 → 7.98.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.
Files changed (89) hide show
  1. package/MIGRATION.md +5 -0
  2. package/README.md +2 -2
  3. package/README.zh-CN.md +2 -2
  4. package/USAGE.md +10 -1
  5. package/deploy/sema-up/cluster-up.sh +8 -4
  6. package/deploy/sema-up/kube-up.sh +40 -15
  7. package/deploy/sema-up/lib/envf.sh +173 -0
  8. package/deploy/sema-up/sema-up.sh +113 -94
  9. package/deploy/sema-up/smoke.sh +8 -1
  10. package/dist/approval.d.ts +28 -0
  11. package/dist/approval.js +24 -0
  12. package/dist/boot/budget-tracing.d.ts +1 -0
  13. package/dist/boot/budget-tracing.js +3 -2
  14. package/dist/boot/config-center.js +4 -7
  15. package/dist/boot/coordinators.js +2 -2
  16. package/dist/boot/deferred-sandbox-path-env.d.ts +5 -2
  17. package/dist/boot/deferred-sandbox-path-env.js +3 -1
  18. package/dist/boot/memory-boundary.d.ts +17 -2
  19. package/dist/boot/memory-boundary.js +11 -0
  20. package/dist/boot/reapers.d.ts +3 -1
  21. package/dist/boot/reapers.js +2 -2
  22. package/dist/boot/resolve-spec.js +15 -10
  23. package/dist/boot/runner-deps.d.ts +2 -1
  24. package/dist/boot/session-faces.d.ts +4 -1
  25. package/dist/boot/session-faces.js +5 -5
  26. package/dist/boot/stage-04-stores.d.ts +1 -0
  27. package/dist/boot/stage-04-stores.js +2 -2
  28. package/dist/boot/stage-05-execution-env.d.ts +1 -0
  29. package/dist/boot/stage-06-runners.d.ts +1 -0
  30. package/dist/boot/stage-07-capability-layer.d.ts +1 -0
  31. package/dist/boot/stage-07-capability-layer.js +10 -14
  32. package/dist/boot/stage-08-reapers.d.ts +2 -3
  33. package/dist/boot/stage-08-reapers.js +2 -2
  34. package/dist/boot/stage-09-leader.d.ts +1 -0
  35. package/dist/boot/stage-09-leader.js +2 -2
  36. package/dist/boot/stage-10-http-server.d.ts +1 -0
  37. package/dist/boot/stores.js +5 -11
  38. package/dist/brain.js +28 -18
  39. package/dist/capabilities/execution-lane.d.ts +5 -7
  40. package/dist/capabilities/execution-lane.js +2 -1
  41. package/dist/capabilities/memory-notice.d.ts +30 -12
  42. package/dist/capabilities/memory-notice.js +8 -1
  43. package/dist/capabilities/skills.d.ts +14 -0
  44. package/dist/capabilities/skills.js +4 -0
  45. package/dist/config-catalog.js +5 -4
  46. package/dist/config-center/apply-effective.js +7 -1
  47. package/dist/config-center/facade.d.ts +2 -1
  48. package/dist/config-invariants.d.ts +2 -2
  49. package/dist/config-invariants.js +9 -1
  50. package/dist/config-types.d.ts +20 -3
  51. package/dist/config.d.ts +9 -0
  52. package/dist/config.js +46 -8
  53. package/dist/env-facts.js +2 -4
  54. package/dist/execution-lane-caps.d.ts +36 -6
  55. package/dist/execution-lane-caps.js +4 -0
  56. package/dist/file-history-capture.d.ts +65 -0
  57. package/dist/file-history-capture.js +21 -0
  58. package/dist/hooks/hook-llm.d.ts +1 -1
  59. package/dist/hooks/hook-llm.js +3 -1
  60. package/dist/hosted-posture.d.ts +1 -1
  61. package/dist/http/resume-legs.d.ts +14 -4
  62. package/dist/http/resume-legs.js +26 -17
  63. package/dist/http/route-ctx.d.ts +35 -9
  64. package/dist/http/routes/approvals-assistant.d.ts +1 -1
  65. package/dist/http/routes/approvals-assistant.js +16 -6
  66. package/dist/http/routes/capabilities.js +2 -0
  67. package/dist/http/routes/runs.js +2 -2
  68. package/dist/http/routes/session-sync.js +6 -1
  69. package/dist/http/server.d.ts +4 -1
  70. package/dist/http/server.js +1 -1
  71. package/dist/http/verify-rounds.d.ts +1 -1
  72. package/dist/memory-scope.d.ts +68 -13
  73. package/dist/memory-scope.js +35 -5
  74. package/dist/model-provider.d.ts +13 -0
  75. package/dist/model-provider.js +3 -0
  76. package/dist/model-route-endpoint.d.ts +82 -0
  77. package/dist/model-route-endpoint.js +55 -0
  78. package/dist/observability/fail-open.d.ts +4 -0
  79. package/dist/observability/fail-open.js +4 -0
  80. package/dist/project-identity.d.ts +29 -0
  81. package/dist/project-identity.js +120 -0
  82. package/dist/run-local.d.ts +14 -4
  83. package/dist/run-local.js +12 -10
  84. package/dist/session-sync.d.ts +4 -1
  85. package/dist/session-sync.js +2 -2
  86. package/dist/task-cwd.d.ts +9 -3
  87. package/dist/task-cwd.js +3 -1
  88. package/dist/trace/redact.d.ts +1 -1
  89. package/package.json +1 -1
package/dist/run-local.js CHANGED
@@ -24,10 +24,9 @@ import { acquireLocalBackendWithWait } from "./plugins/store-lock-wait.js";
24
24
  import { createConfigProvider } from "./config-provider.js";
25
25
  import { applyEffective, applyCenterReadFace, resolveMcpServers, mcpForScenario, resolveA2aPeers, a2aForScenario } from "./config-center/facade.js";
26
26
  import { hostExecutionEnvFactory } from "./plugins/remote-env-host.js";
27
- import { executionLaneHomeDir } from "./execution-lane-caps.js";
27
+ import { executionLaneHomeDir, executionLaneOf } from "./execution-lane-caps.js";
28
28
  import { makeLoadProjectMemory, makeProbeInstructionSources } from "./project-memory.js";
29
- import { loadSkills } from "./capabilities/skills.js";
30
- import { toolsRunOnThisHost } from "./task-cwd.js";
29
+ import { loadDeploymentSkills } from "./capabilities/skills.js";
31
30
  import { createRepoClient } from "./capabilities/repo-tools.js";
32
31
  import { webSearchConfigFromEnv, createWebSearchBackend } from "./plugins/web-search.js";
33
32
  import { buildScenarios, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
@@ -35,7 +34,8 @@ import { createTaskListLane } from "./boot/task-list-lane.js";
35
34
  import { pickHandsRunner, withoutExecutionEnv } from "./capabilities/hands-lane.js";
36
35
  import { HttpError } from "./security.js";
37
36
  import { createMemoryEngineIncidentSink } from "./memory-incident-sink.js";
38
- import { memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
37
+ import { memoryEngineBackendFor, memoryProjectKeyFor, memorySpecForRequest } from "./memory-scope.js";
38
+ import { modelRouteEndpointRefusal } from "./model-route-endpoint.js";
39
39
  import { createMemorySyncRunner, createMemorySyncTransport } from "./memory-sync-client.js";
40
40
  import { buildPricing, cappedCeiling, createTracer } from "./budget.js";
41
41
  import { createSharedRunnerDeps } from "./boot/runner-deps.js";
@@ -100,9 +100,8 @@ export class UsageError extends Error {
100
100
  }
101
101
  export function missingGatewayRequirements(config) {
102
102
  const missing = [];
103
- if (!config.gatewayBaseUrl || !/\/v1\/?$/.test(config.gatewayBaseUrl)) {
104
- missing.push("MODEL_GATEWAY_BASEURL (the OpenAI-compatible gateway URL, must end in /v1)");
105
- }
103
+ if (config.gatewayBaseUrl === undefined)
104
+ return missing;
106
105
  const perModelEnvs = Object.values(config.modelApiKeyEnv ?? {});
107
106
  const haveGatewayKey = !!config.gatewayApiKey;
108
107
  const catalogModelNames = new Set(Object.values(config.models ?? {}).map((m) => m.name));
@@ -210,6 +209,9 @@ export async function runLocal(argv, deps = {}) {
210
209
  catch (err) {
211
210
  logger.warn("config_source_unreachable_using_env", { source: configProvider.kind, err: String(err) });
212
211
  }
212
+ const endpointRefusal = modelRouteEndpointRefusal(config);
213
+ if (endpointRefusal !== undefined)
214
+ throw new Error(endpointRefusal);
213
215
  const unpricedCeiling = buildUnpricedCeilingNotice(config.models, config);
214
216
  if (unpricedCeiling)
215
217
  logger.warn(unpricedCeiling.event, unpricedCeiling.fields);
@@ -424,7 +426,7 @@ export async function runLocal(argv, deps = {}) {
424
426
  const subRunner = new Runner(subRunnerDeps);
425
427
  const handslessRunner = new Runner(withoutExecutionEnv(runnerDeps));
426
428
  const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
427
- const skills = loadSkills(config.skillsDir, { toolsShareThisFilesystem: toolsRunOnThisHost(config) });
429
+ const skills = loadDeploymentSkills(config);
428
430
  const repoClient = config.gitApiBaseUrl ? createRepoClient(config.gitApiKind, config.gitApiBaseUrl, config.gitApiToken) : undefined;
429
431
  const webSearchCfg = webSearchConfigFromEnv();
430
432
  const webSearch = webSearchCfg ? createWebSearchBackend(webSearchCfg) : undefined;
@@ -478,7 +480,7 @@ export async function runLocal(argv, deps = {}) {
478
480
  backgroundScope: "session",
479
481
  oneShot: true,
480
482
  principal: scope,
481
- ...(memoryEngine ? { memory: memorySpecForRequest(scope, undefined) } : {}),
483
+ ...(memoryEngine ? { memory: memorySpecForRequest(scope, memoryProjectKeyFor(config, scope, workspaceDir), undefined) } : {}),
482
484
  model: mention.model ?? "default",
483
485
  getApiKeyAndHeaders: keyResolver,
484
486
  tools: cap.tools,
@@ -489,7 +491,7 @@ export async function runLocal(argv, deps = {}) {
489
491
  ...(a2a ? { a2a } : {}),
490
492
  ...(Object.keys(limits).length > 0 ? { limits } : {}),
491
493
  }, config, workspaceDir, memoryEngine?.root);
492
- logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: config.remoteExec?.provider ?? "in-process" });
494
+ logger.info("run_local_start", { scenario: scenarioName, model: spec.model, sessionId, exec: executionLaneOf(config.remoteExec?.provider) });
493
495
  const settleSessionBackground = async () => {
494
496
  const reaped = defaultTaskRegistry.reapSessionBackground(sessionId, scope);
495
497
  if (reaped === 0)
@@ -140,7 +140,10 @@ export interface SessionManifest {
140
140
  * `null` ONLY for "session does not exist". (Named exportSessionManifest, NOT exportManifest, to avoid the collision
141
141
  * with the history store's own export verb.)
142
142
  */
143
- export declare function exportSessionManifest(sessionId: string, srcBackend: StoreBackend): Promise<{
143
+ export declare function exportSessionManifest(sessionId: string, srcBackend: StoreBackend,
144
+ /** S-589:文件历史读**装配结果**(捕获脸),不直取 `srcBackend.fileHistory()` —— 「这台部署有没有文件历史店」
145
+ * 只在 `assembleFileHistory` 判一次。同一个后端铸的同一只店,四店同源的不变式不变。 */
146
+ historyStore: ServiceFileHistoryStore): Promise<{
144
147
  manifest: SessionManifest;
145
148
  getBlob: BlobGetter;
146
149
  } | null>;
@@ -21,7 +21,7 @@ export async function replayFileHistory(store, scope, envelope, srcGetBlob, opts
21
21
  function ownerAware(backend) {
22
22
  return backend.session();
23
23
  }
24
- export async function exportSessionManifest(sessionId, srcBackend) {
24
+ export async function exportSessionManifest(sessionId, srcBackend, historyStore) {
25
25
  const session = ownerAware(srcBackend);
26
26
  const listEntryIds = session.listEntryIds?.bind(session);
27
27
  if (!listEntryIds)
@@ -31,7 +31,7 @@ export async function exportSessionManifest(sessionId, srcBackend) {
31
31
  return null;
32
32
  const getLeafId = session.getLeafId?.bind(session);
33
33
  const leafId = getLeafId ? await getLeafId(sessionId) : null;
34
- const fs = srcBackend.fileHistory();
34
+ const fs = historyStore;
35
35
  const fileHistory = typeof fs.exportHistory === "function" ? await fs.exportHistory(sessionId) : null;
36
36
  const policyStore = srcBackend.sessionPolicy();
37
37
  const policy = typeof policyStore.listBySession === "function"
@@ -56,12 +56,18 @@ export declare function cwdHonored(config: {
56
56
  * S-377 —— 「**工具跑的那台机器**就是本进程这台吗」。回答的是一个**文件系统同一性**问题,不是权限问题:
57
57
  * server 盘上的一条绝对路径(出厂 `SKILLS_DIR` 下某个技能自己的目录)对模型的工具**有没有意义**。
58
58
  *
59
+ * 判据 = 能力表两位的合取 {@link handsOnWorkerFilePlane}(`coreRemoteExecutionEnv ∧ hostFilePlane`,都读表,
60
+ * 本函数不手写任何车道词):
59
61
  * · `host`(run-on-this-machine,无容器)⇒ 真;
60
- * · `undefined`(in-process 单用户 lane)⇒ 真 —— 该 lane 根本没挂手(core 落 `StubExecutionEnv`),
61
- * 路径对谁都不可达,但它在**文件系统同一性**这条轴上确实是同一台机器,判真让规则只剩一条;
62
+ * · `in-process`(`REMOTE_EXEC` 未设)⇒ **假**(S-602,clay 裁 [ref] A 翻面;改前判真)—— 该 lane 根本
63
+ * 没挂手(core 落 `StubExecutionEnv`),「工具的盘」这句话在这里没有指称对象。改前的理由「文件系统同一性
64
+ * 这条轴上确实是同一台机器,判真让规则只剩一条」把**缺席折成了邻居**:wire 上的 `toolsOnThisHost` 因此
65
+ * 对无手部署说真,消费端的 doctor 据此说「工具在本机」。代价如实记:出厂目录形技能在 in-process 上不再带
66
+ * `baseDir` —— core 律:缺席 ⇒ 结果逐字节同 baseDir 到货之前,而那条 lane 上本来也没有能读它的工具;
62
67
  * · 其余每一条(`k8s` / `e2b` / `ssh` / `adb` / `device` / `local-docker`)⇒ 假:工具的盘在别处,
63
68
  * server 自己的路径在那边**不存在**,声明它等于给模型一条指向不存在文件的线索,还顺带把本机目录
64
- * 布局说了出去。
69
+ * 布局说了出去;
70
+ * · 认不出的词 ⇒ 假(fail-closed:没认出来的车道不许被当成「本机」)。
65
71
  *
66
72
  * 🔴 **为什么不复用 {@link cwdHonored}**:那一只是**权限**判据(单用户 ∧ host),它的 `requirePrincipal`
67
73
  * 那一半防的是「一个租户的输入把 agent 指向另一个租户的文件」。本谓词判的路径不是调用方给的,是**运维
package/dist/task-cwd.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { executionLaneOf, handsOnWorkerFilePlane } from "./execution-lane-caps.js";
2
3
  export const MAX_CWD_CHARS = 4_096;
3
4
  export function isValidCwd(cwd) {
4
5
  return (typeof cwd === "string" &&
@@ -21,7 +22,8 @@ export function cwdHonored(config) {
21
22
  return config.remoteExec?.provider === "host" && config.requirePrincipal !== true;
22
23
  }
23
24
  export function toolsRunOnThisHost(config) {
24
- return config.remoteExec === undefined || config.remoteExec.provider === undefined || config.remoteExec.provider === "host";
25
+ const lane = executionLaneOf(config.remoteExec?.provider);
26
+ return lane !== undefined && handsOnWorkerFilePlane(lane);
25
27
  }
26
28
  export function deviceCwdHonored(config) {
27
29
  return config.remoteExec?.provider === "device";
@@ -190,7 +190,7 @@ export declare function isHierarchicalUrl(raw: string): boolean;
190
190
  * ① **有效性闸**:配置里的那一位应当是一个**绝对 URL**。`new URL(raw)` 解析不动 ⇒ 这一位根本不是 URL
191
191
  * (裸 `host:port`、相对路径、手滑的散文),自由文本的 URL 律对它没有定界依据 ⇒ 返回**占位**
192
192
  * {@link DISPLAY_SAFE_URL_TOKEN},**不回落原值**([ref]:安全轴上的兜底必须 fail-closed 或响亮)。
193
- * 成文代价:`MODEL_GATEWAY_BASEURL=127.0.0.1:8000` 这种缺 scheme 的配置在日志上变成 `«redacted:url»`
193
+ * 成文代价:`MODEL_GATEWAY_BASEURL=gw.internal:8000` 这种缺 scheme 的配置在日志上变成 `«redacted:url»`
194
194
  * —— 而它在 `fetch` 那一侧本来就是必然失败的形(WHATWG 要求绝对 URL),日志上响亮一点方向一致。
195
195
  * ② **空串 = 未设**:里面没有凭据,原样回空串(不铸占位 —— 占位会让「没配」读成「配了但看不见」)。
196
196
  * ⚠️ **保形只到 host / port / path 这一层**(S-483 起如实改口;`test/config-url-display-safe.test.ts`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.96.0",
3
+ "version": "7.98.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",