@sema-agent/server 1.314.0 → 1.315.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/approval-hmac.d.ts +17 -0
- package/dist/approval-hmac.js +27 -0
- package/dist/config-center/apply-effective.d.ts +22 -0
- package/dist/config-center/apply-effective.js +283 -0
- package/dist/config-center/http-client.d.ts +23 -0
- package/dist/config-center/http-client.js +109 -0
- package/dist/config-center/restart-signal.d.ts +12 -0
- package/dist/config-center/restart-signal.js +70 -0
- package/dist/config-center/skills-mcp.d.ts +13 -0
- package/dist/config-center/skills-mcp.js +113 -0
- package/dist/config-center/types.d.ts +143 -0
- package/dist/config-center/types.js +2 -0
- package/dist/fleet/fleet-bus.js +92 -83
- package/dist/hooks/hook-runner.js +18 -9
- package/dist/http/server.d.ts +95 -69
- package/dist/http/server.js +8 -1
- package/dist/index.d.ts +1 -1
- package/dist/leader/leader.js +5 -2
- package/dist/leader/wire.js +169 -165
- package/dist/main.js +462 -451
- package/dist/plugins/checkpoint-store-sql.d.ts +67 -0
- package/dist/plugins/checkpoint-store-sql.js +224 -0
- package/dist/plugins/image-bake-store-sql.d.ts +53 -0
- package/dist/plugins/image-bake-store-sql.js +463 -0
- package/dist/plugins/k8s-bg-scripts.d.ts +19 -0
- package/dist/plugins/k8s-bg-scripts.js +129 -0
- package/dist/plugins/k8s-exec-protocol.d.ts +20 -0
- package/dist/plugins/k8s-exec-protocol.js +87 -0
- package/dist/plugins/pg-checkpoint-store.d.ts +1 -33
- package/dist/plugins/pg-checkpoint-store.js +1 -189
- package/dist/plugins/pg-cost-quota.js +3 -143
- package/dist/plugins/pg-image-bake.d.ts +1 -40
- package/dist/plugins/pg-image-bake.js +1 -420
- package/dist/plugins/pg-rate-limiter.d.ts +2 -32
- package/dist/plugins/pg-rate-limiter.js +4 -147
- package/dist/plugins/remote-env-k8s.d.ts +5 -38
- package/dist/plugins/remote-env-k8s.js +7 -213
- package/dist/plugins/sql-driver.d.ts +25 -0
- package/dist/plugins/sql-driver.js +59 -0
- package/dist/plugins/tidb-checkpoint-store.d.ts +1 -49
- package/dist/plugins/tidb-checkpoint-store.js +1 -191
- package/dist/plugins/tidb-image-bake.d.ts +1 -38
- package/dist/plugins/tidb-image-bake.js +1 -348
- package/dist/plugins/write-behind-counter.d.ts +14 -3
- package/dist/plugins/write-behind-counter.js +39 -12
- package/dist/principal-jwt.d.ts +44 -0
- package/dist/principal-jwt.js +95 -0
- package/dist/security.d.ts +2 -58
- package/dist/security.js +3 -118
- package/dist/sema-registry.d.ts +5 -200
- package/dist/sema-registry.js +4 -567
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -58,7 +58,7 @@ import { createRegistryJwtVerifier } from "./auth-bridge.js";
|
|
|
58
58
|
import { createMetrics } from "./observability/metrics.js";
|
|
59
59
|
import { setRedactionObserver, redactSecrets } from "./trace/redact.js";
|
|
60
60
|
import { RateLimiter } from "./observability/rate-limit.js";
|
|
61
|
-
import { createHttpServer, explicitOperator } from "./http/server.js";
|
|
61
|
+
import { createHttpServer, explicitOperator, } from "./http/server.js";
|
|
62
62
|
import { exportMemoryScope } from "./memory-export.js";
|
|
63
63
|
import { performMemorySync } from "./memory-sync.js";
|
|
64
64
|
import { createMemorySyncRunner, createMemorySyncTransport } from "./memory-sync-client.js";
|
|
@@ -1834,73 +1834,77 @@ async function main() {
|
|
|
1834
1834
|
if (registryJwtVerifier)
|
|
1835
1835
|
logger.info("auth_bridge_enabled", { issuer: authBridgeIssuer });
|
|
1836
1836
|
const hookWakeBus = {};
|
|
1837
|
-
const
|
|
1838
|
-
runner,
|
|
1839
|
-
config,
|
|
1840
|
-
authorize,
|
|
1841
|
-
sessionStoreLabel: config.sessionBackend === "tidb" && backend ? `durable(${backend.kind})` : config.sessionBackend,
|
|
1842
|
-
taskAttachmentStore: taskAttachmentStore ? taskAttachmentStore : undefined,
|
|
1843
|
-
snapshotBlobSqlCapBytes: backend && backend.kind !== "local" && !config.snapshotBlobStore
|
|
1844
|
-
? (config.snapshotBlobSqlMaxBytes ?? (backend.kind === "mysql" ? SQL_BLOB_DEFAULT_MAX_BYTES : undefined))
|
|
1845
|
-
: undefined,
|
|
1846
|
-
modelReady: () => modelReadyState.ready,
|
|
1847
|
-
scenarioDetails,
|
|
1848
|
-
registryJwtVerifier: registryJwtVerifier ? registryJwtVerifier : undefined,
|
|
1849
|
-
hookWakeBus,
|
|
1837
|
+
const stores = {
|
|
1850
1838
|
runStore,
|
|
1851
|
-
fleetBus,
|
|
1852
|
-
workflowsCapable,
|
|
1853
1839
|
resumeAnchorStore: resumeAnchorStore ? resumeAnchorStore : undefined,
|
|
1840
|
+
approvalStore,
|
|
1854
1841
|
approvalExemptionStore: approvalExemptionStore ? approvalExemptionStore : undefined,
|
|
1855
|
-
|
|
1842
|
+
checkpointStore,
|
|
1856
1843
|
sessionPolicyStore: sessionPolicyStore ? sessionPolicyStore : undefined,
|
|
1857
1844
|
fileSnapshotStore: fileSnapshotStore ? fileSnapshotStore : undefined,
|
|
1858
|
-
|
|
1859
|
-
sessionMirrorRuling: principalCaps
|
|
1860
|
-
? async (p) => (await principalCaps.executionRuling(p))?.sessionMirror
|
|
1861
|
-
: undefined,
|
|
1862
|
-
approvalStore,
|
|
1863
|
-
checkpointStore,
|
|
1845
|
+
taskAttachmentStore: taskAttachmentStore ? taskAttachmentStore : undefined,
|
|
1864
1846
|
backgroundAgentStore: backgroundAgentStore ? backgroundAgentStore : undefined,
|
|
1865
|
-
|
|
1866
|
-
parkedReviveInheritedGate: parkedReviveInheritedGate ? parkedReviveInheritedGate : undefined,
|
|
1867
|
-
imageIndex,
|
|
1868
|
-
imageBakes,
|
|
1869
|
-
leaderEndpoint,
|
|
1847
|
+
sessionStorage: ownerAware,
|
|
1870
1848
|
workflowRunStore: workflowRunStore ? workflowRunStore : undefined,
|
|
1871
1849
|
workflowJournalStore: workflowJournalStore ? workflowJournalStore : undefined,
|
|
1850
|
+
imageIndex,
|
|
1851
|
+
imageBakes,
|
|
1852
|
+
outcomeSink: outcomeSink ? outcomeSink : undefined,
|
|
1853
|
+
sendFileLedger: sendFileLedger ? sendFileLedger : undefined,
|
|
1854
|
+
backend: backend ? backend : undefined,
|
|
1855
|
+
};
|
|
1856
|
+
const coordinators = {
|
|
1857
|
+
elicitation: elicitation ? elicitation : undefined,
|
|
1858
|
+
question: question ? question : undefined,
|
|
1859
|
+
toolApproval: toolApproval ? toolApproval : undefined,
|
|
1872
1860
|
workflowAgentRegistry: workflowAgentRegistry ? workflowAgentRegistry : undefined,
|
|
1873
1861
|
subagentSteerRegistry,
|
|
1874
|
-
subagentTaskOutput: (handle, access) => backgroundAgentOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1875
|
-
taskHandleOutput: (handle, access) => taskHandleOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1876
|
-
taskHandleStop: (handle, access) => taskHandleStop(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1877
1862
|
workflowCompletionInbox: workflowCompletionInbox ? workflowCompletionInbox : undefined,
|
|
1878
|
-
|
|
1879
|
-
sessionStorage: ownerAware,
|
|
1863
|
+
fleetBus,
|
|
1880
1864
|
sessionWatch: sessionWatchRegistry ? sessionWatchRegistry : undefined,
|
|
1881
|
-
|
|
1865
|
+
hookWakeBus,
|
|
1866
|
+
sendUserFile: sendUserFileEmitter ? sendUserFileEmitter : undefined,
|
|
1867
|
+
leaderEndpoint,
|
|
1868
|
+
sessionTitler: sessionTitler ? sessionTitler : undefined,
|
|
1869
|
+
};
|
|
1870
|
+
const seams = {
|
|
1871
|
+
sessionAudit,
|
|
1882
1872
|
purgeSession: purgeSession ? purgeSession : undefined,
|
|
1873
|
+
subagentTaskOutput: (handle, access) => backgroundAgentOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1874
|
+
taskHandleOutput: (handle, access) => taskHandleOutput(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1875
|
+
taskHandleStop: (handle, access) => taskHandleStop(defaultTaskRegistry, handle, access, backgroundAgentStore),
|
|
1876
|
+
memoryExport: memoryExportBackend ? (scope) => exportMemoryScope(memoryExportBackend, scope) : undefined,
|
|
1877
|
+
memorySync: memoryExportBackend && memorySyncCursors
|
|
1878
|
+
? (scope, syncReq) => performMemorySync(memoryExportBackend, memorySyncCursors, scope, syncReq)
|
|
1879
|
+
: undefined,
|
|
1880
|
+
sessionMirrorRuling: principalCaps
|
|
1881
|
+
? async (p) => (await principalCaps.executionRuling(p))?.sessionMirror
|
|
1882
|
+
: undefined,
|
|
1883
1883
|
instrumentDegenerate,
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
toolApproval: toolApproval ? toolApproval : undefined,
|
|
1890
|
-
sendUserFile: sendUserFileEmitter ? sendUserFileEmitter : undefined,
|
|
1891
|
-
sendFileLedger: sendFileLedger ? sendFileLedger : undefined,
|
|
1892
|
-
instanceId,
|
|
1884
|
+
sideQueryAccounting,
|
|
1885
|
+
parkedReviveTool: parkedReviveTool ? parkedReviveTool : undefined,
|
|
1886
|
+
parkedReviveInheritedGate: parkedReviveInheritedGate ? parkedReviveInheritedGate : undefined,
|
|
1887
|
+
};
|
|
1888
|
+
const observability = {
|
|
1893
1889
|
logger,
|
|
1894
1890
|
metrics,
|
|
1891
|
+
modelUsage: modelUsageTracker,
|
|
1892
|
+
promptManifests: promptManifestTracker,
|
|
1893
|
+
planCacheProbe,
|
|
1894
|
+
};
|
|
1895
|
+
const governance = {
|
|
1896
|
+
authorize,
|
|
1897
|
+
registryJwtVerifier: registryJwtVerifier ? registryJwtVerifier : undefined,
|
|
1895
1898
|
rateLimiter,
|
|
1896
1899
|
costQuota,
|
|
1897
1900
|
fleetLease: fleetLease ? fleetLease : undefined,
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1901
|
+
};
|
|
1902
|
+
const deployment = {
|
|
1903
|
+
sessionStoreLabel: config.sessionBackend === "tidb" && backend ? `durable(${backend.kind})` : config.sessionBackend,
|
|
1904
|
+
modelReady: () => modelReadyState.ready,
|
|
1905
|
+
scenarioDetails,
|
|
1906
|
+
workflowsCapable,
|
|
1907
|
+
instanceId,
|
|
1904
1908
|
capabilities: {
|
|
1905
1909
|
version: serviceVersion(),
|
|
1906
1910
|
scenarios: Object.keys(scenarios),
|
|
@@ -1910,431 +1914,438 @@ async function main() {
|
|
|
1910
1914
|
planeDeferredState: () => planeDeferredNoHandoff,
|
|
1911
1915
|
drainState,
|
|
1912
1916
|
storeDegraded: storeBackendDegraded,
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1917
|
+
};
|
|
1918
|
+
const knobs = {
|
|
1919
|
+
snapshotBlobSqlCapBytes: backend && backend.kind !== "local" && !config.snapshotBlobStore
|
|
1920
|
+
? (config.snapshotBlobSqlMaxBytes ?? (backend.kind === "mysql" ? SQL_BLOB_DEFAULT_MAX_BYTES : undefined))
|
|
1921
|
+
: undefined,
|
|
1922
|
+
sessionEventsMaxConnections: sessionWatchRegistry ? posIntEnv(process.env.SESSION_EVENTS_MAX_CONNS, 256, 100_000) : undefined,
|
|
1923
|
+
};
|
|
1924
|
+
const resolveSpec = async (body, _req, auth, opts) => {
|
|
1925
|
+
const requested = gateScenarioRequest(await principalCaps?.scenarioRuling(auth?.principal), body.scenario, config.defaultScenario);
|
|
1926
|
+
gateExecutionLane(await principalCaps?.executionRuling(auth?.principal), config.remoteExec?.provider ?? "in-process");
|
|
1927
|
+
const scenarioName = scenarios[requested] ? requested : "default";
|
|
1928
|
+
if (scenarioName === "autonomous")
|
|
1929
|
+
logger.warn("scenario_autonomous_deprecated", { alias: "code", note: "renamed by [891]; alias keeps finalVerification pinned — pass scenario:'code' (+ explicit finalVerification if wanted)" });
|
|
1930
|
+
const cap = selectScenario(scenarios, scenarioName)(body, auth?.principal);
|
|
1931
|
+
const centerDecls = centerPrompts?.declarations;
|
|
1932
|
+
const appendLessPack = centerDecls
|
|
1933
|
+
? centerIdentityAssembled(centerDecls, scenarioName, hasConstitutionAnchors)
|
|
1934
|
+
: providerDropsAppend(cap.promptProvider, typeof body.systemPrompt === "string" ? body.systemPrompt : undefined);
|
|
1935
|
+
const acceptedAppend = acceptAppendSystemPrompt(body.appendSystemPrompt, (detail) => logger.warn("append_system_prompt_dropped", { detail, sessionId: auth?.sessionId ?? null }), appendLessPack);
|
|
1936
|
+
const objective = typeof body.objective === "string" ? body.objective : "";
|
|
1937
|
+
const parsedSettings = parseTaskSettings(body.settings);
|
|
1938
|
+
if (opts?.leg === "fresh" && appendLessPack) {
|
|
1939
|
+
const riderPresent = typeof body.appendSystemPrompt === "string" && body.appendSystemPrompt.length > 0;
|
|
1940
|
+
if (riderPresent || parsedSettings.settings?.outputStyle) {
|
|
1941
|
+
throw new HttpError(400, `${riderPresent ? "appendSystemPrompt" : "settings.outputStyle"} is not supported when the effective prompt is already assembled (constitution anchors in systemPrompt, or a center assembled-identity pack for this scenario): the assembler's pass-through path cannot mount the append slot — fold it into the assembled prompt instead`);
|
|
1935
1942
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1943
|
+
}
|
|
1944
|
+
if (parsedSettings.deferred.length > 0) {
|
|
1945
|
+
logger.warn("task_settings_deferred", { fields: parsedSettings.deferred, sessionId: auth?.sessionId ?? null });
|
|
1946
|
+
}
|
|
1947
|
+
let attachmentNotice;
|
|
1948
|
+
{
|
|
1949
|
+
const reqAtt = body.attachmentIds;
|
|
1950
|
+
if (reqAtt !== undefined) {
|
|
1951
|
+
if (!Array.isArray(reqAtt) || !reqAtt.every((x) => typeof x === "string" && x.length > 0 && x.length <= 64)) {
|
|
1952
|
+
throw new HttpError(400, "`attachmentIds` must be an array of attachment ids (strings)");
|
|
1953
|
+
}
|
|
1954
|
+
if (reqAtt.length > 16)
|
|
1955
|
+
throw new HttpError(400, "`attachmentIds` exceeds the per-task limit (16)");
|
|
1956
|
+
if (reqAtt.length > 0) {
|
|
1957
|
+
if (!taskAttachmentStore)
|
|
1958
|
+
throw new HttpError(501, "attachmentIds require a store backend (DB_BACKEND=tidb|pg|local)");
|
|
1959
|
+
if (!auth?.sessionId)
|
|
1960
|
+
throw new HttpError(400, "`attachmentIds` requires a session-resolving deployment (no authorizer session)");
|
|
1961
|
+
const sid = auth.sessionId;
|
|
1962
|
+
const r = await bindAttachmentsForTask({
|
|
1963
|
+
store: taskAttachmentStore,
|
|
1964
|
+
owner: auth?.principal ?? "default",
|
|
1965
|
+
ids: reqAtt,
|
|
1966
|
+
sessionId: sid,
|
|
1967
|
+
leg: opts?.leg === "fresh" ? "fresh" : "resume",
|
|
1968
|
+
nowMs: Date.now(),
|
|
1969
|
+
onMissing: (id) => {
|
|
1970
|
+
if (opts?.leg === "fresh")
|
|
1971
|
+
throw new HttpError(400, `attachment not found: ${id}`);
|
|
1972
|
+
logger.warn("attachment_missing_on_resume", { sessionId: sid, id });
|
|
1973
|
+
},
|
|
1974
|
+
});
|
|
1975
|
+
attachmentNotice = r.notice;
|
|
1966
1976
|
}
|
|
1967
1977
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1978
|
+
}
|
|
1979
|
+
const execLane = config.remoteExec?.provider ?? "in-process";
|
|
1980
|
+
if (typeof body.cwd === "string" && body.cwd.length > 0 && auth?.sessionId) {
|
|
1981
|
+
if (cwdHonored(config) && isValidCwd(body.cwd))
|
|
1982
|
+
setSessionCwd(auth.sessionId, body.cwd);
|
|
1983
|
+
else if (inProcessSingleUserLane(config) && isValidCwd(body.cwd) && satisfiedByProcessCwd(body.cwd, realpathSync))
|
|
1984
|
+
logger.debug("task_cwd_inherited", { lane: execLane, sessionId: auth.sessionId });
|
|
1985
|
+
else
|
|
1986
|
+
logger.warn("task_cwd_ignored", { honored: cwdHonored(config), lane: execLane, sessionId: auth.sessionId });
|
|
1987
|
+
}
|
|
1988
|
+
if (parsedSettings.settings?.shellEnv && auth?.sessionId) {
|
|
1989
|
+
if (cwdHonored(config))
|
|
1990
|
+
setSessionShellEnv(auth.sessionId, parsedSettings.settings.shellEnv);
|
|
1991
|
+
else if (inProcessSingleUserLane(config)) {
|
|
1992
|
+
const requested = parsedSettings.settings.shellEnv;
|
|
1993
|
+
const mismatched = shellEnvMismatchCount(requested, process.env);
|
|
1994
|
+
if (mismatched === 0)
|
|
1995
|
+
logger.debug("task_shell_env_inherited", { lane: execLane, keys: Object.keys(requested).length, sessionId: auth.sessionId });
|
|
1974
1996
|
else
|
|
1975
|
-
logger.warn("
|
|
1997
|
+
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, mismatchedKeys: mismatched, sessionId: auth.sessionId });
|
|
1976
1998
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
}
|
|
1988
|
-
else
|
|
1989
|
-
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, sessionId: auth.sessionId });
|
|
1999
|
+
else
|
|
2000
|
+
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, sessionId: auth.sessionId });
|
|
2001
|
+
}
|
|
2002
|
+
const taskHooks = (() => {
|
|
2003
|
+
const hc = parsedSettings.settings?.hooks;
|
|
2004
|
+
if (!hc)
|
|
2005
|
+
return undefined;
|
|
2006
|
+
if (config.requirePrincipal === true) {
|
|
2007
|
+
logger.warn("task_hooks_ignored", { honored: false, sessionId: auth?.sessionId ?? null });
|
|
2008
|
+
return undefined;
|
|
1990
2009
|
}
|
|
1991
|
-
const
|
|
1992
|
-
|
|
1993
|
-
|
|
2010
|
+
const effMode = coercePermissionMode(body.permissionMode) ?? parsedSettings.settings?.permissions?.defaultMode;
|
|
2011
|
+
return createTaskHooks(hc, {
|
|
2012
|
+
logger,
|
|
2013
|
+
sessionId: auth?.sessionId ?? "",
|
|
2014
|
+
cwd: (auth?.sessionId ? perSessionCwd.get(auth.sessionId) : undefined) ?? process.cwd(),
|
|
2015
|
+
...(effMode ? { permissionMode: effMode } : {}),
|
|
2016
|
+
...(parsedSettings.settings?.shellEnv ? { shellEnv: parsedSettings.settings.shellEnv } : {}),
|
|
2017
|
+
hookLlm,
|
|
2018
|
+
hookAgent,
|
|
2019
|
+
onHookNotice: (n) => fleetBus.publishHookNotice({
|
|
2020
|
+
...n,
|
|
2021
|
+
...(auth?.principal ? { ownerScope: auth.principal } : {}),
|
|
2022
|
+
...(auth?.sessionId ? { ownerSessionId: auth.sessionId } : {}),
|
|
2023
|
+
}),
|
|
2024
|
+
...(auth?.sessionId
|
|
2025
|
+
? {
|
|
2026
|
+
wake: async (text) => hookWakeBus.deliver
|
|
2027
|
+
?
|
|
2028
|
+
hookWakeBus.deliver(auth.sessionId, `[hook asyncRewake] ${redactSecrets(text)}`)
|
|
2029
|
+
: false,
|
|
2030
|
+
}
|
|
2031
|
+
: {}),
|
|
2032
|
+
});
|
|
2033
|
+
})();
|
|
2034
|
+
const rawAddDirs = body.additionalDirectories;
|
|
2035
|
+
const additionalDirectories = cwdHonored(config) ? parseAdditionalDirectories(rawAddDirs) : undefined;
|
|
2036
|
+
if (rawAddDirs !== undefined && !cwdHonored(config)) {
|
|
2037
|
+
logger.warn("task_additional_directories_ignored", { honored: false, sessionId: auth?.sessionId ?? null });
|
|
2038
|
+
}
|
|
2039
|
+
const wireCatalog = expandTiers(config.models, config.tiers) ?? config.models;
|
|
2040
|
+
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog);
|
|
2041
|
+
if (picked.unknownExplicit !== undefined) {
|
|
2042
|
+
metrics.inc("task_model_unknown_fallback_total");
|
|
2043
|
+
logger.warn("task_model_unknown_fallback", { requested: picked.unknownExplicit.slice(0, 120), fallback: picked.model, sessionId: auth?.sessionId ?? null });
|
|
2044
|
+
}
|
|
2045
|
+
if (Array.isArray(body.images) && body.images.length > 0 && !modelSupportsImages(wireCatalog[picked.model])) {
|
|
2046
|
+
metrics.inc("images_omitted_total", { model: picked.model });
|
|
2047
|
+
logger.warn("images_omitted_no_vision_model", { model: picked.model, count: body.images.length });
|
|
2048
|
+
}
|
|
2049
|
+
let resumeAtEntryId;
|
|
2050
|
+
if (typeof body.resumeAt === "string" && body.resumeAt.length > 0) {
|
|
2051
|
+
if (!auth?.sessionId)
|
|
2052
|
+
throw new HttpError(422, "resumeAt requires a session to branch (resume_at.no_session)");
|
|
2053
|
+
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
2054
|
+
throw new HttpError(501, "resume-at is not available on this worker (no session-store backend for the anchor map)");
|
|
2055
|
+
resumeAtEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.resumeAt, auth.principal ?? null);
|
|
2056
|
+
if (resumeAtEntryId === undefined)
|
|
2057
|
+
throw new HttpError(404, "resumeAt: no such message in this session (resume_at.unknown_event)");
|
|
2058
|
+
}
|
|
2059
|
+
let rewindFilesToEntryId;
|
|
2060
|
+
if (resumeAtEntryId === undefined && typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0) {
|
|
2061
|
+
if (!auth?.sessionId)
|
|
2062
|
+
throw new HttpError(422, "rewindFilesTo requires a session (rewind_files_to.no_session)");
|
|
2063
|
+
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
2064
|
+
throw new HttpError(501, "rewind-files-to is not available on this worker (no session-store backend for the anchor map)");
|
|
2065
|
+
rewindFilesToEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.rewindFilesTo, auth.principal ?? null);
|
|
2066
|
+
if (rewindFilesToEntryId === undefined)
|
|
2067
|
+
throw new HttpError(404, "rewindFilesTo: no such message in this session (rewind_files_to.unknown_event)");
|
|
2068
|
+
}
|
|
2069
|
+
const s4ProjectId = auth?.resolvedProjectId ?? (typeof body.projectId === "string" && body.projectId ? body.projectId : undefined);
|
|
2070
|
+
const s4DefaultScopes = s4ProjectId ? config.projects[s4ProjectId]?.defaultScopes : undefined;
|
|
2071
|
+
const spec = {
|
|
2072
|
+
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
2073
|
+
systemPrompt: typeof body.systemPrompt === "string" ? body.systemPrompt : undefined,
|
|
2074
|
+
appendSystemPrompt: acceptedAppend,
|
|
2075
|
+
sessionId: auth?.sessionId,
|
|
2076
|
+
principal: auth?.principal,
|
|
2077
|
+
images: body.images,
|
|
2078
|
+
...(body.clientContext ? { clientContext: { timeZone: body.clientContext.timeZone, userEmail: body.clientContext.userEmail } } : {}),
|
|
2079
|
+
...(() => {
|
|
2080
|
+
const ct = body.compaction?.clampTolerance;
|
|
2081
|
+
return typeof ct === "number" && Number.isFinite(ct) && ct >= 0 && ct <= 1 ? { compaction: { clampTolerance: ct } } : {};
|
|
2082
|
+
})(),
|
|
2083
|
+
outputSchema: body.outputSchema,
|
|
2084
|
+
...(typeof body.outputRetries === "number" && Number.isFinite(body.outputRetries) && body.outputRetries >= 1
|
|
2085
|
+
? { outputRetries: Math.min(10, Math.floor(body.outputRetries)) }
|
|
2086
|
+
: {}),
|
|
2087
|
+
resumeAt: resumeAtEntryId,
|
|
2088
|
+
resumeAtMode: normalizeResumeAtMode(body.resumeAtMode, resumeAtEntryId !== undefined),
|
|
2089
|
+
requireExistingSession: body.requireExistingSession === true ? true : undefined,
|
|
2090
|
+
enableFork: enableForkFromBody(body, config, Boolean(centerRuntimeCapsResolver)),
|
|
2091
|
+
suggestNextPrompts: normalizeSuggestNextPrompts(body.suggestNextPrompts),
|
|
2092
|
+
rewindFiles: body.rewindFiles === true ? true : undefined,
|
|
2093
|
+
rewindFilesTo: rewindFilesToEntryId,
|
|
2094
|
+
additionalDirectories,
|
|
2095
|
+
enablePlanMode: config.planModeEnabled ? true : undefined,
|
|
2096
|
+
selfOrchestration: selfOrchestrationFromBody({ selfOrchestration: body.selfOrchestration === true || parsedSettings.settings?.ultracode === true }, config, Boolean(centerRuntimeCapsResolver)),
|
|
2097
|
+
forwardSubagentEvents: body.forwardSubagentEvents === true ? true : undefined,
|
|
2098
|
+
retainSubagentSessions: normalizeRetainSubagentSessions(body.retainSubagentSessions),
|
|
2099
|
+
...taskAgentsSpecFragment(body.agents, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null })),
|
|
2100
|
+
...(retainBackgroundProcessesFromBody(body.retainBackgroundProcesses, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null })) === true
|
|
2101
|
+
? { retainBackgroundProcesses: true }
|
|
2102
|
+
: {}),
|
|
2103
|
+
...(() => { const v = toolNameListFromBody(body.excludeTools); return v ? { excludeTools: v } : {}; })(),
|
|
2104
|
+
...(() => { const v = toolNameListFromBody(body.deferTools); return v ? { deferTools: v } : {}; })(),
|
|
2105
|
+
...(() => { const v = promptProfileFromBody(body.promptProfile); return v ? { promptProfile: v } : {}; })(),
|
|
2106
|
+
...(typeof body.interactiveTools === "boolean"
|
|
2107
|
+
? { interactiveTools: body.interactiveTools }
|
|
2108
|
+
: {}),
|
|
2109
|
+
resilience: normalizeResilience(body.resilience, explicitOperator(auth?.principal, config.operatorPrincipals)),
|
|
2110
|
+
finalVerification: cap.finalVerification === true || body.finalVerification === true ? true : undefined,
|
|
2111
|
+
attachments: normalizeAttachments(body.attachments),
|
|
2112
|
+
...(taskHooks ? { hooks: composeHooks(deploymentHooks, taskHooks) } : {}),
|
|
2113
|
+
model: picked.model,
|
|
2114
|
+
...((() => {
|
|
2115
|
+
if (typeof body.compactionModel !== "string" || body.compactionModel.length === 0)
|
|
2116
|
+
return {};
|
|
2117
|
+
const cm = matchCatalogModel(body.compactionModel, wireCatalog);
|
|
2118
|
+
if (cm === undefined) {
|
|
2119
|
+
if (opts?.leg === "fresh") {
|
|
2120
|
+
throw new HttpError(400, `unknown compactionModel "${body.compactionModel.slice(0, 120)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
|
|
2121
|
+
}
|
|
2122
|
+
metrics.inc("task_model_unknown_fallback_total");
|
|
2123
|
+
logger.warn("compaction_model_unknown_fallback", { requested: body.compactionModel.slice(0, 120), sessionId: auth?.sessionId ?? null });
|
|
2124
|
+
return {};
|
|
2125
|
+
}
|
|
2126
|
+
return { compactionModel: cm };
|
|
2127
|
+
})()),
|
|
2128
|
+
thinking: effectiveThinking(body.reasoningEffort, parsedSettings.settings?.ultracode === true),
|
|
2129
|
+
getApiKeyAndHeaders: keyResolver,
|
|
2130
|
+
...(() => {
|
|
2131
|
+
const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, body.council === true || body.debate === true || scenarioName === "team");
|
|
2132
|
+
const declarations = [];
|
|
2133
|
+
if (taskLimitCaps.timeoutSec !== undefined)
|
|
2134
|
+
declarations.push({ key: "server.limits.timeoutSecCap", value: String(taskLimitCaps.timeoutSec), reason: "env TASK_TIMEOUT_MAX_SEC (operator ceiling on caller limits.timeoutSec)" });
|
|
2135
|
+
if (taskLimitCaps.maxOutputTokens !== undefined)
|
|
2136
|
+
declarations.push({ key: "server.limits.maxOutputTokensCap", value: String(taskLimitCaps.maxOutputTokens), reason: "env TASK_MAX_OUTPUT_TOKENS_MAX (operator ceiling)" });
|
|
2137
|
+
if (taskLimitCaps.maxTurns !== undefined)
|
|
2138
|
+
declarations.push({ key: "server.limits.maxTurnsCap", value: String(taskLimitCaps.maxTurns), reason: "env TASK_MAX_TURNS_MAX (operator ceiling)" });
|
|
2139
|
+
if (config.maxTaskCostUsd > 0)
|
|
2140
|
+
declarations.push({ key: "server.budget.maxCostUsdCap", value: String(config.maxTaskCostUsd), reason: "env MAX_TASK_COST_USD (operator ceiling; becomes the effective value when the caller sends none)" });
|
|
2141
|
+
if (config.maxTaskTokens > 0)
|
|
2142
|
+
declarations.push({ key: "server.budget.maxTokensCap", value: String(config.maxTaskTokens), reason: "env MAX_TASK_TOKENS_MAX (operator ceiling; becomes the effective value when the caller sends none)" });
|
|
2143
|
+
if (config.requirePrincipal === true)
|
|
2144
|
+
declarations.push({ key: "server.limits.wallClockBaseSec", value: "2400/3600", reason: "tenancy wall-clock base (multi-tenant; big tasks 3600) — TASK_TIMEOUT_SEC raises, never shrinks" });
|
|
2145
|
+
return { ...(limits !== undefined ? { limits } : {}), ...(declarations.length > 0 ? { configOverrides: declarations } : {}) };
|
|
2146
|
+
})(),
|
|
2147
|
+
...(config.requirePrincipal !== true ? { backgroundScope: "session" } : {}),
|
|
2148
|
+
maxCostUsd: cappedCeiling(body.maxCostUsd, config.maxTaskCostUsd),
|
|
2149
|
+
maxTokens: cappedCeiling(body.maxTokens, config.maxTaskTokens),
|
|
2150
|
+
degrade: (() => {
|
|
2151
|
+
if (!config.degrade || cappedCeiling(body.maxCostUsd, config.maxTaskCostUsd) === undefined)
|
|
1994
2152
|
return undefined;
|
|
1995
|
-
if (
|
|
1996
|
-
|
|
2153
|
+
if (Array.isArray(body.images) && body.images.length > 0 && !config.degrade.toSupportsImages) {
|
|
2154
|
+
metrics.inc("degrade_dropped_total", { reason: "vision_target" });
|
|
2155
|
+
logger.warn("degrade_dropped", { reason: "vision_target", model: picked.model, images: body.images.length });
|
|
1997
2156
|
return undefined;
|
|
1998
2157
|
}
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
...(auth?.sessionId
|
|
2158
|
+
return { to: config.degrade.to, atCostFraction: config.degrade.atCostFraction };
|
|
2159
|
+
})(),
|
|
2160
|
+
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes) : undefined,
|
|
2161
|
+
tools: ((base) => {
|
|
2162
|
+
const extra = [...(selectEnvTool ? [selectEnvTool] : []), ...(sendUserFileToolSpec ? [sendUserFileToolSpec] : [])];
|
|
2163
|
+
const merged = extra.length > 0 ? [...(base ?? []), ...extra] : base;
|
|
2164
|
+
return merged && config.toolDeferLongtail ? applyLongtailDefer(merged, true) : merged;
|
|
2165
|
+
})(cap.tools),
|
|
2166
|
+
skills: mergeUserSkills(cap.skills, body.skills, logger),
|
|
2167
|
+
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, logger),
|
|
2168
|
+
promptProvider: centerDecls ? centerPromptProvider(centerDecls, scenarioName) : cap.promptProvider,
|
|
2169
|
+
toolPolicy: durableEnabled
|
|
2170
|
+
? combinePolicies(createDurableQuestionPolicy(), createDurableAskPolicy({
|
|
2171
|
+
requireApproval: config.approvalRequire, deny: config.approvalDeny, autoBudget: config.approvalAutoBudget, neverAuto: config.approvalNeverAuto,
|
|
2172
|
+
...(approvalExemptionStore && auth?.sessionId
|
|
2014
2173
|
? {
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
hookWakeBus.deliver(auth.sessionId, `[hook asyncRewake] ${redactSecrets(text)}`)
|
|
2018
|
-
: false,
|
|
2174
|
+
exempt: (toolName) => approvalExemptionStore.has(auth.sessionId, toolName),
|
|
2175
|
+
onExempted: (toolName, rawToolName) => logger.info("approval_exempted", { sessionId: auth.sessionId, toolName, rawToolName }),
|
|
2019
2176
|
}
|
|
2020
2177
|
: {}),
|
|
2021
|
-
})
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
metrics.inc("task_model_unknown_fallback_total");
|
|
2032
|
-
logger.warn("task_model_unknown_fallback", { requested: picked.unknownExplicit.slice(0, 120), fallback: picked.model, sessionId: auth?.sessionId ?? null });
|
|
2033
|
-
}
|
|
2034
|
-
if (Array.isArray(body.images) && body.images.length > 0 && !modelSupportsImages(wireCatalog[picked.model])) {
|
|
2035
|
-
metrics.inc("images_omitted_total", { model: picked.model });
|
|
2036
|
-
logger.warn("images_omitted_no_vision_model", { model: picked.model, count: body.images.length });
|
|
2037
|
-
}
|
|
2038
|
-
let resumeAtEntryId;
|
|
2039
|
-
if (typeof body.resumeAt === "string" && body.resumeAt.length > 0) {
|
|
2040
|
-
if (!auth?.sessionId)
|
|
2041
|
-
throw new HttpError(422, "resumeAt requires a session to branch (resume_at.no_session)");
|
|
2042
|
-
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
2043
|
-
throw new HttpError(501, "resume-at is not available on this worker (no session-store backend for the anchor map)");
|
|
2044
|
-
resumeAtEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.resumeAt, auth.principal ?? null);
|
|
2045
|
-
if (resumeAtEntryId === undefined)
|
|
2046
|
-
throw new HttpError(404, "resumeAt: no such message in this session (resume_at.unknown_event)");
|
|
2047
|
-
}
|
|
2048
|
-
let rewindFilesToEntryId;
|
|
2049
|
-
if (resumeAtEntryId === undefined && typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0) {
|
|
2050
|
-
if (!auth?.sessionId)
|
|
2051
|
-
throw new HttpError(422, "rewindFilesTo requires a session (rewind_files_to.no_session)");
|
|
2052
|
-
if (!resumeAnchorStore || !ownerAware.getLeafId)
|
|
2053
|
-
throw new HttpError(501, "rewind-files-to is not available on this worker (no session-store backend for the anchor map)");
|
|
2054
|
-
rewindFilesToEntryId = await resumeAnchorStore.resolve(auth.sessionId, body.rewindFilesTo, auth.principal ?? null);
|
|
2055
|
-
if (rewindFilesToEntryId === undefined)
|
|
2056
|
-
throw new HttpError(404, "rewindFilesTo: no such message in this session (rewind_files_to.unknown_event)");
|
|
2057
|
-
}
|
|
2058
|
-
const s4ProjectId = auth?.resolvedProjectId ?? (typeof body.projectId === "string" && body.projectId ? body.projectId : undefined);
|
|
2059
|
-
const s4DefaultScopes = s4ProjectId ? config.projects[s4ProjectId]?.defaultScopes : undefined;
|
|
2060
|
-
const spec = {
|
|
2061
|
-
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
2062
|
-
systemPrompt: typeof body.systemPrompt === "string" ? body.systemPrompt : undefined,
|
|
2063
|
-
appendSystemPrompt: acceptedAppend,
|
|
2064
|
-
sessionId: auth?.sessionId,
|
|
2065
|
-
principal: auth?.principal,
|
|
2066
|
-
images: body.images,
|
|
2067
|
-
...(body.clientContext ? { clientContext: { timeZone: body.clientContext.timeZone, userEmail: body.clientContext.userEmail } } : {}),
|
|
2068
|
-
...(() => {
|
|
2069
|
-
const ct = body.compaction?.clampTolerance;
|
|
2070
|
-
return typeof ct === "number" && Number.isFinite(ct) && ct >= 0 && ct <= 1 ? { compaction: { clampTolerance: ct } } : {};
|
|
2071
|
-
})(),
|
|
2072
|
-
outputSchema: body.outputSchema,
|
|
2073
|
-
...(typeof body.outputRetries === "number" && Number.isFinite(body.outputRetries) && body.outputRetries >= 1
|
|
2074
|
-
? { outputRetries: Math.min(10, Math.floor(body.outputRetries)) }
|
|
2075
|
-
: {}),
|
|
2076
|
-
resumeAt: resumeAtEntryId,
|
|
2077
|
-
resumeAtMode: normalizeResumeAtMode(body.resumeAtMode, resumeAtEntryId !== undefined),
|
|
2078
|
-
requireExistingSession: body.requireExistingSession === true ? true : undefined,
|
|
2079
|
-
enableFork: enableForkFromBody(body, config, Boolean(centerRuntimeCapsResolver)),
|
|
2080
|
-
suggestNextPrompts: normalizeSuggestNextPrompts(body.suggestNextPrompts),
|
|
2081
|
-
rewindFiles: body.rewindFiles === true ? true : undefined,
|
|
2082
|
-
rewindFilesTo: rewindFilesToEntryId,
|
|
2083
|
-
additionalDirectories,
|
|
2084
|
-
enablePlanMode: config.planModeEnabled ? true : undefined,
|
|
2085
|
-
selfOrchestration: selfOrchestrationFromBody({ selfOrchestration: body.selfOrchestration === true || parsedSettings.settings?.ultracode === true }, config, Boolean(centerRuntimeCapsResolver)),
|
|
2086
|
-
forwardSubagentEvents: body.forwardSubagentEvents === true ? true : undefined,
|
|
2087
|
-
retainSubagentSessions: normalizeRetainSubagentSessions(body.retainSubagentSessions),
|
|
2088
|
-
...taskAgentsSpecFragment(body.agents, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null })),
|
|
2089
|
-
...(retainBackgroundProcessesFromBody(body.retainBackgroundProcesses, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: auth?.sessionId ?? null })) === true
|
|
2090
|
-
? { retainBackgroundProcesses: true }
|
|
2091
|
-
: {}),
|
|
2092
|
-
...(() => { const v = toolNameListFromBody(body.excludeTools); return v ? { excludeTools: v } : {}; })(),
|
|
2093
|
-
...(() => { const v = toolNameListFromBody(body.deferTools); return v ? { deferTools: v } : {}; })(),
|
|
2094
|
-
...(() => { const v = promptProfileFromBody(body.promptProfile); return v ? { promptProfile: v } : {}; })(),
|
|
2095
|
-
...(typeof body.interactiveTools === "boolean"
|
|
2096
|
-
? { interactiveTools: body.interactiveTools }
|
|
2097
|
-
: {}),
|
|
2098
|
-
resilience: normalizeResilience(body.resilience, explicitOperator(auth?.principal, config.operatorPrincipals)),
|
|
2099
|
-
finalVerification: cap.finalVerification === true || body.finalVerification === true ? true : undefined,
|
|
2100
|
-
attachments: normalizeAttachments(body.attachments),
|
|
2101
|
-
...(taskHooks ? { hooks: composeHooks(deploymentHooks, taskHooks) } : {}),
|
|
2102
|
-
model: picked.model,
|
|
2103
|
-
...((() => {
|
|
2104
|
-
if (typeof body.compactionModel !== "string" || body.compactionModel.length === 0)
|
|
2105
|
-
return {};
|
|
2106
|
-
const cm = matchCatalogModel(body.compactionModel, wireCatalog);
|
|
2107
|
-
if (cm === undefined) {
|
|
2108
|
-
if (opts?.leg === "fresh") {
|
|
2109
|
-
throw new HttpError(400, `unknown compactionModel "${body.compactionModel.slice(0, 120)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
|
|
2110
|
-
}
|
|
2111
|
-
metrics.inc("task_model_unknown_fallback_total");
|
|
2112
|
-
logger.warn("compaction_model_unknown_fallback", { requested: body.compactionModel.slice(0, 120), sessionId: auth?.sessionId ?? null });
|
|
2113
|
-
return {};
|
|
2114
|
-
}
|
|
2115
|
-
return { compactionModel: cm };
|
|
2116
|
-
})()),
|
|
2117
|
-
thinking: effectiveThinking(body.reasoningEffort, parsedSettings.settings?.ultracode === true),
|
|
2118
|
-
getApiKeyAndHeaders: keyResolver,
|
|
2119
|
-
...(() => {
|
|
2120
|
-
const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, body.council === true || body.debate === true || scenarioName === "team");
|
|
2121
|
-
const declarations = [];
|
|
2122
|
-
if (taskLimitCaps.timeoutSec !== undefined)
|
|
2123
|
-
declarations.push({ key: "server.limits.timeoutSecCap", value: String(taskLimitCaps.timeoutSec), reason: "env TASK_TIMEOUT_MAX_SEC (operator ceiling on caller limits.timeoutSec)" });
|
|
2124
|
-
if (taskLimitCaps.maxOutputTokens !== undefined)
|
|
2125
|
-
declarations.push({ key: "server.limits.maxOutputTokensCap", value: String(taskLimitCaps.maxOutputTokens), reason: "env TASK_MAX_OUTPUT_TOKENS_MAX (operator ceiling)" });
|
|
2126
|
-
if (taskLimitCaps.maxTurns !== undefined)
|
|
2127
|
-
declarations.push({ key: "server.limits.maxTurnsCap", value: String(taskLimitCaps.maxTurns), reason: "env TASK_MAX_TURNS_MAX (operator ceiling)" });
|
|
2128
|
-
if (config.maxTaskCostUsd > 0)
|
|
2129
|
-
declarations.push({ key: "server.budget.maxCostUsdCap", value: String(config.maxTaskCostUsd), reason: "env MAX_TASK_COST_USD (operator ceiling; becomes the effective value when the caller sends none)" });
|
|
2130
|
-
if (config.maxTaskTokens > 0)
|
|
2131
|
-
declarations.push({ key: "server.budget.maxTokensCap", value: String(config.maxTaskTokens), reason: "env MAX_TASK_TOKENS_MAX (operator ceiling; becomes the effective value when the caller sends none)" });
|
|
2132
|
-
if (config.requirePrincipal === true)
|
|
2133
|
-
declarations.push({ key: "server.limits.wallClockBaseSec", value: "2400/3600", reason: "tenancy wall-clock base (multi-tenant; big tasks 3600) — TASK_TIMEOUT_SEC raises, never shrinks" });
|
|
2134
|
-
return { ...(limits !== undefined ? { limits } : {}), ...(declarations.length > 0 ? { configOverrides: declarations } : {}) };
|
|
2135
|
-
})(),
|
|
2136
|
-
...(config.requirePrincipal !== true ? { backgroundScope: "session" } : {}),
|
|
2137
|
-
maxCostUsd: cappedCeiling(body.maxCostUsd, config.maxTaskCostUsd),
|
|
2138
|
-
maxTokens: cappedCeiling(body.maxTokens, config.maxTaskTokens),
|
|
2139
|
-
degrade: (() => {
|
|
2140
|
-
if (!config.degrade || cappedCeiling(body.maxCostUsd, config.maxTaskCostUsd) === undefined)
|
|
2141
|
-
return undefined;
|
|
2142
|
-
if (Array.isArray(body.images) && body.images.length > 0 && !config.degrade.toSupportsImages) {
|
|
2143
|
-
metrics.inc("degrade_dropped_total", { reason: "vision_target" });
|
|
2144
|
-
logger.warn("degrade_dropped", { reason: "vision_target", model: picked.model, images: body.images.length });
|
|
2145
|
-
return undefined;
|
|
2146
|
-
}
|
|
2147
|
-
return { to: config.degrade.to, atCostFraction: config.degrade.atCostFraction };
|
|
2148
|
-
})(),
|
|
2149
|
-
memory: memoryEngine ? memorySpecForRequest(auth?.memoryScope, body.memoryWrite, s4DefaultScopes) : undefined,
|
|
2150
|
-
tools: ((base) => {
|
|
2151
|
-
const extra = [...(selectEnvTool ? [selectEnvTool] : []), ...(sendUserFileToolSpec ? [sendUserFileToolSpec] : [])];
|
|
2152
|
-
const merged = extra.length > 0 ? [...(base ?? []), ...extra] : base;
|
|
2153
|
-
return merged && config.toolDeferLongtail ? applyLongtailDefer(merged, true) : merged;
|
|
2154
|
-
})(cap.tools),
|
|
2155
|
-
skills: mergeUserSkills(cap.skills, body.skills, logger),
|
|
2156
|
-
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, logger),
|
|
2157
|
-
promptProvider: centerDecls ? centerPromptProvider(centerDecls, scenarioName) : cap.promptProvider,
|
|
2158
|
-
toolPolicy: durableEnabled
|
|
2159
|
-
? combinePolicies(createDurableQuestionPolicy(), createDurableAskPolicy({
|
|
2160
|
-
requireApproval: config.approvalRequire, deny: config.approvalDeny, autoBudget: config.approvalAutoBudget, neverAuto: config.approvalNeverAuto,
|
|
2161
|
-
...(approvalExemptionStore && auth?.sessionId
|
|
2178
|
+
}))
|
|
2179
|
+
: approvalEnabled && approvalStore
|
|
2180
|
+
? createOaApprovalPolicy({
|
|
2181
|
+
store: approvalStore,
|
|
2182
|
+
requireApproval: config.approvalRequire,
|
|
2183
|
+
deny: config.approvalDeny,
|
|
2184
|
+
pollMs: config.approvalPollMs,
|
|
2185
|
+
context: () => ({ sessionId: auth?.sessionId ?? null, owner: auth?.principal ?? null }),
|
|
2186
|
+
neverAuto: config.approvalNeverAuto,
|
|
2187
|
+
...(approvalExemptionStore
|
|
2162
2188
|
? {
|
|
2163
|
-
exempt: (toolName) => approvalExemptionStore.has(
|
|
2164
|
-
onExempted: (
|
|
2189
|
+
exempt: (sessionId, toolName) => approvalExemptionStore.has(sessionId, toolName),
|
|
2190
|
+
onExempted: (sessionId, toolName) => logger.info("approval_exempted", { sessionId, toolName }),
|
|
2165
2191
|
}
|
|
2166
2192
|
: {}),
|
|
2167
|
-
})
|
|
2168
|
-
:
|
|
2169
|
-
?
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
:
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
...(durableEnabled
|
|
2187
|
-
? {
|
|
2188
|
-
checkpointStore,
|
|
2189
|
-
durableApproval: {
|
|
2190
|
-
scope: auth?.principal ?? "_",
|
|
2191
|
-
...(config.approvalTimeoutSec > 0 ? { ttlMs: config.approvalTimeoutSec * 1000 } : {}),
|
|
2192
|
-
},
|
|
2193
|
-
...((rs) => (rs ? { resourceSuspend: rs } : {}))(resourceSuspendOptIn({
|
|
2194
|
-
enabled: config.resourceSuspend,
|
|
2195
|
-
ttlSec: config.resourceSuspendTtlSec,
|
|
2196
|
-
isVerify: body.verify === true,
|
|
2197
|
-
isCascade: body.cascade === true,
|
|
2198
|
-
scope: auth?.principal ?? "_",
|
|
2199
|
-
})),
|
|
2200
|
-
onQuestion: QUESTION_AWAITS_RESUME,
|
|
2201
|
-
}
|
|
2202
|
-
: {}),
|
|
2203
|
-
};
|
|
2204
|
-
const governedBase = applyRuntimeGovernance(spec, { autonomy: config.autonomy, commandPolicy: config.commandPolicy });
|
|
2205
|
-
let governed = governedBase;
|
|
2206
|
-
const bodyMode = coercePermissionMode(body.permissionMode);
|
|
2207
|
-
let effectiveSettings = bodyMode ? withPermissionMode(parsedSettings.settings, bodyMode) : parsedSettings.settings;
|
|
2208
|
-
if (appendLessPack && effectiveSettings?.outputStyle) {
|
|
2209
|
-
logger.warn("output_style_dropped", { detail: "the effective prompt pack cannot mount the append slot (already-assembled systemPrompt or center assembled-identity declaration)", sessionId: auth?.sessionId ?? null });
|
|
2210
|
-
const { outputStyle: _dropped, ...rest } = effectiveSettings;
|
|
2211
|
-
effectiveSettings = Object.keys(rest).length > 0 ? rest : undefined;
|
|
2212
|
-
}
|
|
2213
|
-
if (effectiveSettings?.outputStyle && acceptedAppend && acceptedAppend.length + 2 + effectiveSettings.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
|
|
2214
|
-
logger.warn("output_style_dropped", { detail: `combined append carriers exceed the ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} cap (rider ${acceptedAppend.length} + style ${effectiveSettings.outputStyle.length}) — style dropped (pre-cap stored body on a resume leg?)`, sessionId: auth?.sessionId ?? null });
|
|
2215
|
-
const { outputStyle: _dropped2, ...rest2 } = effectiveSettings;
|
|
2216
|
-
effectiveSettings = Object.keys(rest2).length > 0 ? rest2 : undefined;
|
|
2217
|
-
}
|
|
2218
|
-
const hostSemanticsLane = config.remoteExec === undefined || config.remoteExec.provider === "host";
|
|
2219
|
-
const shellScratchpad = await acceptShellScratchpadDir(body.scratchpadDir, {
|
|
2220
|
-
requirePrincipal: config.requirePrincipal,
|
|
2221
|
-
hostSemanticsLane,
|
|
2222
|
-
warn: (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: auth?.sessionId ?? null }),
|
|
2223
|
-
});
|
|
2224
|
-
const scratchpadDir = shellScratchpad ??
|
|
2225
|
-
(hostSemanticsLane && auth?.sessionId ? await ensureScratchpadDir(config.localDataRoot ?? localRoot, auth.sessionId) : undefined);
|
|
2226
|
-
if (effectiveSettings) {
|
|
2227
|
-
const fsWriteGate = hostSemanticsLane
|
|
2228
|
-
? (() => {
|
|
2229
|
-
const sessionCwd = auth?.sessionId ? effectiveHostWorkspace(perSessionCwd.get(auth.sessionId), {}) : undefined;
|
|
2230
|
-
const gateCwd = sessionCwd ??
|
|
2231
|
-
(config.remoteExec === undefined
|
|
2232
|
-
? process.cwd()
|
|
2233
|
-
: join(config.localDataRoot ?? localRoot, "fs-write-gate-unrooted"));
|
|
2234
|
-
return {
|
|
2235
|
-
env: new NodeExecutionEnv({ cwd: gateCwd }),
|
|
2236
|
-
cwd: gateCwd,
|
|
2237
|
-
...(scratchpadDir ? { scratchpadDir } : {}),
|
|
2238
|
-
...(config.sensitiveWritePatterns.length > 0 ? { sensitivePatterns: config.sensitiveWritePatterns } : {}),
|
|
2239
|
-
...(config.manualModeShellGate ? { shellGate: config.manualModeShellGate } : {}),
|
|
2240
|
-
...(approvalExemptionStore && auth?.sessionId
|
|
2241
|
-
? {
|
|
2242
|
-
isExempt: async (toolName) => {
|
|
2243
|
-
const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
|
|
2244
|
-
if (hit)
|
|
2245
|
-
logger.info("fs_write_gate_exempted", { toolName, sessionId: auth.sessionId });
|
|
2246
|
-
return hit;
|
|
2247
|
-
},
|
|
2248
|
-
}
|
|
2249
|
-
: {}),
|
|
2250
|
-
};
|
|
2251
|
-
})()
|
|
2252
|
-
: undefined;
|
|
2253
|
-
const workflowGate = approvalExemptionStore && auth?.sessionId
|
|
2254
|
-
? {
|
|
2255
|
-
isExempt: async (toolName) => {
|
|
2256
|
-
const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
|
|
2257
|
-
if (hit)
|
|
2258
|
-
logger.info("workflow_gate_exempted", { toolName, sessionId: auth.sessionId });
|
|
2259
|
-
return hit;
|
|
2260
|
-
},
|
|
2261
|
-
}
|
|
2262
|
-
: undefined;
|
|
2263
|
-
try {
|
|
2264
|
-
governed = applyTaskSettings(governedBase, effectiveSettings, fsWriteGate, workflowGate);
|
|
2193
|
+
})
|
|
2194
|
+
: singleUserAutoAcceptBaseline
|
|
2195
|
+
? createAllowDenyPolicy({})
|
|
2196
|
+
: undefined,
|
|
2197
|
+
...(durableEnabled
|
|
2198
|
+
? {
|
|
2199
|
+
checkpointStore,
|
|
2200
|
+
durableApproval: {
|
|
2201
|
+
scope: auth?.principal ?? "_",
|
|
2202
|
+
...(config.approvalTimeoutSec > 0 ? { ttlMs: config.approvalTimeoutSec * 1000 } : {}),
|
|
2203
|
+
},
|
|
2204
|
+
...((rs) => (rs ? { resourceSuspend: rs } : {}))(resourceSuspendOptIn({
|
|
2205
|
+
enabled: config.resourceSuspend,
|
|
2206
|
+
ttlSec: config.resourceSuspendTtlSec,
|
|
2207
|
+
isVerify: body.verify === true,
|
|
2208
|
+
isCascade: body.cascade === true,
|
|
2209
|
+
scope: auth?.principal ?? "_",
|
|
2210
|
+
})),
|
|
2211
|
+
onQuestion: QUESTION_AWAITS_RESUME,
|
|
2265
2212
|
}
|
|
2266
|
-
|
|
2267
|
-
|
|
2213
|
+
: {}),
|
|
2214
|
+
};
|
|
2215
|
+
const governedBase = applyRuntimeGovernance(spec, { autonomy: config.autonomy, commandPolicy: config.commandPolicy });
|
|
2216
|
+
let governed = governedBase;
|
|
2217
|
+
const bodyMode = coercePermissionMode(body.permissionMode);
|
|
2218
|
+
let effectiveSettings = bodyMode ? withPermissionMode(parsedSettings.settings, bodyMode) : parsedSettings.settings;
|
|
2219
|
+
if (appendLessPack && effectiveSettings?.outputStyle) {
|
|
2220
|
+
logger.warn("output_style_dropped", { detail: "the effective prompt pack cannot mount the append slot (already-assembled systemPrompt or center assembled-identity declaration)", sessionId: auth?.sessionId ?? null });
|
|
2221
|
+
const { outputStyle: _dropped, ...rest } = effectiveSettings;
|
|
2222
|
+
effectiveSettings = Object.keys(rest).length > 0 ? rest : undefined;
|
|
2223
|
+
}
|
|
2224
|
+
if (effectiveSettings?.outputStyle && acceptedAppend && acceptedAppend.length + 2 + effectiveSettings.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
|
|
2225
|
+
logger.warn("output_style_dropped", { detail: `combined append carriers exceed the ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} cap (rider ${acceptedAppend.length} + style ${effectiveSettings.outputStyle.length}) — style dropped (pre-cap stored body on a resume leg?)`, sessionId: auth?.sessionId ?? null });
|
|
2226
|
+
const { outputStyle: _dropped2, ...rest2 } = effectiveSettings;
|
|
2227
|
+
effectiveSettings = Object.keys(rest2).length > 0 ? rest2 : undefined;
|
|
2228
|
+
}
|
|
2229
|
+
const hostSemanticsLane = config.remoteExec === undefined || config.remoteExec.provider === "host";
|
|
2230
|
+
const shellScratchpad = await acceptShellScratchpadDir(body.scratchpadDir, {
|
|
2231
|
+
requirePrincipal: config.requirePrincipal,
|
|
2232
|
+
hostSemanticsLane,
|
|
2233
|
+
warn: (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: auth?.sessionId ?? null }),
|
|
2234
|
+
});
|
|
2235
|
+
const scratchpadDir = shellScratchpad ??
|
|
2236
|
+
(hostSemanticsLane && auth?.sessionId ? await ensureScratchpadDir(config.localDataRoot ?? localRoot, auth.sessionId) : undefined);
|
|
2237
|
+
if (effectiveSettings) {
|
|
2238
|
+
const fsWriteGate = hostSemanticsLane
|
|
2239
|
+
? (() => {
|
|
2240
|
+
const sessionCwd = auth?.sessionId ? effectiveHostWorkspace(perSessionCwd.get(auth.sessionId), {}) : undefined;
|
|
2241
|
+
const gateCwd = sessionCwd ??
|
|
2242
|
+
(config.remoteExec === undefined
|
|
2243
|
+
? process.cwd()
|
|
2244
|
+
: join(config.localDataRoot ?? localRoot, "fs-write-gate-unrooted"));
|
|
2245
|
+
return {
|
|
2246
|
+
env: new NodeExecutionEnv({ cwd: gateCwd }),
|
|
2247
|
+
cwd: gateCwd,
|
|
2248
|
+
...(scratchpadDir ? { scratchpadDir } : {}),
|
|
2249
|
+
...(config.sensitiveWritePatterns.length > 0 ? { sensitivePatterns: config.sensitiveWritePatterns } : {}),
|
|
2250
|
+
...(config.manualModeShellGate ? { shellGate: config.manualModeShellGate } : {}),
|
|
2251
|
+
...(approvalExemptionStore && auth?.sessionId
|
|
2252
|
+
? {
|
|
2253
|
+
isExempt: async (toolName) => {
|
|
2254
|
+
const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
|
|
2255
|
+
if (hit)
|
|
2256
|
+
logger.info("fs_write_gate_exempted", { toolName, sessionId: auth.sessionId });
|
|
2257
|
+
return hit;
|
|
2258
|
+
},
|
|
2259
|
+
}
|
|
2260
|
+
: {}),
|
|
2261
|
+
};
|
|
2262
|
+
})()
|
|
2263
|
+
: undefined;
|
|
2264
|
+
const workflowGate = approvalExemptionStore && auth?.sessionId
|
|
2265
|
+
? {
|
|
2266
|
+
isExempt: async (toolName) => {
|
|
2267
|
+
const hit = await approvalExemptionStore.has(auth.sessionId, toolName);
|
|
2268
|
+
if (hit)
|
|
2269
|
+
logger.info("workflow_gate_exempted", { toolName, sessionId: auth.sessionId });
|
|
2270
|
+
return hit;
|
|
2271
|
+
},
|
|
2268
2272
|
}
|
|
2273
|
+
: undefined;
|
|
2274
|
+
try {
|
|
2275
|
+
governed = applyTaskSettings(governedBase, effectiveSettings, fsWriteGate, workflowGate);
|
|
2269
2276
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2277
|
+
catch (e) {
|
|
2278
|
+
throw new HttpError(422, `settings are tighten-only and cannot loosen the deployment policy: ${e.message}`);
|
|
2272
2279
|
}
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
if (!auth?.sessionId) {
|
|
2284
|
-
throw new HttpError(400, "sandboxImageProfile requires a resolved session");
|
|
2285
|
-
}
|
|
2286
|
-
const capsNeeded = Array.isArray(body.capabilitiesNeeded)
|
|
2287
|
-
? body.capabilitiesNeeded.filter((c) => typeof c === "string")
|
|
2288
|
-
: undefined;
|
|
2289
|
-
const resolved = await resolveSandboxImageRef({
|
|
2290
|
-
profile: taskImageProfile,
|
|
2291
|
-
...(capsNeeded && capsNeeded.length > 0 ? { capabilitiesNeeded: capsNeeded } : {}),
|
|
2292
|
-
viewer: { operator: explicitOperator(auth.principal, config.operatorPrincipals), tenantId: auth.principal ?? null },
|
|
2293
|
-
index: imageIndex,
|
|
2294
|
-
});
|
|
2295
|
-
if (!resolved.ok)
|
|
2296
|
-
throw new HttpError(resolved.status, resolved.message);
|
|
2297
|
-
perTaskImage.set(auth.sessionId, resolved.ref);
|
|
2298
|
-
resolvedImageCaps = resolved.capabilities;
|
|
2280
|
+
}
|
|
2281
|
+
if (governed.handsReadOnly === true && Array.isArray(governed.tools)) {
|
|
2282
|
+
governed = { ...governed, tools: stripDelegationTools(governed.tools) };
|
|
2283
|
+
}
|
|
2284
|
+
const bodyProfile = typeof body.sandboxImageProfile === "string" && body.sandboxImageProfile.length > 0 ? body.sandboxImageProfile : undefined;
|
|
2285
|
+
const taskImageProfile = bodyProfile ?? (body.cascade === true || body.verify === true ? undefined : sessionEnvSelection.get(auth?.sessionId));
|
|
2286
|
+
let resolvedImageCaps;
|
|
2287
|
+
if (taskImageProfile !== undefined) {
|
|
2288
|
+
if (config.remoteExec?.provider !== "k8s") {
|
|
2289
|
+
throw new HttpError(400, "sandboxImageProfile is only supported on the k8s sandbox backend");
|
|
2299
2290
|
}
|
|
2300
|
-
if (
|
|
2301
|
-
|
|
2302
|
-
const remoteScratchpadDir = !hostSemanticsLane && isRemoteScratchpadLane(config.remoteExec?.provider)
|
|
2303
|
-
? remoteScratchpadDirFor(auth?.sessionId)
|
|
2304
|
-
: undefined;
|
|
2305
|
-
const factScratchpadDir = scratchpadDir ?? remoteScratchpadDir;
|
|
2306
|
-
const facts = buildEnvFacts({
|
|
2307
|
-
profile: taskImageProfile,
|
|
2308
|
-
capabilities: resolvedImageCaps,
|
|
2309
|
-
...(pkgSourceLane ? { pkgSource: config.sandboxPkgSource } : {}),
|
|
2310
|
-
egress: egressForRemoteExec(config.remoteExec),
|
|
2311
|
-
...(factScratchpadDir ? { scratchpadDir: factScratchpadDir } : {}),
|
|
2312
|
-
resumeFacts: resumeFactsForLane(config.remoteExec?.provider, config.remoteExec?.provider === "k8s" ? { k8sSnapshot: Boolean(config.remoteExec.s3Snapshot) } : undefined),
|
|
2313
|
-
});
|
|
2314
|
-
if (facts)
|
|
2315
|
-
governed = { ...governed, envFacts: facts };
|
|
2291
|
+
if (!imageIndex) {
|
|
2292
|
+
throw new HttpError(400, "sandboxImageProfile requires the image index (sema-registry backend not configured)");
|
|
2316
2293
|
}
|
|
2317
|
-
if (
|
|
2318
|
-
|
|
2319
|
-
if (!dirs.includes(scratchpadDir))
|
|
2320
|
-
governed = { ...governed, additionalDirectories: [...dirs, scratchpadDir] };
|
|
2294
|
+
if (!auth?.sessionId) {
|
|
2295
|
+
throw new HttpError(400, "sandboxImageProfile requires a resolved session");
|
|
2321
2296
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2297
|
+
const capsNeeded = Array.isArray(body.capabilitiesNeeded)
|
|
2298
|
+
? body.capabilitiesNeeded.filter((c) => typeof c === "string")
|
|
2299
|
+
: undefined;
|
|
2300
|
+
const resolved = await resolveSandboxImageRef({
|
|
2301
|
+
profile: taskImageProfile,
|
|
2302
|
+
...(capsNeeded && capsNeeded.length > 0 ? { capabilitiesNeeded: capsNeeded } : {}),
|
|
2303
|
+
viewer: { operator: explicitOperator(auth.principal, config.operatorPrincipals), tenantId: auth.principal ?? null },
|
|
2304
|
+
index: imageIndex,
|
|
2305
|
+
});
|
|
2306
|
+
if (!resolved.ok)
|
|
2307
|
+
throw new HttpError(resolved.status, resolved.message);
|
|
2308
|
+
perTaskImage.set(auth.sessionId, resolved.ref);
|
|
2309
|
+
resolvedImageCaps = resolved.capabilities;
|
|
2310
|
+
}
|
|
2311
|
+
if (config.envFactsEnabled) {
|
|
2312
|
+
const pkgSourceLane = config.remoteExec?.provider === "e2b" || config.remoteExec?.provider === "k8s";
|
|
2313
|
+
const remoteScratchpadDir = !hostSemanticsLane && isRemoteScratchpadLane(config.remoteExec?.provider)
|
|
2314
|
+
? remoteScratchpadDirFor(auth?.sessionId)
|
|
2315
|
+
: undefined;
|
|
2316
|
+
const factScratchpadDir = scratchpadDir ?? remoteScratchpadDir;
|
|
2317
|
+
const facts = buildEnvFacts({
|
|
2318
|
+
profile: taskImageProfile,
|
|
2319
|
+
capabilities: resolvedImageCaps,
|
|
2320
|
+
...(pkgSourceLane ? { pkgSource: config.sandboxPkgSource } : {}),
|
|
2321
|
+
egress: egressForRemoteExec(config.remoteExec),
|
|
2322
|
+
...(factScratchpadDir ? { scratchpadDir: factScratchpadDir } : {}),
|
|
2323
|
+
resumeFacts: resumeFactsForLane(config.remoteExec?.provider, config.remoteExec?.provider === "k8s" ? { k8sSnapshot: Boolean(config.remoteExec.s3Snapshot) } : undefined),
|
|
2324
|
+
});
|
|
2325
|
+
if (facts)
|
|
2326
|
+
governed = { ...governed, envFacts: facts };
|
|
2327
|
+
}
|
|
2328
|
+
if (scratchpadDir !== undefined) {
|
|
2329
|
+
const dirs = governed.additionalDirectories ?? [];
|
|
2330
|
+
if (!dirs.includes(scratchpadDir))
|
|
2331
|
+
governed = { ...governed, additionalDirectories: [...dirs, scratchpadDir] };
|
|
2332
|
+
}
|
|
2333
|
+
if (config.routerEnabled) {
|
|
2334
|
+
const isolatedExecEnv = isIsolatedExecEnv(config.remoteExec?.provider, config.remoteExec?.provider === "k8s" ? config.remoteExec.runtimeClass : undefined);
|
|
2335
|
+
const decision = routeServiceTask({
|
|
2336
|
+
isolatedExecEnv,
|
|
2337
|
+
hasExecutionEnv: config.remoteExec != null,
|
|
2338
|
+
...(config.autonomy ? { autonomy: config.autonomy } : {}),
|
|
2339
|
+
explicitTeam: body.council === true || body.debate === true || scenarioName === "team",
|
|
2340
|
+
});
|
|
2341
|
+
logger.info("orchestration_routed", { mode: decision.mode, reason: decision.reason, sessionId: auth?.sessionId ?? null });
|
|
2342
|
+
if (decision.mode === "supervisor") {
|
|
2343
|
+
return tightenTaskSpec(governed, supPostureOverrides());
|
|
2334
2344
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
}
|
|
2345
|
+
}
|
|
2346
|
+
return governed;
|
|
2347
|
+
};
|
|
2348
|
+
const server = createHttpServer({ runner, config, resolveSpec, stores, coordinators, seams, observability, governance, deployment, knobs });
|
|
2338
2349
|
runDenySweep = server.denyExpiredApprovals;
|
|
2339
2350
|
const bindHost = resolveBindHost(config);
|
|
2340
2351
|
await new Promise((resolve) => (bindHost ? server.listen(config.port, bindHost, resolve) : server.listen(config.port, resolve)));
|