@sema-agent/server 1.230.0 → 1.232.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/dist/capabilities/center-prompts.d.ts +30 -1
- package/dist/capabilities/center-prompts.d.ts.map +1 -1
- package/dist/capabilities/center-prompts.js +69 -0
- package/dist/capabilities/center-prompts.js.map +1 -1
- package/dist/config-lkg.js +2 -2
- package/dist/config-provider.d.ts.map +1 -1
- package/dist/config-provider.js +3 -0
- package/dist/config-provider.js.map +1 -1
- package/dist/http/server.d.ts.map +1 -1
- package/dist/http/server.js +50 -11
- package/dist/http/server.js.map +1 -1
- package/dist/main.js +97 -24
- package/dist/main.js.map +1 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +2 -2
- package/dist/orchestration/workflow-notify-journal.d.ts.map +1 -1
- package/dist/orchestration/workflow-notify-journal.js +2 -1
- package/dist/orchestration/workflow-notify-journal.js.map +1 -1
- package/dist/run-local.d.ts.map +1 -1
- package/dist/run-local.js +35 -2
- package/dist/run-local.js.map +1 -1
- package/dist/sema-registry.d.ts +1 -0
- package/dist/sema-registry.d.ts.map +1 -1
- package/dist/sema-registry.js.map +1 -1
- package/dist/task-settings.d.ts +5 -2
- package/dist/task-settings.d.ts.map +1 -1
- package/dist/task-settings.js +37 -8
- package/dist/task-settings.js.map +1 -1
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { readFileSync, existsSync, realpathSync } from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { loadRemoteExec } from "@sema-agent/registry-core/node";
|
|
5
|
-
import { Runner, TtlSessionStore, uuidv7, FileRosterStore, defaultTaskRegistry, combinePolicies, createDurableQuestionPolicy, createAllowDenyPolicy, tightenTaskSpec, isThinkingLevel, QUESTION_AWAITS_RESUME, FileWorkflowRunStore, InMemoryWorkflowRunStore, workflowsCapability, NodeLspManager, createFileWorkflowScriptStore, expandTiers, NodeExecutionEnv } from "@sema-agent/core";
|
|
6
|
+
import { Runner, TtlSessionStore, uuidv7, FileRosterStore, defaultTaskRegistry, combinePolicies, createDurableQuestionPolicy, createAllowDenyPolicy, tightenTaskSpec, isThinkingLevel, QUESTION_AWAITS_RESUME, FileWorkflowRunStore, InMemoryWorkflowRunStore, workflowsCapability, NodeLspManager, createFileWorkflowScriptStore, expandTiers, NodeExecutionEnv, CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore } from "@sema-agent/core";
|
|
6
7
|
import { PgMemoryEngineBackend, ensurePgMemoryEngineSchema } from "./plugins/memory-engine-pg.js";
|
|
7
8
|
import { TiDBMemoryEngineBackend, ensureTiDBMemoryEngineSchema } from "./plugins/memory-engine-tidb.js";
|
|
8
9
|
import { PgMemoryHistoryStore, ensurePgMemoryHistorySchema, PgMemorySyncStore, ensurePgMemorySyncSchema } from "./plugins/memory-sync-store-pg.js";
|
|
@@ -71,7 +72,7 @@ import { ToolApprovalCoordinator } from "./tool-approval.js";
|
|
|
71
72
|
import { applyEffective, mutateInPlace, logEffectiveDiff, applyCenterSkills, resolveMcpServers, mcpForScenario, restartReasons } from "./sema-registry.js";
|
|
72
73
|
import { ensureSealedKeyStore, reportExecutionPublicKey } from "./sealed-key.js";
|
|
73
74
|
import { createConfigProvider, raceBootFetch, BOOT_FETCH_DEFERRED } from "./config-provider.js";
|
|
74
|
-
import {
|
|
75
|
+
import { validatePromptsDomain, centerPromptProvider, applyCatalogToSource, CORE_ENGINE_VERSION } from "./capabilities/center-prompts.js";
|
|
75
76
|
import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "./config-lkg.js";
|
|
76
77
|
import { TiDBRosterStore, PgRosterStore, ensureTiDBRosterSchema, ensurePgRosterSchema } from "./plugins/roster-store-sql.js";
|
|
77
78
|
import { createPrincipalCapsClient, gateExecutionLane, scopedTokenNeedsWorker, applyObserverEnvOptIn } from "./runtime-caps-resolver.js";
|
|
@@ -159,23 +160,78 @@ async function main() {
|
|
|
159
160
|
}
|
|
160
161
|
};
|
|
161
162
|
let centerPrompts;
|
|
162
|
-
|
|
163
|
+
let pendingCatalogFaces;
|
|
164
|
+
const retryPendingCatalog = async (phase) => {
|
|
165
|
+
if (!pendingCatalogFaces)
|
|
166
|
+
return;
|
|
167
|
+
const { target } = pendingCatalogFaces;
|
|
168
|
+
if (await applyCatalogToSource(promptSource, target, centerPrompts, logger, phase)) {
|
|
169
|
+
centerPrompts = target;
|
|
170
|
+
pendingCatalogFaces = undefined;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const promptEpochDir = join(config.localDataRoot ?? localRoot, "prompt-epoch");
|
|
174
|
+
const promptStateDir = join(promptEpochDir, "state", cc?.worker === undefined ? "global" : `worker-${createHash("sha256").update(cc.worker).digest("hex").slice(0, 16)}`);
|
|
175
|
+
const promptSource = (() => {
|
|
176
|
+
try {
|
|
177
|
+
return new CenterPromptSource({
|
|
178
|
+
store: new FilePromptArtifactStore(promptEpochDir),
|
|
179
|
+
stateStore: new FilePromptSourceStateStore(promptStateDir),
|
|
180
|
+
engineVersion: CORE_ENGINE_VERSION,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
logger.warn("center_prompts_store_unwritable", { dir: promptEpochDir, err: String(e), note: "file-backed prompt-epoch store unavailable — memory fallback (catalog candidate not restart-durable); built-ins/declaration axis unaffected" });
|
|
185
|
+
return new CenterPromptSource({ store: new MemoryPromptArtifactStore(), stateStore: new MemoryPromptSourceStateStore(), engineVersion: CORE_ENGINE_VERSION });
|
|
186
|
+
}
|
|
187
|
+
})();
|
|
188
|
+
if (configProvider && !cc?.dryRun) {
|
|
189
|
+
try {
|
|
190
|
+
await promptSource.restore();
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
logger.warn("center_prompts_catalog_restore_failed", { err: String(e), note: "disk LKG unavailable — catalog candidate absent until the next adopt; declaration axis and built-ins unaffected" });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const adoptCenterPrompts = async (eff, phase) => {
|
|
163
197
|
const raw = eff?.prompts;
|
|
164
198
|
if (raw === undefined) {
|
|
165
199
|
if (centerPrompts)
|
|
166
200
|
logger.info("center_prompts_cleared", { phase, note: "effective carries no prompts key (publish gate off) — built-in providers resume" });
|
|
167
|
-
|
|
201
|
+
const cleared = await applyCatalogToSource(promptSource, undefined, centerPrompts, logger, phase);
|
|
202
|
+
if (cleared) {
|
|
203
|
+
centerPrompts = undefined;
|
|
204
|
+
pendingCatalogFaces = undefined;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
pendingCatalogFaces = { target: undefined };
|
|
208
|
+
}
|
|
168
209
|
return;
|
|
169
210
|
}
|
|
170
|
-
const v =
|
|
211
|
+
const v = validatePromptsDomain(raw);
|
|
171
212
|
if (!v.ok) {
|
|
172
|
-
logger.warn("center_prompts_invalid", { phase, error: v.error, kept: centerPrompts?.packId ?? "(builtin)", note: "malformed prompts face rejected (core assemble would THROW per task) — keeping the previous pack/built-ins; fix the center payload" });
|
|
213
|
+
logger.warn("center_prompts_invalid", { phase, error: v.error, kept: centerPrompts?.declarations?.packId ?? (centerPrompts?.catalog ? "(catalog)" : "(builtin)"), note: "malformed prompts face rejected (core assemble would THROW per task) — keeping the previous pack/built-ins; fix the center payload" });
|
|
173
214
|
return;
|
|
174
215
|
}
|
|
175
|
-
if (centerPrompts?.
|
|
176
|
-
logger.info("center_prompts_adopted", {
|
|
216
|
+
if (centerPrompts?.identity !== v.value.identity) {
|
|
217
|
+
logger.info("center_prompts_adopted", {
|
|
218
|
+
phase,
|
|
219
|
+
axes: v.value.axes,
|
|
220
|
+
...(v.value.declarations
|
|
221
|
+
? { packId: v.value.declarations.packId, contentDigest: v.value.declarations.contentDigest, sections: v.value.declarations.sections.length, scenarioOverrides: Object.keys(v.value.declarations.scenarioOverrides ?? {}).length }
|
|
222
|
+
: {}),
|
|
223
|
+
...(v.value.catalog ? { artifactDigest: v.value.catalog.artifact.artifactDigest, catalogDigest: v.value.catalog.artifact.payload.catalogDigest, sourceRevision: v.value.catalog.sourceRevision } : {}),
|
|
224
|
+
note: "new tasks assemble the new pack (epoch re-pins at the next task boundary); in-flight sessions stay pinned",
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const transitioned = await applyCatalogToSource(promptSource, v.value, centerPrompts, logger, phase);
|
|
228
|
+
if (transitioned) {
|
|
229
|
+
centerPrompts = v.value;
|
|
230
|
+
pendingCatalogFaces = undefined;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
pendingCatalogFaces = { target: v.value };
|
|
177
234
|
}
|
|
178
|
-
centerPrompts = v.value;
|
|
179
235
|
};
|
|
180
236
|
let bootConfigPending;
|
|
181
237
|
const lkgEnabled = configProvider?.kind === "remote" && process.env.CONFIG_LKG_DISABLED !== "true";
|
|
@@ -209,9 +265,9 @@ async function main() {
|
|
|
209
265
|
logger.info("config_loaded_lkg", { path: lkgPath, savedAt: read.lkg.savedAt, why, note: "booting from the persisted last-known-good (all restart-to-apply faces included) — the live pull continues in the background and reconciles on arrival" });
|
|
210
266
|
return { effective: read.lkg.effective, ...(read.lkg.etag !== undefined ? { etag: read.lkg.etag } : {}) };
|
|
211
267
|
};
|
|
212
|
-
const bootApplyLkgInline = (lkgR) => {
|
|
268
|
+
const bootApplyLkgInline = async (lkgR) => {
|
|
213
269
|
applyEffective(config, lkgR.effective, logger, { sealedKeys });
|
|
214
|
-
adoptCenterPrompts(lkgR.effective, "boot-lkg");
|
|
270
|
+
await adoptCenterPrompts(lkgR.effective, "boot-lkg");
|
|
215
271
|
markRosterLanded(lkgR.effective);
|
|
216
272
|
effective = lkgR.effective;
|
|
217
273
|
latestEffective = lkgR.effective;
|
|
@@ -240,7 +296,7 @@ async function main() {
|
|
|
240
296
|
}
|
|
241
297
|
if (raced === BOOT_FETCH_DEFERRED && lkgFallback) {
|
|
242
298
|
try {
|
|
243
|
-
bootApplyLkgInline(lkgFallback);
|
|
299
|
+
await bootApplyLkgInline(lkgFallback);
|
|
244
300
|
}
|
|
245
301
|
catch (applyErr) {
|
|
246
302
|
lkgBooted = false;
|
|
@@ -250,7 +306,7 @@ async function main() {
|
|
|
250
306
|
const r = raced === BOOT_FETCH_DEFERRED ? null : raced;
|
|
251
307
|
if (r) {
|
|
252
308
|
const bootPromptsRaw = r.effective.prompts;
|
|
253
|
-
const bootPromptsOk = bootPromptsRaw === undefined ||
|
|
309
|
+
const bootPromptsOk = bootPromptsRaw === undefined || validatePromptsDomain(bootPromptsRaw).ok;
|
|
254
310
|
const bootClean = (r.domainErrors ?? []).length === 0 && bootPromptsOk;
|
|
255
311
|
if (bootClean)
|
|
256
312
|
ccEtag = r.etag;
|
|
@@ -261,7 +317,7 @@ async function main() {
|
|
|
261
317
|
}
|
|
262
318
|
else {
|
|
263
319
|
applyEffective(config, r.effective, logger, { sealedKeys });
|
|
264
|
-
adoptCenterPrompts(r.effective, "boot");
|
|
320
|
+
await adoptCenterPrompts(r.effective, "boot");
|
|
265
321
|
markRosterLanded(r.effective);
|
|
266
322
|
effective = r.effective;
|
|
267
323
|
if (bootClean)
|
|
@@ -282,7 +338,7 @@ async function main() {
|
|
|
282
338
|
if (lkgFallback) {
|
|
283
339
|
lkgBooted = true;
|
|
284
340
|
try {
|
|
285
|
-
bootApplyLkgInline(lkgFallback);
|
|
341
|
+
await bootApplyLkgInline(lkgFallback);
|
|
286
342
|
}
|
|
287
343
|
catch (applyErr) {
|
|
288
344
|
lkgBooted = false;
|
|
@@ -742,9 +798,9 @@ async function main() {
|
|
|
742
798
|
})
|
|
743
799
|
: undefined;
|
|
744
800
|
const fleetBus = new FleetEventBus();
|
|
745
|
-
const workflowRunStore = baseWorkflowRunStore
|
|
801
|
+
const workflowRunStore = baseWorkflowRunStore
|
|
746
802
|
? new JournalingWorkflowRunStore(baseWorkflowRunStore, workflowNotifyGate, fleetBus)
|
|
747
|
-
:
|
|
803
|
+
: undefined;
|
|
748
804
|
const workflowJournalStore = config.selfOrchestrationEnabled && backend ? backend.workflowJournal() : undefined;
|
|
749
805
|
const outcomeSink = backend?.outcomeSink();
|
|
750
806
|
const workflowAgentRegistry = config.selfOrchestrationEnabled ? new WorkflowAgentRegistry() : undefined;
|
|
@@ -815,6 +871,7 @@ async function main() {
|
|
|
815
871
|
warn: (msg, fields) => logger.warn(msg, fields),
|
|
816
872
|
});
|
|
817
873
|
const runnerDeps = {
|
|
874
|
+
promptSource,
|
|
818
875
|
...(rosterStore ? { rosterStore } : {}),
|
|
819
876
|
brain,
|
|
820
877
|
models: config.models,
|
|
@@ -1003,7 +1060,7 @@ async function main() {
|
|
|
1003
1060
|
if (sessionTitler)
|
|
1004
1061
|
logger.info("session_auto_title_enabled", {});
|
|
1005
1062
|
const workflowsCapable = workflowsCapability(runnerDeps);
|
|
1006
|
-
const subRunner = new Runner({ brain, models: config.models, roles: config.roles, pricing, tracer, ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}) });
|
|
1063
|
+
const subRunner = new Runner({ brain, models: config.models, roles: config.roles, pricing, tracer, promptSource, ...(executionEnvFactory ? { executionEnvFactory } : {}), ...(lspManager ? { lspManager } : {}) });
|
|
1007
1064
|
const authorize = createAuthorizer(config, sessionStore);
|
|
1008
1065
|
const runStore = backend ? backend.run() : undefined;
|
|
1009
1066
|
const resumeAnchorStore = backend ? backend.resumeAnchor() : undefined;
|
|
@@ -1043,6 +1100,11 @@ async function main() {
|
|
|
1043
1100
|
hint: "host-semantics lane with no approval face: permissionMode default/auto Write/Edit asks will auto-deny (fail-closed); wire TOOL_APPROVAL_ENABLED=true or DURABLE_APPROVAL=true to answer them",
|
|
1044
1101
|
});
|
|
1045
1102
|
}
|
|
1103
|
+
if (config.selfOrchestrationEnabled && config.remoteExec !== undefined && config.remoteExec.provider !== "host" && !toolApproval && !durableEnabled) {
|
|
1104
|
+
logger.warn("workflow_gate_no_responder", {
|
|
1105
|
+
hint: "self-orchestration with no approval face: permissionMode default/auto/acceptEdits run_workflow asks will auto-deny (fail-closed); wire TOOL_APPROVAL_ENABLED=true or DURABLE_APPROVAL=true to answer them",
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1046
1108
|
if (singleUserAutoAcceptBaseline) {
|
|
1047
1109
|
logger.info("tool_policy_single_user_default", {
|
|
1048
1110
|
posture: "adjudicated auto-accept — ALL write/hand/MCP tool surfaces auto-allowed (core per-surface UNGATED enumeration suppressed for single-user turnkey)",
|
|
@@ -1176,10 +1238,11 @@ async function main() {
|
|
|
1176
1238
|
return;
|
|
1177
1239
|
refreshInFlight = true;
|
|
1178
1240
|
try {
|
|
1241
|
+
await retryPendingCatalog("refresh-retry");
|
|
1179
1242
|
const r = prefetched !== undefined ? prefetched : await configProvider.fetchEffective(ccEtag);
|
|
1180
1243
|
if (r) {
|
|
1181
1244
|
const promptsRaw = r.effective.prompts;
|
|
1182
|
-
const promptsGate = promptsRaw !== undefined ?
|
|
1245
|
+
const promptsGate = promptsRaw !== undefined ? validatePromptsDomain(promptsRaw) : { ok: true };
|
|
1183
1246
|
const badDomains = [
|
|
1184
1247
|
...new Set([...(r.domainErrors ?? []).map((de) => de.domain), ...(promptsGate.ok ? [] : ["prompts"])]),
|
|
1185
1248
|
]
|
|
@@ -1208,7 +1271,7 @@ async function main() {
|
|
|
1208
1271
|
}
|
|
1209
1272
|
else {
|
|
1210
1273
|
applyEffective(config, r.effective, logger, { teamsOnly: true, sealedKeys });
|
|
1211
|
-
adoptCenterPrompts(r.effective, "refresh");
|
|
1274
|
+
await adoptCenterPrompts(r.effective, "refresh");
|
|
1212
1275
|
markRosterLanded(r.effective);
|
|
1213
1276
|
mutateInPlace(pricing, buildPricing(config.models));
|
|
1214
1277
|
keyResolver = buildKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys);
|
|
@@ -1257,7 +1320,7 @@ async function main() {
|
|
|
1257
1320
|
};
|
|
1258
1321
|
const deferredBootApplyInner = async (r) => {
|
|
1259
1322
|
const promptsRaw = r.effective.prompts;
|
|
1260
|
-
const promptsGate = promptsRaw !== undefined ?
|
|
1323
|
+
const promptsGate = promptsRaw !== undefined ? validatePromptsDomain(promptsRaw) : { ok: true };
|
|
1261
1324
|
if ((r.domainErrors ?? []).length > 0 || !promptsGate.ok) {
|
|
1262
1325
|
logger.warn("config_boot_deferred_candidate_rejected", {
|
|
1263
1326
|
version: r.effective.version,
|
|
@@ -1272,7 +1335,7 @@ async function main() {
|
|
|
1272
1335
|
return;
|
|
1273
1336
|
}
|
|
1274
1337
|
applyEffective(config, r.effective, logger, { teamsOnly: true, sealedKeys });
|
|
1275
|
-
adoptCenterPrompts(r.effective, "boot-deferred");
|
|
1338
|
+
await adoptCenterPrompts(r.effective, "boot-deferred");
|
|
1276
1339
|
markRosterLanded(r.effective);
|
|
1277
1340
|
mutateInPlace(pricing, buildPricing(config.models));
|
|
1278
1341
|
keyResolver = buildKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys);
|
|
@@ -1633,7 +1696,7 @@ async function main() {
|
|
|
1633
1696
|
})(cap.tools),
|
|
1634
1697
|
skills: mergeUserSkills(cap.skills, body.skills, logger),
|
|
1635
1698
|
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, logger),
|
|
1636
|
-
promptProvider: centerPrompts ? centerPromptProvider(centerPrompts, scenarioName) : cap.promptProvider,
|
|
1699
|
+
promptProvider: centerPrompts?.declarations ? centerPromptProvider(centerPrompts.declarations, scenarioName) : cap.promptProvider,
|
|
1637
1700
|
toolPolicy: durableEnabled
|
|
1638
1701
|
? combinePolicies(createDurableQuestionPolicy(), createDurableAskPolicy({
|
|
1639
1702
|
requireApproval: config.approvalRequire, deny: config.approvalDeny, autoBudget: config.approvalAutoBudget, neverAuto: config.approvalNeverAuto,
|
|
@@ -1714,8 +1777,18 @@ async function main() {
|
|
|
1714
1777
|
};
|
|
1715
1778
|
})()
|
|
1716
1779
|
: undefined;
|
|
1780
|
+
const workflowGate = approvalExemptionStore && auth?.sessionId
|
|
1781
|
+
? {
|
|
1782
|
+
isExempt: async (toolName) => {
|
|
1783
|
+
const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
|
|
1784
|
+
if (hit)
|
|
1785
|
+
logger.info("workflow_gate_exempted", { toolName, sessionId: auth.sessionId });
|
|
1786
|
+
return hit;
|
|
1787
|
+
},
|
|
1788
|
+
}
|
|
1789
|
+
: undefined;
|
|
1717
1790
|
try {
|
|
1718
|
-
governed = applyTaskSettings(governedBase, effectiveSettings, fsWriteGate);
|
|
1791
|
+
governed = applyTaskSettings(governedBase, effectiveSettings, fsWriteGate, workflowGate);
|
|
1719
1792
|
}
|
|
1720
1793
|
catch (e) {
|
|
1721
1794
|
throw new HttpError(422, `settings are tighten-only and cannot loosen the deployment policy: ${e.message}`);
|