@sema-agent/server 7.101.0 → 7.102.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 +23 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +58 -4
- package/dist/approval-card.d.ts +35 -2
- package/dist/approval-card.js +19 -1
- package/dist/background-session-reap.d.ts +55 -0
- package/dist/background-session-reap.js +90 -0
- package/dist/boot/config-center.d.ts +16 -4
- package/dist/boot/config-center.js +44 -15
- 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-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 +9 -3
- package/dist/capabilities/builtin-tools.d.ts +14 -1
- package/dist/capabilities/builtin-tools.js +3 -0
- 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 +9 -4
- package/dist/config-center/apply-effective.js +5 -12
- 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/read-warnings.d.ts +19 -48
- package/dist/config-center/read-warnings.js +7 -49
- package/dist/config-center/restart-signal.d.ts +8 -11
- package/dist/config-center/types.d.ts +4 -2
- package/dist/config-provider.js +1 -48
- package/dist/config-types.d.ts +77 -5
- package/dist/config-types.js +5 -0
- package/dist/config.js +49 -13
- package/dist/device-store.d.ts +1 -1
- package/dist/fleet/fleet-bus.d.ts +30 -4
- package/dist/fleet/fleet-bus.js +20 -4
- package/dist/fleet/fleet-reconciler.d.ts +29 -6
- package/dist/fleet/fleet-reconciler.js +109 -79
- package/dist/fleet-client.d.ts +21 -7
- package/dist/fleet-client.js +41 -12
- package/dist/fleet-lease.d.ts +1 -1
- package/dist/http/approval-sweeps.js +5 -20
- package/dist/http/dispatch.js +20 -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 +21 -8
- package/dist/http/server.js +2 -2
- package/dist/model-entry-refusal.d.ts +11 -10
- package/dist/model-entry-refusal.js +13 -10
- package/dist/observability/fail-open.d.ts +6 -2
- package/dist/observability/fail-open.js +6 -2
- 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 +11 -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 +18 -5
- package/dist/tool-approval.d.ts +39 -1
- package/dist/tool-approval.js +37 -8
- package/dist/trace/core-keyset-guard.d.ts +3 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/package.json +3 -3
|
@@ -3,7 +3,7 @@ import { readFile as fsReadFile } from "node:fs/promises";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { loadRemoteExec } from "@sema-agent/settings-schema/node";
|
|
6
|
-
import { skillContentHash } from "@sema-agent/settings-schema";
|
|
6
|
+
import { CENTER_CREDENTIAL_ENV, skillContentHash } from "@sema-agent/settings-schema";
|
|
7
7
|
import { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, } from "@sema-agent/core";
|
|
8
8
|
import { buildPricing } from "../budget.js";
|
|
9
9
|
import { applyCenterPlugins } from "../capabilities/center-plugins.js";
|
|
@@ -12,7 +12,8 @@ import { validatePromptsDomain, CORE_ENGINE_VERSION } from "../prompts-domain-va
|
|
|
12
12
|
import { centerScenarios, centerScenarioDetails } from "../capabilities/scenarios.js";
|
|
13
13
|
import { configLkgEnabled, isRosterGateArmed } from "../config.js";
|
|
14
14
|
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg, legacyV1LkgPath, migrateV1Lkg } from "../config-lkg.js";
|
|
15
|
-
import { answerStillCurrent, centerStateBin, credentialIdentityNow } from "../center-credential.js";
|
|
15
|
+
import { answerStillCurrent, centerStateBin, credentialIdentityNow, judgeCenterCredentialAtBoot } from "../center-credential.js";
|
|
16
|
+
import { buildCenterCredentialHealthView, createCenterCredentialRenewer } from "../center-credential-renewer.js";
|
|
16
17
|
import { centerManagedConfigKeys } from "../config-center/apply-effective.js";
|
|
17
18
|
import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "../config-provider.js";
|
|
18
19
|
import { executionLaneCaps, executionLaneOf } from "../execution-lane-caps.js";
|
|
@@ -63,13 +64,15 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
63
64
|
let pendingRestart;
|
|
64
65
|
const cc = config.configCenter;
|
|
65
66
|
const bootCredential = cc?.credential.read();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
67
|
+
const bootVerdict = bootCredential === undefined ? undefined : judgeCenterCredentialAtBoot(bootCredential);
|
|
68
|
+
if (bootVerdict?.verdict === "refuse")
|
|
69
|
+
throw new Error(bootVerdict.sentence);
|
|
70
|
+
if (bootVerdict?.verdict === "loud") {
|
|
71
|
+
logger.error("center_credential_unreadable", { key: CENTER_CREDENTIAL_ENV.tokenFile, failure: bootVerdict.failure, reason: bootVerdict.reason, effect: bootVerdict.effect });
|
|
72
72
|
}
|
|
73
|
+
const credentialRenewer = cc !== undefined && cc.credential.origin.from === "file"
|
|
74
|
+
? createCenterCredentialRenewer({ source: cc.credential, centerUrl: cc.baseUrl, leadMs: config.centerCredentialRenewLeadMs, logger })
|
|
75
|
+
: undefined;
|
|
73
76
|
const currentIdentity = () => (cc === undefined ? undefined : credentialIdentityNow(cc.credential));
|
|
74
77
|
const candidateIdentity = new WeakMap();
|
|
75
78
|
const candidateIdentityOf = (eff) => candidateIdentity.get(eff);
|
|
@@ -134,12 +137,31 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
134
137
|
});
|
|
135
138
|
}
|
|
136
139
|
};
|
|
140
|
+
const selfReportListeners = [];
|
|
141
|
+
const notifySelfReport = (changed) => {
|
|
142
|
+
for (const listener of selfReportListeners) {
|
|
143
|
+
try {
|
|
144
|
+
listener(changed);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
logger.warn("self_report_listener_failed", { changed, error: err instanceof Error ? err.message : String(err), note: "a self-report subscriber threw; the state change stands regardless and the next fleet heartbeat carries it" });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
137
151
|
const markRosterLanded = (eff) => {
|
|
138
152
|
if (!modelReadyState.ready && (eff.models?.models ?? []).some((m) => m.enabled !== false)) {
|
|
139
153
|
modelReadyState.ready = true;
|
|
140
154
|
logger.info("model_roster_landed", { note: "ready gate open — billable submissions accepted" });
|
|
155
|
+
notifySelfReport("roster_landed");
|
|
141
156
|
}
|
|
142
157
|
};
|
|
158
|
+
const publishRestart = (next) => {
|
|
159
|
+
const prev = pendingRestart;
|
|
160
|
+
pendingRestart = next;
|
|
161
|
+
const same = prev === undefined || next === undefined ? prev === next : prev.version === next.version && prev.since === next.since && prev.reasons.length === next.reasons.length && prev.reasons.every((r, i) => r === next.reasons[i]);
|
|
162
|
+
if (!same)
|
|
163
|
+
notifySelfReport("restart_signal");
|
|
164
|
+
};
|
|
143
165
|
let centerPrompts;
|
|
144
166
|
let pendingCatalogFaces;
|
|
145
167
|
const retryPendingCatalog = async (phase) => {
|
|
@@ -566,6 +588,9 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
566
588
|
getKeyResolver: () => keyResolver,
|
|
567
589
|
getCenterPrompts: () => centerPrompts,
|
|
568
590
|
modelReady: () => modelReadyState.ready,
|
|
591
|
+
onSelfReportChange: (listener) => {
|
|
592
|
+
selfReportListeners.push(listener);
|
|
593
|
+
},
|
|
569
594
|
restartState: () => pendingRestart,
|
|
570
595
|
planeDeferredState: () => planeDeferredNoHandoff,
|
|
571
596
|
configApplyState: () => (configProvider ? applyLedger.view() : undefined),
|
|
@@ -663,7 +688,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
663
688
|
if (liveSkillMiss)
|
|
664
689
|
bootSkillStale = true;
|
|
665
690
|
if (liveSkillMiss && (bootPublished || (!lkgSurvivesRestart && lastPrewarmBodiesVerified))) {
|
|
666
|
-
|
|
691
|
+
publishRestart({ reasons: ["skills"], version: bootLkgCandidate.effective.version, since: Date.now() });
|
|
667
692
|
logger.warn("config_boot_skill_stale_restart", { version: bootLkgCandidate.effective.version, durableHandoff: bootPublished, note: bootPublished ? "live skill application incomplete but the durable LKG carries the full candidate — skills restart published (the next boot reads the complete LKG)" : "live skill application incomplete on a non-durable deployment but every enabled body is verified in the cache — skills restart published (transient failure proven repaired; the restarted process re-pulls live)" });
|
|
668
693
|
}
|
|
669
694
|
else if (liveSkillMiss || (!bootPublished && lkgSurvivesRestart)) {
|
|
@@ -719,14 +744,14 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
719
744
|
const promoted = lkgSurvivesRestart || skillsDebt ? await persistLkgDurable(planeDeferredNoHandoff.candidate, planeDeferredNoHandoff.candidateEtag) : false;
|
|
720
745
|
const skillsProofPromotion = !promoted && !lkgSurvivesRestart && skillsDebt && lastPrewarmBodiesVerified;
|
|
721
746
|
if (skillsProofPromotion) {
|
|
722
|
-
|
|
747
|
+
publishRestart({ reasons: ["skills"], version: planeDeferredNoHandoff.version, since: Date.now() });
|
|
723
748
|
logger.info("config_boot_skill_debt_promoted", { version: planeDeferredNoHandoff.version, note: "skill bodies verified on a source-confirmed-current candidate — the withheld skills restart is now published (non-durable lane, repair proven)" });
|
|
724
749
|
planeDeferredNoHandoff = undefined;
|
|
725
750
|
}
|
|
726
751
|
else if (promoted) {
|
|
727
752
|
const promotedReasons = [...new Set(planeDeferredNoHandoff.blocked ?? [])];
|
|
728
753
|
if (promotedReasons.length > 0) {
|
|
729
|
-
|
|
754
|
+
publishRestart({ reasons: promotedReasons, version: planeDeferredNoHandoff.version, since: Date.now() });
|
|
730
755
|
}
|
|
731
756
|
logger.info("models_tiers_deferred_promoted", { version: planeDeferredNoHandoff.version, reasons: promotedReasons, note: promotedReasons.length > 0 ? "handoff persistence recovered on a source-confirmed-current candidate — the withheld restart signal is now published" : "boot publication retry completed — LKG now durable, no restart needed (nothing was withheld)" });
|
|
732
757
|
planeDeferredNoHandoff = undefined;
|
|
@@ -826,13 +851,13 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
826
851
|
}
|
|
827
852
|
}
|
|
828
853
|
if (reasons.length === 0) {
|
|
829
|
-
|
|
854
|
+
publishRestart(undefined);
|
|
830
855
|
}
|
|
831
856
|
else if (!pendingRestart || pendingRestart.reasons.join(",") !== reasons.join(",")) {
|
|
832
|
-
|
|
857
|
+
publishRestart({ reasons, version: r.effective.version, since: Date.now() });
|
|
833
858
|
}
|
|
834
859
|
else {
|
|
835
|
-
|
|
860
|
+
publishRestart({ ...pendingRestart, version: r.effective.version });
|
|
836
861
|
}
|
|
837
862
|
logger.info("sema_registry_refreshed", {
|
|
838
863
|
version: r.effective.version,
|
|
@@ -949,7 +974,7 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
949
974
|
logger.warn("restart_candidate_publication_incomplete", { version: r.effective.version, blockedReasons: blocked, note: "late-boot candidate publication incomplete on a durable-declared deployment — restart signal withheld; retried every tick" });
|
|
950
975
|
}
|
|
951
976
|
if (reasons.length > 0)
|
|
952
|
-
|
|
977
|
+
publishRestart({ reasons, version: r.effective.version, since: Date.now() });
|
|
953
978
|
logger.info("config_loaded_deferred", { source: configProvider.kind, version: r.effective.version, models: (r.effective.models?.models ?? []).filter((m) => m.enabled !== false).length, ...(reasons.length > 0 ? { restartRequired: true, restartReasons: reasons } : {}) });
|
|
954
979
|
};
|
|
955
980
|
if (bootConfigPending) {
|
|
@@ -971,6 +996,10 @@ export async function createConfigCenterRuntime(ctx) {
|
|
|
971
996
|
clearInterval(ccTimer);
|
|
972
997
|
ccTimer = undefined;
|
|
973
998
|
}
|
|
999
|
+
credentialRenewer?.stop();
|
|
1000
|
+
},
|
|
1001
|
+
centerCredentialState() {
|
|
1002
|
+
return cc === undefined ? undefined : buildCenterCredentialHealthView(cc.credential.health(), credentialRenewer);
|
|
974
1003
|
},
|
|
975
1004
|
};
|
|
976
1005
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
2
|
+
import { reportHardKillReceipts } from "../background-session-reap.js";
|
|
2
3
|
import { liveHostForegroundChildCount, reapHostForegroundChildren } from "../plugins/host-platform.js";
|
|
3
4
|
import { liveEphemeralHostWorkspaceCount, reapEphemeralHostWorkspaces } from "../plugins/host-workspace-registry.js";
|
|
5
|
+
const PROCESS_EXIT_INCLUDES_RETAINED = false;
|
|
4
6
|
export function installProcessExitBoundary({ logger }) {
|
|
5
7
|
const reapOwnChildProcesses = () => {
|
|
6
8
|
try {
|
|
@@ -22,6 +24,15 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
22
24
|
logger.warn("shutdown_foreground_reap_failed", { err: String(err) });
|
|
23
25
|
}
|
|
24
26
|
};
|
|
27
|
+
const reapBackgroundHard = () => {
|
|
28
|
+
try {
|
|
29
|
+
const receipts = defaultTaskRegistry.killAllBackgroundShellsNow({ includeRetained: PROCESS_EXIT_INCLUDES_RETAINED, reason: "process_exit" });
|
|
30
|
+
reportHardKillReceipts(logger, receipts, "process_exit");
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
logger.warn("shutdown_background_hard_kill_failed", { err: String(err) });
|
|
34
|
+
}
|
|
35
|
+
};
|
|
25
36
|
const reapOwnHostWorkspaces = () => {
|
|
26
37
|
try {
|
|
27
38
|
const { removed, failed } = reapEphemeralHostWorkspaces();
|
|
@@ -42,6 +53,12 @@ export function installProcessExitBoundary({ logger }) {
|
|
|
42
53
|
catch (err) {
|
|
43
54
|
console.error("shutdown_exit_boundary_child_reap_threw", err);
|
|
44
55
|
}
|
|
56
|
+
try {
|
|
57
|
+
reapBackgroundHard();
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.error("shutdown_exit_boundary_background_hard_kill_threw", err);
|
|
61
|
+
}
|
|
45
62
|
try {
|
|
46
63
|
reapOwnHostWorkspaces();
|
|
47
64
|
}
|
package/dist/boot/runner-deps.js
CHANGED
|
@@ -180,6 +180,7 @@ export function createRunnerDeps(ctx) {
|
|
|
180
180
|
onAsk: createRunnerDepsOnAsk(toolApproval),
|
|
181
181
|
autoMode: {
|
|
182
182
|
...(config.autoModeClassifierFallback !== undefined ? { classifierFallback: config.autoModeClassifierFallback } : {}),
|
|
183
|
+
...(config.autoModeClassifierTimeoutMs !== undefined ? { timeoutMs: config.autoModeClassifierTimeoutMs } : {}),
|
|
183
184
|
},
|
|
184
185
|
sessionStore,
|
|
185
186
|
memoryBackend: memoryEngine ? memoryEngine.backend : undefined,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { applyGovernedVerdictAbsenceWarning, applyLocalAutoModeDeny, applyMemoryOptOutGrant, applyObserverEnvOptIn, centerEntitlementSourceWired, createPrincipalEntitlementsClient, } from "../runtime-caps-resolver.js";
|
|
2
2
|
import { scopedTokenNeedsWorker } from "../center-credential.js";
|
|
3
|
+
import { CENTER_CREDENTIAL_ENV } from "@sema-agent/settings-schema";
|
|
3
4
|
export function assertMemoryCapturePolicyWirable(input) {
|
|
4
5
|
if (input.policy !== "governed")
|
|
5
6
|
return;
|
|
@@ -13,7 +14,7 @@ export function assertMemoryCapturePolicyWirable(input) {
|
|
|
13
14
|
`refusal would read as an entitlement denial rather than the misconfiguration it is. This version has TWO verdict sources ` +
|
|
14
15
|
`— wire either one: (1) the \`memory_optout_grant\` table on a SQL store backend (DB_BACKEND=mysql|pg; the table is ` +
|
|
15
16
|
`created by the central ensureSchema and administered through /v1/admin/memory-optout), or (2) a config center that ` +
|
|
16
|
-
`EMITS \`allowMemoryOptOut\` in each principal's entitlement caps (SEMA_REGISTRY_URL +
|
|
17
|
+
`EMITS \`allowMemoryOptOut\` in each principal's entitlement caps (SEMA_REGISTRY_URL + ${CENTER_CREDENTIAL_ENV.token}, ` +
|
|
17
18
|
`SEMA_REGISTRY_DRY_RUN off — dry-run observes without applying, so it is not a source; and note the key is OPTIONAL in ` +
|
|
18
19
|
`the entitlement schema: a center that never emits it leaves every verdict absent, i.e. every opt-out still refused). ` +
|
|
19
20
|
`Or set MEMORY_CAPTURE_POLICY=open (opt-outs take effect; only an explicit per-principal false denies) or ` +
|
|
@@ -39,7 +40,7 @@ export function createRuntimeCaps(ctx) {
|
|
|
39
40
|
}
|
|
40
41
|
if (centerEntitlementSourceWired(config) && config.configCenter && scopedTokenNeedsWorker(config.configCenter.credential.read(), config.configCenter.worker)) {
|
|
41
42
|
logger.warn("runtime_caps_scoped_token_no_worker", {
|
|
42
|
-
reason:
|
|
43
|
+
reason: `${CENTER_CREDENTIAL_ENV.token} is a worker-scoped wpt_ token but SEMA_REGISTRY_WORKER is unset → center 403s per-principal caps → ALL workflow self-orchestration will be fail-closed denied. Set SEMA_REGISTRY_WORKER (the orchestrator normally injects it) or use the full SERVICE_PULL_TOKEN.`,
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
const principalCaps = centerEntitlementSourceWired(config) && config.configCenter
|
|
@@ -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) {
|
|
@@ -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;
|
|
@@ -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,7 @@ export async function runStage10(ctx) {
|
|
|
149
150
|
restartState: () => configCenter.restartState(),
|
|
150
151
|
planeDeferredState: () => configCenter.planeDeferredState(),
|
|
151
152
|
configApplyState: () => configCenter.configApplyState(),
|
|
153
|
+
centerCredentialState: () => configCenter.centerCredentialState(),
|
|
152
154
|
mcpRevocations,
|
|
153
155
|
mcpRevocationState: () => configCenter.mcpRevocationState(),
|
|
154
156
|
configRefreshNow: () => configCenter.refreshNow(),
|
|
@@ -186,6 +188,8 @@ export async function runStage10(ctx) {
|
|
|
186
188
|
isLiveOnThisReplica: server.isRunLiveOnThisReplica,
|
|
187
189
|
...(runStore ? { runs: runStore } : {}),
|
|
188
190
|
...(workflowRunStore ? { workflows: workflowRunStore } : {}),
|
|
191
|
+
agents: backgroundAgentStore,
|
|
192
|
+
hasPendingAsk: toolApproval ? (originTaskId) => toolApproval.hasLivePendingFrom(originTaskId) : undefined,
|
|
189
193
|
instanceId,
|
|
190
194
|
logger,
|
|
191
195
|
metrics,
|
|
@@ -235,10 +239,12 @@ export async function runStage10(ctx) {
|
|
|
235
239
|
const fleetClient = startFleetClientFromEnv(config, {
|
|
236
240
|
instanceId,
|
|
237
241
|
version: serviceVersion(),
|
|
238
|
-
|
|
242
|
+
readiness: () => readinessOf(deployment),
|
|
243
|
+
restart: () => deployment.restartState?.(),
|
|
239
244
|
...(fleetUsage ? { usage: fleetUsage } : {}),
|
|
240
245
|
logger: { info: (m, d) => logger.info(m, d ?? {}), warn: (m, d) => logger.warn(m, d ?? {}) },
|
|
241
246
|
});
|
|
247
|
+
configCenter.onSelfReportChange(() => void fleetClient?.announceNow());
|
|
242
248
|
if (fleetClient)
|
|
243
249
|
logger.info("fleet_client_started", { worker: config.configCenter?.worker, address: buildDisplaySafeUrl(process.env.FLEET_ADVERTISE_ADDRESS ?? "") });
|
|
244
250
|
logger.info("listening", {
|
|
@@ -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
|
|
@@ -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
|