@tangle-network/agent-runtime 0.323.0 → 0.325.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/{activation-DpipXGti.js → activation--9-iyGR8.js} +3 -3
- package/dist/{activation-DpipXGti.js.map → activation--9-iyGR8.js.map} +1 -1
- package/dist/{activation-D4hHi27J.d.ts → activation-Q3CJgiCu.d.ts} +2 -2
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +2 -2
- package/dist/{bundle-Cw-QdGmH.js → bundle-BJJmfEsw.js} +2 -2
- package/dist/{bundle-Cw-QdGmH.js.map → bundle-BJJmfEsw.js.map} +1 -1
- package/dist/candidate-execution/index.js +5 -5
- package/dist/{coordination-driver-COSL19sL.js → coordination-driver-DkkUVe9g.js} +271 -156
- package/dist/coordination-driver-DkkUVe9g.js.map +1 -0
- package/dist/{delegate-silSKPSB.js → delegate-BDsaIl2K.js} +2 -2
- package/dist/{delegate-silSKPSB.js.map → delegate-BDsaIl2K.js.map} +1 -1
- package/dist/{durable-file-DWQA4ooo.js → durable-file-B_eJr6Mb.js} +40 -8
- package/dist/durable-file-B_eJr6Mb.js.map +1 -0
- package/dist/durable.d.ts +2 -2
- package/dist/durable.js +70 -40
- package/dist/durable.js.map +1 -1
- package/dist/graph-Cuz6Ubzd.js +348 -0
- package/dist/graph-Cuz6Ubzd.js.map +1 -0
- package/dist/{graph-registry-BuJbzTzF.js → graph-registry-DAI6KNXB.js} +19 -34
- package/dist/graph-registry-DAI6KNXB.js.map +1 -0
- package/dist/{improvement-cycle-BeN9wahG.js → improvement-cycle-B5Z8cHKx.js} +10 -10
- package/dist/{improvement-cycle-BeN9wahG.js.map → improvement-cycle-B5Z8cHKx.js.map} +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +18 -15
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +3 -3
- package/dist/intelligence.js +7 -7
- package/dist/jsonl-file-DBv31uPi.js +206 -0
- package/dist/jsonl-file-DBv31uPi.js.map +1 -0
- package/dist/kernel.d.ts +2 -2
- package/dist/kernel.js +13 -13
- package/dist/{loop-runner-bin-DkhIbFBp.js → loop-runner-bin-C16VR9cI.js} +3 -3
- package/dist/{loop-runner-bin-DkhIbFBp.js.map → loop-runner-bin-C16VR9cI.js.map} +1 -1
- package/dist/{loop-runner-bin-Bsux_MGx.d.ts → loop-runner-bin-Co7JKSwi.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +6 -6
- package/dist/{model-policy-CNe257pB.js → model-policy-CyCUwHed.js} +2 -2
- package/dist/model-policy-CyCUwHed.js.map +1 -0
- package/dist/{openai-tools-e02ABKl0.d.ts → openai-tools-CbgZrQJ_.d.ts} +2 -2
- package/dist/{prepare-CFQLx9e3.js → prepare-DpavgJT8.js} +4 -4
- package/dist/{prepare-CFQLx9e3.js.map → prepare-DpavgJT8.js.map} +1 -1
- package/dist/{profile-BTbpdL9h.js → profile-ZS7_KLwK.js} +2 -2
- package/dist/{profile-BTbpdL9h.js.map → profile-ZS7_KLwK.js.map} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/{protected-model-port-f1N2f0Uq.js → protected-model-port-BLyyfL3l.js} +4 -4
- package/dist/{protected-model-port-f1N2f0Uq.js.map → protected-model-port-BLyyfL3l.js.map} +1 -1
- package/dist/{protected-redaction-DylCC_ot.js → protected-redaction-DFCeo4vg.js} +2 -2
- package/dist/{protected-redaction-DylCC_ot.js.map → protected-redaction-DFCeo4vg.js.map} +1 -1
- package/dist/{provision-supervisor-DdWu6mqu.js → provision-supervisor-4BoHpGFJ.js} +7 -7
- package/dist/{provision-supervisor-DdWu6mqu.js.map → provision-supervisor-4BoHpGFJ.js.map} +1 -1
- package/dist/{run-layout-DSCWdbX2.js → run-layout-Cu8H7aeh.js} +2 -2
- package/dist/{run-layout-DSCWdbX2.js.map → run-layout-Cu8H7aeh.js.map} +1 -1
- package/dist/{runtime-DhPIc7XV.js → runtime-B9X_U-aV.js} +84 -80
- package/dist/runtime-B9X_U-aV.js.map +1 -0
- package/dist/{search-executor-BS-WJpti.js → search-executor-C-b4NaFl.js} +13 -5
- package/dist/search-executor-C-b4NaFl.js.map +1 -0
- package/dist/{server-CEDOUOdz.js → server-CcHaXgUT.js} +4 -4
- package/dist/{server-CEDOUOdz.js.map → server-CcHaXgUT.js.map} +1 -1
- package/dist/{supervise-CwWI7kIk.js → supervise-BlaB4CeL.js} +739 -22
- package/dist/supervise-BlaB4CeL.js.map +1 -0
- package/dist/{supervisor-CSKkm-e1.js → supervisor-fq4JGynd.js} +10940 -10787
- package/dist/supervisor-fq4JGynd.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +14 -14
- package/dist/{top-app-DaiR4LXM.js → top-app-BaMw1W2z.js} +2 -2
- package/dist/{top-app-DaiR4LXM.js.map → top-app-BaMw1W2z.js.map} +1 -1
- package/dist/tui/bin.js +1 -1
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +2 -2
- package/dist/{index-7h7-L6Tk.d.ts → types-5r334mcg.d.ts} +17425 -17267
- package/dist/{workspace-streams-DFAhW7hF.js → workspace-streams-CcoARX4v.js} +2 -2
- package/dist/{workspace-streams-DFAhW7hF.js.map → workspace-streams-CcoARX4v.js.map} +1 -1
- package/package.json +3 -3
- package/skills/profile-authoring/SKILL.md +1 -1
- package/dist/coordination-driver-COSL19sL.js.map +0 -1
- package/dist/durable-file-DWQA4ooo.js.map +0 -1
- package/dist/graph-DbQ-BXKr.js +0 -805
- package/dist/graph-DbQ-BXKr.js.map +0 -1
- package/dist/graph-registry-BuJbzTzF.js.map +0 -1
- package/dist/model-policy-CNe257pB.js.map +0 -1
- package/dist/runtime-DhPIc7XV.js.map +0 -1
- package/dist/search-executor-BS-WJpti.js.map +0 -1
- package/dist/supervise-CwWI7kIk.js.map +0 -1
- package/dist/supervisor-CSKkm-e1.js.map +0 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as assertNoSymlinkDescendant } from "./durable-file-B_eJr6Mb.js";
|
|
2
|
+
import { $n as readHarnessTranscript, $r as renderUnsupported, A as scopeOwnerExecutorNodeContext, At as bindReusableExecutorExecutionId, B as consumeScopeRetainedOwnerResult, Bt as createRouterTranscript, C as deriveNodeExecutionIdentity, Ct as checkVerdictOf, D as recordScopeOwnerMaterialization, E as recordScopeOwnerDriverAttempt, F as seatExecutionProfile, Fn as bridgeRuntimeAttachmentsKey, G as scopeRetainedOwnerContext, Gr as defineProfileMaterializationContract, H as prepareScopeRetainedOwnerSeatSwitch, Hr as assertProfileMaterialization, Ht as WORKER_TRACE_PROPAGATION, I as abandonScopeRetainedOwnerInvocation, In as bridgeStopSignalKey, It as snapshotExecutorConfig, J as scopeRetainedOwnerResourceReader, Jn as linkAbort, Jr as promptControlProfileMaterialization, K as scopeRetainedOwnerJournalRoot, Kn as RunCancellationReason, Kr as fullProfileMaterialization, L as beginScopeRetainedOwnerDrive, M as SeatChain, Mi as retainedExecutorSeamKey, N as SeatChainExhaustedError, O as recordScopeOwnerPause, P as authoredSeatStages, Pt as createExecutor, Qn as persistHarnessTranscript, R as bindScopeRetainedOwnerEnvironmentId, Sr as toOtelAttributes, St as bestComposite, T as meterRuntimeOwnedProviderAttempt, Tn as routerBrain, U as prepareScopeRetainedOwnerTask, V as noteScopeRetainedOwnerCoordination, W as reconcileScopeRetainedOwnerEnvironment, Wr as controlProfileMaterialization, X as scopeRetainedOwnerResult, Y as scopeRetainedOwnerRestorePoint, Yn as runAbortable, Yr as promptModelProfileMaterialization, Yt as createActivityLog, Z as scopeRetainedOwnerTurnEnded, Zt as createInbox, _ as isDriverSpec, _i as runtimeOwnedExecutorMaterialization, _t as CONTINUATIONS_DIR, ai as attestRuntimeOwnedScopeOwner, at as runtimeGraphMetadataKey, b as assertRecursiveReservationPolicy, bi as runtimeOwnedScopeOwnerRuntime, bt as admitContinuationPolicy, c as runTree, cn as bridgeAdmissionRefusal, da as detachedSnapshot, en as PEER_MAIL_WIRE_KEY, f as runDriverWithRetry, fa as executorFailure, g as driverExecutorFactory, ga as assertValidBudget, gi as runtimeOwnedExecutorExecutionBinding, gr as createOtelExporter, h as driverChild, hi as runtimeOwnedDriveHarnessProviderEvidence, ht as gateOnDeliverable, i as bestDelivered, it as providerVisibleProfile, ji as registerRetainedExecutorPreparation, jn as resolveAgentEnvironmentProvider, jt as captureReusableExecutorConfig, k as restoreScopeOwnerAcceptedExecution, la as contentAddress, li as inheritRuntimeOwnedExecutorAttestation, ln as bridgeModelRouteRefusal, mi as recordRuntimeOwnedDriveHarnessProviderEvidence, n as createRootHandle, nt as coordinationMcpAlias, oi as authoredAgentIdentity, on as isLiveNodeStatus, p as summarizeDriverAttempts, pa as errMessage, pi as providerAttemptEvidence, q as scopeRetainedOwnerPriorSpend, qr as profileMaterializationAxes$1, r as createSupervisor, ri as worktreeCliProfileMaterialization, rn as isPeerMailEnvelope, rt as coordinationProfileToolPrefix, s as runFinalizer, sa as parseWorkerToolTraceArtifact, ti as unsupportedProfileDimensions, u as HarnessTurnFailedError, va as meterUsageEvent, vi as runtimeOwnedExecutorProviderEvidence, vr as generateSpanId, w as meterRuntimeOwnedAccounting, wt as createContinuationKeeper, x as beginScopeOwnerAttempt, xa as spendFromUsageTotals, ya as newUsageTotals, yi as runtimeOwnedPendingExecutorMaterialization, yt as CheckUnavailableError, z as bindScopeRetainedOwnerProvider } from "./supervisor-fq4JGynd.js";
|
|
2
3
|
import { f as RuntimeRunStateError, i as ConfigError, m as ValidationError } from "./errors-DodWX-cb.js";
|
|
3
|
-
import { Dt as teardownSurfaces, Et as teardownExecutor, V as addSpend, Z as isAsyncIterable$1, ct as withTimeout, dt as addResourceSpend, lt as zeroSpend, mt as withBudgetResources, pt as resourceTelemetry, q as errorMessage, rt as sleep, st as unmeteredSpend, yt as DEFAULT_SUCCESSFUL_SHUTDOWN_MS } from "./workspace-streams-
|
|
4
|
-
import {
|
|
5
|
-
import { n as
|
|
4
|
+
import { Dt as teardownSurfaces, Et as teardownExecutor, V as addSpend, Z as isAsyncIterable$1, ct as withTimeout, dt as addResourceSpend, lt as zeroSpend, mt as withBudgetResources, pt as resourceTelemetry, q as errorMessage, rt as sleep, st as unmeteredSpend, yt as DEFAULT_SUCCESSFUL_SHUTDOWN_MS } from "./workspace-streams-CcoARX4v.js";
|
|
5
|
+
import { a as readCommittedJsonLines, n as isNoEntError, r as prepareJsonlAppend } from "./jsonl-file-DBv31uPi.js";
|
|
6
|
+
import { _ as agentHarness, a as concreteProfileModel, c as profileModelExecutionSettings, n as assertModelAllowed, o as enforceTokenLimits, r as assertProfileModelsAllowed, s as profileBridgeWireModel, t as assertExecutableAgentProfile, v as harnessRunsAgent } from "./model-policy-CyCUwHed.js";
|
|
6
7
|
import { t as composeRuntimeHooks } from "./runtime-hooks-tXpAarhW.js";
|
|
7
|
-
import { C as createFileRunContext, F as createCoordinationToolsForManager, N as coordinationVerbNames, O as applyRunCancellation, T as withRunContext, c as refreshedWake, g as progressStop, h as plateau, k as watchRunCancellation, l as resolveWakePolicy, n as createSteerAcknowledger, o as composeWakeInput, p as createProgressTracker, r as driverAgent, s as deadlineWarningAt, t as createCancelAcknowledger, w as createInMemoryRunContext } from "./coordination-driver-
|
|
8
|
+
import { C as createFileRunContext, F as createCoordinationToolsForManager, N as coordinationVerbNames, O as applyRunCancellation, T as withRunContext, c as refreshedWake, g as progressStop, h as plateau, k as watchRunCancellation, l as resolveWakePolicy, n as createSteerAcknowledger, o as composeWakeInput, p as createProgressTracker, r as driverAgent, s as deadlineWarningAt, t as createCancelAcknowledger, w as createInMemoryRunContext } from "./coordination-driver-DkkUVe9g.js";
|
|
8
9
|
import { r as createStdioToolServer, t as PROTOCOL_VERSION } from "./tool-server-Dqer2M4_.js";
|
|
9
|
-
import {
|
|
10
|
+
import { c as loadGraph, i as graphRegistry } from "./graph-registry-DAI6KNXB.js";
|
|
11
|
+
import { k as writeRunCancellation, o as readRunCancelRequest, s as readRunCancellation } from "./run-layout-Cu8H7aeh.js";
|
|
10
12
|
import { agentProfileSchema, canonicalAgentProfileDigest, canonicalCandidateDigest, canonicalCandidateJson, validateAgentProfileSecurity } from "@tangle-network/agent-interface";
|
|
11
13
|
import { toolSpansToTraceAnalysisStore } from "@tangle-network/agent-eval";
|
|
12
14
|
import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -640,6 +642,7 @@ async function serveCoordinationMcpForManager(opts, lifetime) {
|
|
|
640
642
|
scope: opts.scope,
|
|
641
643
|
blobs: opts.blobs,
|
|
642
644
|
makeWorkerAgent: opts.makeWorkerAgent,
|
|
645
|
+
...opts.graphs ? { graphs: opts.graphs } : {},
|
|
643
646
|
...opts.authorizeDownMessage ? { authorizeDownMessage: opts.authorizeDownMessage } : {},
|
|
644
647
|
perWorker: opts.perWorker,
|
|
645
648
|
...opts.deliverable ? { deliverable: opts.deliverable } : {},
|
|
@@ -911,6 +914,620 @@ async function serveCoordinationMcpForManager(opts, lifetime) {
|
|
|
911
914
|
};
|
|
912
915
|
}
|
|
913
916
|
//#endregion
|
|
917
|
+
//#region src/runtime/supervise/prompt-registry.ts
|
|
918
|
+
/**
|
|
919
|
+
*
|
|
920
|
+
* The kernel prompt registry — versioned prompt text as DATA, addressed by `PromptHandle`.
|
|
921
|
+
*
|
|
922
|
+
* A role expressed as a builder FUNCTION is a role that can never improve: the only optimizable
|
|
923
|
+
* surface it leaves is whatever thin string a caller happens to inject, while the real doctrine
|
|
924
|
+
* sits hardcoded in TypeScript. This registry is the inverse: every standing instruction is a
|
|
925
|
+
* versioned entry (`<surface>` + `v<n>`), so a graph edge, a supervisor front door, or an
|
|
926
|
+
* optimizer names a handle and the TEXT is swappable, sweepable, and diffable without a code
|
|
927
|
+
* change. Graph edges (`runGraph`) carry handles, never inline prose.
|
|
928
|
+
*
|
|
929
|
+
* A profile or graph may opt into one of these versioned texts. Runtime does not select a standing
|
|
930
|
+
* supervisor policy when the profile omits one.
|
|
931
|
+
*
|
|
932
|
+
* @experimental
|
|
933
|
+
*/
|
|
934
|
+
const HANDLE_PATTERN = /^(.+)\/v(\d+)$/;
|
|
935
|
+
/**
|
|
936
|
+
* Parse `'<surface>/v<n>'` into a {@link PromptHandle}. The shorthand for authoring a graph edge:
|
|
937
|
+
* `directive: promptHandle('delegates/worker-brief/v1')`.
|
|
938
|
+
*/
|
|
939
|
+
function promptHandle(ref) {
|
|
940
|
+
if (typeof ref !== "string" || ref.length === 0) throw new ValidationError("promptHandle: ref must be a non-empty string");
|
|
941
|
+
const match = HANDLE_PATTERN.exec(ref);
|
|
942
|
+
if (!match) throw new ValidationError(`promptHandle: ${JSON.stringify(ref)} is not a versioned prompt reference (<surface>/v<n>)`);
|
|
943
|
+
const version = Number(match[2]);
|
|
944
|
+
if (!Number.isSafeInteger(version) || version < 0) throw new ValidationError(`promptHandle: invalid version in ${JSON.stringify(ref)}`);
|
|
945
|
+
return {
|
|
946
|
+
surface: match[1],
|
|
947
|
+
version
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
/** The string form of a handle: `<surface>/v<n>`. */
|
|
951
|
+
function formatPromptHandle(handle) {
|
|
952
|
+
return `${handle.surface}/v${handle.version}`;
|
|
953
|
+
}
|
|
954
|
+
/** Create a registry, optionally seeded. Entries are copied; the registry never aliases caller state. */
|
|
955
|
+
function createPromptRegistry(seed) {
|
|
956
|
+
const entries = /* @__PURE__ */ new Map();
|
|
957
|
+
const keyOf = (surface, version) => `${surface}/v${version}`;
|
|
958
|
+
const register = (entry) => {
|
|
959
|
+
if (typeof entry.surface !== "string" || entry.surface.length === 0) throw new ValidationError("prompt registry: entry.surface must be a non-empty string");
|
|
960
|
+
if (!Number.isSafeInteger(entry.version) || entry.version < 0) throw new ValidationError("prompt registry: entry.version must be a non-negative integer");
|
|
961
|
+
if (typeof entry.text !== "string" || entry.text.length === 0) throw new ValidationError(`prompt registry: entry ${keyOf(entry.surface, entry.version)} has no text — an empty directive is the silent-substitution failure this registry exists to prevent`);
|
|
962
|
+
const key = keyOf(entry.surface, entry.version);
|
|
963
|
+
if (entries.has(key)) throw new ValidationError(`prompt registry: ${key} is already registered — versions are immutable; register a new version instead`);
|
|
964
|
+
entries.set(key, Object.freeze({ ...entry }));
|
|
965
|
+
};
|
|
966
|
+
for (const entry of seed ?? []) register(entry);
|
|
967
|
+
return {
|
|
968
|
+
resolve(handle) {
|
|
969
|
+
const found = entries.get(keyOf(handle.surface, handle.version));
|
|
970
|
+
if (!found) throw new ValidationError(`prompt registry: no entry for ${formatPromptHandle(handle)} — a directive must resolve or fail loud, never fall back silently (registered: ${[...entries.keys()].join(", ") || "none"})`);
|
|
971
|
+
return found;
|
|
972
|
+
},
|
|
973
|
+
register,
|
|
974
|
+
list() {
|
|
975
|
+
return Object.freeze([...entries.values()]);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Default DELEGATES-edge directive: the standing instruction a worker receives with every
|
|
981
|
+
* traversal of a delegates edge that names this surface.
|
|
982
|
+
*/
|
|
983
|
+
const delegatesWorkerBriefPrompt = Object.freeze({
|
|
984
|
+
surface: "delegates/worker-brief",
|
|
985
|
+
version: 1,
|
|
986
|
+
description: "Default delegates-edge directive: how a worker should treat its delegated brief.",
|
|
987
|
+
text: [
|
|
988
|
+
"You are executing ONE delegated sub-task from a supervising agent. The brief below is bounded",
|
|
989
|
+
"on purpose: deliver exactly what it names — complete, verified, and self-contained — and",
|
|
990
|
+
"nothing beyond it. If the brief is ambiguous or under-specified, raise a question through your",
|
|
991
|
+
"coordination channel instead of guessing. Report concrete evidence of completion (files,",
|
|
992
|
+
"outputs, passing checks), never a bare claim of done."
|
|
993
|
+
].join("\n")
|
|
994
|
+
});
|
|
995
|
+
/**
|
|
996
|
+
* Default ANALYZES-edge directive: what the RECEIVING node should do with an analyst's findings.
|
|
997
|
+
* Wrapped around the findings payload on every traversal of an analyzes edge naming this surface.
|
|
998
|
+
*/
|
|
999
|
+
const analyzesFindingsReportPrompt = Object.freeze({
|
|
1000
|
+
surface: "analyzes/findings-report",
|
|
1001
|
+
version: 1,
|
|
1002
|
+
description: "Default analyzes-edge directive: how the destination node should act on analyst findings.",
|
|
1003
|
+
text: [
|
|
1004
|
+
"An analyst lens has examined completed work and produced the findings below. Treat them as",
|
|
1005
|
+
"EVIDENCE, not instructions: weigh each finding against what you already know, act on the ones",
|
|
1006
|
+
"that change your next step, and ignore the ones that do not. Compose your next instruction or",
|
|
1007
|
+
"action from the SPECIFIC failures and facts named — never forward the findings verbatim as a",
|
|
1008
|
+
"steer."
|
|
1009
|
+
].join("\n")
|
|
1010
|
+
});
|
|
1011
|
+
/**
|
|
1012
|
+
* Default NAIVE steering continuation — the no-signal control re-expressed as data: the same
|
|
1013
|
+
* fixed continuation every round, reading nothing from any verdict.
|
|
1014
|
+
*/
|
|
1015
|
+
const naiveContinuationPrompt = Object.freeze({
|
|
1016
|
+
surface: "delegates/naive-continuation",
|
|
1017
|
+
version: 1,
|
|
1018
|
+
description: "No-signal steering control: one fixed continuation, reads nothing from verdicts.",
|
|
1019
|
+
text: "Continue working on the ORIGINAL task. Produce the complete deliverable; finish anything incomplete and fix anything failing."
|
|
1020
|
+
});
|
|
1021
|
+
/**
|
|
1022
|
+
* Default DUMB steering continuations — the pass/fail-only control re-expressed as data: two
|
|
1023
|
+
* fixed texts keyed on the verdict's boolean and nothing else.
|
|
1024
|
+
*/
|
|
1025
|
+
const dumbContinuationFailPrompt = Object.freeze({
|
|
1026
|
+
surface: "delegates/dumb-continuation-fail",
|
|
1027
|
+
version: 1,
|
|
1028
|
+
description: "Pass/fail-only steering control, fail branch: reads only verdict.valid.",
|
|
1029
|
+
text: "Your last attempt did NOT pass verification. Rework the task and produce a complete, correct deliverable; do not repeat the failed approach unchanged."
|
|
1030
|
+
});
|
|
1031
|
+
/** The pass branch of the dumb steering control — see {@link dumbContinuationFailPrompt}. */
|
|
1032
|
+
const dumbContinuationPassPrompt = Object.freeze({
|
|
1033
|
+
surface: "delegates/dumb-continuation-pass",
|
|
1034
|
+
version: 1,
|
|
1035
|
+
description: "Pass/fail-only steering control, pass branch: reads only verdict.valid.",
|
|
1036
|
+
text: "Your last attempt passed verification. Finalize your work and stop."
|
|
1037
|
+
});
|
|
1038
|
+
/** The kernel's seeded registry: every surface the runtime's own builders derive from. A caller
|
|
1039
|
+
* may register additional surfaces/versions on the returned registry. */
|
|
1040
|
+
function kernelPromptRegistry() {
|
|
1041
|
+
return createPromptRegistry([
|
|
1042
|
+
delegatesWorkerBriefPrompt,
|
|
1043
|
+
analyzesFindingsReportPrompt,
|
|
1044
|
+
naiveContinuationPrompt,
|
|
1045
|
+
dumbContinuationFailPrompt,
|
|
1046
|
+
dumbContinuationPassPrompt
|
|
1047
|
+
]);
|
|
1048
|
+
}
|
|
1049
|
+
//#endregion
|
|
1050
|
+
//#region src/runtime/supervise/graph-overlay.ts
|
|
1051
|
+
/**
|
|
1052
|
+
* The graph layer over the managers that run one `AgentGraph`.
|
|
1053
|
+
*
|
|
1054
|
+
* `runGraph` and a manager's `run_graph` tool execute a graph the same way: the graph's root node is
|
|
1055
|
+
* a manager in the supervise kernel, and this module supplies what the graph adds around it —
|
|
1056
|
+
* node pinning (spawn authorization), the driver brief, analyst routes, edge continuity defaults,
|
|
1057
|
+
* and the edge ledger with its journal twin. `runGraph` composes it into the root `supervise()`
|
|
1058
|
+
* call; `supervise()` composes it into the nested manager a `run_graph` spawn starts, so a graph
|
|
1059
|
+
* run as a subtask is one subtree of the caller's run, spending from the caller's conserved pool.
|
|
1060
|
+
*
|
|
1061
|
+
* Nothing here schedules anything. It produces the values a manager's construction takes
|
|
1062
|
+
* (`authorizeSpawn`, `resolveSpawnProfile`, `analyzeOnSettle`, `continuityByProfile`) and
|
|
1063
|
+
* observes what the kernel reports back (spawn bindings, steers, findings).
|
|
1064
|
+
*/
|
|
1065
|
+
/** Default per-edge traversal cap — the cyclic-graph backstop when an edge names none. */
|
|
1066
|
+
const defaultEdgeTraversalCap = 32;
|
|
1067
|
+
function edgeId(edge) {
|
|
1068
|
+
return edge.kind === "delegates" ? `delegates:${edge.from}->${edge.to}` : `analyzes:${edge.analyst}:${edge.over.join("+")}->${edge.to}`;
|
|
1069
|
+
}
|
|
1070
|
+
/** Validate a topology and resolve every directive BEFORE any compute is spent — an invalid
|
|
1071
|
+
* topology or an unknown directive is a configuration fault, never a mid-run surprise. */
|
|
1072
|
+
function validateGraphTopology(nodes, edges, registry, analysts) {
|
|
1073
|
+
if (!Array.isArray(nodes) || nodes.length === 0) throw new ValidationError("runGraph: graph.nodes must be a non-empty array");
|
|
1074
|
+
if (!Array.isArray(edges) || edges.length === 0) throw new ValidationError("runGraph: graph.edges must be a non-empty array");
|
|
1075
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1076
|
+
for (const node of nodes) {
|
|
1077
|
+
if (typeof node.id !== "string" || node.id.length === 0) throw new ValidationError("runGraph: every node needs a non-empty string id");
|
|
1078
|
+
if (byId.has(node.id)) throw new ValidationError(`runGraph: duplicate node id '${node.id}'`);
|
|
1079
|
+
const parsed = agentProfileSchema.safeParse(node.profile);
|
|
1080
|
+
if (!parsed.success) throw new ValidationError(`runGraph: node '${node.id}' has an invalid AgentProfile: ${parsed.error.message}`);
|
|
1081
|
+
if (node.profile.name !== node.id) throw new ValidationError(`runGraph: node '${node.id}' has profile.name ${JSON.stringify(node.profile.name)} — profile.name IS the node identity (node pinning and analyst routing match on it) and must equal the node id`);
|
|
1082
|
+
if (node.profile.metadata?.["agentRuntimeGraph"] !== void 0) throw new ValidationError(`runGraph: node '${node.id}' carries metadata.${runtimeGraphMetadataKey}, which Runtime writes only for the root of a graph started by run_graph; a node cannot hold a graph`);
|
|
1083
|
+
byId.set(node.id, node);
|
|
1084
|
+
}
|
|
1085
|
+
const requireNode = (id, where) => {
|
|
1086
|
+
const node = byId.get(id);
|
|
1087
|
+
if (!node) throw new ValidationError(`runGraph: ${where} references unknown node '${id}'`);
|
|
1088
|
+
return node;
|
|
1089
|
+
};
|
|
1090
|
+
const delegates = edges.filter((edge) => edge.kind === "delegates");
|
|
1091
|
+
const analyzes = edges.filter((edge) => edge.kind === "analyzes");
|
|
1092
|
+
if (delegates.length === 0) throw new ValidationError("runGraph: at least one delegates edge is required (who spawns whom)");
|
|
1093
|
+
for (const edge of edges) registry.resolve(edge.directive);
|
|
1094
|
+
for (const edge of delegates) {
|
|
1095
|
+
requireNode(edge.from, edgeId(edge));
|
|
1096
|
+
requireNode(edge.to, edgeId(edge));
|
|
1097
|
+
if (edge.from === edge.to) throw new ValidationError(`runGraph: ${edgeId(edge)} delegates to itself — the driver↔worker cycle is the settle-return loop, not a self-edge`);
|
|
1098
|
+
if (edge.continuity !== void 0 && edge.continuity !== "fresh" && edge.continuity !== "resume") throw new ValidationError(`runGraph: ${edgeId(edge)} has invalid continuity ${JSON.stringify(edge.continuity)} — a delegates edge's continuity is 'fresh' or 'resume'`);
|
|
1099
|
+
}
|
|
1100
|
+
const delegatedTo = new Set(delegates.map((edge) => edge.to));
|
|
1101
|
+
const roots = [...new Set(delegates.map((edge) => edge.from))].filter((id) => !delegatedTo.has(id));
|
|
1102
|
+
if (roots.length !== 1) throw new ValidationError(`runGraph: expected exactly ONE root (a node that delegates and is never delegated to), found ${roots.length === 0 ? "none — delegates edges form a cycle with no entry" : roots.join(", ")}. P0 executes driver↔worker(s); nested driver graphs are P3.`);
|
|
1103
|
+
const root = requireNode(roots[0], "root resolution");
|
|
1104
|
+
if (root.profile.tools?.[`${coordinationProfileToolPrefix}spawn_worker`] !== true) throw new ValidationError(`runGraph: root node '${root.id}' has delegates edges but does not declare ${JSON.stringify(`${coordinationProfileToolPrefix}spawn_worker`)} — the graph cannot spawn any declared worker`);
|
|
1105
|
+
for (const edge of delegates) if (edge.from !== root.id) throw new ValidationError(`runGraph: ${edgeId(edge)} delegates from a non-root node — P0 executes one driver over its workers (the 2-node cyclic case, star-generalized); deeper delegation is P3`);
|
|
1106
|
+
const analystIds = /* @__PURE__ */ new Set();
|
|
1107
|
+
const analystNodes = /* @__PURE__ */ new Map();
|
|
1108
|
+
for (const edge of analyzes) {
|
|
1109
|
+
if (edge.continuity !== void 0) throw new ValidationError(`runGraph: ${edgeId(edge)} carries continuity — analysts are spawned by the analyst machinery (every analyst run is a fresh session over settled evidence), so continuity is a delegates-edge axis only`);
|
|
1110
|
+
if (analystIds.has(edge.analyst)) throw new ValidationError(`runGraph: two analyzes edges share analyst '${edge.analyst}' — one analyzes edge per analyst lens (traversals are ledgered by analyst id; a second edge would silently absorb the first's). Register the lens under a second id for a second edge.`);
|
|
1111
|
+
analystIds.add(edge.analyst);
|
|
1112
|
+
const analystNode = byId.get(edge.analyst);
|
|
1113
|
+
const inRegistry = analysts?.kinds.some((kind) => kind.id === edge.analyst) === true;
|
|
1114
|
+
if (analystNode !== void 0 && inRegistry) throw new ValidationError(`runGraph: ${edgeId(edge)} analyst '${edge.analyst}' is BOTH a graph node and a lens in the analysts registry — the id alone distinguishes the two analyst forms, so this is ambiguous; rename the node or register the lens under another id`);
|
|
1115
|
+
if (analystNode !== void 0) {
|
|
1116
|
+
if (analystNode.id === root.id) throw new ValidationError(`runGraph: ${edgeId(edge)} names the ROOT as its analyst — the root is the driver; give the analyst its own node with no delegates edge pointing at it`);
|
|
1117
|
+
if (delegatedTo.has(analystNode.id)) throw new ValidationError(`runGraph: ${edgeId(edge)} names node '${edge.analyst}' as its analyst, but that node is a delegates target — oracle doctrine: an analyst is never delegated to. An analyst NODE is legal only with NO delegates edge pointing at it; give the analyst its own delegates-free node or pass a lens id from RunGraphOptions.analysts.`);
|
|
1118
|
+
analystNodes.set(analystNode.id, analystNode);
|
|
1119
|
+
} else if (!analysts) throw new ValidationError(`runGraph: ${edgeId(edge)} analyst '${edge.analyst}' is not a graph node, and no RunGraphOptions.analysts registry was provided to resolve it as a lens`);
|
|
1120
|
+
else if (!inRegistry) throw new ValidationError(`runGraph: ${edgeId(edge)} analyst '${edge.analyst}' is neither a graph node nor in the analysts registry (known lenses: ${analysts.kinds.map((kind) => kind.id).join(", ") || "none"})`);
|
|
1121
|
+
if (edge.over.length === 0) throw new ValidationError(`runGraph: ${edgeId(edge)} must analyze at least one node`);
|
|
1122
|
+
for (const over of edge.over) {
|
|
1123
|
+
requireNode(over, edgeId(edge));
|
|
1124
|
+
if (over === root.id) throw new ValidationError(`runGraph: ${edgeId(edge)} analyzes the ROOT — analysts observe settled workers, and the root never settles as one, so this edge would silently never fire; list delegates-target nodes only`);
|
|
1125
|
+
}
|
|
1126
|
+
requireNode(edge.to, edgeId(edge));
|
|
1127
|
+
}
|
|
1128
|
+
for (const edge of analyzes) for (const over of edge.over) if (analystNodes.has(over)) throw new ValidationError(`runGraph: ${edgeId(edge)} analyzes '${over}', which is an analyst node — an analyst run settles as a finding, never as a worker, so this edge would silently never fire; analyst nodes are not analyzable`);
|
|
1129
|
+
const workers = /* @__PURE__ */ new Map();
|
|
1130
|
+
const delegatesByWorker = /* @__PURE__ */ new Map();
|
|
1131
|
+
for (const edge of delegates) {
|
|
1132
|
+
if (delegatesByWorker.has(edge.to)) throw new ValidationError(`runGraph: node '${edge.to}' is the target of two delegates edges — one delegation directive per worker node (version the directive instead of forking the edge)`);
|
|
1133
|
+
delegatesByWorker.set(edge.to, edge);
|
|
1134
|
+
workers.set(edge.to, requireNode(edge.to, edgeId(edge)));
|
|
1135
|
+
}
|
|
1136
|
+
for (const node of nodes) if (node.id !== root.id && !workers.has(node.id) && !analystNodes.has(node.id)) throw new ValidationError(`runGraph: node '${node.id}' has no delegates edge to it — an unreachable node never runs`);
|
|
1137
|
+
return {
|
|
1138
|
+
root,
|
|
1139
|
+
workers,
|
|
1140
|
+
delegatesByWorker,
|
|
1141
|
+
analyzes,
|
|
1142
|
+
analystNodes
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
/** The root node's canonical profile with the graph brief appended: which nodes the driver may
|
|
1146
|
+
* spawn, by exact name, each with its delegation cap and continuity. */
|
|
1147
|
+
function graphRootProfile(validated, registry) {
|
|
1148
|
+
const { root, workers, delegatesByWorker, analyzes, analystNodes } = validated;
|
|
1149
|
+
const driverAnalyzesBriefs = analyzes.filter((edge) => edge.to === root.id).map((edge) => analystNodes.has(edge.analyst) ? `Findings from analyst '${edge.analyst}' (a tool-equipped analyst agent node, over: ${edge.over.join(", ")}) will arrive as finding events.` : `Findings from analyst '${edge.analyst}' (over: ${edge.over.join(", ")}) will arrive as finding events.\n${registry.resolve(edge.directive).text}`);
|
|
1150
|
+
const graphBrief = [
|
|
1151
|
+
"AGENT GRAPH: you are the driver node of a fixed topology. You may spawn ONLY these worker",
|
|
1152
|
+
"nodes, by EXACT name (spawn_worker with profile: { name: '<node id>' }; the node's full",
|
|
1153
|
+
"profile is pinned by the graph — any other profile fields you author are ignored):",
|
|
1154
|
+
...[...workers.values()].map((node) => {
|
|
1155
|
+
const edge = delegatesByWorker.get(node.id);
|
|
1156
|
+
const cap = edge.maxTraversals ?? 32;
|
|
1157
|
+
const description = typeof node.profile.description === "string" && node.profile.description.length > 0 ? ` — ${node.profile.description}` : "";
|
|
1158
|
+
const continuityNote = edge.continuity === "resume" ? "; continuity: resume — each spawn after the first re-attaches to this node's latest settled session (spawn again to continue it; steer while it is live)" : "";
|
|
1159
|
+
return `- '${node.id}'${description} (delegation cap: ${cap} traversals${continuityNote})`;
|
|
1160
|
+
}),
|
|
1161
|
+
...driverAnalyzesBriefs.length > 0 ? ["", ...driverAnalyzesBriefs] : []
|
|
1162
|
+
].join("\n");
|
|
1163
|
+
return {
|
|
1164
|
+
...root.profile,
|
|
1165
|
+
prompt: {
|
|
1166
|
+
...root.profile.prompt ?? {},
|
|
1167
|
+
instructions: [...root.profile.prompt?.instructions ?? [], graphBrief]
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
const byteLength = (text) => Buffer.byteLength(text, "utf8");
|
|
1172
|
+
function stringifyPayload(payload) {
|
|
1173
|
+
if (typeof payload === "string") return payload;
|
|
1174
|
+
try {
|
|
1175
|
+
return JSON.stringify(payload) ?? String(payload);
|
|
1176
|
+
} catch {
|
|
1177
|
+
return String(payload);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Build the graph layer for one validated graph. Each delegates directive is appended to the
|
|
1182
|
+
* worker profile's `prompt.instructions` per traversal, each analyzes edge becomes an
|
|
1183
|
+
* analyst-on-settle route with a real DESTINATION, and every traversal is ledgered and journaled.
|
|
1184
|
+
*/
|
|
1185
|
+
function createGraphOverlay(validated, opts) {
|
|
1186
|
+
const { root, workers, delegatesByWorker, analyzes, analystNodes } = validated;
|
|
1187
|
+
const { registry, journal, runId, now } = opts;
|
|
1188
|
+
const ledger = [];
|
|
1189
|
+
const journaled = /* @__PURE__ */ new Set();
|
|
1190
|
+
const traversalCounts = /* @__PURE__ */ new Map();
|
|
1191
|
+
const capSpend = /* @__PURE__ */ new Map();
|
|
1192
|
+
const spend = (edge) => {
|
|
1193
|
+
capSpend.set(edge, (capSpend.get(edge) ?? 0) + 1);
|
|
1194
|
+
};
|
|
1195
|
+
const exhausted = /* @__PURE__ */ new Set();
|
|
1196
|
+
const exhaustedDelegates = /* @__PURE__ */ new Set();
|
|
1197
|
+
const journalWrites = [];
|
|
1198
|
+
let ledgerSeq = 0;
|
|
1199
|
+
let graphNodeId;
|
|
1200
|
+
const appendJournal = (entry, nodeIdForEvent) => {
|
|
1201
|
+
if (journaled.has(entry)) return Promise.resolve();
|
|
1202
|
+
journaled.add(entry);
|
|
1203
|
+
const write = journal.appendEvent(runId, {
|
|
1204
|
+
kind: "edge",
|
|
1205
|
+
id: nodeIdForEvent,
|
|
1206
|
+
...graphNodeId === void 0 ? {} : { graph: graphNodeId },
|
|
1207
|
+
edge: {
|
|
1208
|
+
kind: entry.kind,
|
|
1209
|
+
from: entry.from,
|
|
1210
|
+
to: entry.to,
|
|
1211
|
+
directive: entry.directive
|
|
1212
|
+
},
|
|
1213
|
+
traversal: entry.traversal,
|
|
1214
|
+
outcome: entry.outcome,
|
|
1215
|
+
continuity: entry.continuity,
|
|
1216
|
+
bytes: entry.bytes,
|
|
1217
|
+
...entry.reason !== void 0 ? { reason: entry.reason } : {},
|
|
1218
|
+
seq: ledgerSeq++,
|
|
1219
|
+
at: new Date(now()).toISOString()
|
|
1220
|
+
});
|
|
1221
|
+
journalWrites.push(write);
|
|
1222
|
+
return write;
|
|
1223
|
+
};
|
|
1224
|
+
const settleUnbound = (pending) => {
|
|
1225
|
+
const refused = {
|
|
1226
|
+
...pending,
|
|
1227
|
+
outcome: "unpropagated",
|
|
1228
|
+
bytes: 0,
|
|
1229
|
+
reason: `no-live-worker-bound (spawn refused after the factory, or a keyed re-spawn deduplicated to a completed result; ${pending.bytes} composed bytes never crossed)`
|
|
1230
|
+
};
|
|
1231
|
+
ledger[ledger.indexOf(pending)] = refused;
|
|
1232
|
+
return appendJournal(refused, `graph:${refused.to}`);
|
|
1233
|
+
};
|
|
1234
|
+
const record = (entry, final) => {
|
|
1235
|
+
const count = (traversalCounts.get(entry.edge) ?? 0) + 1;
|
|
1236
|
+
traversalCounts.set(entry.edge, count);
|
|
1237
|
+
const row = {
|
|
1238
|
+
...entry,
|
|
1239
|
+
traversal: count
|
|
1240
|
+
};
|
|
1241
|
+
ledger.push(row);
|
|
1242
|
+
if (final) {
|
|
1243
|
+
spend(row.edge);
|
|
1244
|
+
appendJournal(row, row.workerId ?? `graph:${row.to}`);
|
|
1245
|
+
}
|
|
1246
|
+
return row;
|
|
1247
|
+
};
|
|
1248
|
+
const nodeByWorkerId = /* @__PURE__ */ new Map();
|
|
1249
|
+
const pendingByAssignment = /* @__PURE__ */ new Map();
|
|
1250
|
+
const pendingKey = (parentNodeId, assignmentId) => `${parentNodeId ?? ""}\u0000${assignmentId}`;
|
|
1251
|
+
const pinNode = (input) => {
|
|
1252
|
+
if (opts.subtask === true) graphNodeId ??= input.parentNodeId;
|
|
1253
|
+
const requested = typeof input.profile?.name === "string" ? input.profile.name : void 0;
|
|
1254
|
+
if (input.analyst !== void 0) {
|
|
1255
|
+
const analystNode = analystNodes.get(input.analyst);
|
|
1256
|
+
if (!analystNode || requested !== analystNode.id) throw new ValidationError(`runGraph: analyst run for ${JSON.stringify(input.analyst)} does not name an analyst node of this graph (analyst nodes: ${[...analystNodes.keys()].join(", ") || "none"})`);
|
|
1257
|
+
return analystNode.profile;
|
|
1258
|
+
}
|
|
1259
|
+
if (input.profile.metadata?.["agentRuntimeGraph"] !== void 0) throw new ValidationError("runGraph: a node of a graph cannot start another graph — run_graph inside a graph is refused; add the work as nodes of this graph instead");
|
|
1260
|
+
const node = requested !== void 0 ? workers.get(requested) : void 0;
|
|
1261
|
+
if (!node) throw new ValidationError(`runGraph: spawn_worker named profile ${JSON.stringify(requested)} which is not a worker node of this graph (nodes: ${[...workers.keys()].join(", ")}). Spawn by node id: profile.name selects the node; the node profile itself is pinned by the graph.`);
|
|
1262
|
+
const edge = delegatesByWorker.get(node.id);
|
|
1263
|
+
const id = edgeId(edge);
|
|
1264
|
+
const cap = edge.maxTraversals ?? 32;
|
|
1265
|
+
const used = capSpend.get(id) ?? 0;
|
|
1266
|
+
const spawnContinuity = input.continuity ?? "fresh";
|
|
1267
|
+
if (used >= cap) {
|
|
1268
|
+
exhausted.add(id);
|
|
1269
|
+
exhaustedDelegates.add(id);
|
|
1270
|
+
record({
|
|
1271
|
+
edge: id,
|
|
1272
|
+
kind: "delegates",
|
|
1273
|
+
from: edge.from,
|
|
1274
|
+
to: edge.to,
|
|
1275
|
+
directive: formatPromptHandle(edge.directive),
|
|
1276
|
+
outcome: "unpropagated",
|
|
1277
|
+
continuity: spawnContinuity,
|
|
1278
|
+
bytes: 0,
|
|
1279
|
+
reason: `traversal-cap-exhausted (max ${cap})`
|
|
1280
|
+
}, true);
|
|
1281
|
+
throw new ValidationError(`runGraph: delegates edge ${id} exhausted its traversal cap (${cap}) — the cyclic-graph backstop refused this spawn`);
|
|
1282
|
+
}
|
|
1283
|
+
const directiveText = registry.resolve(edge.directive).text;
|
|
1284
|
+
const taskText = stringifyPayload(input.task);
|
|
1285
|
+
const bytes = byteLength(directiveText) + byteLength(taskText);
|
|
1286
|
+
const row = record({
|
|
1287
|
+
edge: id,
|
|
1288
|
+
kind: "delegates",
|
|
1289
|
+
from: edge.from,
|
|
1290
|
+
to: edge.to,
|
|
1291
|
+
directive: formatPromptHandle(edge.directive),
|
|
1292
|
+
outcome: bytes === 0 ? "empty" : "delivered",
|
|
1293
|
+
continuity: spawnContinuity,
|
|
1294
|
+
bytes,
|
|
1295
|
+
...bytes === 0 ? { reason: "no directive text and no task payload" } : {}
|
|
1296
|
+
}, false);
|
|
1297
|
+
const key = pendingKey(input.parentNodeId, input.assignmentId);
|
|
1298
|
+
const stale = pendingByAssignment.get(key);
|
|
1299
|
+
if (stale !== void 0) settleUnbound(stale);
|
|
1300
|
+
pendingByAssignment.set(key, row);
|
|
1301
|
+
return directiveText.length === 0 ? node.profile : {
|
|
1302
|
+
...node.profile,
|
|
1303
|
+
prompt: {
|
|
1304
|
+
...node.profile.prompt ?? {},
|
|
1305
|
+
instructions: [...node.profile.prompt?.instructions ?? [], directiveText]
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
};
|
|
1309
|
+
const composeGuidance = (profile) => opts.guidance ? opts.guidance(profile) : profile;
|
|
1310
|
+
const resolveSpawnProfile = (authored) => {
|
|
1311
|
+
const requested = typeof authored.name === "string" ? authored.name : void 0;
|
|
1312
|
+
const node = (requested !== void 0 ? workers.get(requested) : void 0) ?? (requested !== void 0 ? analystNodes.get(requested) : void 0);
|
|
1313
|
+
return node ? composeGuidance(node.profile) : authored;
|
|
1314
|
+
};
|
|
1315
|
+
const authorizeSpawn = (input) => {
|
|
1316
|
+
const pinned = composeGuidance(pinNode(input));
|
|
1317
|
+
if (!opts.authorizeSpawn) return { profile: pinned };
|
|
1318
|
+
return opts.authorizeSpawn({
|
|
1319
|
+
...input,
|
|
1320
|
+
profile: pinned
|
|
1321
|
+
});
|
|
1322
|
+
};
|
|
1323
|
+
const routes = analyzes.map((edge) => {
|
|
1324
|
+
const analystNode = analystNodes.get(edge.analyst);
|
|
1325
|
+
if (analystNode) return {
|
|
1326
|
+
kind: edge.analyst,
|
|
1327
|
+
over: edge.over,
|
|
1328
|
+
agent: analystNode.profile,
|
|
1329
|
+
directive: registry.resolve(edge.directive).text,
|
|
1330
|
+
...edge.to === root.id ? {} : { to: edge.to }
|
|
1331
|
+
};
|
|
1332
|
+
return edge.to === root.id ? {
|
|
1333
|
+
kind: edge.analyst,
|
|
1334
|
+
over: edge.over
|
|
1335
|
+
} : {
|
|
1336
|
+
kind: edge.analyst,
|
|
1337
|
+
over: edge.over,
|
|
1338
|
+
to: edge.to,
|
|
1339
|
+
directive: registry.resolve(edge.directive).text
|
|
1340
|
+
};
|
|
1341
|
+
});
|
|
1342
|
+
const continuityByProfile = {};
|
|
1343
|
+
for (const [nodeId, edge] of delegatesByWorker) if (edge.continuity !== void 0) continuityByProfile[nodeId] = edge.continuity;
|
|
1344
|
+
const strippedByDigest = /* @__PURE__ */ new Map();
|
|
1345
|
+
const observeMessages = (authorize) => {
|
|
1346
|
+
return (input) => {
|
|
1347
|
+
const decision = authorize(input);
|
|
1348
|
+
if (decision.instruction !== input.instruction) strippedByDigest.set(canonicalCandidateDigest(decision.instruction), { composedBytes: byteLength(input.instruction) });
|
|
1349
|
+
return decision;
|
|
1350
|
+
};
|
|
1351
|
+
};
|
|
1352
|
+
const routedAnalyzesByAnalyst = /* @__PURE__ */ new Map();
|
|
1353
|
+
const driverAnalyzesByAnalyst = /* @__PURE__ */ new Map();
|
|
1354
|
+
for (const edge of analyzes) (edge.to === root.id ? driverAnalyzesByAnalyst : routedAnalyzesByAnalyst).set(edge.analyst, edge);
|
|
1355
|
+
const analyzesCapReached = (edge) => {
|
|
1356
|
+
const cap = edge.maxTraversals ?? 32;
|
|
1357
|
+
if ((capSpend.get(edgeId(edge)) ?? 0) < cap) return false;
|
|
1358
|
+
exhausted.add(edgeId(edge));
|
|
1359
|
+
return true;
|
|
1360
|
+
};
|
|
1361
|
+
const ledgerAnalyzes = (edge, outcome, bytes, reason, workerId) => {
|
|
1362
|
+
const capped = analyzesCapReached(edge);
|
|
1363
|
+
record({
|
|
1364
|
+
edge: edgeId(edge),
|
|
1365
|
+
kind: "analyzes",
|
|
1366
|
+
from: edge.over.join("+"),
|
|
1367
|
+
to: edge.to,
|
|
1368
|
+
directive: formatPromptHandle(edge.directive),
|
|
1369
|
+
outcome: capped ? "unpropagated" : outcome,
|
|
1370
|
+
continuity: "steer",
|
|
1371
|
+
bytes,
|
|
1372
|
+
...capped ? { reason: `traversal-cap-exhausted (max ${edge.maxTraversals ?? 32})` } : reason !== void 0 ? { reason } : {},
|
|
1373
|
+
...workerId !== void 0 ? { workerId } : {}
|
|
1374
|
+
}, true);
|
|
1375
|
+
};
|
|
1376
|
+
const onCoordinationEvent = (event) => {
|
|
1377
|
+
if (event.type === "finding") {
|
|
1378
|
+
const edge = driverAnalyzesByAnalyst.get(event.finding.analyst);
|
|
1379
|
+
if (!edge) return;
|
|
1380
|
+
const sourceNode = nodeByWorkerId.get(event.finding.fromWorker);
|
|
1381
|
+
if (sourceNode === void 0 || !edge.over.includes(sourceNode)) return;
|
|
1382
|
+
const findingsText = event.finding.findings === void 0 ? "" : stringifyPayload(event.finding.findings);
|
|
1383
|
+
const directiveBytes = byteLength(registry.resolve(edge.directive).text);
|
|
1384
|
+
const empty = findingsText.length === 0;
|
|
1385
|
+
ledgerAnalyzes(edge, empty ? "empty" : "delivered", directiveBytes + byteLength(findingsText), empty ? "analyst returned no findings" : void 0, event.finding.fromWorker);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
if (event.type === "steer") {
|
|
1389
|
+
const down = event.down;
|
|
1390
|
+
if (event.analyst !== void 0) {
|
|
1391
|
+
const edge = routedAnalyzesByAnalyst.get(event.analyst);
|
|
1392
|
+
if (!edge) return;
|
|
1393
|
+
ledgerAnalyzes(edge, down.delivered ? "delivered" : "unpropagated", byteLength(down.instruction), down.delivered ? void 0 : down.outcome, down.toWorker);
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
const nodeId = nodeByWorkerId.get(down.toWorker);
|
|
1397
|
+
if (nodeId === void 0) return;
|
|
1398
|
+
const edge = delegatesByWorker.get(nodeId);
|
|
1399
|
+
if (!edge) return;
|
|
1400
|
+
const stripped = strippedByDigest.get(down.instructionDigest);
|
|
1401
|
+
record({
|
|
1402
|
+
edge: edgeId(edge),
|
|
1403
|
+
kind: "delegates",
|
|
1404
|
+
from: edge.from,
|
|
1405
|
+
to: edge.to,
|
|
1406
|
+
directive: formatPromptHandle(edge.directive),
|
|
1407
|
+
outcome: !down.delivered ? "unpropagated" : stripped ? "stripped" : "delivered",
|
|
1408
|
+
continuity: "steer",
|
|
1409
|
+
bytes: byteLength(down.instruction),
|
|
1410
|
+
...!down.delivered ? { reason: down.outcome } : stripped ? { reason: `authorization narrowed ${stripped.composedBytes} composed bytes` } : {},
|
|
1411
|
+
workerId: down.toWorker
|
|
1412
|
+
}, true);
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
const bindSpawn = (parentNodeId, assignmentId, childId) => {
|
|
1416
|
+
const key = pendingKey(parentNodeId, assignmentId);
|
|
1417
|
+
const pending = pendingByAssignment.get(key);
|
|
1418
|
+
if (!pending) return void 0;
|
|
1419
|
+
pendingByAssignment.delete(key);
|
|
1420
|
+
const bound = {
|
|
1421
|
+
...pending,
|
|
1422
|
+
workerId: childId
|
|
1423
|
+
};
|
|
1424
|
+
ledger[ledger.indexOf(pending)] = bound;
|
|
1425
|
+
nodeByWorkerId.set(childId, bound.to);
|
|
1426
|
+
spend(bound.edge);
|
|
1427
|
+
return appendJournal(bound, childId);
|
|
1428
|
+
};
|
|
1429
|
+
const settle = async () => {
|
|
1430
|
+
for (const pending of pendingByAssignment.values()) await settleUnbound(pending);
|
|
1431
|
+
pendingByAssignment.clear();
|
|
1432
|
+
await Promise.all(journalWrites);
|
|
1433
|
+
return {
|
|
1434
|
+
ledger: Object.freeze(ledger.map((row) => Object.freeze({ ...row }))),
|
|
1435
|
+
exhaustedEdges: Object.freeze([...exhausted]),
|
|
1436
|
+
exhaustedDelegates: Object.freeze([...exhaustedDelegates])
|
|
1437
|
+
};
|
|
1438
|
+
};
|
|
1439
|
+
return {
|
|
1440
|
+
routes,
|
|
1441
|
+
continuityByProfile,
|
|
1442
|
+
authorizeSpawn,
|
|
1443
|
+
resolveSpawnProfile,
|
|
1444
|
+
observeMessages,
|
|
1445
|
+
onCoordinationEvent,
|
|
1446
|
+
bindSpawn,
|
|
1447
|
+
settle
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
function isRecord$1(value) {
|
|
1451
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1452
|
+
}
|
|
1453
|
+
function parseDirective(raw, where) {
|
|
1454
|
+
if (typeof raw === "string") return promptHandle(raw);
|
|
1455
|
+
if (isRecord$1(raw) && typeof raw.surface === "string" && typeof raw.version === "number") return {
|
|
1456
|
+
surface: raw.surface,
|
|
1457
|
+
version: raw.version
|
|
1458
|
+
};
|
|
1459
|
+
throw new ValidationError(`run_graph: ${where}.directive must be a versioned directive reference such as 'delegates/worker-brief/v1'`);
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Read graph data a model wrote, or a stored graph's topology. Edge directives may be written as
|
|
1463
|
+
* `'<surface>/v<n>'` strings. The budget and deliverable are the tool's arguments, so a graph that
|
|
1464
|
+
* carries its own is refused rather than one of the two silently ignored.
|
|
1465
|
+
*/
|
|
1466
|
+
function parseGraphSubtaskTopology(raw) {
|
|
1467
|
+
if (!isRecord$1(raw)) throw new ValidationError("run_graph: graph must be an object { nodes, edges }");
|
|
1468
|
+
for (const key of Object.keys(raw)) {
|
|
1469
|
+
if (key === "nodes" || key === "edges") continue;
|
|
1470
|
+
if (key === "budget" || key === "deliverable") throw new ValidationError(`run_graph: graph.${key} is not read — pass ${key} as run_graph's own argument`);
|
|
1471
|
+
throw new ValidationError(`run_graph: graph.${key} is not part of a graph; use nodes and edges`);
|
|
1472
|
+
}
|
|
1473
|
+
if (!Array.isArray(raw.nodes) || !Array.isArray(raw.edges)) throw new ValidationError("run_graph: graph.nodes and graph.edges must be arrays");
|
|
1474
|
+
return {
|
|
1475
|
+
nodes: raw.nodes.map((node, index) => {
|
|
1476
|
+
if (!isRecord$1(node) || typeof node.id !== "string" || !isRecord$1(node.profile)) throw new ValidationError(`run_graph: graph.nodes[${index}] must be { id, profile }`);
|
|
1477
|
+
return {
|
|
1478
|
+
id: node.id,
|
|
1479
|
+
profile: node.profile
|
|
1480
|
+
};
|
|
1481
|
+
}),
|
|
1482
|
+
edges: raw.edges.map((edge, index) => {
|
|
1483
|
+
const where = `graph.edges[${index}]`;
|
|
1484
|
+
if (!isRecord$1(edge)) throw new ValidationError(`run_graph: ${where} must be an object`);
|
|
1485
|
+
const directive = parseDirective(edge.directive, where);
|
|
1486
|
+
if (edge.kind === "delegates") return {
|
|
1487
|
+
...edge,
|
|
1488
|
+
directive
|
|
1489
|
+
};
|
|
1490
|
+
if (edge.kind === "analyzes") return {
|
|
1491
|
+
...edge,
|
|
1492
|
+
directive
|
|
1493
|
+
};
|
|
1494
|
+
throw new ValidationError(`run_graph: ${where}.kind must be 'delegates' or 'analyzes'`);
|
|
1495
|
+
})
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Validate a `run_graph` graph and compose the profile its spawn runs: the root node's canonical
|
|
1500
|
+
* profile, the driver brief, and the topology under `metadata.agentRuntimeGraph`. That metadata is
|
|
1501
|
+
* part of the profile's identity, so a keyed `run_graph` that resumes runs the same graph, and the
|
|
1502
|
+
* provider-visible projection removes it before any provider sees the profile.
|
|
1503
|
+
*/
|
|
1504
|
+
function prepareGraphSubtask(topology, opts) {
|
|
1505
|
+
const validated = validateGraphTopology(topology.nodes, topology.edges, opts.registry, opts.analysts);
|
|
1506
|
+
const brief = graphRootProfile(validated, opts.registry);
|
|
1507
|
+
const marked = {
|
|
1508
|
+
...brief,
|
|
1509
|
+
metadata: {
|
|
1510
|
+
...brief.metadata ?? {},
|
|
1511
|
+
[runtimeGraphMetadataKey]: {
|
|
1512
|
+
nodes: topology.nodes,
|
|
1513
|
+
edges: topology.edges
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
const parsed = agentProfileSchema.safeParse(opts.guidance ? opts.guidance(marked) : marked);
|
|
1518
|
+
if (!parsed.success) throw new ValidationError(`run_graph: the graph's root profile is not a valid AgentProfile: ${parsed.error.message}`);
|
|
1519
|
+
return {
|
|
1520
|
+
profile: parsed.data,
|
|
1521
|
+
root: validated.root.id,
|
|
1522
|
+
nodes: topology.nodes.map((node) => node.id)
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
/** The topology a `run_graph` root profile carries, or `undefined` for any other profile. */
|
|
1526
|
+
function graphSubtaskOf(profile) {
|
|
1527
|
+
const raw = profile.metadata?.[runtimeGraphMetadataKey];
|
|
1528
|
+
return raw === void 0 ? void 0 : parseGraphSubtaskTopology(raw);
|
|
1529
|
+
}
|
|
1530
|
+
//#endregion
|
|
914
1531
|
//#region src/runtime/supervise/otel-spans.ts
|
|
915
1532
|
/**
|
|
916
1533
|
* Supervisor tree → OTLP spans. OPT-IN, off by default.
|
|
@@ -1940,6 +2557,7 @@ function buildSupervisorAgent(profile, deps, testBrain) {
|
|
|
1940
2557
|
...deps.onProviderModel ? { onProviderModel: deps.onProviderModel } : {},
|
|
1941
2558
|
blobs: deps.blobs,
|
|
1942
2559
|
makeWorkerAgent: deps.makeWorkerAgent,
|
|
2560
|
+
...deps.graphs ? { graphs: deps.graphs } : {},
|
|
1943
2561
|
...deps.authorizeDownMessage ? { authorizeDownMessage: deps.authorizeDownMessage } : {},
|
|
1944
2562
|
perWorker: deps.perWorker,
|
|
1945
2563
|
...deps.preserveOwnerTurns ? { preserveOwnerTurns: true } : {},
|
|
@@ -2053,6 +2671,7 @@ function buildSupervisorAgent(profile, deps, testBrain) {
|
|
|
2053
2671
|
scope,
|
|
2054
2672
|
blobs: deps.blobs,
|
|
2055
2673
|
makeWorkerAgent: deps.makeWorkerAgent,
|
|
2674
|
+
...deps.graphs ? { graphs: deps.graphs } : {},
|
|
2056
2675
|
...deps.authorizeDownMessage ? { authorizeDownMessage: deps.authorizeDownMessage } : {},
|
|
2057
2676
|
perWorker: deps.perWorker,
|
|
2058
2677
|
...coordination ?? {},
|
|
@@ -3896,10 +4515,12 @@ async function verifyProfilePromotions(table) {
|
|
|
3896
4515
|
const { verifySealedExperiment } = await import("@tangle-network/agent-eval/experiment");
|
|
3897
4516
|
for (const [name, entry] of promoted) if (!await verifySealedExperiment(entry.promotion.experiment)) throw new ValidationError(`supervise: opts.registry.profiles ${JSON.stringify(name)} cites a sealed play whose digest does not match its spec`);
|
|
3898
4517
|
}
|
|
3899
|
-
/** Capabilities a data-only consumer may require before building an opted-in run.
|
|
4518
|
+
/** Capabilities a data-only consumer may require before building an opted-in run. `graphTools`:
|
|
4519
|
+
* a manager whose profile grants `run_graph` can start an agent graph as one subtask. */
|
|
3900
4520
|
const superviseFleetCapabilities = Object.freeze({
|
|
3901
4521
|
peerAudit: true,
|
|
3902
|
-
traceTools: true
|
|
4522
|
+
traceTools: true,
|
|
4523
|
+
graphTools: true
|
|
3903
4524
|
});
|
|
3904
4525
|
const superviseOptionKeySet = /* @__PURE__ */ new Set([
|
|
3905
4526
|
"allowedModels",
|
|
@@ -3926,6 +4547,7 @@ const superviseOptionKeySet = /* @__PURE__ */ new Set([
|
|
|
3926
4547
|
"execution",
|
|
3927
4548
|
"extraTools",
|
|
3928
4549
|
"finalizer",
|
|
4550
|
+
"graphRegistry",
|
|
3929
4551
|
"hooks",
|
|
3930
4552
|
"inheritSpawnRights",
|
|
3931
4553
|
"journal",
|
|
@@ -4340,6 +4962,31 @@ function superviseWithTestBrain(profile, task, opts) {
|
|
|
4340
4962
|
const { brain, ...runtimeOptions } = opts;
|
|
4341
4963
|
return superviseWithContext(profile, task, runtimeOptions, brain);
|
|
4342
4964
|
}
|
|
4965
|
+
/** A stored graph's topology, from the registry `SuperviseOptions.graphRegistry` names. */
|
|
4966
|
+
async function storedGraphTopology(dir, digest) {
|
|
4967
|
+
if (dir === void 0) throw new ValidationError("run_graph: this run names no graph registry (SuperviseOptions.graphRegistry), so a graphDigest cannot resolve; pass the graph as data");
|
|
4968
|
+
const stored = await loadGraph(graphRegistry(dir), digest);
|
|
4969
|
+
if (stored === void 0) throw new ValidationError(`run_graph: the graph registry holds no graph ${digest}`);
|
|
4970
|
+
return parseGraphSubtaskTopology({
|
|
4971
|
+
nodes: stored.nodes,
|
|
4972
|
+
edges: stored.edges
|
|
4973
|
+
});
|
|
4974
|
+
}
|
|
4975
|
+
/**
|
|
4976
|
+
* What a `run_graph` subtask settles with once its root manager returned and its subtree closed:
|
|
4977
|
+
* the root's result and the graph's edge ledger. A delegates cap that refused work while the root
|
|
4978
|
+
* delivered nothing ended the graph, not the task, so that fails loud with the cap named, as
|
|
4979
|
+
* `runGraph` fails a root graph with `GraphEdgeCapError`.
|
|
4980
|
+
*/
|
|
4981
|
+
async function graphSubtaskOutput(overlay, out) {
|
|
4982
|
+
const { ledger, exhaustedEdges, exhaustedDelegates } = await overlay.settle();
|
|
4983
|
+
if ((out === void 0 || out === null) && exhaustedDelegates.length > 0) throw new ValidationError(`run_graph: edge traversal cap exhausted on ${exhaustedDelegates.join(", ")} and the graph delivered nothing — the cap (the cyclic-graph backstop), not the task, ended it; the edge ledger is in the run journal`);
|
|
4984
|
+
return {
|
|
4985
|
+
deliverable: out === void 0 ? null : out,
|
|
4986
|
+
edges: ledger,
|
|
4987
|
+
...exhaustedEdges.length === 0 ? {} : { exhaustedEdges }
|
|
4988
|
+
};
|
|
4989
|
+
}
|
|
4343
4990
|
/**
|
|
4344
4991
|
* The composer `profileGuidance` selects, or `undefined` when no guidance is selected. The result
|
|
4345
4992
|
* is re-validated as an AgentProfile, and a composition that breaks the schema is refused as a
|
|
@@ -4603,13 +5250,51 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4603
5250
|
let spans;
|
|
4604
5251
|
const traceUnpropagated = options.backend ? workerTraceUnpropagatedDeclaration(options.backend.backend) : void 0;
|
|
4605
5252
|
const recoveryFactories = /* @__PURE__ */ new WeakMap();
|
|
5253
|
+
const graphOverlays = /* @__PURE__ */ new Set();
|
|
5254
|
+
const graphSubtasks = options.makeWorkerAgent === void 0 ? { prepare: async (input) => {
|
|
5255
|
+
try {
|
|
5256
|
+
const topology = input.graphDigest === void 0 ? parseGraphSubtaskTopology(input.graph) : await storedGraphTopology(options.graphRegistry, input.graphDigest);
|
|
5257
|
+
const prepared = prepareGraphSubtask(topology, {
|
|
5258
|
+
registry: kernelPromptRegistry(),
|
|
5259
|
+
...analysts ? { analysts } : {},
|
|
5260
|
+
...guidanceComposer ? { guidance: guidanceComposer } : {}
|
|
5261
|
+
});
|
|
5262
|
+
for (const profile of [prepared.profile, ...topology.nodes.filter((node) => node.id !== prepared.root).map((node) => guidanceComposer?.(node.profile) ?? node.profile)]) {
|
|
5263
|
+
assertProfileModelsAllowed(profile, options.allowedModels);
|
|
5264
|
+
options.resolveSpawnProfile?.(profile);
|
|
5265
|
+
}
|
|
5266
|
+
return {
|
|
5267
|
+
ok: true,
|
|
5268
|
+
...prepared
|
|
5269
|
+
};
|
|
5270
|
+
} catch (error) {
|
|
5271
|
+
return {
|
|
5272
|
+
ok: false,
|
|
5273
|
+
reason: errMessage(error)
|
|
5274
|
+
};
|
|
5275
|
+
}
|
|
5276
|
+
} } : void 0;
|
|
5277
|
+
const graphOverlayFor = (topology) => {
|
|
5278
|
+
const registry = kernelPromptRegistry();
|
|
5279
|
+
const overlay = createGraphOverlay(validateGraphTopology(topology.nodes, topology.edges, registry, analysts), {
|
|
5280
|
+
registry,
|
|
5281
|
+
journal,
|
|
5282
|
+
runId,
|
|
5283
|
+
now,
|
|
5284
|
+
...guidanceComposer ? { guidance: guidanceComposer } : {},
|
|
5285
|
+
...options.authorizeSpawn ? { authorizeSpawn: options.authorizeSpawn } : {},
|
|
5286
|
+
subtask: true
|
|
5287
|
+
});
|
|
5288
|
+
graphOverlays.add(overlay);
|
|
5289
|
+
return overlay;
|
|
5290
|
+
};
|
|
4606
5291
|
let makeWorkerAgent = options.makeWorkerAgent;
|
|
4607
5292
|
if (!makeWorkerAgent) {
|
|
4608
5293
|
if (!options.backend && !options.makeLeafAgent) throw new ValidationError("supervise: provide opts.backend (where workers run), opts.makeLeafAgent, or opts.makeWorkerAgent");
|
|
4609
5294
|
const withRetry = (make) => withWorkerSpawnRetry(make, options.workerRetry, { ...options.onWorkerRetry ? { onRetry: options.onWorkerRetry } : {} });
|
|
4610
5295
|
const makeLeaf = withRetry(options.makeLeafAgent ?? workerFromBackend(options.backend, deliverable));
|
|
4611
5296
|
const securityPolicy = options.profileSecurity ?? DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY;
|
|
4612
|
-
const makeRecursiveWorkerFor = (parent, parentIdentity, depth, parentOwnerId, analystLineage = false, peerRootOwnerId) => {
|
|
5297
|
+
const makeRecursiveWorkerFor = (parent, parentIdentity, depth, parentOwnerId, analystLineage = false, peerRootOwnerId, graph) => {
|
|
4613
5298
|
const makeRecursiveWorker = (authoredProfile, spawnContext, recovering = false) => {
|
|
4614
5299
|
if (!spawnContext) throw new ValidationError("supervise: backend-derived workers require spawn context");
|
|
4615
5300
|
const input = freezeDetachedProfile(authoredProfile);
|
|
@@ -4627,7 +5312,8 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4627
5312
|
...spawnContext.analyst !== void 0 ? { analyst: spawnContext.analyst } : {},
|
|
4628
5313
|
...spawnContext.continuity !== void 0 ? { continuity: spawnContext.continuity } : {}
|
|
4629
5314
|
});
|
|
4630
|
-
const
|
|
5315
|
+
const authorize = graph?.authorizeSpawn ?? options.authorizeSpawn;
|
|
5316
|
+
const decision = !recovering && authorize ? freezeDetached(authorize(authorizationInput)) : Object.freeze({
|
|
4631
5317
|
profile: input,
|
|
4632
5318
|
...spawnContext.execution ? { execution: spawnContext.execution } : {}
|
|
4633
5319
|
});
|
|
@@ -4665,6 +5351,10 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4665
5351
|
}));
|
|
4666
5352
|
}
|
|
4667
5353
|
const ownerId = childCoordinationOwner(parentOwnerId, childExecution.identity, spawnContext, depth);
|
|
5354
|
+
const subtask = graphSubtaskOf(authorized);
|
|
5355
|
+
if (subtask !== void 0 && graph !== void 0) throw new ValidationError("supervise: a node of a graph cannot start another graph; add the work as nodes");
|
|
5356
|
+
const ownGraph = subtask === void 0 ? void 0 : graphOverlayFor(subtask);
|
|
5357
|
+
const subtreeGraph = ownGraph ?? graph;
|
|
4668
5358
|
const nestedDriveHarness = isExternalSupervisor(authorized) ? driveHarnessForOwner(freezeDetached({
|
|
4669
5359
|
runId,
|
|
4670
5360
|
runNamespace,
|
|
@@ -4679,9 +5369,22 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4679
5369
|
assertProfileContract(authorized, isExternalSupervisor(authorized) ? driverMaterialization : promptModelProfileMaterialization, `supervise driver ${JSON.stringify(spawnContext.label)}`, true);
|
|
4680
5370
|
if (managerBackend) assertBridgeProfileMaterializes(profileWithoutDeclaredRuntimeCoordinationTools(authorized), managerBackend, `supervise driver ${JSON.stringify(spawnContext.label)}`);
|
|
4681
5371
|
const rootPeerOwner = options.peerAudit ? depth === 1 ? ownerId : peerRootOwnerId : void 0;
|
|
4682
|
-
const childFactory = makeRecursiveWorkerFor(authorized, childExecution.identity, depth + 1, ownerId, analystLineage || spawnContext.analyst !== void 0 || spawnContext.assignmentId.startsWith("analyst:"), rootPeerOwner);
|
|
5372
|
+
const childFactory = makeRecursiveWorkerFor(authorized, childExecution.identity, depth + 1, ownerId, analystLineage || spawnContext.analyst !== void 0 || spawnContext.assignmentId.startsWith("analyst:"), rootPeerOwner, subtreeGraph);
|
|
4683
5373
|
const nestedPerWorker = defaultPerWorker(spawnContext.budget, ownerShare);
|
|
4684
|
-
const
|
|
5374
|
+
const runMessageAuthority = authorizeDownFor(authorized, depth + 1);
|
|
5375
|
+
const authorizeNestedMessage = subtreeGraph && runMessageAuthority ? subtreeGraph.observeMessages(runMessageAuthority) : runMessageAuthority;
|
|
5376
|
+
const nestedAnalyzeOnSettle = subtreeGraph ? subtreeGraph.routes.length > 0 ? subtreeGraph.routes : void 0 : options.analyzeOnSettle;
|
|
5377
|
+
const nestedContinuity = subtreeGraph ? Object.keys(subtreeGraph.continuityByProfile).length > 0 ? subtreeGraph.continuityByProfile : void 0 : options.continuityByProfile;
|
|
5378
|
+
const runResolveSpawnProfile = options.resolveSpawnProfile;
|
|
5379
|
+
const nestedResolveSpawnProfile = subtreeGraph ? (authored) => {
|
|
5380
|
+
const pinned = subtreeGraph.resolveSpawnProfile(authored);
|
|
5381
|
+
return runResolveSpawnProfile && pinned !== authored ? runResolveSpawnProfile(pinned) : pinned;
|
|
5382
|
+
} : runResolveSpawnProfile;
|
|
5383
|
+
const nestedComposeSpawnProfile = subtreeGraph ? composeSpawnProfile : composeSpawnProfileFor(authorized);
|
|
5384
|
+
const nestedObserveNodeEvent = subtreeGraph ? async (context, event, record) => {
|
|
5385
|
+
await observeNodeEvent?.(context, event, record);
|
|
5386
|
+
subtreeGraph.onCoordinationEvent(event);
|
|
5387
|
+
} : observeNodeEvent;
|
|
4685
5388
|
let acceptedSubmission = false;
|
|
4686
5389
|
let unassessedOutput = false;
|
|
4687
5390
|
const peerAudit = depth === 1 ? peerAuditFor(spawnContext.parentNodeId) : void 0;
|
|
@@ -4694,6 +5397,7 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4694
5397
|
},
|
|
4695
5398
|
...spawnResourceRoot === void 0 ? {} : { spawnResourceRoot },
|
|
4696
5399
|
makeWorkerAgent: childFactory,
|
|
5400
|
+
...graphSubtasks ? { graphs: graphSubtasks } : {},
|
|
4697
5401
|
...spawnContext.sourceEvidenceRefs ? { sourceEvidenceRefs: spawnContext.sourceEvidenceRefs } : {},
|
|
4698
5402
|
...authorizeNestedMessage ? { authorizeDownMessage: authorizeNestedMessage } : {},
|
|
4699
5403
|
perWorker: nestedPerWorker,
|
|
@@ -4711,20 +5415,20 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4711
5415
|
...rootPeerOwner ? { peerRootOwnerId: rootPeerOwner } : {}
|
|
4712
5416
|
},
|
|
4713
5417
|
...options.resolveSupervisorTools ? { resolveSupervisorTools: options.resolveSupervisorTools } : {},
|
|
4714
|
-
...
|
|
4715
|
-
observeNodeEvent,
|
|
5418
|
+
...nestedObserveNodeEvent ? {
|
|
5419
|
+
observeNodeEvent: nestedObserveNodeEvent,
|
|
4716
5420
|
replaySettlements: true
|
|
4717
5421
|
} : {},
|
|
4718
5422
|
...analysts ? { analysts } : {},
|
|
4719
5423
|
...options.escalateQuestion ? { escalateQuestion: options.escalateQuestion } : {},
|
|
4720
|
-
...!analystLineage && spawnContext.analyst === void 0 && !spawnContext.assignmentId.startsWith("analyst:") &&
|
|
5424
|
+
...!analystLineage && spawnContext.analyst === void 0 && !spawnContext.assignmentId.startsWith("analyst:") && nestedAnalyzeOnSettle ? { analyzeOnSettle: nestedAnalyzeOnSettle } : {},
|
|
4721
5425
|
...options.watchWorkers ? { watchWorkers: options.watchWorkers } : {},
|
|
4722
5426
|
...options.stallAfterMs !== void 0 ? { stallAfterMs: options.stallAfterMs } : {},
|
|
4723
5427
|
...options.wake !== void 0 ? { wake: options.wake } : {},
|
|
4724
|
-
...
|
|
5428
|
+
...nestedContinuity ? { continuityByProfile: nestedContinuity } : {},
|
|
4725
5429
|
...spawnPreflight ? { preflightSpawn: spawnPreflight } : {},
|
|
4726
|
-
...
|
|
4727
|
-
...
|
|
5430
|
+
...nestedResolveSpawnProfile ? { resolveSpawnProfile: nestedResolveSpawnProfile } : {},
|
|
5431
|
+
...nestedComposeSpawnProfile ? { composeSpawnProfile: nestedComposeSpawnProfile } : {},
|
|
4728
5432
|
...profileTable ? { profiles: profileTable } : {},
|
|
4729
5433
|
...options.peerMail ? { peerMail: options.peerMail } : {},
|
|
4730
5434
|
...options.stopRule ? { stopRule: stopRuleOf(options.stopRule) } : {},
|
|
@@ -4752,7 +5456,7 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4752
5456
|
},
|
|
4753
5457
|
...options.steerDir === void 0 ? {} : { steerDir: resolve(options.steerDir) },
|
|
4754
5458
|
...options.runDir === void 0 && options.steerDir === void 0 ? {} : { controlScope: "subtree" }
|
|
4755
|
-
}), journal, childExecution.ref, () => acceptedSubmission, recoveryFactories.get(childFactory), () => unassessedOutput, seatManagedLeaf ? childDeliverable : void 0);
|
|
5459
|
+
}), journal, childExecution.ref, () => acceptedSubmission, recoveryFactories.get(childFactory), () => unassessedOutput, seatManagedLeaf ? childDeliverable : void 0, ownGraph ? (out) => graphSubtaskOutput(ownGraph, out) : void 0);
|
|
4756
5460
|
};
|
|
4757
5461
|
if (options.makeLeafAgent === void 0 && options.backend?.backend === "provider" && !options.backend.steering) {
|
|
4758
5462
|
const factory = registerRetainedExecutorPreparation(createExecutor(options.backend), ({ spawned, profile, task }) => {
|
|
@@ -4804,6 +5508,7 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4804
5508
|
...rootPeerAudit ? { peerAudit: rootPeerAudit } : {},
|
|
4805
5509
|
blobs,
|
|
4806
5510
|
makeWorkerAgent: workerFactory,
|
|
5511
|
+
...graphSubtasks ? { graphs: graphSubtasks } : {},
|
|
4807
5512
|
...authorizeRootMessage ? { authorizeDownMessage: authorizeRootMessage } : {},
|
|
4808
5513
|
perWorker,
|
|
4809
5514
|
...ownerShare > 0 ? { preserveOwnerTurns: true } : {},
|
|
@@ -4882,7 +5587,19 @@ function superviseInternal(profile, task, opts, testBrain) {
|
|
|
4882
5587
|
now
|
|
4883
5588
|
}) : void 0;
|
|
4884
5589
|
const recorder = spans;
|
|
4885
|
-
const
|
|
5590
|
+
const graphSpawnBinder = graphSubtasks ? { onEvent: (event) => {
|
|
5591
|
+
if (graphOverlays.size === 0) return;
|
|
5592
|
+
if (event.target !== "agent.spawn" || event.phase !== "after") return;
|
|
5593
|
+
const payload = event.payload;
|
|
5594
|
+
if (typeof payload?.childId !== "string" || typeof payload.assignmentId !== "string") return;
|
|
5595
|
+
const writes = [];
|
|
5596
|
+
for (const overlay of graphOverlays) {
|
|
5597
|
+
const write = overlay.bindSpawn(event.parentId, payload.assignmentId, payload.childId);
|
|
5598
|
+
if (write !== void 0) writes.push(write);
|
|
5599
|
+
}
|
|
5600
|
+
return writes.length === 0 ? void 0 : Promise.all(writes).then(() => void 0);
|
|
5601
|
+
} } : void 0;
|
|
5602
|
+
const hooks = recorder || graphSpawnBinder ? composeRuntimeHooks(options.hooks, recorder?.hooks, graphSpawnBinder) : options.hooks;
|
|
4886
5603
|
const supervisor = createSupervisor();
|
|
4887
5604
|
if (runControl !== void 0) supervisor.attach(runControl);
|
|
4888
5605
|
const cancellation = options.runDir !== void 0 && runControl !== void 0 ? watchRunCancellation(resolve(options.runDir), cancelDurableRun) : void 0;
|
|
@@ -4998,6 +5715,6 @@ function rootProviderModelEvidenceFromExecution(evidence) {
|
|
|
4998
5715
|
return evidence ?? rootProviderModelEvidence([]);
|
|
4999
5716
|
}
|
|
5000
5717
|
//#endregion
|
|
5001
|
-
export { serveCoordinationMcp as S, readRootStream as _, superviseRootProfile as a, composeReentryTask as b, isPreSpawnExecutorFailure as c, withWorkerSpawnRetry as d, assertCoordinationBinding as f, ROOT_STREAM_FILE as g, supervisorAgentWithTestBrain as h, superviseFleetCapabilities as i, resolveWorkerSpawnRetry as l, supervisorAgent as m, profileGuidanceComposer as n, superviseWithTestBrain as o, resolveSupervisorProfile as p, supervise as r, workerFromBackend as s, DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY as t, retryPreSpawnRefusals as u, readRootStreamReceipt as v, createSupervisorSpanRecorder as x, UNPROVEN_CONTINUITY as y };
|
|
5718
|
+
export { dumbContinuationPassPrompt as A, defaultEdgeTraversalCap as C, createPromptRegistry as D, analyzesFindingsReportPrompt as E, serveCoordinationMcp as F, kernelPromptRegistry as M, naiveContinuationPrompt as N, delegatesWorkerBriefPrompt as O, promptHandle as P, createGraphOverlay as S, validateGraphTopology as T, readRootStream as _, superviseRootProfile as a, composeReentryTask as b, isPreSpawnExecutorFailure as c, withWorkerSpawnRetry as d, assertCoordinationBinding as f, ROOT_STREAM_FILE as g, supervisorAgentWithTestBrain as h, superviseFleetCapabilities as i, formatPromptHandle as j, dumbContinuationFailPrompt as k, resolveWorkerSpawnRetry as l, supervisorAgent as m, profileGuidanceComposer as n, superviseWithTestBrain as o, resolveSupervisorProfile as p, supervise as r, workerFromBackend as s, DEFAULT_AUTHORED_PROFILE_SECURITY_POLICY as t, retryPreSpawnRefusals as u, readRootStreamReceipt as v, graphRootProfile as w, createSupervisorSpanRecorder as x, UNPROVEN_CONTINUITY as y };
|
|
5002
5719
|
|
|
5003
|
-
//# sourceMappingURL=supervise-
|
|
5720
|
+
//# sourceMappingURL=supervise-BlaB4CeL.js.map
|