@sema-agent/server 7.6.0 → 7.7.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.
@@ -25,6 +25,19 @@ export declare function createPermissionDeniedMeter(metrics: Pick<Metrics, "inc"
25
25
  *
26
26
  * Pure observation: every hook returns `undefined`, so it never rewrites args, never gates, never alters
27
27
  * the result (and per core's hooks invariant a hook's `allow` can't bypass the policy gate anyway).
28
+ *
29
+ * 🔴 core 5.20.0 起这条「纯观察」性质必须**声明**出来(`preToolUseObservational`),不能只写在注释里:
30
+ * core 5.19.0 的委派折叠按「PreToolUse 席位在不在」把父的 screening 面折进子代的祖先约束链——它分不出
31
+ * 诊断 tracer 与真裁决者。后果是**这个默认关的诊断旋钮**一开,该部署所有 hook-wired 父的 parked 子代
32
+ * checkpoint 就记 `parentConstraintCount=2`,而跨副本赎回腿(`boot/parked-revive-gate.ts`)恒供 1 ⇒
33
+ * core pre-CAS 响亮拒、行永久 pending(层数 park 时写死,事后关旋钮/重批/回滚都不改)。
34
+ * 声明之后该面不铸链条目,count 回到 1,病路消灭。
35
+ * ⛔ 打这个标的前提是**真的一条裁决都不出**:core 对声明了却返回判词的面是「拒绝采纳 + onError 告警」
36
+ * (classification `observational-hook-verdict-ignored`),即判词被静默丢弃——把标打到会裁决的面上比原
37
+ * 缺陷更坏。本文件三个 pre/post 回调恒返 `undefined`,`permissionDenied` 本就是 void 观察槽。
38
+ * 📎 连带的**可观测**变化(不是回归):core 的「可写工具面无 effect-aware 门」启动告警此前把本 tracer
39
+ * 算作一道门而被抑制;声明之后它不再算,于是「没配任何 policy 层 + 开着 TOOL_TRACE」的部署升级后会
40
+ * 多出那行告警。方向正确——tracer 从来没有门住任何东西,原先的抑制本身就是一次静默 fail-open。
28
41
  */
29
42
  export declare function createToolTracer(logger: Logger): Hooks;
30
43
  //# sourceMappingURL=tool-trace.d.ts.map
@@ -33,9 +33,23 @@ export function createPermissionDeniedMeter(metrics) {
33
33
  *
34
34
  * Pure observation: every hook returns `undefined`, so it never rewrites args, never gates, never alters
35
35
  * the result (and per core's hooks invariant a hook's `allow` can't bypass the policy gate anyway).
36
+ *
37
+ * 🔴 core 5.20.0 起这条「纯观察」性质必须**声明**出来(`preToolUseObservational`),不能只写在注释里:
38
+ * core 5.19.0 的委派折叠按「PreToolUse 席位在不在」把父的 screening 面折进子代的祖先约束链——它分不出
39
+ * 诊断 tracer 与真裁决者。后果是**这个默认关的诊断旋钮**一开,该部署所有 hook-wired 父的 parked 子代
40
+ * checkpoint 就记 `parentConstraintCount=2`,而跨副本赎回腿(`boot/parked-revive-gate.ts`)恒供 1 ⇒
41
+ * core pre-CAS 响亮拒、行永久 pending(层数 park 时写死,事后关旋钮/重批/回滚都不改)。
42
+ * 声明之后该面不铸链条目,count 回到 1,病路消灭。
43
+ * ⛔ 打这个标的前提是**真的一条裁决都不出**:core 对声明了却返回判词的面是「拒绝采纳 + onError 告警」
44
+ * (classification `observational-hook-verdict-ignored`),即判词被静默丢弃——把标打到会裁决的面上比原
45
+ * 缺陷更坏。本文件三个 pre/post 回调恒返 `undefined`,`permissionDenied` 本就是 void 观察槽。
46
+ * 📎 连带的**可观测**变化(不是回归):core 的「可写工具面无 effect-aware 门」启动告警此前把本 tracer
47
+ * 算作一道门而被抑制;声明之后它不再算,于是「没配任何 policy 层 + 开着 TOOL_TRACE」的部署升级后会
48
+ * 多出那行告警。方向正确——tracer 从来没有门住任何东西,原先的抑制本身就是一次静默 fail-open。
36
49
  */
37
50
  export function createToolTracer(logger) {
38
51
  return {
52
+ preToolUseObservational: true,
39
53
  preToolUse(toolName, input, ctx) {
40
54
  logger.info("tool_trace", { phase: "pre", id: ctx.toolCallId, tool: toolName, arg: summarize(input) });
41
55
  return undefined;
package/dist/run-local.js CHANGED
@@ -56,6 +56,7 @@ import { loadSkills } from "./capabilities/skills.js";
56
56
  import { GiteaClient } from "./capabilities/repo-tools.js";
57
57
  import { webSearchConfigFromEnv, createWebSearchBackend } from "./plugins/web-search.js";
58
58
  import { buildScenarios, selectScenario, centerScenarios } from "./capabilities/scenarios.js";
59
+ import { pickHandsRunner, withoutExecutionEnv } from "./capabilities/hands-lane.js";
59
60
  import { HttpError } from "./security.js";
60
61
  import { memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
61
62
  import { createMemorySyncRunner, createMemorySyncTransport } from "./memory-sync-client.js";
@@ -495,7 +496,7 @@ export async function runLocal(argv, deps = {}) {
495
496
  ...(ctx.classification !== undefined ? { classification: ctx.classification } : {}),
496
497
  err: String(err),
497
498
  });
498
- const runner = new Runner({
499
+ const runnerDeps = {
499
500
  brain,
500
501
  models: config.models,
501
502
  roles: config.roles,
@@ -521,14 +522,21 @@ export async function runLocal(argv, deps = {}) {
521
522
  ...(config.projectMemoryEnabled
522
523
  ? { loadProjectMemory: makeLoadProjectMemory({ logger }), probeInstructionSources: makeProbeInstructionSources() }
523
524
  : {}),
524
- });
525
+ };
526
+ const runner = new Runner(runnerDeps);
525
527
  // Sub-task runner (council lenses/team) — mirrors main.ts's subRunner, INCLUDING executionEnvFactory so a delegated
526
528
  // child gets hands (Bash/Read/Edit) on the host lane. Without it the child's handsEnabled is false — the exact
527
529
  // "subagent couldn't run pwd" defect fixed at main.ts:799; this is its run-local twin, caught by the systematic audit.
528
530
  // [1367]① fork server half(main.ts subRunner 同款):ForkRoutingSessionStore——fork/resume 形
529
531
  // (requireExisting)→ host 文件店优先(core 1.350 hostSessionFork 在宿主店 fork,拆店=响亮
530
532
  // resume.session_not_found),普通子任务 → 私有 TTL 店(throwaway 姿势保留)。
531
- const subRunner = new Runner({ brain, models: config.models, roles: config.roles, pricing, promptSource, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), onError: engineOnError, onAsk, ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}) });
533
+ const subRunnerDeps = { brain, models: config.models, roles: config.roles, pricing, promptSource, sessionStore: new ForkRoutingSessionStore(sessionStore, new TtlSessionStore({ defaultTtlDays: 1 / 24 })), onError: engineOnError, onAsk, ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}) };
534
+ const subRunner = new Runner(subRunnerDeps);
535
+ // #196:无手孪生一对 —— **mirrors main.ts**(那边是 `handslessRunner` / `handslessSubRunner` 两只,同 deps
536
+ // 摘掉 executionEnvFactory)。run-local 是同形装配点,漏这一对 = 本地 lane 上 scan/council/team 的最终
537
+ // roster 仍被并集进全量可写手(server 修了、CLI 静默留病 —— 这条腿的 subRunner 当年就是这么漏配的)。
538
+ const handslessRunner = new Runner(withoutExecutionEnv(runnerDeps));
539
+ const handslessSubRunner = new Runner(withoutExecutionEnv(subRunnerDeps));
532
540
  // Capability layer (loadSkills + buildScenarios + selectScenario) — assembled exactly like main.ts.
533
541
  const skills = loadSkills(config.skillsDir);
534
542
  const repoClient = config.gitApiBaseUrl ? new GiteaClient(config.gitApiBaseUrl, config.gitApiToken) : undefined;
@@ -537,7 +545,7 @@ export async function runLocal(argv, deps = {}) {
537
545
  const webSearchCfg = webSearchConfigFromEnv();
538
546
  const webSearch = webSearchCfg ? createWebSearchBackend(webSearchCfg) : undefined;
539
547
  const scenarioDeps = {
540
- runner, subRunner, model: "default", skills, repoClient, metrics, logger,
548
+ runner, subRunner, handslessSubRunner, model: "default", skills, repoClient, metrics, logger,
541
549
  ...(webSearch ? { webSearch } : {}),
542
550
  brandIdentity: true, // run-local is always a local/TOC deployment → brand the default scenario as Sema.
543
551
  };
@@ -617,8 +625,10 @@ export async function runLocal(argv, deps = {}) {
617
625
  // ── Run ONE task to completion (the sync /v1/tasks path: plain runTask, no verify/cascade). ──
618
626
  let result;
619
627
  let exitCode = 0;
628
+ // #196:与 HTTP 腿同一条选路 —— 场景声明 hands:"none" 时任务跑无手 Runner(band 不 mount)。
629
+ const taskRunner = pickHandsRunner(cap.hands, { full: runner, handsless: handslessRunner });
620
630
  try {
621
- result = await runner.runTask(spec);
631
+ result = await taskRunner.runTask(spec);
622
632
  }
623
633
  catch (err) {
624
634
  printErr(`task crashed: ${err instanceof Error ? err.message : String(err)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/server",
3
- "version": "7.6.0",
3
+ "version": "7.7.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",
@@ -54,7 +54,7 @@
54
54
  "build:binary:run-local:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/run-local.ts --outfile dist/run-local-darwin-arm64"
55
55
  },
56
56
  "dependencies": {
57
- "@sema-agent/core": "^5.19.0",
57
+ "@sema-agent/core": "^5.21.0",
58
58
  "@sema-agent/registry-core": "^0.16.0",
59
59
  "e2b": "^2.28.0",
60
60
  "libsodium-wrappers": "^0.8.4",