@sema-agent/server 7.119.0 → 7.121.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/MIGRATION.md +129 -0
- package/USAGE.md +72 -23
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +2 -2
- package/deploy/sema-up/chart/templates/server.yaml +2 -2
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +1 -1
- package/dist/boot/config-center.d.ts +5 -7
- package/dist/boot/config-center.js +37 -13
- package/dist/boot/engine-lease.d.ts +1 -1
- package/dist/boot/execution-env.js +3 -2
- package/dist/boot/fatal-exit.d.ts +7 -1
- package/dist/boot/fatal-exit.js +2 -1
- package/dist/boot/resolve-spec.js +1 -0
- package/dist/boot/runner-deps.d.ts +4 -3
- package/dist/boot/runner-deps.js +7 -3
- package/dist/boot/shutdown.d.ts +9 -10
- package/dist/boot/shutdown.js +54 -16
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-09-leader.d.ts +2 -9
- package/dist/boot/stage-10-http-server.d.ts +1 -9
- package/dist/boot/stage-10-http-server.js +31 -8
- package/dist/capabilities/builtin-tools.d.ts +31 -8
- package/dist/capabilities/builtin-tools.js +22 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.d.ts +8 -6
- package/dist/capabilities/scenarios.js +3 -3
- package/dist/capabilities/send-user-file-tool.d.ts +6 -3
- package/dist/capabilities/send-user-file-tool.js +1 -1
- package/dist/config-catalog.js +13 -7
- package/dist/config-center/center-request.d.ts +16 -1
- package/dist/config-center/center-request.js +36 -5
- package/dist/config-lkg.d.ts +33 -5
- package/dist/config-lkg.js +55 -11
- package/dist/config-types.d.ts +46 -3
- package/dist/config-types.js +6 -0
- package/dist/config.d.ts +33 -4
- package/dist/config.js +107 -15
- package/dist/deployment-governance.d.ts +3 -1
- package/dist/deployment-governance.js +3 -1
- package/dist/device-store.d.ts +7 -0
- package/dist/device-store.js +4 -0
- package/dist/device-ws-hub.js +17 -9
- package/dist/device-ws-protocol.d.ts +15 -0
- package/dist/fleet/drain-entry.d.ts +87 -0
- package/dist/fleet/drain-entry.js +35 -0
- package/dist/fleet/engine-signal.d.ts +144 -0
- package/dist/fleet/engine-signal.js +60 -0
- package/dist/fleet/serving-lease.d.ts +47 -0
- package/dist/fleet/serving-lease.js +235 -0
- package/dist/fleet-client.d.ts +35 -19
- package/dist/fleet-client.js +49 -25
- package/dist/http/approval-sweeps.js +3 -5
- package/dist/http/dispatch.js +18 -13
- package/dist/http/health-self-report.d.ts +60 -0
- package/dist/http/health-self-report.js +53 -0
- package/dist/http/principal-gate.d.ts +8 -1
- package/dist/http/principal-gate.js +1 -0
- package/dist/http/readiness.d.ts +25 -5
- package/dist/http/readiness.js +31 -6
- package/dist/http/resume-legs.js +5 -1
- package/dist/http/route-ctx.d.ts +6 -4
- package/dist/http/route-table.d.ts +3 -0
- package/dist/http/route-table.js +4 -1
- package/dist/http/routes/a2a-serve.d.ts +1 -1
- package/dist/http/routes/a2a-serve.js +5 -5
- package/dist/http/routes/admin-drain.d.ts +12 -31
- package/dist/http/routes/admin-drain.js +15 -9
- package/dist/http/routes/approvals-assistant.d.ts +3 -3
- package/dist/http/routes/approvals-assistant.js +3 -3
- package/dist/http/routes/capabilities.js +3 -1
- package/dist/http/routes/devices.js +6 -5
- package/dist/http/routes/leader.d.ts +1 -1
- package/dist/http/routes/leader.js +1 -1
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/notify-wake.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +1 -1
- package/dist/http/routes/rules.js +14 -6
- package/dist/http/routes/runs.d.ts +2 -2
- package/dist/http/routes/runs.js +2 -2
- package/dist/http/routes/side-query.d.ts +1 -1
- package/dist/http/routes/side-query.js +1 -1
- package/dist/http/routes/tasks.d.ts +2 -2
- package/dist/http/routes/tasks.js +3 -3
- package/dist/http/server.d.ts +7 -21
- package/dist/http/server.js +20 -1
- package/dist/http/wire-types.d.ts +7 -1
- package/dist/list-entry-display.d.ts +14 -0
- package/dist/list-entry-display.js +14 -0
- package/dist/model-reach-scope.d.ts +15 -3
- package/dist/model-reach-scope.js +3 -2
- package/dist/model-unreachable-notice.d.ts +2 -1
- package/dist/model-unreachable-notice.js +1 -0
- package/dist/namespaced-rule-name.js +2 -6
- package/dist/observability/fail-open.d.ts +20 -0
- package/dist/observability/fail-open.js +20 -0
- package/dist/operator-ask.d.ts +1 -1
- package/dist/plugins/one-time-migrations.d.ts +8 -0
- package/dist/plugins/one-time-migrations.js +72 -3
- package/dist/plugins/permission-rule-store-file.js +2 -6
- package/dist/plugins/permission-rule-store-sql.d.ts +65 -6
- package/dist/plugins/permission-rule-store-sql.js +166 -59
- package/dist/plugins/remote-env-device.d.ts +12 -1
- package/dist/plugins/remote-env-device.js +13 -6
- package/dist/plugins/scheduler-support.d.ts +8 -4
- package/dist/plugins/scheduler-support.js +5 -5
- package/dist/request-key-closure.js +1 -1
- package/dist/rule-entry-list.d.ts +0 -1
- package/dist/rule-entry-list.js +4 -9
- package/dist/rules-consent.d.ts +16 -3
- package/dist/rules-consent.js +8 -4
- package/dist/run-local.js +2 -0
- package/dist/runs.js +1 -1
- package/dist/sema-config-dir.d.ts +19 -0
- package/dist/sema-config-dir.js +33 -0
- package/dist/session-policy-wire.js +5 -4
- package/dist/spec-fields.d.ts +5 -4
- package/dist/task-settings.d.ts +3 -3
- package/dist/tool-approval.d.ts +7 -0
- package/dist/tool-approval.js +4 -1
- package/dist/trace/core-keyset-guard.d.ts +2 -2
- package/dist/trace/engine-notice-wire.d.ts +6 -4
- package/dist/trace/engine-notice-wire.js +16 -9
- package/dist/trace/self-minted-wire.d.ts +78 -0
- package/dist/trace/self-minted-wire.js +32 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +56 -14
- package/package.json +3 -3
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* `err` 的 fatal 日志文本:标题过形状律一次。纯函数,零副作用。
|
|
3
|
+
*
|
|
4
|
+
* 标题 = `String(err)`;异常**自带机器码**(`err.code` 是串 —— 引擎的构造期拒因都带,如 `config.agent_config_dir_invalid`)⇒ 按 Node 给自家
|
|
5
|
+
* 带码异常的写法 `<name> [<code>]: <message>` 把码写进标题(`String(err)` 不带 `code`,修前拒启行里看不到引擎的码)。一条规则,不分谁铸的:
|
|
6
|
+
* 多数 Node 自己的 `ERR_*` 异常本来就印成这一形(逐字不变),系统调用异常(`EEXIST` 等)标题里多一次码。
|
|
7
|
+
*/
|
|
2
8
|
export declare function buildFatalErrorText(err: unknown): string;
|
|
3
9
|
/**
|
|
4
10
|
* 进程级 fatal 出口的**唯一一只腿**:同一只 {@link buildFatalErrorText} 产物写两个面,然后按崩溃码退。
|
package/dist/boot/fatal-exit.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { redactSecrets } from "../trace/redact.js";
|
|
2
2
|
import { createLogger } from "../observability/logger.js";
|
|
3
3
|
export function buildFatalErrorText(err) {
|
|
4
|
-
|
|
4
|
+
const code = err instanceof Error ? err.code : undefined;
|
|
5
|
+
return redactSecrets(typeof code === "string" && err instanceof Error ? `${err.name} [${code}]: ${err.message}` : String(err));
|
|
5
6
|
}
|
|
6
7
|
export function fatalExit(err) {
|
|
7
8
|
const text = buildFatalErrorText(err);
|
|
@@ -331,6 +331,7 @@ export function createResolveSpec(ctx) {
|
|
|
331
331
|
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
332
332
|
systemPrompt: typeof body.systemPrompt === "string" ? body.systemPrompt : undefined,
|
|
333
333
|
appendSystemPrompt: acceptedAppend,
|
|
334
|
+
...(body.outputStyle !== undefined ? { outputStyle: body.outputStyle } : {}),
|
|
334
335
|
sessionId: auth?.sessionId,
|
|
335
336
|
principal: auth?.principal,
|
|
336
337
|
images: body.images,
|
|
@@ -311,9 +311,10 @@ export declare function createEngineNoticeSeat(logger: {
|
|
|
311
311
|
* 「键为 undefined」与「键缺席」对引擎逐字等价)。**不复制引擎缺省**(`roots`/`static-face`/`carry`/`open`/
|
|
312
312
|
* CC parity 20/200 一个都不抄):上游改缺省之日起本仓不会成为第二份真源。
|
|
313
313
|
*/
|
|
314
|
-
export type DeploymentPostureSeats = Pick<RunnerDeps, "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry" | "writeProtectedPaths" | "allowedTools">;
|
|
315
|
-
/** 本族读的配置切面:席名与 config 键同名的那几席 + 运维 allow 表(席 `allowedTools` ← config `approvalGrant`,env 名 `APPROVAL_GRANT` 不改)
|
|
316
|
-
|
|
314
|
+
export type DeploymentPostureSeats = Pick<RunnerDeps, "readFace" | "readDenyPatterns" | "readDenyBuiltinTiers" | "readDenyBuiltinExclude" | "memoryDelegationEvidence" | "memoryProvenance" | "memoryCapturePolicy" | "delegationEntryCaps" | "crossSessionInbound" | "crossSessionDialogExpiry" | "writeProtectedPaths" | "allowedTools" | "agentConfigDir">;
|
|
315
|
+
/** 本族读的配置切面:席名与 config 键同名的那几席 + 运维 allow 表(席 `allowedTools` ← config `approvalGrant`,env 名 `APPROVAL_GRANT` 不改)
|
|
316
|
+
* + LKG 覆写路径(`readDenyPatterns` 席并入它派生的读拒行,`lkgReadDenyRows`)。 */
|
|
317
|
+
export type DeploymentPostureConfig = Pick<ServiceConfig, Exclude<keyof DeploymentPostureSeats, "allowedTools"> | "approvalGrant" | "configLkgPath">;
|
|
317
318
|
export declare function buildDeploymentPostureSeats(config: DeploymentPostureConfig): DeploymentPostureSeats;
|
|
318
319
|
export declare function createSharedRunnerDeps(ctx: SharedRunnerDepsCtx): SharedRunnerDeps;
|
|
319
320
|
export declare function createRunnerDeps(ctx: RunnerDepsCtx): RunnerDeps;
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createFileWorkflowScriptStore } from "@sema-agent/core";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { listCollabWorkflows, resolveCollabWorkflow } from "../capabilities/collab-workflows.js";
|
|
4
|
+
import { lkgReadDenyRows } from "../config-lkg.js";
|
|
4
5
|
import { fleetBackgroundChildPublisher, FleetEventBus } from "../fleet/fleet-bus.js";
|
|
5
6
|
import { createMemoryEngineIncidentSink } from "../memory-incident-sink.js";
|
|
6
7
|
import { createMemorySessionIncarnationSeat, sessionFaceReaderOf } from "./session-incarnation-seat.js";
|
|
@@ -9,7 +10,7 @@ import { createHardenedVmRunner } from "../orchestration/hardened-vm-runner.js";
|
|
|
9
10
|
import { createWorkerHardenedVmRunner } from "../orchestration/hardened-vm-worker-runner.js";
|
|
10
11
|
import { WorkflowAgentRegistry } from "../orchestration/workflow-agent-steer.js";
|
|
11
12
|
import { resolveServedSession } from "../orchestration/workflow-completion-inbox.js";
|
|
12
|
-
import { defaultEngineNoticeRouter,
|
|
13
|
+
import { defaultEngineNoticeRouter, redactNoticeRuleText } from "../trace/engine-notice-wire.js";
|
|
13
14
|
import { WorkflowNotifyGate } from "../orchestration/workflow-notify-journal.js";
|
|
14
15
|
import { makeLoadProjectMemory, makeProbeInstructionSources } from "../project-memory.js";
|
|
15
16
|
import { createInstructionSourceSeat } from "../instruction-source-notice.js";
|
|
@@ -41,7 +42,7 @@ const PROMPT_CACHE_BREAK_LEVELS = new Map(Object.entries(PROMPT_CACHE_BREAK_CAUS
|
|
|
41
42
|
const CEILING_ORIGINS = new Set(["walltime", "turns"]);
|
|
42
43
|
export function createEngineNoticeForwarder(logger, router = defaultEngineNoticeRouter, metrics) {
|
|
43
44
|
return (notice) => {
|
|
44
|
-
const detail =
|
|
45
|
+
const detail = redactNoticeRuleText(notice.code, notice.detail);
|
|
45
46
|
logger.warn("engine_notice", { code: notice.code, message: notice.message, ...(detail !== undefined ? { detail } : {}) });
|
|
46
47
|
if (metrics !== undefined && notice.code === "task.interrupt_unconsumed") {
|
|
47
48
|
const origin = notice.detail?.origin;
|
|
@@ -57,11 +58,14 @@ export function createEngineNoticeSeat(logger, router = defaultEngineNoticeRoute
|
|
|
57
58
|
}
|
|
58
59
|
export function buildDeploymentPostureSeats(config) {
|
|
59
60
|
const crossSessionLayers = buildCrossSessionInboundLayers(config);
|
|
61
|
+
const lkgRows = lkgReadDenyRows(config.configLkgPath);
|
|
62
|
+
const readDenyAdditions = lkgRows.length === 0 ? config.readDenyPatterns : [...(config.readDenyPatterns ?? []), ...lkgRows];
|
|
60
63
|
const seats = {
|
|
61
64
|
readFace: config.readFace ? config.readFace : undefined,
|
|
62
|
-
readDenyPatterns:
|
|
65
|
+
readDenyPatterns: readDenyAdditions ? readDenyAdditions : undefined,
|
|
63
66
|
readDenyBuiltinTiers: config.readDenyBuiltinTiers ?? undefined,
|
|
64
67
|
readDenyBuiltinExclude: config.readDenyBuiltinExclude ?? undefined,
|
|
68
|
+
agentConfigDir: config.agentConfigDir ?? undefined,
|
|
65
69
|
memoryDelegationEvidence: config.memoryDelegationEvidence ?? undefined,
|
|
66
70
|
memoryProvenance: config.memoryProvenance ?? undefined,
|
|
67
71
|
memoryCapturePolicy: config.memoryCapturePolicy ?? undefined,
|
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -26,11 +26,12 @@ import type { Logger } from "../observability/logger.js";
|
|
|
26
26
|
import type { startOtlpExporter } from "../observability/otel-exporter.js";
|
|
27
27
|
import type { CostQuota } from "../observability/cost-quota.js";
|
|
28
28
|
import type { RateLimiter } from "../observability/rate-limit.js";
|
|
29
|
-
import type {
|
|
29
|
+
import type { startFleetClientFromConfig } from "../fleet-client.js";
|
|
30
30
|
import type { BreakerStateStore, CostQuotaStore, RateLimiterStore, StoreBackend } from "../plugins/store-backend.js";
|
|
31
31
|
import type { WorkflowNotifyJournalStore } from "../orchestration/workflow-notify-journal.js";
|
|
32
32
|
import type { ToolApprovalCoordinator } from "../tool-approval.js";
|
|
33
33
|
import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
34
|
+
import { type DrainState } from "../fleet/drain-entry.js";
|
|
34
35
|
export interface ShutdownCtx {
|
|
35
36
|
config: ServiceConfig;
|
|
36
37
|
/** [ref]①:崩溃遗言的 version 键(与 /v1/capabilities.version 同源=main 的 serviceVersion())。 */
|
|
@@ -61,16 +62,10 @@ export interface ShutdownCtx {
|
|
|
61
62
|
subRunner: Runner;
|
|
62
63
|
lspManager: RunnerDeps["lspManager"];
|
|
63
64
|
workflowNotifyJournal: WorkflowNotifyJournalStore | undefined;
|
|
64
|
-
fleetClient: ReturnType<typeof
|
|
65
|
+
fleetClient: ReturnType<typeof startFleetClientFromConfig>;
|
|
65
66
|
backend: StoreBackend | undefined;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
since?: number;
|
|
69
|
-
inflight?: () => number;
|
|
70
|
-
lastActivityAt?: () => number;
|
|
71
|
-
attachedStreams?: () => number;
|
|
72
|
-
lastAttachEndedAt?: () => number;
|
|
73
|
-
};
|
|
67
|
+
/** 编排器片 2 件 2:共享排空盒子(`fleet/drain-entry.ts`)—— 本函数往上装**唯一**入口 `enter`。 */
|
|
68
|
+
drainState: DrainState;
|
|
74
69
|
/** [ref]-2:store 活体探针(main 建)——不停的话 hardShutdown 后仍对正在关闭的池发探针,刷假
|
|
75
70
|
* store_probe_dead 告警(文件头契约 3 的同族漏网)。缺席 = 该部署形没建探针。 */
|
|
76
71
|
storeLiveProbe: {
|
|
@@ -95,6 +90,10 @@ export interface ShutdownCtx {
|
|
|
95
90
|
/** S-929 F1:checkpoint 店的 park 提交观察层(`plugins/park-commit-watch.ts`;在场 ⇔ 本部署有 checkpoint 店)。hardShutdown 在
|
|
96
91
|
* `backend.close()` 之前等它 quiesce —— 在飞的 `put`(审批 park / 资源挂起…,与审批协调器在不在场无关)不许被抽掉连接池。 */
|
|
97
92
|
parkCommits: ParkCommitWatch | undefined;
|
|
93
|
+
/** 编排器片 2 件 3:服务租约客户端(在场 ⇔ fleet 成员 ∧ 中心车道配齐)。hardShutdown 起点停它的续租定时器(文件头契约 3 同族)。 */
|
|
94
|
+
servingLease?: {
|
|
95
|
+
stop(): void;
|
|
96
|
+
} | undefined;
|
|
98
97
|
}
|
|
99
98
|
/**
|
|
100
99
|
* 受控退的**后台宽限**还要等多久(ms)—— hardShutdown 软停后台 shell 之后、`process.exit` 之前,给软停过的行**一次**
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -8,14 +8,16 @@ import { installProcessExitBoundary } from "./exit-boundary.js";
|
|
|
8
8
|
import { createEngineLeaseTracker } from "./engine-lease.js";
|
|
9
9
|
import { writeExitLast, readExitLast, clearExitLast } from "./exit-last.js";
|
|
10
10
|
import { isScriptRealmRejection, describeRejectionReason } from "../orchestration/hardened-vm-runner.js";
|
|
11
|
+
import { DRAIN_CAUSE_COUNTS_AS_FIRST_STOP_SIGNAL, HARD_STOP_ACTION_ID } from "../fleet/drain-entry.js";
|
|
11
12
|
const HARD_STOP_GRACE_MS = 10_000;
|
|
13
|
+
const FINAL_EXIT_MS = 15_000;
|
|
12
14
|
export function backgroundGraceRemainingMs(a) {
|
|
13
15
|
if (a.softStopped <= 0)
|
|
14
16
|
return 0;
|
|
15
17
|
return Math.max(0, Math.min(a.softStoppedAt + a.graceMs, a.deadlineMs) - a.now);
|
|
16
18
|
}
|
|
17
19
|
export function installShutdownHandlers(ctx) {
|
|
18
|
-
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, toolApproval, parkCommits, } = ctx;
|
|
20
|
+
const { config, logger, server, reaper, fleetReconcile, retentionLane, releaseRetentionLease, otelExporter, breakerState, costQuota, rateLimiter, runner, subRunner, lspManager, workflowNotifyJournal, fleetClient, backend, drainState, storeLiveProbe, configCenter, version, deviceHub, toolApproval, parkCommits, servingLease, } = ctx;
|
|
19
21
|
const dataRoot = config.localDataRoot;
|
|
20
22
|
if (dataRoot) {
|
|
21
23
|
const prior = readCrashLast(dataRoot);
|
|
@@ -69,12 +71,14 @@ export function installShutdownHandlers(ctx) {
|
|
|
69
71
|
};
|
|
70
72
|
process.on("unhandledRejection", onUnhandledRejection);
|
|
71
73
|
let closing = false;
|
|
74
|
+
let closingAt = 0;
|
|
72
75
|
let parentWatch;
|
|
73
76
|
let engineLease;
|
|
74
77
|
const hardShutdown = () => {
|
|
75
78
|
if (closing)
|
|
76
79
|
return;
|
|
77
80
|
closing = true;
|
|
81
|
+
closingAt = Date.now();
|
|
78
82
|
if (dataRoot)
|
|
79
83
|
clearCrashLast(dataRoot);
|
|
80
84
|
const graceDeadlineMs = Date.now() + HARD_STOP_GRACE_MS;
|
|
@@ -101,6 +105,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
101
105
|
parentWatch?.stop();
|
|
102
106
|
engineLease?.stop();
|
|
103
107
|
storeLiveProbe?.stop();
|
|
108
|
+
servingLease?.stop();
|
|
104
109
|
void deviceHub?.close().catch((err) => logger.warn("device_hub_close_failed", { err: String(err) }));
|
|
105
110
|
configCenter?.stopRefreshLoop();
|
|
106
111
|
otelExporter?.stop();
|
|
@@ -133,7 +138,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
133
138
|
.finally(() => backgroundGrace)
|
|
134
139
|
.finally(() => process.exit(0));
|
|
135
140
|
});
|
|
136
|
-
const finalExit = setTimeout(() => { logger.warn("hard_shutdown_final_deadline", { afterMs:
|
|
141
|
+
const finalExit = setTimeout(() => { logger.warn("hard_shutdown_final_deadline", { afterMs: FINAL_EXIT_MS }); process.exit(0); }, FINAL_EXIT_MS);
|
|
137
142
|
finalExit.unref?.();
|
|
138
143
|
server.closeIdleConnections?.();
|
|
139
144
|
const forceClose = setTimeout(() => server.closeAllConnections?.(), HARD_STOP_GRACE_MS);
|
|
@@ -141,36 +146,67 @@ export function installShutdownHandlers(ctx) {
|
|
|
141
146
|
};
|
|
142
147
|
let draining = false;
|
|
143
148
|
let drainStartedAt = 0;
|
|
149
|
+
let firstStopSignalAt;
|
|
144
150
|
let drainTick;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
let current;
|
|
152
|
+
const enterDrain = (entry, bySignal = false, at = Date.now()) => {
|
|
153
|
+
if (current !== undefined)
|
|
154
|
+
return { ...current, state: "already_draining" };
|
|
155
|
+
if (closing)
|
|
156
|
+
return { actionId: HARD_STOP_ACTION_ID, since: closingAt, deadlineAt: closingAt + FINAL_EXIT_MS, state: "already_draining" };
|
|
148
157
|
draining = true;
|
|
149
158
|
drainStartedAt = performance.now();
|
|
159
|
+
firstStopSignalAt = bySignal ? drainStartedAt : undefined;
|
|
160
|
+
const since = at;
|
|
161
|
+
current = { actionId: entry.actionId, since, deadlineAt: entry.deadlineAt };
|
|
150
162
|
drainState.draining = true;
|
|
151
|
-
|
|
152
|
-
drainState.
|
|
163
|
+
drainState.since = since;
|
|
164
|
+
drainState.actionId = entry.actionId;
|
|
165
|
+
drainState.deadlineAt = entry.deadlineAt;
|
|
166
|
+
const windowMs = Math.max(0, entry.deadlineAt - since);
|
|
167
|
+
const deadlineMono = drainStartedAt + windowMs;
|
|
168
|
+
deviceHub?.beginDrain({ graceMs: () => windowMs });
|
|
169
|
+
drainState.yieldInflight?.();
|
|
170
|
+
toolApproval?.beginDrain();
|
|
153
171
|
void fleetClient?.announceNow();
|
|
154
172
|
const inflight = drainState.inflight?.() ?? 0;
|
|
155
|
-
logger.info("draining_started", { inflight,
|
|
173
|
+
logger.info("draining_started", { actionId: entry.actionId, inflight, deadlineAt: entry.deadlineAt, windowMs });
|
|
156
174
|
if (inflight === 0) {
|
|
157
175
|
hardShutdown();
|
|
158
|
-
return;
|
|
176
|
+
return { ...current, state: "draining" };
|
|
159
177
|
}
|
|
160
178
|
const tick = setInterval(() => {
|
|
161
179
|
const n = drainState.inflight?.() ?? 0;
|
|
162
|
-
const
|
|
163
|
-
if (n === 0 ||
|
|
180
|
+
const now = performance.now();
|
|
181
|
+
if (n === 0 || now >= deadlineMono) {
|
|
164
182
|
clearInterval(tick);
|
|
165
183
|
drainTick = undefined;
|
|
166
|
-
logger.info("drain_complete", { inflight: n, elapsedMs:
|
|
184
|
+
logger.info("drain_complete", { actionId: entry.actionId, inflight: n, elapsedMs: Math.round(now - drainStartedAt), timedOut: n > 0 });
|
|
167
185
|
hardShutdown();
|
|
168
186
|
}
|
|
169
187
|
}, 1_000);
|
|
170
188
|
drainTick = tick;
|
|
189
|
+
return { ...current, state: "draining" };
|
|
190
|
+
};
|
|
191
|
+
const drainOnCause = (cause) => {
|
|
192
|
+
const at = Date.now();
|
|
193
|
+
enterDrain({ actionId: cause, deadlineAt: at + config.drainGraceMs }, DRAIN_CAUSE_COUNTS_AS_FIRST_STOP_SIGNAL[cause], at);
|
|
171
194
|
};
|
|
195
|
+
const enterByRequest = (entry) => enterDrain(entry);
|
|
196
|
+
drainState.enter = enterByRequest;
|
|
172
197
|
const onStopSignalWhileDraining = (signal) => {
|
|
173
|
-
const
|
|
198
|
+
const now = performance.now();
|
|
199
|
+
if (firstStopSignalAt === undefined) {
|
|
200
|
+
firstStopSignalAt = now;
|
|
201
|
+
logger.info("drain_signal_after_request_drain_ignored", {
|
|
202
|
+
signal,
|
|
203
|
+
actionId: current?.actionId,
|
|
204
|
+
deadlineAt: current?.deadlineAt,
|
|
205
|
+
note: "this drain was entered by a drain request / lease denial / self-exit and its deadline is fixed — the first stop signal does not shorten it; a second stop signal at least DRAIN_SECOND_SIGNAL_MIN_GAP_MS later hard-stops",
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const sinceFirst = now - firstStopSignalAt;
|
|
174
210
|
const minGapMs = config.drainSecondSignalMinGapMs;
|
|
175
211
|
if (sinceFirst < minGapMs) {
|
|
176
212
|
logger.info("drain_duplicate_signal_ignored", { signal, sinceFirstMs: Math.floor(sinceFirst), minGapMs });
|
|
@@ -180,7 +216,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
180
216
|
hardShutdown();
|
|
181
217
|
};
|
|
182
218
|
const firstStopSignal = {
|
|
183
|
-
SIGTERM:
|
|
219
|
+
SIGTERM: () => drainOnCause("signal:SIGTERM"),
|
|
184
220
|
SIGINT: hardShutdown,
|
|
185
221
|
};
|
|
186
222
|
const onStopSignal = (signal) => {
|
|
@@ -200,7 +236,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
200
236
|
inflight: () => drainState.inflight?.() ?? 0,
|
|
201
237
|
lastActivityAt: () => drainState.lastActivityAt?.() ?? 0,
|
|
202
238
|
isStopped: () => closing || draining,
|
|
203
|
-
escalate:
|
|
239
|
+
escalate: () => drainOnCause("signal:SIGHUP"),
|
|
204
240
|
shutdown: hardShutdown,
|
|
205
241
|
idleGraceMs: config.sighupIdleGraceMs,
|
|
206
242
|
log: (event, fields) => logger.info(event, fields),
|
|
@@ -231,7 +267,7 @@ export function installShutdownHandlers(ctx) {
|
|
|
231
267
|
selfExit: (report) => {
|
|
232
268
|
if (dataRoot)
|
|
233
269
|
writeExitLast(dataRoot, { version, ...report });
|
|
234
|
-
|
|
270
|
+
drainOnCause("self-exit:attachment");
|
|
235
271
|
},
|
|
236
272
|
lingerMs: config.engineAutoExit ? config.engineLingerMs : Number.POSITIVE_INFINITY,
|
|
237
273
|
...(config.parentPid !== undefined
|
|
@@ -259,6 +295,8 @@ export function installShutdownHandlers(ctx) {
|
|
|
259
295
|
}
|
|
260
296
|
parentWatch?.stop();
|
|
261
297
|
engineLease?.stop();
|
|
298
|
+
if (drainState.enter === enterByRequest)
|
|
299
|
+
drainState.enter = undefined;
|
|
262
300
|
},
|
|
263
301
|
};
|
|
264
302
|
}
|
|
@@ -13,6 +13,7 @@ import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub
|
|
|
13
13
|
import { setRunTerminalLogObserver } from "../observability/run-terminal.js";
|
|
14
14
|
import { setRedactionObserver } from "../trace/redact.js";
|
|
15
15
|
import { installOutboundDispatcher } from "../outbound-dispatcher.js";
|
|
16
|
+
import { provisionSemaConfigDir } from "../sema-config-dir.js";
|
|
16
17
|
export function runStage01() {
|
|
17
18
|
const config = loadConfig();
|
|
18
19
|
const runStaleFailure = crossInvariant("run-stale-heartbeat").check({ live: config, next: config });
|
|
@@ -44,6 +45,7 @@ export function runStage01() {
|
|
|
44
45
|
else
|
|
45
46
|
logger.info("run_failed", fields);
|
|
46
47
|
});
|
|
48
|
+
provisionSemaConfigDir(config, logger);
|
|
47
49
|
const localRoot = configLocalRoot(config);
|
|
48
50
|
const rootsSplit = splitLocalRoots({
|
|
49
51
|
localDataRoot: config.localDataRoot,
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import type { runStage08 } from "./stage-08-reapers.js";
|
|
2
|
+
import type { DrainState } from "../fleet/drain-entry.js";
|
|
2
3
|
export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>): {
|
|
3
|
-
drainState:
|
|
4
|
-
draining: boolean;
|
|
5
|
-
since?: number;
|
|
6
|
-
reason?: string;
|
|
7
|
-
inflight?: () => number;
|
|
8
|
-
lastActivityAt?: () => number;
|
|
9
|
-
attachedStreams?: () => number;
|
|
10
|
-
lastAttachEndedAt?: () => number;
|
|
11
|
-
};
|
|
4
|
+
drainState: DrainState;
|
|
12
5
|
hookWakeBus: {
|
|
13
6
|
deliver?: (sessionId: string, text: string) => Promise<boolean>;
|
|
14
7
|
};
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import type { runStage09 } from "./stage-09-leader.js";
|
|
2
2
|
export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>): Promise<{
|
|
3
|
-
drainState:
|
|
4
|
-
draining: boolean;
|
|
5
|
-
since?: number;
|
|
6
|
-
reason?: string;
|
|
7
|
-
inflight?: () => number;
|
|
8
|
-
lastActivityAt?: () => number;
|
|
9
|
-
attachedStreams?: () => number;
|
|
10
|
-
lastAttachEndedAt?: () => number;
|
|
11
|
-
};
|
|
3
|
+
drainState: import("../fleet/drain-entry.js").DrainState;
|
|
12
4
|
hookWakeBus: {
|
|
13
5
|
deliver?: (sessionId: string, text: string) => Promise<boolean>;
|
|
14
6
|
};
|
|
@@ -13,9 +13,11 @@ import { SQL_BLOB_DEFAULT_MAX_BYTES } from "../plugins/blob-backend.js";
|
|
|
13
13
|
import { createStoreLiveProbe } from "../store-live-probe.js";
|
|
14
14
|
import { counterStoreLabel } from "../plugins/store-backend.js";
|
|
15
15
|
import { sessionStoreLabelOf } from "../store-posture.js";
|
|
16
|
-
import {
|
|
16
|
+
import { startFleetClientFromConfig } from "../fleet-client.js";
|
|
17
17
|
import { createCenterWiringReader } from "../capabilities/center-wiring.js";
|
|
18
|
-
import {
|
|
18
|
+
import { mintEngineSignal } from "../fleet/engine-signal.js";
|
|
19
|
+
import { createServingLeaseClient } from "../fleet/serving-lease.js";
|
|
20
|
+
import { fleetFenceLaneOf } from "../config.js";
|
|
19
21
|
import { createResolveSpec } from "./resolve-spec.js";
|
|
20
22
|
import { executionLaneOf } from "../execution-lane-caps.js";
|
|
21
23
|
import { startFleetReconciler } from "../fleet/fleet-reconciler.js";
|
|
@@ -133,6 +135,24 @@ export async function runStage10(ctx) {
|
|
|
133
135
|
const storeLiveProbe = backend && backend.kind !== "local" && backend.dbNowMs && config.storeProbeIntervalMs > 0
|
|
134
136
|
? createStoreLiveProbe({ probe: () => backend.dbNowMs(), intervalMs: config.storeProbeIntervalMs, logger })
|
|
135
137
|
: undefined;
|
|
138
|
+
const fenceLane = fleetFenceLaneOf(config);
|
|
139
|
+
const servingLease = fenceLane !== undefined
|
|
140
|
+
? createServingLeaseClient({
|
|
141
|
+
center: fenceLane.center,
|
|
142
|
+
generation: fenceLane.generation,
|
|
143
|
+
instanceId,
|
|
144
|
+
dataRoot: config.localDataRoot,
|
|
145
|
+
outageMaxMs: config.fleetLeaseOutageMaxMs,
|
|
146
|
+
drain: (entry) => {
|
|
147
|
+
const enter = drainState.enter;
|
|
148
|
+
if (enter === undefined)
|
|
149
|
+
throw new Error("serving lease denied before the drain entry was installed — refusing to keep serving without a drain");
|
|
150
|
+
enter(entry);
|
|
151
|
+
},
|
|
152
|
+
drainWindowMs: () => config.drainGraceMs,
|
|
153
|
+
logger: { info: (m, d) => logger.info(m, d ?? {}), warn: (m, d) => logger.warn(m, d ?? {}), error: (m, d) => logger.error(m, d ?? {}) },
|
|
154
|
+
})
|
|
155
|
+
: undefined;
|
|
136
156
|
const deployment = {
|
|
137
157
|
sessionStoreLabel: sessionStoreLabelOf(config.sessionBackend, backend?.kind),
|
|
138
158
|
modelReady: () => configCenter.modelReady(),
|
|
@@ -154,15 +174,16 @@ export async function runStage10(ctx) {
|
|
|
154
174
|
},
|
|
155
175
|
},
|
|
156
176
|
restartState: () => configCenter.restartState(),
|
|
157
|
-
planeDeferredState: () => configCenter.planeDeferredState(),
|
|
158
177
|
configApplyState: () => configCenter.configApplyState(),
|
|
159
178
|
centerCredentialState: () => configCenter.centerCredentialState(),
|
|
160
179
|
modelRefusalsState: () => configCenter.modelRefusalsState(),
|
|
180
|
+
configHandoffState: () => configCenter.configHandoffState(),
|
|
161
181
|
mcpRevocations,
|
|
162
182
|
mcpRevocationState: () => configCenter.mcpRevocationState(),
|
|
163
183
|
configRefreshNow: () => configCenter.refreshNow(),
|
|
164
184
|
configCenterManagedKeys: () => configCenter.centerManagedKeys(),
|
|
165
185
|
drainState,
|
|
186
|
+
servingLease: servingLease ? () => servingLease.view() : undefined,
|
|
166
187
|
storePosture,
|
|
167
188
|
centerWiring: createCenterWiringReader({ config, pullState: () => configCenter.centerPullState(), fleetLease, usageReport: fleetUsage !== undefined }),
|
|
168
189
|
storeLiveState: storeLiveProbe ? () => storeLiveProbe.state() : undefined,
|
|
@@ -244,19 +265,19 @@ export async function runStage10(ctx) {
|
|
|
244
265
|
...("code" in e ? { code: String(e.code) } : {}),
|
|
245
266
|
});
|
|
246
267
|
});
|
|
247
|
-
const fleetClient =
|
|
268
|
+
const fleetClient = startFleetClientFromConfig(config, {
|
|
248
269
|
instanceId,
|
|
249
270
|
version: serviceVersion(),
|
|
250
|
-
|
|
251
|
-
restart: () => deployment.restartState?.(),
|
|
271
|
+
signal: () => mintEngineSignal({ ...deployment, config }),
|
|
252
272
|
modelRefusals: () => deployment.modelRefusalsState?.(),
|
|
273
|
+
...(servingLease ? { onCenterCapabilities: (caps) => servingLease.noteCenterCapabilities(caps) } : {}),
|
|
253
274
|
...(fleetUsage ? { usage: fleetUsage } : {}),
|
|
254
275
|
logger: { info: (m, d) => logger.info(m, d ?? {}), warn: (m, d) => logger.warn(m, d ?? {}) },
|
|
255
276
|
});
|
|
256
277
|
configCenter.onSelfReportChange(() => void fleetClient?.announceNow());
|
|
257
278
|
if (fleetClient) {
|
|
258
|
-
const advertised =
|
|
259
|
-
logger.info("fleet_client_started", { worker: config.configCenter?.worker, usageReport: fleetUsage !== undefined, announce: advertised !==
|
|
279
|
+
const advertised = config.fleetAdvertiseAddress;
|
|
280
|
+
logger.info("fleet_client_started", { worker: config.configCenter?.worker, usageReport: fleetUsage !== undefined, announce: advertised !== undefined, ...(advertised !== undefined ? { address: buildDisplaySafeUrl(advertised) } : {}) });
|
|
260
281
|
}
|
|
261
282
|
const failoverFirstByte = buildFailoverFirstByteNotice(config);
|
|
262
283
|
if (failoverFirstByte)
|
|
@@ -310,7 +331,9 @@ export async function runStage10(ctx) {
|
|
|
310
331
|
deviceHub: deviceLane?.hub,
|
|
311
332
|
retentionLane: retentionLaneStarted,
|
|
312
333
|
releaseRetentionLease: retentionLaneStore !== undefined ? () => retentionLaneStore.release(instanceId) : undefined,
|
|
334
|
+
servingLease,
|
|
313
335
|
});
|
|
336
|
+
servingLease?.resumeStickyDenial();
|
|
314
337
|
return { ...ctx };
|
|
315
338
|
}
|
|
316
339
|
//# sourceMappingURL=stage-10-http-server.js.map
|
|
@@ -1,19 +1,42 @@
|
|
|
1
|
-
import type { SubagentSpawnContext, ToolSpec } from "@sema-agent/core";
|
|
1
|
+
import type { SubagentSpawnContext, SubagentToolOptions, ToolSpec } from "@sema-agent/core";
|
|
2
2
|
/** Current time — the model has no clock; OA/most tasks need it. No side effects. CC-parity tool name `Now`
|
|
3
3
|
* (PascalCase, core 1.176 first-party rename wrap-up — the SERVICE owns this one; `nowTool` is not a core tool).
|
|
4
4
|
* effect:"read" so it never suspends → no durable-resume rename strand (no pending-tool checkpoint to canonicalize). */
|
|
5
5
|
export declare function nowTool(): ToolSpec;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 委派子代逐次注入的**一组**工具:`tools` 是这组**可能**注入的全部工具对象,`forSpawn` 只在这些对象里选「这一次 spawn 拿不拿」(缺席 = 每次都拿)。
|
|
8
|
+
* 名册与工厂读的是同一张 `tools` —— 工厂只能交出名册里那几只对象,结构上交不出名册外的东西(core 7.46.0 #1432 的「声明不说谎」在本仓由形状保证,
|
|
9
|
+
* 不靠两张表对拍)。
|
|
10
|
+
*/
|
|
11
|
+
export interface SubagentExtraToolSet {
|
|
12
|
+
readonly tools: readonly ToolSpec[];
|
|
13
|
+
readonly forSpawn?: (ctx: SubagentSpawnContext) => boolean;
|
|
14
|
+
}
|
|
15
|
+
/** 委派工具上与逐次注入相关的两键(core `SubagentToolOptions` 的 `extraTools` / `extraToolNames`):工厂(本仓的恒同步)+ 它的名册。 */
|
|
16
|
+
export interface SubagentExtraToolOptions {
|
|
17
|
+
readonly extraTools: (ctx: SubagentSpawnContext) => ToolSpec[];
|
|
18
|
+
readonly extraToolNames: NonNullable<SubagentToolOptions["extraToolNames"]>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* #1110(core 7.32.0)—— 委派子代的**逐次注入**:`Now` + 部署的 extra tools(今天 = SendUserFile)。
|
|
8
22
|
*
|
|
9
23
|
* 为什么 `Now` 走这条通道:core 7.32.0 起子代按**身份**继承场景层 bundle 的工具(`assembleCodeTools` 交给 Agent 的
|
|
10
24
|
* `inheritedTools` ∩ 父 run 真挂载),而 `Now` 是本仓在 bundle **旁边**组的宿主工具(scenarios.ts),宿主工具**从不**被继承
|
|
11
25
|
* (core:继承整张 `spec.tools` 会把宿主工具带过宿主自己的逐次门)—— 逐次注入是它到达子代的唯一通道。一个工厂、两个产地:
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
26
|
+
* 部署那一组的门(只读内建排除)在它自己的 `forSpawn` 里,这里只做合成。
|
|
27
|
+
*
|
|
28
|
+
* core 7.46.0 #1432 —— **工厂与名册一个来源**:返回委派工具的两键,`extraTools`(每次 spawn 交出 `forSpawn` 选中的那几只)与
|
|
29
|
+
* `extraToolNames`(全部可能交出的那几只的名字 / 别名 / 内容来源,从同一批 `ToolSpec` 读出)。名册在场 ⇒ 引擎重新能列出子代的工具池:
|
|
30
|
+
* 定义级 / 工具级 / `TaskSpec.agents` 清单里的退役拼法与大小写孪生回到开跑前拒(`config.agent.unknown_tool`),记忆内容来源读者按声明读这几只。
|
|
31
|
+
* 修前(core 7.32.0–7.45.x)工厂恒在场 ⇒ 池不可静态知 ⇒ 那一族拼法只告不拒、委派结果一律按「外部」读。
|
|
32
|
+
* 工厂**不抛**:各组的 `tools` 是装配期就建好的对象;部署 `forSpawn` 的抛由 core 收成「这一 spawn 什么都不继承 + 模型面披露句」(onExtraToolsError 记 warn)。
|
|
33
|
+
* 一种拼法出现在两只工具上(部署工具与 `Now` 撞名 / 别名撞)⇒ core 在建委派工具处抛 `config.extra_tool_names`(`shape`),不静默取其一。
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSubagentExtraTools(deployment?: SubagentExtraToolSet): SubagentExtraToolOptions;
|
|
36
|
+
/**
|
|
37
|
+
* `onExtraToolsError` 收到的错误 → 运维行 `subagent_extra_tools_error` 的字段:句子,加上错误**自带**的码与 `detail.reason`(在场才铸)。
|
|
38
|
+
* core 7.46.0 #1432 被拒的 spawn(产物不在名册里)带 `config.extra_tool_names` + `undeclared_name` / `undeclared_origin`;部署工厂自己抛的错多半两位都不带。
|
|
39
|
+
* 本仓不按码分支、不重铸 —— 只把错误说的话原样过境到运维面(修前只记句子,码与原因词丢在这一跳)。
|
|
17
40
|
*/
|
|
18
|
-
export declare function
|
|
41
|
+
export declare function extraToolsErrorFields(err: unknown): Record<string, unknown>;
|
|
19
42
|
//# sourceMappingURL=builtin-tools.d.ts.map
|
|
@@ -9,6 +9,27 @@ export function nowTool() {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
export function createSubagentExtraTools(deployment) {
|
|
12
|
-
|
|
12
|
+
const sets = [{ tools: [nowTool()] }, ...(deployment !== undefined ? [deployment] : [])];
|
|
13
|
+
return {
|
|
14
|
+
extraTools: (ctx) => sets.flatMap((s) => (s.forSpawn === undefined || s.forSpawn(ctx) ? [...s.tools] : [])),
|
|
15
|
+
extraToolNames: sets.flatMap((s) => s.tools).map((t) => ({
|
|
16
|
+
name: t.name,
|
|
17
|
+
...(t.aliases !== undefined ? { aliases: [...t.aliases] } : {}),
|
|
18
|
+
...(t.contentOrigin !== undefined ? { contentOrigin: t.contentOrigin } : {}),
|
|
19
|
+
})),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function extraToolsErrorFields(err) {
|
|
23
|
+
const fields = { err: err instanceof Error ? err.message : String(err) };
|
|
24
|
+
if (err === null || typeof err !== "object")
|
|
25
|
+
return fields;
|
|
26
|
+
const code = Reflect.get(err, "code");
|
|
27
|
+
if (typeof code === "string")
|
|
28
|
+
fields.code = code;
|
|
29
|
+
const detail = Reflect.get(err, "detail");
|
|
30
|
+
const reason = detail !== null && typeof detail === "object" ? Reflect.get(detail, "reason") : undefined;
|
|
31
|
+
if (typeof reason === "string")
|
|
32
|
+
fields.reason = reason;
|
|
33
|
+
return fields;
|
|
13
34
|
}
|
|
14
35
|
//# sourceMappingURL=builtin-tools.js.map
|
|
@@ -39,7 +39,7 @@ import type { NamedKeysOf } from "../request-key-closure.js";
|
|
|
39
39
|
*/
|
|
40
40
|
export declare const COMPOSITE_CAPABILITY_MEMBERS: {
|
|
41
41
|
readonly deviceExecutor: readonly ["enabled", "protocolVersion", "maxInflightPerDevice", "wsPath", "management"];
|
|
42
|
-
readonly fleet: readonly ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice"];
|
|
42
|
+
readonly fleet: readonly ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice", "leaseClient", "generationEcho"];
|
|
43
43
|
readonly memoryEngine: readonly ["backend", "vectorMode"];
|
|
44
44
|
readonly store: readonly ["declared", "backend", "durable", "degradedReason", "sql"];
|
|
45
45
|
readonly centerWiring: readonly ["effectivePull", "effectiveRevision", "lease", "leaseHealth", "failMode", "usageReport", "issuer", "caller"];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const COMPOSITE_CAPABILITY_MEMBERS = {
|
|
2
2
|
deviceExecutor: ["enabled", "protocolVersion", "maxInflightPerDevice", "wsPath", "management"],
|
|
3
|
-
fleet: ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice"],
|
|
3
|
+
fleet: ["stream", "sessionScope", "observe", "resume", "bgNotifyFailClosed", "steerPriority", "hookFailureNotice", "leaseClient", "generationEcho"],
|
|
4
4
|
memoryEngine: ["backend", "vectorMode"],
|
|
5
5
|
store: ["declared", "backend", "durable", "degradedReason", "sql"],
|
|
6
6
|
centerWiring: ["effectivePull", "effectiveRevision", "lease", "leaseHealth", "failMode", "usageReport", "issuer", "caller"],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type WebFetchConfig, type BackgroundAgentStore, type CheckpointStore, type PromptProvider, type Runner, type SkillSpec, type
|
|
1
|
+
import { type WebFetchConfig, type BackgroundAgentStore, type CheckpointStore, type PromptProvider, type Runner, type SkillSpec, type TaskListStore, type ToolSpec, type WebSearchConfig } from "@sema-agent/core";
|
|
2
2
|
import type { Metrics } from "../observability/metrics.js";
|
|
3
3
|
import type { Logger } from "../observability/logger.js";
|
|
4
|
+
import { type SubagentExtraToolSet } from "./builtin-tools.js";
|
|
4
5
|
import { type RepoReadClient } from "./repo-tools.js";
|
|
5
6
|
import { type LoadedSkill } from "./skills.js";
|
|
6
7
|
import { type ScenarioHands } from "./hands-lane.js";
|
|
@@ -90,12 +91,13 @@ export interface ScenarioDeps {
|
|
|
90
91
|
* core 1.287 `SubagentToolOptions.extraTools` seam wire-through — per-SPAWN dynamic tool injection into the
|
|
91
92
|
* delegated (Agent-tool) child roster. Deployment-injected per-task tools (today: SendUserFile — its instance is
|
|
92
93
|
* execute-time late-bound via ctx.taskId → TaskEnvRegistry, so ONE spec serves every spawn) cannot ride the
|
|
93
|
-
* ASSEMBLY-time static `subagent.tools` pool;
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
94
|
+
* ASSEMBLY-time static `subagent.tools` pool; core evaluates the factory at each spawn and merges its product into the
|
|
95
|
+
* pool, then it goes through core's `resolveToolSubset` whitelist like any other tool (agent-def allowTools/denyTools
|
|
96
|
+
* still govern — no extra gate needed on our side). A SET, not a bare factory (core 7.46.0 #1432): its `tools` are both
|
|
97
|
+
* what a spawn can be handed and the roster the delegation tool declares (`extraToolNames`), so the factory cannot hand
|
|
98
|
+
* out a tool the roster does not name. Absent ⇒ the delegation tool injects `Now` alone.
|
|
97
99
|
*/
|
|
98
|
-
subagentExtraTools?:
|
|
100
|
+
subagentExtraTools?: SubagentExtraToolSet;
|
|
99
101
|
/**
|
|
100
102
|
* core 1.364 durable background agents([ref] S1,[ref] 提货单②写半场):后台子代 `a*` 行的
|
|
101
103
|
* durable 执行记录 store。**必须与 `RunnerDeps.backgroundAgentStore` 同实例**(读写双点配对,engine
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CODE_AGENT_PROMPT, CODE_SYSTEM_PROMPT, DEFAULT_SYSTEM_PROMPT, WEB_FETCH_TOOL_NAME, assembleCodeTools, defaultTaskRegistry } from "@sema-agent/core";
|
|
2
2
|
import { HttpError, createCodedHttpError } from "../security.js";
|
|
3
|
-
import { createSubagentExtraTools, nowTool } from "./builtin-tools.js";
|
|
3
|
+
import { createSubagentExtraTools, extraToolsErrorFields, nowTool } from "./builtin-tools.js";
|
|
4
4
|
import { parseRepo, repoToolsFor } from "./repo-tools.js";
|
|
5
5
|
import { createCouncilTool, clampRounds } from "./code-review-council.js";
|
|
6
6
|
import { stablePrompt } from "./prompt.js";
|
|
@@ -70,9 +70,9 @@ export function buildScenarios(deps) {
|
|
|
70
70
|
...(deps.checkpointStore ? { checkpointStore: deps.checkpointStore } : {}),
|
|
71
71
|
...(deps.ensureChildSessionDurable ? { ensureChildSessionDurable: deps.ensureChildSessionDurable } : {}),
|
|
72
72
|
},
|
|
73
|
-
|
|
73
|
+
...createSubagentExtraTools(deps.subagentExtraTools),
|
|
74
74
|
...(deps.logger
|
|
75
|
-
? { onExtraToolsError: (err, info) => deps.logger?.warn?.("subagent_extra_tools_error", { ...info,
|
|
75
|
+
? { onExtraToolsError: (err, info) => deps.logger?.warn?.("subagent_extra_tools_error", { ...info, ...extraToolsErrorFields(err) }) }
|
|
76
76
|
: {}),
|
|
77
77
|
},
|
|
78
78
|
...(webSearch ? { webSearch } : {}),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ToolSpec } from "@sema-agent/core";
|
|
2
2
|
import type { IssuedFileLink } from "../plugins/send-user-file.js";
|
|
3
|
+
import type { SubagentExtraToolSet } from "./builtin-tools.js";
|
|
3
4
|
/** The frame the web/shell renders as a file card. Rides the durable events tail (replayable). */
|
|
4
5
|
export interface FileLinkFrame {
|
|
5
6
|
type: "file_link";
|
|
@@ -44,7 +45,9 @@ export declare function sendUserFileTool(deps: {
|
|
|
44
45
|
}): ToolSpec;
|
|
45
46
|
export declare const SEND_USER_FILE_TOOL_NAME = "SendUserFile";
|
|
46
47
|
/**
|
|
47
|
-
*
|
|
48
|
+
* The deployment's group for the delegated-child injection (`createSubagentExtraTools` in `builtin-tools.ts` composes it with
|
|
49
|
+
* `Now` into the delegation tool's `extraTools` factory AND its `extraToolNames` roster — one list, read twice): SendUserFile,
|
|
50
|
+
* handed to every spawn except a read-only builtin agent's.
|
|
48
51
|
*
|
|
49
52
|
* F2 (MED, codex; a product judgment of this server, kept): read-only builtin agents (Explore/Plan) must NOT get
|
|
50
53
|
* SendUserFile — a read-only agent that can read sensitive files AND mint public links off them breaks the read-only
|
|
@@ -59,5 +62,5 @@ export declare const SEND_USER_FILE_TOOL_NAME = "SendUserFile";
|
|
|
59
62
|
*/
|
|
60
63
|
export declare function subagentSendUserFileExtraTools(deps: {
|
|
61
64
|
spec: ToolSpec;
|
|
62
|
-
}):
|
|
65
|
+
}): SubagentExtraToolSet;
|
|
63
66
|
//# sourceMappingURL=send-user-file-tool.d.ts.map
|