@sema-agent/server 7.101.1 → 7.103.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 +84 -0
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/USAGE.md +156 -9
- package/dist/approval-card.d.ts +35 -2
- package/dist/approval-card.js +19 -1
- package/dist/background-session-reap.d.ts +58 -0
- package/dist/background-session-reap.js +90 -0
- package/dist/bake-runner/main.d.ts +21 -3
- package/dist/bake-runner/main.js +18 -11
- package/dist/boot/config-center.d.ts +21 -4
- package/dist/boot/config-center.js +62 -19
- package/dist/boot/exit-boundary.js +17 -0
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +3 -4
- package/dist/boot/shutdown.d.ts +2 -1
- package/dist/boot/shutdown.js +33 -12
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-07-capability-layer.js +6 -4
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +13 -4
- package/dist/brain.d.ts +28 -8
- package/dist/brain.js +20 -4
- package/dist/capabilities/builtin-tools.d.ts +14 -1
- package/dist/capabilities/builtin-tools.js +3 -0
- package/dist/capabilities/center-plugins.d.ts +9 -3
- package/dist/capabilities/center-plugins.js +5 -10
- package/dist/capabilities/scenarios.d.ts +1 -1
- package/dist/capabilities/scenarios.js +3 -3
- package/dist/center-credential-renewer.d.ts +76 -0
- package/dist/center-credential-renewer.js +359 -0
- package/dist/center-credential.d.ts +76 -22
- package/dist/center-credential.js +119 -43
- package/dist/config-catalog.js +17 -8
- package/dist/config-center/apply-effective.d.ts +16 -0
- package/dist/config-center/apply-effective.js +26 -21
- package/dist/config-center/center-request.d.ts +13 -0
- package/dist/config-center/center-request.js +23 -3
- package/dist/config-center/facade.d.ts +1 -1
- package/dist/config-center/http-client.js +2 -5
- package/dist/config-center/mcp-revocation.d.ts +2 -2
- package/dist/config-center/mcp-revocation.js +1 -1
- package/dist/config-center/read-warnings.d.ts +19 -48
- package/dist/config-center/read-warnings.js +7 -49
- package/dist/config-center/restart-signal.d.ts +8 -21
- package/dist/config-center/restart-signal.js +2 -12
- package/dist/config-center/types.d.ts +4 -2
- package/dist/config-provider.js +1 -48
- package/dist/config-types.d.ts +107 -17
- package/dist/config-types.js +7 -2
- package/dist/config.d.ts +7 -0
- package/dist/config.js +91 -29
- package/dist/device-store.d.ts +1 -1
- package/dist/env-name-allowlist-knobs.d.ts +21 -7
- package/dist/env-name-allowlist-knobs.js +7 -2
- package/dist/fleet-client.d.ts +27 -7
- package/dist/fleet-client.js +43 -12
- package/dist/fleet-lease.d.ts +1 -1
- package/dist/host-lsp-manager.d.ts +4 -3
- package/dist/host-lsp-manager.js +2 -6
- package/dist/http/approval-sweeps.js +5 -20
- package/dist/http/dispatch.js +24 -14
- package/dist/http/readiness.d.ts +87 -0
- package/dist/http/readiness.js +54 -0
- package/dist/http/resume-legs.js +5 -4
- package/dist/http/route-table.d.ts +7 -0
- package/dist/http/route-table.js +6 -0
- package/dist/http/routes/a2a-serve.js +6 -14
- package/dist/http/routes/approvals-assistant.js +1 -0
- package/dist/http/routes/background.d.ts +80 -0
- package/dist/http/routes/background.js +94 -0
- package/dist/http/routes/capabilities.js +2 -0
- package/dist/http/server.d.ts +25 -8
- package/dist/http/server.js +2 -2
- package/dist/leader/wire.d.ts +8 -1
- package/dist/leader/wire.js +4 -3
- package/dist/model-entry-refusal.d.ts +42 -19
- package/dist/model-entry-refusal.js +34 -19
- package/dist/model-route-endpoint.d.ts +10 -0
- package/dist/model-route-endpoint.js +6 -2
- package/dist/observability/fail-open.d.ts +2 -2
- package/dist/observability/fail-open.js +2 -2
- package/dist/observability/secret-env-scrub.d.ts +12 -0
- package/dist/observability/secret-env-scrub.js +12 -0
- package/dist/outbound-dispatcher.d.ts +125 -0
- package/dist/outbound-dispatcher.js +211 -0
- package/dist/parked-decide.d.ts +11 -5
- package/dist/parked-decide.js +4 -1
- package/dist/parked-revive-surface.d.ts +47 -0
- package/dist/parked-revive-surface.js +20 -0
- package/dist/plugins/background-shell-support.d.ts +20 -1
- package/dist/plugins/background-shell-support.js +26 -0
- package/dist/plugins/host-platform.d.ts +16 -1
- package/dist/plugins/host-platform.js +11 -0
- package/dist/plugins/remote-env-host.d.ts +14 -1
- package/dist/plugins/remote-env-host.js +15 -10
- package/dist/project-memory.js +3 -6
- package/dist/run-local.js +2 -0
- package/dist/server-secret-env.d.ts +97 -24
- package/dist/server-secret-env.js +37 -1
- package/dist/tool-approval.d.ts +30 -1
- package/dist/tool-approval.js +31 -8
- package/dist/trace/core-keyset-guard.d.ts +9 -4
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/project.js +13 -0
- package/dist/trace/redact.d.ts +11 -0
- package/dist/trace/redact.js +1 -0
- package/package.json +4 -3
|
@@ -4,7 +4,8 @@ import { PlanCacheProbe } from "../plan-cache-probe.js";
|
|
|
4
4
|
import { purgeScratchpadDir } from "../env-facts.js";
|
|
5
5
|
import { setLeafAdvanceListener } from "../session-leaf-bus.js";
|
|
6
6
|
import { SessionWatchRegistry, posIntEnv } from "../session-watch.js";
|
|
7
|
-
import {
|
|
7
|
+
import { peerSessionBoxHandle } from "@sema-agent/core";
|
|
8
|
+
import { reapSessionBackgroundHard } from "../background-session-reap.js";
|
|
8
9
|
export function createSessionFaces(ctx) {
|
|
9
10
|
const { config, logger, metrics, localRoot, backend, sessionStore, runStore, checkpointStore, toolResultStore, resumeAnchorStore, approvalExemptionStore, sessionPolicyStore, taskAttachmentStore, fileHistoryErasure, workflowCompletionInbox, taskListLane, deviceStore, dropSessionScoped, mailboxStore, mailboxRecipientLifecycle, } = ctx;
|
|
10
11
|
const mysqlPool = backend?.mysqlPool();
|
|
@@ -87,9 +88,7 @@ export function createSessionFaces(ctx) {
|
|
|
87
88
|
}
|
|
88
89
|
await purgeScratchpadDir(config.localDataRoot ?? localRoot, sessionId);
|
|
89
90
|
try {
|
|
90
|
-
|
|
91
|
-
if (reaped > 0)
|
|
92
|
-
logger.info("session_background_reaped", { sessionId, reaped });
|
|
91
|
+
await reapSessionBackgroundHard(sessionId, owner ?? "default", { includeRetained: false, reason: "session_deleted" }, logger);
|
|
93
92
|
}
|
|
94
93
|
catch (err) {
|
|
95
94
|
logger.warn("session_background_reap_failed", { sessionId, err: String(err) });
|
package/dist/boot/shutdown.d.ts
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* 时点即"从此刻起信号可被优雅处理";提前注册会让一个尚未 listen 的进程走 drain 分支。
|
|
10
10
|
* 2. 三个 `process.on` 的**相对次序**保持 SIGTERM → SIGINT → SIGHUP(与原文件逐字一致);
|
|
11
11
|
* 它们互不覆盖,但 handler 之间共享 `closing`/`draining` 两个 latch,次序变化会改变
|
|
12
|
-
* "第二个信号"的语义读数。
|
|
12
|
+
* "第二个信号"的语义读数。S-752 起「排空期的第二发」只有**一条**判据({@link installShutdownHandlers}
|
|
13
|
+
* 内 `onStopSignalWhileDraining`:与排空起点相隔 ≥ `drainSecondSignalMinGapMs` 才硬停),SIGTERM / SIGINT 共用。
|
|
13
14
|
* 3. `clearInterval(reaper)` 必须是 hardShutdown 的第一件事(在 `server.close()` 之前),否则
|
|
14
15
|
* 收尾期还会有 reaper tick 打向正在关闭的池。
|
|
15
16
|
* 4. **进程级监听一律成对**([ref] 二轮件4):本函数装的六只(三信号 + [ref]① 双钩 + S-557 退出边界钩
|
package/dist/boot/shutdown.js
CHANGED
|
@@ -106,16 +106,13 @@ export function installShutdownHandlers(ctx) {
|
|
|
106
106
|
forceClose.unref?.();
|
|
107
107
|
};
|
|
108
108
|
let draining = false;
|
|
109
|
+
let drainStartedAt = 0;
|
|
109
110
|
let drainTick;
|
|
110
111
|
const drainThenShutdown = () => {
|
|
111
|
-
if (closing)
|
|
112
|
-
return;
|
|
113
|
-
if (draining) {
|
|
114
|
-
logger.info("drain_second_signal_hard_stop", {});
|
|
115
|
-
hardShutdown();
|
|
112
|
+
if (closing || draining)
|
|
116
113
|
return;
|
|
117
|
-
}
|
|
118
114
|
draining = true;
|
|
115
|
+
drainStartedAt = performance.now();
|
|
119
116
|
drainState.draining = true;
|
|
120
117
|
deviceHub?.beginDrain({ graceMs: () => config.drainGraceMs });
|
|
121
118
|
drainState.since = Date.now();
|
|
@@ -126,10 +123,9 @@ export function installShutdownHandlers(ctx) {
|
|
|
126
123
|
hardShutdown();
|
|
127
124
|
return;
|
|
128
125
|
}
|
|
129
|
-
const t0 = performance.now();
|
|
130
126
|
const tick = setInterval(() => {
|
|
131
127
|
const n = drainState.inflight?.() ?? 0;
|
|
132
|
-
const elapsed = Math.round(performance.now() -
|
|
128
|
+
const elapsed = Math.round(performance.now() - drainStartedAt);
|
|
133
129
|
if (n === 0 || elapsed >= config.drainGraceMs) {
|
|
134
130
|
clearInterval(tick);
|
|
135
131
|
drainTick = undefined;
|
|
@@ -139,8 +135,33 @@ export function installShutdownHandlers(ctx) {
|
|
|
139
135
|
}, 1_000);
|
|
140
136
|
drainTick = tick;
|
|
141
137
|
};
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
const onStopSignalWhileDraining = (signal) => {
|
|
139
|
+
const sinceFirst = performance.now() - drainStartedAt;
|
|
140
|
+
const minGapMs = config.drainSecondSignalMinGapMs;
|
|
141
|
+
if (sinceFirst < minGapMs) {
|
|
142
|
+
logger.info("drain_duplicate_signal_ignored", { signal, sinceFirstMs: Math.floor(sinceFirst), minGapMs });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
logger.info("drain_second_signal_hard_stop", { signal, sinceFirstMs: Math.floor(sinceFirst) });
|
|
146
|
+
hardShutdown();
|
|
147
|
+
};
|
|
148
|
+
const firstStopSignal = {
|
|
149
|
+
SIGTERM: drainThenShutdown,
|
|
150
|
+
SIGINT: hardShutdown,
|
|
151
|
+
};
|
|
152
|
+
const onStopSignal = (signal) => {
|
|
153
|
+
if (closing)
|
|
154
|
+
return;
|
|
155
|
+
if (draining) {
|
|
156
|
+
onStopSignalWhileDraining(signal);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
firstStopSignal[signal]();
|
|
160
|
+
};
|
|
161
|
+
const onSigterm = () => onStopSignal("SIGTERM");
|
|
162
|
+
const onSigint = () => onStopSignal("SIGINT");
|
|
163
|
+
process.on("SIGTERM", onSigterm);
|
|
164
|
+
process.on("SIGINT", onSigint);
|
|
144
165
|
const onSighup = createSighupIdleHandler({
|
|
145
166
|
inflight: () => drainState.inflight?.() ?? 0,
|
|
146
167
|
lastActivityAt: () => drainState.lastActivityAt?.() ?? 0,
|
|
@@ -194,8 +215,8 @@ export function installShutdownHandlers(ctx) {
|
|
|
194
215
|
exitBoundary.dispose();
|
|
195
216
|
process.removeListener("uncaughtException", onUncaughtException);
|
|
196
217
|
process.removeListener("unhandledRejection", onUnhandledRejection);
|
|
197
|
-
process.removeListener("SIGTERM",
|
|
198
|
-
process.removeListener("SIGINT",
|
|
218
|
+
process.removeListener("SIGTERM", onSigterm);
|
|
219
|
+
process.removeListener("SIGINT", onSigint);
|
|
199
220
|
process.removeListener("SIGHUP", onSighup);
|
|
200
221
|
onSighup.stop();
|
|
201
222
|
if (drainTick !== undefined) {
|
|
@@ -12,6 +12,7 @@ import { installFileHistoryFailureRecorder } from "../file-history-disclosure.js
|
|
|
12
12
|
import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub.js";
|
|
13
13
|
import { setRunTerminalLogObserver } from "../observability/run-terminal.js";
|
|
14
14
|
import { setRedactionObserver } from "../trace/redact.js";
|
|
15
|
+
import { installOutboundDispatcher } from "../outbound-dispatcher.js";
|
|
15
16
|
export function runStage01() {
|
|
16
17
|
const config = loadConfig();
|
|
17
18
|
const runStaleFailure = crossInvariant("run-stale-heartbeat").check({ live: config, next: config });
|
|
@@ -56,6 +57,7 @@ export function runStage01() {
|
|
|
56
57
|
note: "LOCAL_DATA_ROOT moved the local backend's DATA root, but config.d / remote-exec.json are still read from the config root (LOCAL_DATA_ROOT is not consulted there). If you meant to move both, set CONFIG_LOCAL_DIR to the same directory.",
|
|
57
58
|
});
|
|
58
59
|
}
|
|
60
|
+
installOutboundDispatcher(logger);
|
|
59
61
|
return { config, localRoot, logger, metrics };
|
|
60
62
|
}
|
|
61
63
|
//# sourceMappingURL=stage-01-config.js.map
|
|
@@ -10,7 +10,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
|
|
|
10
10
|
imageBakes: import("../plugins/store-backend.js").ImageBake | undefined;
|
|
11
11
|
imageIndex: import("../plugins/store-backend.js").ImageIndex | undefined;
|
|
12
12
|
parkedReviveInheritedGate: ((row: import("@sema-agent/core").BackgroundAgentRecord, identity: import("./parked-revive-gate.js").ParkedReviveIdentity) => Promise<import("./parked-revive-gate.js").RebuiltInheritedGate>) | undefined;
|
|
13
|
-
|
|
13
|
+
parkedReviveSurface: import("../parked-revive-surface.js").ParkedReviveSurfaceFactory | undefined;
|
|
14
14
|
rateLimiter: RateLimiter | import("../plugins/pg-rate-limiter.js").PgRateLimiter | import("../plugins/tidb-rate-limiter.js").TiDBRateLimiter;
|
|
15
15
|
resumeAnchorStore: import("../plugins/store-backend.js").ResumeAnchorStore | undefined;
|
|
16
16
|
runStore: import("../plugins/store-backend.js").RunStore | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_MODEL_REF } from "../model-select.js";
|
|
2
|
-
import { probeSearchBackend
|
|
2
|
+
import { probeSearchBackend } from "@sema-agent/core";
|
|
3
3
|
import { selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
4
4
|
import { subagentSendUserFileExtraTools } from "../capabilities/send-user-file-tool.js";
|
|
5
5
|
import { parseCapEnv, parseNumOrFailNonNegative } from "../config.js";
|
|
@@ -17,6 +17,7 @@ import { selfOrchestrationDenial } from "../task-workflow.js";
|
|
|
17
17
|
import { centerEntitlementSourceWired } from "../runtime-caps-resolver.js";
|
|
18
18
|
import { reclaimOrphansAtBoot } from "../boot-reclaim.js";
|
|
19
19
|
import { createParkedReviveInheritedGate } from "./parked-revive-gate.js";
|
|
20
|
+
import { createParkedReviveSurface } from "../parked-revive-surface.js";
|
|
20
21
|
import { createWebFetchSummarizeLane } from "./webfetch-summarize-lane.js";
|
|
21
22
|
import { createRunnerDepsOnAsk } from "./runner-deps.js";
|
|
22
23
|
import { bindRateLimiter, bindRunStore } from "./late-binds.js";
|
|
@@ -141,8 +142,9 @@ export async function runStage07(ctx) {
|
|
|
141
142
|
: undefined,
|
|
142
143
|
};
|
|
143
144
|
const scenarios = buildScenarios(scenarioDeps);
|
|
144
|
-
const
|
|
145
|
-
const
|
|
145
|
+
const builtinDefaultScenario = scenarios.default;
|
|
146
|
+
const parkedReviveSurface = checkpointStore && backgroundAgentStore && builtinDefaultScenario ? createParkedReviveSurface(builtinDefaultScenario) : undefined;
|
|
147
|
+
const parkedReviveInheritedGate = parkedReviveSurface && config.durableApproval
|
|
146
148
|
? createParkedReviveInheritedGate({
|
|
147
149
|
config, question, approvalExemptionStore, logger, localRoot,
|
|
148
150
|
memoryEngineRoot: memoryEngine?.root,
|
|
@@ -155,6 +157,6 @@ export async function runStage07(ctx) {
|
|
|
155
157
|
const builtinScenarioNames = Object.keys(scenarioDetails);
|
|
156
158
|
configCenter.applyCenterScenarios({ scenarioDeps, scenarios, scenarioDetails, builtinScenarioNames });
|
|
157
159
|
logger.info("capabilities", { skills: skills.length, scenarios: Object.keys(scenarios), repoTools: Boolean(repoClient) });
|
|
158
|
-
return { ...ctx, approvalExemptionStore, approvalNonceStore, authorize, imageBakes, imageIndex, parkedReviveInheritedGate,
|
|
160
|
+
return { ...ctx, approvalExemptionStore, approvalNonceStore, authorize, imageBakes, imageIndex, parkedReviveInheritedGate, parkedReviveSurface, rateLimiter, resumeAnchorStore, runStore, scenarioDetails, scenarios, selectEnvTool, taskLimitCaps, taskTimeoutSec, webSearchProvider: webSearchCfg?.provider };
|
|
159
161
|
}
|
|
160
162
|
//# sourceMappingURL=stage-07-capability-layer.js.map
|
|
@@ -23,7 +23,7 @@ export declare function runStage08(ctx: Awaited<ReturnType<typeof runStage07>>):
|
|
|
23
23
|
imageBakes: import("../plugins/store-backend.js").ImageBake | undefined;
|
|
24
24
|
imageIndex: import("../plugins/store-backend.js").ImageIndex | undefined;
|
|
25
25
|
parkedReviveInheritedGate: ((row: import("@sema-agent/core").BackgroundAgentRecord, identity: import("./parked-revive-gate.js").ParkedReviveIdentity) => Promise<import("./parked-revive-gate.js").RebuiltInheritedGate>) | undefined;
|
|
26
|
-
|
|
26
|
+
parkedReviveSurface: import("../parked-revive-surface.js").ParkedReviveSurfaceFactory | undefined;
|
|
27
27
|
rateLimiter: import("../index.js").RateLimiter | import("../plugins/pg-rate-limiter.js").PgRateLimiter | import("../plugins/tidb-rate-limiter.js").TiDBRateLimiter;
|
|
28
28
|
resumeAnchorStore: import("../plugins/store-backend.js").ResumeAnchorStore | undefined;
|
|
29
29
|
runStore: import("../plugins/store-backend.js").RunStore | undefined;
|
|
@@ -57,7 +57,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
|
|
|
57
57
|
imageBakes: import("../plugins/store-backend.js").ImageBake | undefined;
|
|
58
58
|
imageIndex: import("../plugins/store-backend.js").ImageIndex | undefined;
|
|
59
59
|
parkedReviveInheritedGate: ((row: import("@sema-agent/core").BackgroundAgentRecord, identity: import("./parked-revive-gate.js").ParkedReviveIdentity) => Promise<import("./parked-revive-gate.js").RebuiltInheritedGate>) | undefined;
|
|
60
|
-
|
|
60
|
+
parkedReviveSurface: import("../parked-revive-surface.js").ParkedReviveSurfaceFactory | undefined;
|
|
61
61
|
rateLimiter: import("../index.js").RateLimiter | import("../plugins/pg-rate-limiter.js").PgRateLimiter | import("../plugins/tidb-rate-limiter.js").TiDBRateLimiter;
|
|
62
62
|
resumeAnchorStore: import("../plugins/store-backend.js").ResumeAnchorStore | undefined;
|
|
63
63
|
runStore: import("../plugins/store-backend.js").RunStore | undefined;
|
|
@@ -57,7 +57,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
|
|
|
57
57
|
imageBakes: import("../plugins/store-backend.js").ImageBake | undefined;
|
|
58
58
|
imageIndex: import("../plugins/store-backend.js").ImageIndex | undefined;
|
|
59
59
|
parkedReviveInheritedGate: ((row: import("@sema-agent/core").BackgroundAgentRecord, identity: import("./parked-revive-gate.js").ParkedReviveIdentity) => Promise<import("./parked-revive-gate.js").RebuiltInheritedGate>) | undefined;
|
|
60
|
-
|
|
60
|
+
parkedReviveSurface: import("../parked-revive-surface.js").ParkedReviveSurfaceFactory | undefined;
|
|
61
61
|
rateLimiter: import("../index.js").RateLimiter | import("../plugins/pg-rate-limiter.js").PgRateLimiter | import("../plugins/tidb-rate-limiter.js").TiDBRateLimiter;
|
|
62
62
|
resumeAnchorStore: import("../plugins/store-backend.js").ResumeAnchorStore | undefined;
|
|
63
63
|
runStore: import("../plugins/store-backend.js").RunStore | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { autoRunOnRecommendationEffective, defaultTaskRegistry } from "@sema-agent/core";
|
|
2
2
|
import { posIntEnv } from "../session-watch.js";
|
|
3
|
-
import { brainSummary } from "../brain.js";
|
|
3
|
+
import { brainSummary, buildFailoverFirstByteNotice } from "../brain.js";
|
|
4
4
|
import { resolveBindHost } from "../config.js";
|
|
5
5
|
import { buildWriteProtectionPosture } from "../write-protection.js";
|
|
6
6
|
import { isPricingConfigured } from "../budget.js";
|
|
@@ -13,6 +13,7 @@ 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 { startFleetClientFromEnv } from "../fleet-client.js";
|
|
16
|
+
import { readinessOf } from "../http/readiness.js";
|
|
16
17
|
import { createResolveSpec } from "./resolve-spec.js";
|
|
17
18
|
import { startFleetReconciler } from "../fleet/fleet-reconciler.js";
|
|
18
19
|
import { createSideQueryLane } from "./side-query-lane.js";
|
|
@@ -23,7 +24,7 @@ import { bindServerLateSeats } from "./late-binds.js";
|
|
|
23
24
|
import { serviceVersion } from "../service-version.js";
|
|
24
25
|
import { buildDisplaySafeUrl } from "../trace/redact.js";
|
|
25
26
|
export async function runStage10(ctx) {
|
|
26
|
-
const { approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, config, configCenter, costQuota, deploymentHooks, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportBackend, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate,
|
|
27
|
+
const { approvalAskAudit, approvalExemptionStore, approvalNonceStore, authorize, backend, backgroundAgentStore, brain, breakerState, centerRuntimeCapsResolver, checkpointStore, config, configCenter, costQuota, deploymentHooks, deviceLane, drainState, durableEnabled, elicitation, fenceSessionOwner, fileHistoryStore, fleetBus, fleetLease, fleetUsage, governanceSeams, handslessRunner, hookAgent, hookLlm, hookWakeBus, imageBakes, imageIndex, instanceId, instrumentDegenerate, leaderEndpoint, localRoot, logger, lspManager, mcpRevocations, memoryBundleFaces, memoryComplianceFaces, memoryConsolidationFaces, memoryEngine, memoryExportBackend, memoryOptOutGrantStore, memoryOriginFaces, memoryPosture, memorySyncCursors, metrics, modelUsageTracker, orgMemoryAdmission, otelExporter, outcomeSink, ownerAware, parkedReviveInheritedGate, parkedReviveSurface, perSessionCwd, perTaskImage, planCacheProbe, pricing, principalCaps, promptManifestTracker, purgeSession, question, rateLimiter, reaper, registryJwtVerifier, resumeAnchorStore, retentionLaneStarted, retentionLaneStore, ruleConsent, runStore, runner, runnerDeps, runtimeCapsPeekResolver, scenarioDetails, scenarios, selectEnvTool, sendFileLedger, sendUserFileEmitter, sendUserFileToolSpec, sessionAudit, sessionEnvSelection, sessionMemoryStatusFace, sessionPolicyStore, sessionShellGateRegistry, sessionTitler, sessionWatchRegistry, setSessionCwd, setSessionShellEnv, sharedMemoryStore, sideQueryAccounting, sqlEngineFacts, sqlWorkflowRunStore, staticWiring, storeBackendDegraded, subRunner, subagentSteerRegistry, taskAttachmentStore, taskLimitCaps, taskTimeoutSec, toolApproval, toolResultStore, usageWindowStore, webSearchProvider, workflowAgentRegistry, workflowAgentSessionIndex, workflowCompletionInbox, workflowJournalStore, workflowModelAllowlistSnapshot, workflowNotifyGate, workflowNotifyJournal, workflowRecoverOpts, workflowRunStore, workflowsCapable } = ctx;
|
|
27
28
|
const stores = {
|
|
28
29
|
runStore,
|
|
29
30
|
resumeAnchorStore: resumeAnchorStore ? resumeAnchorStore : undefined,
|
|
@@ -95,7 +96,7 @@ export async function runStage10(ctx) {
|
|
|
95
96
|
: undefined,
|
|
96
97
|
instrumentDegenerate,
|
|
97
98
|
sideQueryAccounting,
|
|
98
|
-
|
|
99
|
+
parkedReviveSurface: parkedReviveSurface ? parkedReviveSurface : undefined,
|
|
99
100
|
parkedReviveInheritedGate: parkedReviveInheritedGate ? parkedReviveInheritedGate : undefined,
|
|
100
101
|
};
|
|
101
102
|
const observability = {
|
|
@@ -149,6 +150,8 @@ export async function runStage10(ctx) {
|
|
|
149
150
|
restartState: () => configCenter.restartState(),
|
|
150
151
|
planeDeferredState: () => configCenter.planeDeferredState(),
|
|
151
152
|
configApplyState: () => configCenter.configApplyState(),
|
|
153
|
+
centerCredentialState: () => configCenter.centerCredentialState(),
|
|
154
|
+
modelRefusalsState: () => configCenter.modelRefusalsState(),
|
|
152
155
|
mcpRevocations,
|
|
153
156
|
mcpRevocationState: () => configCenter.mcpRevocationState(),
|
|
154
157
|
configRefreshNow: () => configCenter.refreshNow(),
|
|
@@ -237,12 +240,18 @@ export async function runStage10(ctx) {
|
|
|
237
240
|
const fleetClient = startFleetClientFromEnv(config, {
|
|
238
241
|
instanceId,
|
|
239
242
|
version: serviceVersion(),
|
|
240
|
-
|
|
243
|
+
readiness: () => readinessOf(deployment),
|
|
244
|
+
restart: () => deployment.restartState?.(),
|
|
245
|
+
modelRefusals: () => deployment.modelRefusalsState?.(),
|
|
241
246
|
...(fleetUsage ? { usage: fleetUsage } : {}),
|
|
242
247
|
logger: { info: (m, d) => logger.info(m, d ?? {}), warn: (m, d) => logger.warn(m, d ?? {}) },
|
|
243
248
|
});
|
|
249
|
+
configCenter.onSelfReportChange(() => void fleetClient?.announceNow());
|
|
244
250
|
if (fleetClient)
|
|
245
251
|
logger.info("fleet_client_started", { worker: config.configCenter?.worker, address: buildDisplaySafeUrl(process.env.FLEET_ADVERTISE_ADDRESS ?? "") });
|
|
252
|
+
const failoverFirstByte = buildFailoverFirstByteNotice(config);
|
|
253
|
+
if (failoverFirstByte)
|
|
254
|
+
logger.warn("failover_first_byte_lane", failoverFirstByte);
|
|
246
255
|
logger.info("listening", {
|
|
247
256
|
port: config.port,
|
|
248
257
|
bindHost: bindHost ?? "0.0.0.0/::(all interfaces)",
|
package/dist/brain.d.ts
CHANGED
|
@@ -12,12 +12,14 @@ export declare const FAST_FAIL_MAX_RETRIES = 2;
|
|
|
12
12
|
* Build the external "Brain" (LLM) from config.
|
|
13
13
|
*
|
|
14
14
|
* Composition (A1 + the 1.38 resilience stack, ordered timeout-innermost → breaker → failover-outermost):
|
|
15
|
-
* - **Tiered timeouts** (1.38
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* prefill legitimately takes minutes
|
|
20
|
-
* same prompt back to the same queue
|
|
15
|
+
* - **Tiered timeouts** (1.38; re-cut by core 7.33.0 along the segments of a call) are passed into each
|
|
16
|
+
* brain at creation: `firstByteTimeoutMs` (fetch() → response headers; S-753: **passed only when the
|
|
17
|
+
* operator set `MODEL_FIRST_BYTE_TIMEOUT_MS`** — absent = no key, core's own default, which carries an
|
|
18
|
+
* upload allowance and one widened retry of its own), `firstTokenTimeoutMs` (headers → first delta,
|
|
19
|
+
* 600s since S-202 — a self-hosted backend's long prefill legitimately takes minutes, and 120s turned that
|
|
20
|
+
* into a retry handing the same prompt back to the same queue) and `idleTimeoutMs`. The TCP + TLS connect
|
|
21
|
+
* is the transport's own clock (core 7.33.0), not a knob here. env =0 = no engine clock on that segment
|
|
22
|
+
* and the transport's header / body clocks off too (the connect keeps the transport's own clock).
|
|
21
23
|
* - **Circuit breaker** (`createCircuitBreakerBrain`) wraps the *primary* gateway route(s) when
|
|
22
24
|
* `MODEL_CIRCUIT_BREAKER=true`: after N transient failures it opens and fast-fails, so failover
|
|
23
25
|
* switches to the bare backup immediately instead of waiting out each timeout. The last gateway
|
|
@@ -30,14 +32,32 @@ export declare const FAST_FAIL_MAX_RETRIES = 2;
|
|
|
30
32
|
* ↔ vLLM is a *routing* choice, not failover.)
|
|
31
33
|
*
|
|
32
34
|
* When no fallback URL, no Anthropic key, and no resilience thresholds are configured, this returns the
|
|
33
|
-
* bare openai brain (carrying the
|
|
34
|
-
*
|
|
35
|
+
* bare openai brain (carrying the watchdogs: core's own first-byte default unless `MODEL_FIRST_BYTE_TIMEOUT_MS`
|
|
36
|
+
* is set, plus the server's first-token / idle defaults; a knob at 0 = no engine clock on that segment and the
|
|
37
|
+
* transport's header / body clocks off too). The Model itself (id / contextWindow / maxTokens / provider) flows
|
|
35
38
|
* per-request through `Runner({ models })`.
|
|
36
39
|
*/
|
|
37
40
|
export declare function createBrain(config: ServiceConfig, deps?: {
|
|
38
41
|
fetchImpl?: typeof fetch;
|
|
39
42
|
breakerState?: BreakerState;
|
|
40
43
|
}): Brain;
|
|
44
|
+
/**
|
|
45
|
+
* S-753 复审(opus F2 + codex C1)—— **failover 拓扑 × 首字节段没有部署窗**的启动期披露(纯数据,`build*`;告警由 boot 出)。
|
|
46
|
+
*
|
|
47
|
+
* 缺省下首字节段不铸键(core 自缺省当家,[ref])、`0` = 该段不设引擎钟;而切备只发生在一次调用**失败之后**。于是主网关接了连接
|
|
48
|
+
* 却不回响应头时:缺省 ⇒ 要等 core 的首字节 lane 走完(缺省首窗 + 一次加宽重试;本仓不铸 `firstByteRetries`,S-753 车PA)才切备,
|
|
49
|
+
* 时间预算短于那一段的调用在备网关被尝试之前就被取消 —— 以 core 7.33.x 缺省计 lane ≈ 15 min,code-review council 每个镜头的 180 s 与 team
|
|
50
|
+
* discuss 的 600 s 都在其内(车PA codex r1:600 s 在主网关的加宽重试窗里到点,不是「只剩余量」);
|
|
51
|
+
* `0` ⇒ 首字节 lane 永不切备。启动日志里同行的 `gatewayRetryCap:"fast-fail:…"` 只管共享重试梯子,读起来却像「会快切」—— 这条披露把它补齐。
|
|
52
|
+
* 显式设了正数窗 ⇒ `undefined`(部署已表态);单路由 ⇒ `undefined`(没有备可切)。**不替运维铸窗**:出路是旋钮,不是本仓的数。
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildFailoverFirstByteNotice(config: ServiceConfig): {
|
|
55
|
+
readonly knob: "MODEL_FIRST_BYTE_TIMEOUT_MS";
|
|
56
|
+
readonly fallbacks: number;
|
|
57
|
+
readonly firstByteTimeoutMs: number | null;
|
|
58
|
+
readonly effect: string;
|
|
59
|
+
readonly fix: string;
|
|
60
|
+
} | undefined;
|
|
41
61
|
/** One-line summary of the active brain composition, for the startup log. */
|
|
42
62
|
export declare function brainSummary(config: ServiceConfig): Record<string, unknown>;
|
|
43
63
|
//# sourceMappingURL=brain.d.ts.map
|
package/dist/brain.js
CHANGED
|
@@ -38,7 +38,7 @@ export function createBrain(config, deps = {}) {
|
|
|
38
38
|
const { fetchImpl, breakerState } = deps;
|
|
39
39
|
const r = config.resilience ?? DEFAULT_RESILIENCE;
|
|
40
40
|
const timeouts = {
|
|
41
|
-
|
|
41
|
+
...(r.firstByteTimeoutMs !== undefined ? { firstByteTimeoutMs: r.firstByteTimeoutMs } : {}),
|
|
42
42
|
firstTokenTimeoutMs: r.firstTokenTimeoutMs,
|
|
43
43
|
idleTimeoutMs: r.idleTimeoutMs,
|
|
44
44
|
};
|
|
@@ -135,6 +135,22 @@ export function createBrain(config, deps = {}) {
|
|
|
135
135
|
}
|
|
136
136
|
return brain;
|
|
137
137
|
}
|
|
138
|
+
export function buildFailoverFirstByteNotice(config) {
|
|
139
|
+
const r = config.resilience ?? DEFAULT_RESILIENCE;
|
|
140
|
+
const fallbacks = config.gatewayFallbackUrls.length;
|
|
141
|
+
if (fallbacks === 0 || (r.firstByteTimeoutMs !== undefined && r.firstByteTimeoutMs > 0))
|
|
142
|
+
return undefined;
|
|
143
|
+
const zero = r.firstByteTimeoutMs === 0;
|
|
144
|
+
return {
|
|
145
|
+
knob: "MODEL_FIRST_BYTE_TIMEOUT_MS",
|
|
146
|
+
fallbacks,
|
|
147
|
+
firstByteTimeoutMs: r.firstByteTimeoutMs ?? null,
|
|
148
|
+
effect: zero
|
|
149
|
+
? "the first-byte lane never fails over a primary that accepts the connection but sends no response headers (0 = no engine clock on that segment); only a run-level limit ends that wait"
|
|
150
|
+
: "a primary that accepts the connection but sends no response headers is failed over only after core's default first-byte lane runs out (the first window, then one widened retry); a call with a time budget shorter than that — the code-review council's 180 s lenses and team discuss's 600 s, with core 7.33.x defaults — is cancelled before the backup is ever tried",
|
|
151
|
+
fix: "set MODEL_FIRST_BYTE_TIMEOUT_MS to the longest response-header wait a healthy primary needs (queue + prefill), so a hung primary is cut over after that window and its one widened retry",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
138
154
|
export function brainSummary(config) {
|
|
139
155
|
const r = config.resilience ?? DEFAULT_RESILIENCE;
|
|
140
156
|
const hasFailover = config.gatewayFallbackUrls.length > 0;
|
|
@@ -147,9 +163,9 @@ export function brainSummary(config) {
|
|
|
147
163
|
failover: hasFailover,
|
|
148
164
|
anthropicRoute: Boolean(config.anthropic),
|
|
149
165
|
anthropicCacheBreakpoints: config.anthropic?.cacheBreakpoints ?? null,
|
|
150
|
-
|
|
151
|
-
firstTokenTimeoutMs: r.firstTokenTimeoutMs
|
|
152
|
-
idleTimeoutMs: r.idleTimeoutMs
|
|
166
|
+
firstByteTimeoutMs: r.firstByteTimeoutMs ?? null,
|
|
167
|
+
firstTokenTimeoutMs: r.firstTokenTimeoutMs,
|
|
168
|
+
idleTimeoutMs: r.idleTimeoutMs,
|
|
153
169
|
circuitBreaker: breakerActive,
|
|
154
170
|
circuitBreakerRequested: r.circuitBreaker,
|
|
155
171
|
gatewayRetryCap: config.gatewayMaxRetries !== undefined
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import type { ToolSpec } from "@sema-agent/core";
|
|
1
|
+
import type { SubagentSpawnContext, 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
|
+
/**
|
|
7
|
+
* #1110(core 7.32.0)—— 委派子代的**逐次注入**工厂(`SubagentToolOptions.extraTools`):`Now` + 部署的 extra tools(今天 = SendUserFile)。
|
|
8
|
+
*
|
|
9
|
+
* 为什么 `Now` 走这条通道:core 7.32.0 起子代按**身份**继承场景层 bundle 的工具(`assembleCodeTools` 交给 Agent 的
|
|
10
|
+
* `inheritedTools` ∩ 父 run 真挂载),而 `Now` 是本仓在 bundle **旁边**组的宿主工具(scenarios.ts),宿主工具**从不**被继承
|
|
11
|
+
* (core:继承整张 `spec.tools` 会把宿主工具带过宿主自己的逐次门)—— 逐次注入是它到达子代的唯一通道。一个工厂、两个产地:
|
|
12
|
+
* 部署工厂的门(SendUserFile 的审批面预判 / 只读内建排除)原样在它自己那只函数里,这里只做合成。
|
|
13
|
+
* ⚠️ 工厂恒在场 ⇒ core 不再给 Agent 工具铸静态 `agentToolPool`(core:工厂可在 spawn 时注入身份未知的工具 ⇒ 池不可静态知 ⇒
|
|
14
|
+
* 记忆内容来源读者按「外部」读,fail-closed)。本仓 default bundle 的继承面本来就含 WebFetch(外部),这一翻面只在
|
|
15
|
+
* 「子代面恰好不含任何外部工具」的窄形上把委派结果多判一次外部,方向是收紧。
|
|
16
|
+
* 工厂**不抛**:`nowTool()` 是纯构造;部署工厂的抛由 core 收成「这一 spawn 什么都不继承 + 模型面披露句」(onExtraToolsError 记 warn)。
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSubagentExtraTools(deployment?: (ctx: SubagentSpawnContext) => ToolSpec[]): (ctx: SubagentSpawnContext) => ToolSpec[];
|
|
6
19
|
//# sourceMappingURL=builtin-tools.d.ts.map
|
|
@@ -39,14 +39,19 @@ export type PluginValidation = {
|
|
|
39
39
|
};
|
|
40
40
|
/** 条款 1/2/4:https-only、host 全等白名单、sha 40hex。纯函数,worker 侧纵深复验(不信任 wire 已验过)。 */
|
|
41
41
|
export declare function validatePluginDecl(decl: PluginDeclWire, allowHosts: readonly string[]): PluginValidation;
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* 条款 3:clone 计划(argv 序列)。纯数据,让"步骤"可被锚定。
|
|
44
|
+
*
|
|
45
|
+
* 7.103.0(S-684 残余):计划**只**产 argv。隔离 env(收紧③:GIT_CONFIG_GLOBAL/SYSTEM=/dev/null、GIT_TERMINAL_PROMPT=0)的唯一属主是
|
|
46
|
+
* `gitSubprocessEnv({ isolateConfig: true })` —— 修前这三键写在这里、由 `runGit` 叠在 `{ ...process.env }` 上,一件姿势两个写者,
|
|
47
|
+
* 而剥密恰好落在两者之外。锚点随之移到真 spawn 的 env 上(`test/secret-env-scrub-host-legs.test.ts` R2:假 git 读到的整份 env)。
|
|
48
|
+
*/
|
|
43
49
|
export declare function gitClonePlan(o: {
|
|
44
50
|
url: string;
|
|
45
51
|
dest: string;
|
|
46
52
|
sha?: string;
|
|
47
53
|
}): {
|
|
48
54
|
steps: string[][];
|
|
49
|
-
env: Record<string, string>;
|
|
50
55
|
};
|
|
51
56
|
/** manifest 本体尺寸上限(#97 redesign⑥ V2-⑦:**新的本地输入上限**,非既有格式事实——manifest 只被
|
|
52
57
|
* 消费一个 `skillsPath` 字段,几行 JSON;超界视为畸形输入整条拒装)。 */
|
|
@@ -101,6 +106,7 @@ export declare function applyCenterPlugins(baseline: LoadedSkill[], eff: {
|
|
|
101
106
|
/** 测试口:跳过 validate(materialize 只接受已验声明;真 git 腿用本地 bare repo,validate 层的
|
|
102
107
|
* https-only 单独测——两层分开,谁也不掩护谁)。生产恒 false/缺席。 */
|
|
103
108
|
skipValidate?: boolean;
|
|
104
|
-
|
|
109
|
+
/** 测试口:替换真 git(生产恒缺席)。env 不在这一格上 —— 缺省腿自己经唯一构造取(替身腿本来就不起 git)。 */
|
|
110
|
+
runGit?: (args: string[]) => Promise<void>;
|
|
105
111
|
}): Promise<ApplyPluginsResult>;
|
|
106
112
|
//# sourceMappingURL=center-plugins.d.ts.map
|
|
@@ -4,6 +4,7 @@ import { promises as fsp, realpathSync, existsSync, readFileSync, lstatSync, sta
|
|
|
4
4
|
import { join, resolve, isAbsolute, sep } from "node:path";
|
|
5
5
|
import { assertConfined, loadSkills } from "./skills.js";
|
|
6
6
|
import { buildDisplaySafeUrl, redactSecrets } from "../trace/redact.js";
|
|
7
|
+
import { gitSubprocessEnv } from "../server-secret-env.js";
|
|
7
8
|
const execFileP = promisify(execFile);
|
|
8
9
|
export const MAX_PLUGIN_SOURCE_URL_CHARS = 2048;
|
|
9
10
|
export const DEFAULT_PLUGIN_ALLOW_HOSTS = ["github.com"];
|
|
@@ -53,13 +54,8 @@ export function validatePluginDecl(decl, allowHosts) {
|
|
|
53
54
|
return { ok: true, name, url };
|
|
54
55
|
}
|
|
55
56
|
export function gitClonePlan(o) {
|
|
56
|
-
const env = {
|
|
57
|
-
GIT_CONFIG_GLOBAL: "/dev/null",
|
|
58
|
-
GIT_CONFIG_SYSTEM: "/dev/null",
|
|
59
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
60
|
-
};
|
|
61
57
|
if (o.sha === undefined) {
|
|
62
|
-
return { steps: [["clone", "--depth", "1", "--quiet", o.url, o.dest]]
|
|
58
|
+
return { steps: [["clone", "--depth", "1", "--quiet", o.url, o.dest]] };
|
|
63
59
|
}
|
|
64
60
|
return {
|
|
65
61
|
steps: [
|
|
@@ -67,7 +63,6 @@ export function gitClonePlan(o) {
|
|
|
67
63
|
["-C", o.dest, "fetch", "--depth", "1", "--quiet", o.url, o.sha],
|
|
68
64
|
["-C", o.dest, "checkout", "--quiet", o.sha],
|
|
69
65
|
],
|
|
70
|
-
env,
|
|
71
66
|
};
|
|
72
67
|
}
|
|
73
68
|
export const PLUGIN_MANIFEST_MAX_BYTES = 64 * 1024;
|
|
@@ -130,8 +125,8 @@ export async function applyCenterPlugins(baseline, eff, opts) {
|
|
|
130
125
|
const out = { skills: [...baseline], failures: [], letGo: [], lkgUsed: [] };
|
|
131
126
|
if (declared.length === 0)
|
|
132
127
|
return out;
|
|
133
|
-
const runGit = opts.runGit ?? (async (args
|
|
134
|
-
await execFileP("git", args, { env: {
|
|
128
|
+
const runGit = opts.runGit ?? (async (args) => {
|
|
129
|
+
await execFileP("git", args, { env: gitSubprocessEnv({ site: "server.center-plugins.git-clone", isolateConfig: true }), timeout: 120_000, maxBuffer: 4 * 1024 * 1024 });
|
|
135
130
|
});
|
|
136
131
|
const taken = new Set(baseline.map((s) => s.spec.name));
|
|
137
132
|
for (const decl of declared) {
|
|
@@ -155,7 +150,7 @@ export async function applyCenterPlugins(baseline, eff, opts) {
|
|
|
155
150
|
await fsp.mkdir(staging, { recursive: true });
|
|
156
151
|
const plan = gitClonePlan({ url: v.url, dest: staging, sha: v.sha });
|
|
157
152
|
for (const step of plan.steps)
|
|
158
|
-
await runGit(step
|
|
153
|
+
await runGit(step);
|
|
159
154
|
await fsp.rm(liveDir, { recursive: true, force: true });
|
|
160
155
|
await fsp.mkdir(join(opts.cacheRoot, v.name), { recursive: true });
|
|
161
156
|
await fsp.rename(staging, liveDir);
|
|
@@ -43,7 +43,7 @@ export interface ScenarioContext {
|
|
|
43
43
|
* 等于让一个租户读另一个租户的清单(同 spec 组装处那条「sessionId comes from `auth`, NEVER the
|
|
44
44
|
* body」的逐字纪律)。
|
|
45
45
|
*
|
|
46
|
-
* 缺席 = 这条调用形本来就没有会话(`
|
|
46
|
+
* 缺席 = 这条调用形本来就没有会话(`parked-revive-surface.ts` 对深于一层的行只取 boot 期那只裸 Agent 工具、
|
|
47
47
|
* `builtinScenarioDetails` 的工具名探针)。此时会话级设施退化为 per-call 实例 —— 不为它发明
|
|
48
48
|
* 一个假 session。
|
|
49
49
|
*/
|
|
@@ -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 } from "../security.js";
|
|
3
|
-
import { nowTool } from "./builtin-tools.js";
|
|
3
|
+
import { createSubagentExtraTools, 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,8 +70,8 @@ export function buildScenarios(deps) {
|
|
|
70
70
|
...(deps.checkpointStore ? { checkpointStore: deps.checkpointStore } : {}),
|
|
71
71
|
...(deps.ensureChildSessionDurable ? { ensureChildSessionDurable: deps.ensureChildSessionDurable } : {}),
|
|
72
72
|
},
|
|
73
|
-
|
|
74
|
-
...(deps.
|
|
73
|
+
extraTools: createSubagentExtraTools(deps.subagentExtraTools),
|
|
74
|
+
...(deps.logger
|
|
75
75
|
? { onExtraToolsError: (err, info) => deps.logger?.warn?.("subagent_extra_tools_error", { ...info, err: err instanceof Error ? err.message : String(err) }) }
|
|
76
76
|
: {}),
|
|
77
77
|
},
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { CenterCredentialFailure, CenterCredentialHealth, CenterCredentialSource } from "./center-credential.js";
|
|
2
|
+
import type { Logger } from "./observability/logger.js";
|
|
3
|
+
export declare const CENTER_CREDENTIAL_RENEW_LEAD_KEY = "CENTER_CREDENTIAL_RENEW_LEAD_MS";
|
|
4
|
+
/** 缺省提前量:5 min(设计 §0)。 */
|
|
5
|
+
export declare const CENTER_CREDENTIAL_RENEW_LEAD_DEFAULT_MS: number;
|
|
6
|
+
/** 下界 = 一次续签请求的传输上界:更短的提前量连一次尝试都装不下,令牌注定先过期(配了 ≈ 没配)。 */
|
|
7
|
+
export declare const CENTER_CREDENTIAL_RENEW_LEAD_MIN_MS = 8000;
|
|
8
|
+
/** 上界 = 契约访问令牌寿命(`ACCESS_TOKEN_TTL_SECONDS`)之半:提前量 ≥ 寿命 ⇒ 每只刚铸出来的令牌都已「该续签」,续签环空转。 */
|
|
9
|
+
export declare const CENTER_CREDENTIAL_RENEW_LEAD_MAX_MS: number;
|
|
10
|
+
/**
|
|
11
|
+
* `CENTER_CREDENTIAL_RENEW_LEAD_MS` 的唯一解析口([ref] A 档:坏值拒启,不夹取、不回默认 —— 凭证轴上一根被静默改掉的旋钮 =
|
|
12
|
+
* 部署以为续签开着 / 关着)。收 **raw 值**(调用点写字面 `process.env.<键>`,目录门按字面对账)。
|
|
13
|
+
* · 缺席 / 空串 ⇒ 缺省 300000;`0` ⇒ 关续签(只读信封);
|
|
14
|
+
* · 其余必须是整数毫秒且落在 [{@link CENTER_CREDENTIAL_RENEW_LEAD_MIN_MS}, {@link CENTER_CREDENTIAL_RENEW_LEAD_MAX_MS}]。
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseCenterCredentialRenewLeadMs(raw: string | undefined): number;
|
|
17
|
+
/** 续签失败的成因闭集。两形会自己重试(`pending`):`center_unavailable`(中心不可用)与 `write_failed`(续签已成交、改写没落地 ——
|
|
18
|
+
* 新令牌留在内存里重写,绝不拿已消费的 refresh token 再续一次);其余四形是终态(`failed`),等文件内容变化(壳重新登录 / 手工修)。 */
|
|
19
|
+
export type CenterCredentialRenewalFailure = "invalid_grant" | "issuer_mismatch" | "rejected" | "malformed_grant" | "write_failed" | "center_unavailable";
|
|
20
|
+
type RetryingFailure = Extract<CenterCredentialRenewalFailure, "center_unavailable" | "write_failed">;
|
|
21
|
+
type TerminalFailure = Exclude<CenterCredentialRenewalFailure, RetryingFailure>;
|
|
22
|
+
/** 续签器的状态(`/health.centerCredential.renewal` 的来源;`idle` 不上 wire)。非 `idle` 的状态恒**关于**文件里某一只 refresh
|
|
23
|
+
* token —— 文件换了一只(壳轮换 / 重新登录 / 登出 / 换成裸行),下一次取值即清回 `idle`(codex F3)。 */
|
|
24
|
+
export type CenterCredentialRenewal = {
|
|
25
|
+
readonly state: "idle";
|
|
26
|
+
} | {
|
|
27
|
+
readonly state: "pending";
|
|
28
|
+
readonly reason: RetryingFailure;
|
|
29
|
+
readonly since: number;
|
|
30
|
+
readonly attempts: number;
|
|
31
|
+
readonly retryAt: number;
|
|
32
|
+
} | {
|
|
33
|
+
readonly state: "failed";
|
|
34
|
+
readonly reason: TerminalFailure;
|
|
35
|
+
readonly since: number;
|
|
36
|
+
};
|
|
37
|
+
export interface CenterCredentialRenewer {
|
|
38
|
+
renewal(): CenterCredentialRenewal;
|
|
39
|
+
/** 最近一次读到的信封的访问令牌到期时刻(epoch ms;最近一次取值不是信封 ⇒ undefined)。 */
|
|
40
|
+
sessionExpiresAt(): number | undefined;
|
|
41
|
+
/** 退订 + 停定时器(幂等;在飞的那一次照常落地 —— 它的结果对壳同样有用)。 */
|
|
42
|
+
stop(): void;
|
|
43
|
+
}
|
|
44
|
+
/** `/health.centerCredential` 的 wire 形(免鉴权面:只有闭集词、时刻与计数 —— 不带路径、不带 reason 原句、不带令牌)。 */
|
|
45
|
+
export interface CenterCredentialHealthView {
|
|
46
|
+
readonly state: "ok" | "unreadable";
|
|
47
|
+
readonly failure?: CenterCredentialFailure;
|
|
48
|
+
readonly since?: number;
|
|
49
|
+
readonly failures?: number;
|
|
50
|
+
readonly renewal?: {
|
|
51
|
+
readonly state: "pending" | "failed";
|
|
52
|
+
readonly reason: CenterCredentialRenewalFailure;
|
|
53
|
+
readonly since: number;
|
|
54
|
+
readonly expiresAt?: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** 健康态 + 续签态 → `/health` 那一格;都健康 ⇒ `undefined`(键缺席,正常形状不变)。 */
|
|
58
|
+
export declare function buildCenterCredentialHealthView(health: CenterCredentialHealth, renewer: CenterCredentialRenewer | undefined): CenterCredentialHealthView | undefined;
|
|
59
|
+
export interface CenterCredentialRenewerDeps {
|
|
60
|
+
/** 文件形凭证来源(续签器只从它的取值被触发;文件路径取自它的 `origin`)。 */
|
|
61
|
+
readonly source: CenterCredentialSource;
|
|
62
|
+
/** `configCenter.url` —— 续签只向与它同源的 `issuer` 发。 */
|
|
63
|
+
readonly centerUrl: string;
|
|
64
|
+
/** `CENTER_CREDENTIAL_RENEW_LEAD_MS`(已过 {@link parseCenterCredentialRenewLeadMs});0 = 关续签。 */
|
|
65
|
+
readonly leadMs: number;
|
|
66
|
+
readonly logger: Logger;
|
|
67
|
+
readonly now?: () => number;
|
|
68
|
+
readonly fetchImpl?: typeof fetch;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 续签器工厂(活对象:订阅来源的取值、持一只定时器、持单飞与退避状态)。只对文件形来源有意义 —— env / absent 形调用即抛
|
|
72
|
+
* (装配点只在文件形时装它;装错 = 编程错误,响亮)。
|
|
73
|
+
*/
|
|
74
|
+
export declare function createCenterCredentialRenewer(deps: CenterCredentialRenewerDeps): CenterCredentialRenewer;
|
|
75
|
+
export {};
|
|
76
|
+
//# sourceMappingURL=center-credential-renewer.d.ts.map
|