@noopolis/daimon 0.2.0 → 0.2.2
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/README.md +6 -0
- package/dist/contracts/attentionContract.d.ts +25 -0
- package/dist/contracts/attentionContract.d.ts.map +1 -1
- package/dist/contracts/attentionContract.js +8 -1
- package/dist/contracts/grokBrokerTaskClock.d.ts +18 -0
- package/dist/contracts/grokBrokerTaskClock.d.ts.map +1 -0
- package/dist/contracts/grokBrokerTaskClock.js +16 -0
- package/dist/contracts/organizationRuntimeContract.d.ts +76 -0
- package/dist/contracts/organizationRuntimeContract.d.ts.map +1 -1
- package/dist/contracts/organizationRuntimeContract.js +2 -0
- package/dist/contracts/runtimeContractManifest.d.ts +222 -15
- package/dist/contracts/runtimeContractManifest.d.ts.map +1 -1
- package/dist/contracts/runtimeContractManifest.js +35 -10
- package/dist/contracts/shellEnvironmentPolicy.d.ts +3 -0
- package/dist/contracts/shellEnvironmentPolicy.d.ts.map +1 -0
- package/dist/contracts/shellEnvironmentPolicy.js +5 -0
- package/dist/contracts/wakeMomentContract.d.ts +61 -0
- package/dist/contracts/wakeMomentContract.d.ts.map +1 -0
- package/dist/contracts/wakeMomentContract.js +27 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/examples/jungianPlayAgent.d.ts +1 -0
- package/dist/examples/jungianPlayAgent.d.ts.map +1 -1
- package/dist/examples/jungianPlayAgent.js +6 -2
- package/dist/observability/causalEvents.d.ts +3 -3
- package/dist/observability/causalEvents.d.ts.map +1 -1
- package/dist/observability/causalEvents.js +4 -4
- package/dist/pi/cliEngineSpawn.d.ts +2 -2
- package/dist/pi/cliEngineSpawn.d.ts.map +1 -1
- package/dist/pi/cliEngineSpawn.js +7 -2
- package/dist/pi/cliEnvironment.d.ts.map +1 -1
- package/dist/pi/cliEnvironment.js +2 -0
- package/dist/pi/cliMcpRegistration.d.ts +1 -1
- package/dist/pi/cliMcpRegistration.d.ts.map +1 -1
- package/dist/pi/cliMcpRegistration.js +1 -1
- package/dist/pi/cliSession.d.ts +2 -0
- package/dist/pi/cliSession.d.ts.map +1 -1
- package/dist/pi/cliSession.js +3 -80
- package/dist/pi/cliSessionMcp.d.ts +9 -0
- package/dist/pi/cliSessionMcp.d.ts.map +1 -0
- package/dist/pi/cliSessionMcp.js +80 -0
- package/dist/pi/engineTaskClock.d.ts +9 -0
- package/dist/pi/engineTaskClock.d.ts.map +1 -0
- package/dist/pi/engineTaskClock.js +28 -0
- package/dist/pi/grokHomeMcpRegistration.d.ts.map +1 -1
- package/dist/pi/grokHomeMcpRegistration.js +2 -1
- package/dist/pi/grokSandbox.js +1 -1
- package/dist/pi/memoryClock.d.ts +25 -0
- package/dist/pi/memoryClock.d.ts.map +1 -0
- package/dist/pi/memoryClock.js +18 -0
- package/dist/pi/piAgentHandle.d.ts +3 -1
- package/dist/pi/piAgentHandle.d.ts.map +1 -1
- package/dist/pi/piAgentHandle.js +5 -2
- package/dist/pi/piHarness.d.ts +8 -2
- package/dist/pi/piHarness.d.ts.map +1 -1
- package/dist/pi/piHarness.js +28 -12
- package/dist/pi/taskClockProcess.d.ts +6 -0
- package/dist/pi/taskClockProcess.d.ts.map +1 -0
- package/dist/pi/taskClockProcess.js +8 -0
- package/dist/pi/turnCausal.d.ts +4 -2
- package/dist/pi/turnCausal.d.ts.map +1 -1
- package/dist/pi/turnCausal.js +4 -4
- package/dist/pi/wakeAcceptance.d.ts +1 -1
- package/dist/pi/wakeAcceptance.d.ts.map +1 -1
- package/dist/pi/wakeAcceptance.js +2 -2
- package/dist/runtime/agentSkillsDirectory.d.ts +25 -0
- package/dist/runtime/agentSkillsDirectory.d.ts.map +1 -0
- package/dist/runtime/agentSkillsDirectory.js +101 -0
- package/dist/runtime/agySubscriptionBootstrap.js +1 -1
- package/dist/runtime/agySubscriptionRealm.js +1 -1
- package/dist/runtime/attention.d.ts +5 -0
- package/dist/runtime/attention.d.ts.map +1 -1
- package/dist/runtime/attention.js +14 -1
- package/dist/runtime/attentionDispatcher.d.ts +14 -2
- package/dist/runtime/attentionDispatcher.d.ts.map +1 -1
- package/dist/runtime/attentionDispatcher.js +127 -33
- package/dist/runtime/cli.js +5 -0
- package/dist/runtime/contract-manifest.json +1 -1
- package/dist/runtime/contract-manifest.sha256 +1 -1
- package/dist/runtime/engineBrokerCapabilities.d.ts +10 -0
- package/dist/runtime/engineBrokerCapabilities.d.ts.map +1 -1
- package/dist/runtime/engineBrokerCapabilities.js +10 -0
- package/dist/runtime/engineBrokerControlClient.d.ts +12 -1
- package/dist/runtime/engineBrokerControlClient.d.ts.map +1 -1
- package/dist/runtime/engineBrokerControlClient.js +139 -43
- package/dist/runtime/engineBrokerCredentialJournal.d.ts +2 -0
- package/dist/runtime/engineBrokerCredentialJournal.d.ts.map +1 -1
- package/dist/runtime/engineBrokerCredentialJournal.js +9 -0
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts +3 -2
- package/dist/runtime/engineBrokerInferenceProtocol.d.ts.map +1 -1
- package/dist/runtime/engineBrokerInferenceProtocol.js +4 -4
- package/dist/runtime/engineBrokerMcpCallLog.d.ts +11 -0
- package/dist/runtime/engineBrokerMcpCallLog.d.ts.map +1 -1
- package/dist/runtime/engineBrokerMcpCallLog.js +13 -1
- package/dist/runtime/engineBrokerMcpFacade.d.ts +5 -2
- package/dist/runtime/engineBrokerMcpFacade.d.ts.map +1 -1
- package/dist/runtime/engineBrokerMcpFacade.js +5 -2
- package/dist/runtime/engineBrokerNativeClient.js +2 -2
- package/dist/runtime/engineBrokerProtocol.d.ts +42 -10
- package/dist/runtime/engineBrokerProtocol.d.ts.map +1 -1
- package/dist/runtime/engineBrokerProtocol.js +97 -14
- package/dist/runtime/engineBrokerSealLedger.d.ts.map +1 -1
- package/dist/runtime/engineBrokerSealLedger.js +9 -0
- package/dist/runtime/engineBrokerService.d.ts +8 -2
- package/dist/runtime/engineBrokerService.d.ts.map +1 -1
- package/dist/runtime/engineBrokerService.js +95 -37
- package/dist/runtime/engineBrokerServiceCli.js +1 -1
- package/dist/runtime/engineBrokerServiceConfig.d.ts +15 -2
- package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -1
- package/dist/runtime/engineBrokerServiceConfig.js +53 -11
- package/dist/runtime/engineBrokerTurnRegistry.d.ts +1 -1
- package/dist/runtime/engineBrokerTurnRegistry.d.ts.map +1 -1
- package/dist/runtime/engineBrokerTurnRegistry.js +7 -6
- package/dist/runtime/engineDispatcher.d.ts +2 -0
- package/dist/runtime/engineDispatcher.d.ts.map +1 -1
- package/dist/runtime/engineDispatcher.js +14 -2
- package/dist/runtime/engineReadiness.js +1 -1
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts +1 -0
- package/dist/runtime/grokBrokerCredentialAuthority.d.ts.map +1 -1
- package/dist/runtime/grokBrokerCredentialAuthority.js +48 -22
- package/dist/runtime/grokBrokerCredentialReader.d.ts +1 -0
- package/dist/runtime/grokBrokerCredentialReader.d.ts.map +1 -1
- package/dist/runtime/grokBrokerCredentialReader.js +2 -1
- package/dist/runtime/grokBrokerProjection.d.ts +26 -2
- package/dist/runtime/grokBrokerProjection.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProjection.js +18 -7
- package/dist/runtime/grokBrokerProviderClock.d.ts +26 -0
- package/dist/runtime/grokBrokerProviderClock.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProviderClock.js +133 -0
- package/dist/runtime/grokBrokerProxy.d.ts +17 -3
- package/dist/runtime/grokBrokerProxy.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProxy.js +73 -9
- package/dist/runtime/grokBrokerProxyJson.d.ts +10 -0
- package/dist/runtime/grokBrokerProxyJson.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxyJson.js +31 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProxyRequest.js +17 -6
- package/dist/runtime/grokBrokerRealmLease.js +1 -1
- package/dist/runtime/grokBrokerRefresh.js +1 -1
- package/dist/runtime/grokBrokerRunBudget.d.ts +20 -0
- package/dist/runtime/grokBrokerRunBudget.d.ts.map +1 -0
- package/dist/runtime/grokBrokerRunBudget.js +85 -0
- package/dist/runtime/grokBrokerSlot.d.ts +6 -0
- package/dist/runtime/grokBrokerSlot.d.ts.map +1 -0
- package/dist/runtime/grokBrokerSlot.js +21 -0
- package/dist/runtime/grokBrokerTaskClock.d.ts +32 -0
- package/dist/runtime/grokBrokerTaskClock.d.ts.map +1 -0
- package/dist/runtime/grokBrokerTaskClock.js +120 -0
- package/dist/runtime/grokBrokerTurnMeter.d.ts +55 -3
- package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -1
- package/dist/runtime/grokBrokerTurnMeter.js +90 -4
- package/dist/runtime/grokBrokerWorkerConfig.d.ts +5 -2
- package/dist/runtime/grokBrokerWorkerConfig.d.ts.map +1 -1
- package/dist/runtime/grokBrokerWorkerConfig.js +22 -3
- package/dist/runtime/grokEngineBroker.d.ts +43 -3
- package/dist/runtime/grokEngineBroker.d.ts.map +1 -1
- package/dist/runtime/grokEngineBroker.js +159 -71
- package/dist/runtime/grokEngineBrokerTurn.d.ts +32 -8
- package/dist/runtime/grokEngineBrokerTurn.d.ts.map +1 -1
- package/dist/runtime/grokEngineBrokerTurn.js +204 -21
- package/dist/runtime/grokEngineBrokerTurnEnd.d.ts +88 -0
- package/dist/runtime/grokEngineBrokerTurnEnd.d.ts.map +1 -0
- package/dist/runtime/grokEngineBrokerTurnEnd.js +148 -0
- package/dist/runtime/grokInferenceProxy.d.ts.map +1 -1
- package/dist/runtime/grokInferenceProxy.js +3 -0
- package/dist/runtime/grokSubscriptionRealm.js +1 -1
- package/dist/runtime/grokWorkerAttestation.d.ts +12 -5
- package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerAttestation.js +5 -3
- package/dist/runtime/grokWorkerHomeAttestation.d.ts +51 -5
- package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerHomeAttestation.js +103 -8
- package/dist/runtime/grokWorkerSkills.d.ts +86 -0
- package/dist/runtime/grokWorkerSkills.d.ts.map +1 -0
- package/dist/runtime/grokWorkerSkills.js +135 -0
- package/dist/runtime/index.d.ts +10 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +8 -1
- package/dist/runtime/native/daimon-engine-broker +0 -0
- package/dist/runtime/organizationRuntime.d.ts +3 -0
- package/dist/runtime/organizationRuntime.d.ts.map +1 -1
- package/dist/runtime/organizationRuntimeAdmission.d.ts +6 -0
- package/dist/runtime/organizationRuntimeAdmission.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeAdmission.js +22 -0
- package/dist/runtime/organizationRuntimeControl.d.ts +9 -0
- package/dist/runtime/organizationRuntimeControl.d.ts.map +1 -1
- package/dist/runtime/organizationRuntimeControl.js +72 -24
- package/dist/runtime/organizationRuntimeHost.d.ts.map +1 -1
- package/dist/runtime/organizationRuntimeHost.js +13 -4
- package/dist/runtime/organizationRuntimeParsing.d.ts.map +1 -1
- package/dist/runtime/organizationRuntimeParsing.js +4 -1
- package/dist/runtime/organizationRuntimeReadiness.d.ts.map +1 -1
- package/dist/runtime/organizationRuntimeReadiness.js +8 -0
- package/dist/runtime/organizationRuntimeRecording.d.ts +7 -0
- package/dist/runtime/organizationRuntimeRecording.d.ts.map +1 -0
- package/dist/runtime/organizationRuntimeRecording.js +58 -0
- package/dist/runtime/physicalReadiness.d.ts +12 -0
- package/dist/runtime/physicalReadiness.d.ts.map +1 -1
- package/dist/runtime/physicalReadiness.js +43 -9
- package/dist/runtime/productionAgentTools.d.ts.map +1 -1
- package/dist/runtime/productionAgentTools.js +13 -5
- package/dist/runtime/relocateRuntimeConfig.d.ts +14 -0
- package/dist/runtime/relocateRuntimeConfig.d.ts.map +1 -0
- package/dist/runtime/relocateRuntimeConfig.js +38 -0
- package/dist/runtime/schedule.d.ts.map +1 -1
- package/dist/runtime/schedule.js +12 -7
- package/dist/runtime/storeCoordination.d.ts +10 -0
- package/dist/runtime/storeCoordination.d.ts.map +1 -1
- package/dist/runtime/storeCoordination.js +23 -0
- package/dist/runtime/taskClock.d.ts +42 -0
- package/dist/runtime/taskClock.d.ts.map +1 -0
- package/dist/runtime/taskClock.js +102 -0
- package/dist/runtime/taskClockProcess.d.ts +17 -0
- package/dist/runtime/taskClockProcess.d.ts.map +1 -0
- package/dist/runtime/taskClockProcess.js +58 -0
- package/dist/runtime/turnRequestLedger.d.ts +0 -5
- package/dist/runtime/turnRequestLedger.d.ts.map +1 -1
- package/dist/runtime/turnRequestLedger.js +23 -21
- package/dist/runtime/wakeAcceptanceClaimDiagnostics.d.ts +34 -0
- package/dist/runtime/wakeAcceptanceClaimDiagnostics.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceClaimDiagnostics.js +79 -0
- package/dist/runtime/wakeAcceptanceIndex.d.ts +55 -0
- package/dist/runtime/wakeAcceptanceIndex.d.ts.map +1 -0
- package/dist/runtime/wakeAcceptanceIndex.js +158 -0
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts +9 -1
- package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts.map +1 -1
- package/dist/runtime/wakeAcceptanceProcessIdentity.js +5 -1
- package/dist/runtime/wakeAcceptanceRecord.d.ts +2 -0
- package/dist/runtime/wakeAcceptanceRecord.d.ts.map +1 -1
- package/dist/runtime/wakeAcceptanceRecord.js +4 -2
- package/dist/runtime/wakeAcceptanceRetention.d.ts +25 -1
- package/dist/runtime/wakeAcceptanceRetention.d.ts.map +1 -1
- package/dist/runtime/wakeAcceptanceRetention.js +28 -2
- package/dist/runtime/wakeAcceptanceStore.d.ts +8 -8
- package/dist/runtime/wakeAcceptanceStore.d.ts.map +1 -1
- package/dist/runtime/wakeAcceptanceStore.js +66 -63
- package/dist/runtime/wakeFuse.d.ts +58 -3
- package/dist/runtime/wakeFuse.d.ts.map +1 -1
- package/dist/runtime/wakeFuse.js +106 -7
- package/dist/runtime/wakeMomentFs.d.ts +27 -0
- package/dist/runtime/wakeMomentFs.d.ts.map +1 -0
- package/dist/runtime/wakeMomentFs.js +223 -0
- package/dist/runtime/wakeMomentHistory.d.ts +26 -0
- package/dist/runtime/wakeMomentHistory.d.ts.map +1 -0
- package/dist/runtime/wakeMomentHistory.js +109 -0
- package/dist/runtime/wakeMomentIo.d.ts +22 -0
- package/dist/runtime/wakeMomentIo.d.ts.map +1 -0
- package/dist/runtime/wakeMomentIo.js +114 -0
- package/dist/runtime/wakeMomentRecorder.d.ts +33 -0
- package/dist/runtime/wakeMomentRecorder.d.ts.map +1 -0
- package/dist/runtime/wakeMomentRecorder.js +81 -0
- package/dist/runtime/wakeMomentRetention.d.ts +7 -0
- package/dist/runtime/wakeMomentRetention.d.ts.map +1 -0
- package/dist/runtime/wakeMomentRetention.js +143 -0
- package/dist/runtime/wakeMomentRows.d.ts +8 -0
- package/dist/runtime/wakeMomentRows.d.ts.map +1 -0
- package/dist/runtime/wakeMomentRows.js +66 -0
- package/dist/runtime/wakeMomentSnapshot.d.ts +56 -0
- package/dist/runtime/wakeMomentSnapshot.d.ts.map +1 -0
- package/dist/runtime/wakeMomentSnapshot.js +248 -0
- package/package.json +4 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { brokerClockObservation } from "./grokBrokerTaskClock.js";
|
|
1
2
|
import { chmod, lstat, unlink } from "node:fs/promises";
|
|
2
3
|
import { createServer } from "node:net";
|
|
3
|
-
import { encodeEngineBrokerFrame, EngineBrokerFrameDecoder, parseEngineBrokerRequest } from "./engineBrokerProtocol.js";
|
|
4
|
+
import { encodeEngineBrokerFrame, EngineBrokerFrameDecoder, EngineBrokerProtocolMismatch, parseEngineBrokerRequest } from "./engineBrokerProtocol.js";
|
|
4
5
|
import { EngineBrokerTurnFailure } from "./grokEngineBroker.js";
|
|
5
6
|
import { GROK_INFERENCE_PROXY_BASE_URL } from "./engineBrokerInferenceProtocol.js";
|
|
6
7
|
import { GrokInferenceGrantRefused } from "./grokInferenceGrants.js";
|
|
@@ -12,7 +13,11 @@ export async function startEngineBrokerServiceWithIdentity(broker, socketPath, e
|
|
|
12
13
|
throw new Error("engine broker service requires broker identity");
|
|
13
14
|
await removeOwnedSocket(socketPath, expectedUid);
|
|
14
15
|
const active = new Map(), connections = new Set();
|
|
15
|
-
const server = createServer((socket) => {
|
|
16
|
+
const server = createServer((socket) => {
|
|
17
|
+
connections.add(socket);
|
|
18
|
+
socket.once("close", () => connections.delete(socket));
|
|
19
|
+
serveEngineBrokerConnection(socket, broker, active);
|
|
20
|
+
});
|
|
16
21
|
await listen(server, socketPath);
|
|
17
22
|
try {
|
|
18
23
|
await chmod(socketPath, 0o600);
|
|
@@ -48,43 +53,88 @@ export async function startEngineBrokerServiceWithIdentity(broker, socketPath, e
|
|
|
48
53
|
* reader has disconnected.
|
|
49
54
|
*/
|
|
50
55
|
function handleSocketError(socket, owned) { socket.on("error", () => { owned()?.controller.abort(); socket.destroy(); }); }
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
/** @internal The production connection handler, also exercised over an in-memory transport. */
|
|
57
|
+
export function serveEngineBrokerConnection(socket, broker, active = new Map()) {
|
|
58
|
+
const decoder = new EngineBrokerFrameDecoder();
|
|
59
|
+
let started = false;
|
|
60
|
+
let owned;
|
|
61
|
+
handleSocketError(socket, () => owned);
|
|
62
|
+
socket.once("close", () => owned?.controller.abort());
|
|
63
|
+
socket.on("data", (chunk) => {
|
|
64
|
+
try {
|
|
65
|
+
for (const value of decoder.push(chunk)) {
|
|
66
|
+
const request = parseEngineBrokerRequest(value);
|
|
67
|
+
if (request.kind === "health") {
|
|
68
|
+
if (started)
|
|
69
|
+
throw new Error();
|
|
70
|
+
started = true;
|
|
71
|
+
const ready = broker.readiness();
|
|
72
|
+
if (ready.providerProxyPort !== 43123 || ready.mcpFacadePort !== 43124 ||
|
|
73
|
+
ready.registrations < 1 || ready.credentialStale || !ready.realmLease || !ready.workerIsolation) {
|
|
74
|
+
throw new Error();
|
|
75
|
+
}
|
|
76
|
+
return send(socket, {
|
|
77
|
+
version: request.version, kind: "ready", requestId: request.requestId, brokerUid: 2100,
|
|
78
|
+
providerProxyPort: 43123, mcpFacadePort: 43124, registrations: ready.registrations,
|
|
79
|
+
credentialStale: false, realmLease: true, workerIsolation: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (request.kind === "cancel_turn") {
|
|
83
|
+
if (owned?.turnId !== request.turnId)
|
|
84
|
+
throw new Error("turn not owned by connection");
|
|
85
|
+
owned.controller.abort();
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (request.kind === "request_inference_grant" || request.kind === "release_inference_grant") {
|
|
89
|
+
if (started)
|
|
90
|
+
throw new Error();
|
|
91
|
+
started = true;
|
|
92
|
+
serveInferenceGrant(socket, broker, request);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (request.kind === "reset_slot") {
|
|
96
|
+
if (started || broker.resetSlot === undefined)
|
|
97
|
+
throw new Error();
|
|
98
|
+
started = true;
|
|
99
|
+
void broker.resetSlot(request.slot).then(() => send(socket, {
|
|
100
|
+
version: request.version, kind: "slot_reset", requestId: request.requestId, slot: request.slot
|
|
101
|
+
}), () => socket.destroy());
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const key = `${request.slot ?? request.agentId}:${request.turnId}`;
|
|
105
|
+
if (started || active.has(key))
|
|
106
|
+
throw new Error();
|
|
107
|
+
started = true;
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
owned = { turnId: request.turnId, controller };
|
|
110
|
+
active.set(key, controller);
|
|
111
|
+
socket.write(encodeEngineBrokerFrame({
|
|
112
|
+
version: request.version, kind: "accepted", requestId: request.requestId, turnId: request.turnId
|
|
113
|
+
}));
|
|
114
|
+
void broker.turn(request.agentId, request.wakeId, request.prompt, request.mcpEndpoint, controller.signal, request.limits, request.processClock, request.slot).then((result) => send(socket, {
|
|
115
|
+
version: request.version, kind: "completed", requestId: request.requestId, turnId: request.turnId,
|
|
116
|
+
text: result.text, ...brokerClockObservation(result.shellClock, result.providerClock),
|
|
117
|
+
...(result.cleanupDiagnostic === undefined ? {} : { cleanupDiagnostic: result.cleanupDiagnostic }),
|
|
118
|
+
workerPid: result.workerPid, workerUid: result.workerUid, workerStartTime: result.workerStartTime,
|
|
119
|
+
outcome: "completed", usage: result.usage, model: result.model, requests: result.requests, limitReason: "none"
|
|
120
|
+
}), (error) => failed(socket, request, error, controller.signal.aborted)).finally(() => {
|
|
121
|
+
if (active.get(key) === controller)
|
|
122
|
+
active.delete(key);
|
|
123
|
+
owned = undefined;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
62
126
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (error instanceof EngineBrokerProtocolMismatch && !socket.writableEnded) {
|
|
129
|
+
// Flush one small, closed diagnostic before FIN; destroy would lose it.
|
|
130
|
+
socket.pause();
|
|
131
|
+
socket.end(encodeEngineBrokerFrame(error.diagnostic));
|
|
132
|
+
}
|
|
133
|
+
else
|
|
134
|
+
socket.destroy();
|
|
66
135
|
}
|
|
67
|
-
|
|
68
|
-
if (started)
|
|
69
|
-
throw new Error();
|
|
70
|
-
started = true;
|
|
71
|
-
serveInferenceGrant(socket, broker, request);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
if (started || active.has(request.turnId))
|
|
75
|
-
throw new Error();
|
|
76
|
-
started = true;
|
|
77
|
-
const controller = new AbortController();
|
|
78
|
-
owned = { turnId: request.turnId, controller };
|
|
79
|
-
active.set(request.turnId, controller);
|
|
80
|
-
socket.write(encodeEngineBrokerFrame({ version: request.version, kind: "accepted", requestId: request.requestId, turnId: request.turnId }));
|
|
81
|
-
void broker.turn(request.agentId, request.wakeId, request.prompt, request.mcpEndpoint, controller.signal, request.limits).then((result) => send(socket, { version: request.version, kind: "completed", requestId: request.requestId, turnId: request.turnId, text: result.text, workerPid: result.workerPid, workerUid: result.workerUid, workerStartTime: result.workerStartTime, outcome: "completed", usage: result.usage, model: result.model, requests: result.requests, limitReason: "none" }), (error) => failed(socket, request, error, controller.signal.aborted)).finally(() => { if (active.get(request.turnId) === controller)
|
|
82
|
-
active.delete(request.turnId); owned = undefined; });
|
|
83
|
-
}
|
|
136
|
+
});
|
|
84
137
|
}
|
|
85
|
-
catch {
|
|
86
|
-
socket.destroy();
|
|
87
|
-
} }); }
|
|
88
138
|
/**
|
|
89
139
|
* Every failure the broker raises for a known registration carries its
|
|
90
140
|
* accounting (a wake that tried to raise a limit: `usage: null`, zero
|
|
@@ -99,7 +149,15 @@ function failed(socket, request, error, aborted) {
|
|
|
99
149
|
return;
|
|
100
150
|
}
|
|
101
151
|
const code = error instanceof EngineBrokerTurnFailure ? error.code : aborted ? "cancelled" : "engine_failed";
|
|
102
|
-
send(socket, {
|
|
152
|
+
send(socket, {
|
|
153
|
+
version: request.version, kind: "failed", requestId: request.requestId, turnId: request.turnId, code,
|
|
154
|
+
...(error instanceof EngineBrokerTurnFailure ? brokerClockObservation(error.shellClock, error.providerClock) : {}),
|
|
155
|
+
...(error instanceof EngineBrokerTurnFailure && error.diagnostic ? { diagnostic: error.diagnostic } : {}),
|
|
156
|
+
...(error instanceof EngineBrokerTurnFailure && error.mcpCalls ? { mcpCalls: error.mcpCalls } : {}),
|
|
157
|
+
...(error instanceof EngineBrokerTurnFailure && error.cleanupDiagnostic ? { cleanupDiagnostic: error.cleanupDiagnostic } : {}),
|
|
158
|
+
outcome: "failed", usage: accounting.usage, model: accounting.model,
|
|
159
|
+
requests: accounting.requests, limitReason: accounting.limitReason
|
|
160
|
+
});
|
|
103
161
|
}
|
|
104
162
|
/** One grant verb per connection, answered and closed; any failure becomes a closed-code refusal and never touches turn state. */
|
|
105
163
|
function serveInferenceGrant(socket, broker, request) {
|
|
@@ -10,7 +10,7 @@ export async function runEngineBrokerServiceCli() {
|
|
|
10
10
|
if (process.getuid?.() !== 2100)
|
|
11
11
|
throw new Error("engine broker service requires broker identity");
|
|
12
12
|
const config = parseEngineBrokerServiceConfig(await readRootConfig(ENGINE_BROKER_SERVICE_CONFIG));
|
|
13
|
-
const broker = await startGrokEngineBroker({ grokCommand: "/usr/local/bin/grok", nativeClient: "/opt/daimon/bin/daimon-engine-broker", credentialHome: config.credentialHome, turnStore: config.turnStore, registrations: config.registrations, ...(config.inferenceLedgerPath === undefined ? {} : { inferenceLedgerPath: config.inferenceLedgerPath }) });
|
|
13
|
+
const broker = await startGrokEngineBroker({ grokCommand: "/usr/local/bin/grok", nativeClient: "/opt/daimon/bin/daimon-engine-broker", credentialHome: config.credentialHome, turnStore: config.turnStore, registrations: config.registrations, maxRunRequests: config.maxRunRequests, runRequestStore: config.runRequestStore, ...(config.inferenceLedgerPath === undefined ? {} : { inferenceLedgerPath: config.inferenceLedgerPath }) });
|
|
14
14
|
const service = await startEngineBrokerService(broker);
|
|
15
15
|
let stopping;
|
|
16
16
|
const stop = () => { stopping ??= service.close(); return stopping; };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type EngineBrokerTurnLimits } from "./engineBrokerTurnAccounting.js";
|
|
2
2
|
import { type GrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
|
|
3
3
|
export declare const ENGINE_BROKER_SERVICE_V1: "noopolis.daimon.engine-broker-service.v1";
|
|
4
|
+
export declare const ENGINE_BROKER_SERVICE_V3: "noopolis.daimon.engine-broker-service.v3";
|
|
4
5
|
export declare const ENGINE_BROKER_SERVICE_V2: "noopolis.daimon.engine-broker-service.v2";
|
|
5
6
|
/** One root-provisioned broker slot. Every field is fixed at provisioning time; a wake can only lower `limits`. */
|
|
6
7
|
export type EngineBrokerServiceRegistration = Readonly<{
|
|
@@ -15,6 +16,13 @@ export type EngineBrokerServiceRegistration = Readonly<{
|
|
|
15
16
|
usageLedgerPath: string;
|
|
16
17
|
limits: EngineBrokerTurnLimits;
|
|
17
18
|
model: GrokBrokerModelPolicy;
|
|
19
|
+
/**
|
|
20
|
+
* Digest of the skills root provisioning rendered into `$GROK_HOME/skills`
|
|
21
|
+
* (`grokWorkerSkillsSha256`), attested before every turn. Optional in v2
|
|
22
|
+
* registrations and v3 slot policies; absent means the slot has no skills and
|
|
23
|
+
* the directory must not exist.
|
|
24
|
+
*/
|
|
25
|
+
skillsSha256?: string;
|
|
18
26
|
}>;
|
|
19
27
|
/**
|
|
20
28
|
* `inferenceLedgerPath` (v2, optional) is where evaluator inference grants
|
|
@@ -28,6 +36,8 @@ export type EngineBrokerServiceConfig = Readonly<{
|
|
|
28
36
|
turnStore: string;
|
|
29
37
|
registrations: readonly EngineBrokerServiceRegistration[];
|
|
30
38
|
inferenceLedgerPath?: string;
|
|
39
|
+
maxRunRequests?: number;
|
|
40
|
+
runRequestStore?: string;
|
|
31
41
|
}>;
|
|
32
42
|
/** The per-request stream written beside a registration's usage ledger. */
|
|
33
43
|
export declare const engineBrokerRequestLedgerPathFor: (usageLedgerPath: string) => string;
|
|
@@ -40,9 +50,12 @@ export declare const engineBrokerSealLedgerPathFor: (usageLedgerPath: string) =>
|
|
|
40
50
|
/**
|
|
41
51
|
* Strict `service.json` parser.
|
|
42
52
|
*
|
|
53
|
+
* v3 retains seven-field registrations and binds slotPolicies by slot; agent IDs
|
|
54
|
+
* may repeat, while worker UIDs, slots and ledger streams must be distinct.
|
|
43
55
|
* v2 requires every registration to declare its usage ledger, limits and model
|
|
44
|
-
* (`model.id`/`model.reasoningEffort` from the closed lists)
|
|
45
|
-
*
|
|
56
|
+
* (`model.id`/`model.reasoningEffort` from the closed lists) and may declare
|
|
57
|
+
* `skillsSha256` (v3: on its slot policy); unknown keys at any level are
|
|
58
|
+
* refused. v1 is still accepted and receives today's defaults:
|
|
46
59
|
* the container ledger, {@link DEFAULT_GROK_BROKER_TURN_LIMITS}, and
|
|
47
60
|
* `grok-4.6`/`low`.
|
|
48
61
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engineBrokerServiceConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerServiceConfig.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC5I,OAAO,EAAuF,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAK7J,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAE5F,mHAAmH;AACnH,MAAM,MAAM,+BAA+B,GAAG,QAAQ,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IACpI,oJAAoJ;IACpJ,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"engineBrokerServiceConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerServiceConfig.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgE,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC5I,OAAO,EAAuF,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAK7J,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAC5F,eAAO,MAAM,wBAAwB,EAAG,0CAAmD,CAAC;AAE5F,mHAAmH;AACnH,MAAM,MAAM,+BAA+B,GAAG,QAAQ,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IACpI,oJAAoJ;IACpJ,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AACH;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,SAAS,+BAA+B,EAAE,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAc5O,2EAA2E;AAC3E,eAAO,MAAM,gCAAgC,GAAI,iBAAiB,MAAM,KAAG,MAAgF,CAAC;AAE5J;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,iBAAiB,MAAM,KAAG,MAA6E,CAAC;AAEtJ;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAyDxF"}
|
|
@@ -5,6 +5,7 @@ import { grokWorkerEventsPathFor } from "./grokWorkerSandboxProfile.js";
|
|
|
5
5
|
import { TURN_REQUEST_LEDGER } from "./turnRequestLedger.js";
|
|
6
6
|
import { TURN_USAGE_LEDGER } from "./turnUsageLedger.js";
|
|
7
7
|
export const ENGINE_BROKER_SERVICE_V1 = "noopolis.daimon.engine-broker-service.v1";
|
|
8
|
+
export const ENGINE_BROKER_SERVICE_V3 = "noopolis.daimon.engine-broker-service.v3";
|
|
8
9
|
export const ENGINE_BROKER_SERVICE_V2 = "noopolis.daimon.engine-broker-service.v2";
|
|
9
10
|
const V1_REGISTRATION = ["agentId", "slot", "workerUid", "workspace", "profilePath", "eventsPath", "profileSha256"];
|
|
10
11
|
const V2_REGISTRATION = [...V1_REGISTRATION, "usageLedgerPath", "limits", "model"];
|
|
@@ -29,48 +30,88 @@ export const engineBrokerSealLedgerPathFor = (usageLedgerPath) => path.posix.joi
|
|
|
29
30
|
/**
|
|
30
31
|
* Strict `service.json` parser.
|
|
31
32
|
*
|
|
33
|
+
* v3 retains seven-field registrations and binds slotPolicies by slot; agent IDs
|
|
34
|
+
* may repeat, while worker UIDs, slots and ledger streams must be distinct.
|
|
32
35
|
* v2 requires every registration to declare its usage ledger, limits and model
|
|
33
|
-
* (`model.id`/`model.reasoningEffort` from the closed lists)
|
|
34
|
-
*
|
|
36
|
+
* (`model.id`/`model.reasoningEffort` from the closed lists) and may declare
|
|
37
|
+
* `skillsSha256` (v3: on its slot policy); unknown keys at any level are
|
|
38
|
+
* refused. v1 is still accepted and receives today's defaults:
|
|
35
39
|
* the container ledger, {@link DEFAULT_GROK_BROKER_TURN_LIMITS}, and
|
|
36
40
|
* `grok-4.6`/`low`.
|
|
37
41
|
*/
|
|
38
42
|
export function parseEngineBrokerServiceConfig(value) {
|
|
39
43
|
if (!plain(value))
|
|
40
44
|
throw invalid();
|
|
41
|
-
const
|
|
45
|
+
const v3 = value.version === ENGINE_BROKER_SERVICE_V3;
|
|
46
|
+
const v2 = v3 || value.version === ENGINE_BROKER_SERVICE_V2;
|
|
42
47
|
if (!v2 && value.version !== ENGINE_BROKER_SERVICE_V1)
|
|
43
48
|
throw invalid();
|
|
44
|
-
const top = ["version", "credentialHome", "turnStore", "registrations"];
|
|
49
|
+
const top = ["version", "credentialHome", "turnStore", "registrations", ...(v3 ? ["slotPolicies"] : [])];
|
|
50
|
+
if (v3 && Object.hasOwn(value, "maxRunRequests")) {
|
|
51
|
+
if (!Number.isSafeInteger(value.maxRunRequests) || value.maxRunRequests < 1)
|
|
52
|
+
throw invalid();
|
|
53
|
+
top.push("maxRunRequests");
|
|
54
|
+
}
|
|
55
|
+
if (v3 && Object.hasOwn(value, "runRequestStore")) {
|
|
56
|
+
if (!absolute(value.runRequestStore) || value.maxRunRequests === undefined)
|
|
57
|
+
throw invalid();
|
|
58
|
+
top.push("runRequestStore");
|
|
59
|
+
}
|
|
45
60
|
exact(value, v2 && Object.hasOwn(value, "inferenceLedgerPath") ? [...top, "inferenceLedgerPath"] : top);
|
|
46
61
|
if (!absolute(value.credentialHome) || !absolute(value.turnStore) || !Array.isArray(value.registrations) || value.registrations.length === 0)
|
|
47
62
|
throw invalid();
|
|
48
|
-
const
|
|
63
|
+
const policies = new Map();
|
|
64
|
+
if (v3) {
|
|
65
|
+
if (!Array.isArray(value.slotPolicies) || value.slotPolicies.length !== value.registrations.length)
|
|
66
|
+
throw invalid();
|
|
67
|
+
for (const policy of value.slotPolicies) {
|
|
68
|
+
if (!plain(policy))
|
|
69
|
+
throw invalid();
|
|
70
|
+
exact(policy, ["slot", "usageLedgerPath", "limits", "model", ...withSkills(policy)]);
|
|
71
|
+
if (!Number.isSafeInteger(policy.slot) || policy.slot < 0 || policies.has(policy.slot))
|
|
72
|
+
throw invalid();
|
|
73
|
+
policies.set(policy.slot, policy);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const seen = new Set(), slots = new Set(), workers = new Set();
|
|
77
|
+
const ledgers = new Set();
|
|
49
78
|
const registrations = value.registrations.map((entry) => {
|
|
50
79
|
if (!plain(entry))
|
|
51
80
|
throw invalid();
|
|
52
|
-
exact(entry, v2 ? V2_REGISTRATION : V1_REGISTRATION);
|
|
81
|
+
exact(entry, v2 && !v3 ? [...V2_REGISTRATION, ...withSkills(entry)] : V1_REGISTRATION);
|
|
53
82
|
const { agentId, slot, workerUid, workspace, profilePath, eventsPath, profileSha256 } = entry;
|
|
54
|
-
if (typeof agentId !== "string" || !agentId.trim() || seen.has(agentId) || !Number.isSafeInteger(slot) || slot < 0 || slots.has(slot) || !Number.isSafeInteger(workerUid) || workerUid < 2200 || !absolute(workspace) || !absolute(profilePath) || !absolute(eventsPath) || typeof profileSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(profileSha256) || eventsPath !== grokWorkerEventsPathFor(profilePath) || !profilePath.endsWith("/sandbox.toml"))
|
|
83
|
+
if (typeof agentId !== "string" || !agentId.trim() || (!v3 && seen.has(agentId)) || !Number.isSafeInteger(slot) || slot < 0 || slots.has(slot) || !Number.isSafeInteger(workerUid) || workerUid < 2200 || workers.has(workerUid) || !absolute(workspace) || !absolute(profilePath) || !absolute(eventsPath) || typeof profileSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(profileSha256) || eventsPath !== grokWorkerEventsPathFor(profilePath) || !profilePath.endsWith("/sandbox.toml"))
|
|
55
84
|
throw invalid();
|
|
56
85
|
seen.add(agentId);
|
|
57
86
|
slots.add(slot);
|
|
87
|
+
workers.add(workerUid);
|
|
58
88
|
const base = { agentId, slot: slot, workerUid: workerUid, workspace, profilePath, eventsPath, profileSha256 };
|
|
59
89
|
if (!v2)
|
|
60
90
|
return { ...base, usageLedgerPath: TURN_USAGE_LEDGER.filePath, limits: DEFAULT_GROK_BROKER_TURN_LIMITS, model: DEFAULT_GROK_BROKER_MODEL_POLICY };
|
|
61
|
-
const
|
|
91
|
+
const policy = v3 ? policies.get(slot) : entry;
|
|
92
|
+
if (policy === undefined)
|
|
93
|
+
throw invalid();
|
|
94
|
+
const usageLedgerPath = policy.usageLedgerPath;
|
|
62
95
|
if (!ledgerPath(usageLedgerPath) || usageLedgerPath === engineBrokerRequestLedgerPathFor(usageLedgerPath) || usageLedgerPath === engineBrokerSealLedgerPathFor(usageLedgerPath))
|
|
63
96
|
throw invalid();
|
|
97
|
+
const streams = [usageLedgerPath, engineBrokerRequestLedgerPathFor(usageLedgerPath), engineBrokerSealLedgerPathFor(usageLedgerPath)];
|
|
98
|
+
if (v3 && streams.some((file) => ledgers.has(file)))
|
|
99
|
+
throw invalid();
|
|
100
|
+
streams.forEach((file) => ledgers.add(file));
|
|
64
101
|
let limits;
|
|
65
102
|
try {
|
|
66
|
-
limits = parseEngineBrokerTurnLimits(
|
|
103
|
+
limits = parseEngineBrokerTurnLimits(policy.limits);
|
|
67
104
|
}
|
|
68
105
|
catch {
|
|
69
106
|
throw invalid();
|
|
70
107
|
}
|
|
71
|
-
|
|
108
|
+
if (Object.hasOwn(policy, "skillsSha256") && (typeof policy.skillsSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(policy.skillsSha256)))
|
|
109
|
+
throw invalid();
|
|
110
|
+
return { ...base, usageLedgerPath, limits, model: parseServiceModel(policy.model), ...(Object.hasOwn(policy, "skillsSha256") ? { skillsSha256: policy.skillsSha256 } : {}) };
|
|
72
111
|
});
|
|
73
|
-
const base = { credentialHome: value.credentialHome, turnStore: value.turnStore, registrations
|
|
112
|
+
const base = { credentialHome: value.credentialHome, turnStore: value.turnStore, registrations,
|
|
113
|
+
...(value.runRequestStore === undefined ? {} : { runRequestStore: value.runRequestStore }),
|
|
114
|
+
...(value.maxRunRequests === undefined ? {} : { maxRunRequests: value.maxRunRequests }) };
|
|
74
115
|
if (!Object.hasOwn(value, "inferenceLedgerPath"))
|
|
75
116
|
return base;
|
|
76
117
|
const inferenceLedgerPath = value.inferenceLedgerPath;
|
|
@@ -81,6 +122,7 @@ export function parseEngineBrokerServiceConfig(value) {
|
|
|
81
122
|
throw invalid();
|
|
82
123
|
return { ...base, inferenceLedgerPath };
|
|
83
124
|
}
|
|
125
|
+
const withSkills = (value) => Object.hasOwn(value, "skillsSha256") ? ["skillsSha256"] : [];
|
|
84
126
|
const ledgerPath = (item) => absolute(item) && item.endsWith(".jsonl") && path.posix.normalize(item) === item;
|
|
85
127
|
function parseServiceModel(value) {
|
|
86
128
|
if (!plain(value))
|
|
@@ -48,7 +48,7 @@ export declare class EngineBrokerTurnRegistry {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Strict record parser. v2 accepts exactly `{version,digest,state,bootId}`
|
|
51
|
-
* plus `response` and its sealed `ledger` bytes when terminal, and the response
|
|
51
|
+
* plus `response` and its sealed `ledger` bytes when terminal, and the response may be a v2, v3 or v4 terminal frame (older frames upgrade on read).
|
|
52
52
|
* v1 records keep their historical looser shape and are upgraded on read: no
|
|
53
53
|
* usage (`null`), zero requests, `limitReason: "none"`, the declared model.
|
|
54
54
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engineBrokerTurnRegistry.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerTurnRegistry.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"engineBrokerTurnRegistry.d.ts","sourceRoot":"","sources":["../../src/runtime/engineBrokerTurnRegistry.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmK,KAAK,mBAAmB,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AACzQ,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAwD,KAAK,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAE/H,KAAK,KAAK,GAAG,OAAO,CAAC,mBAAmB,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;AAClE,KAAK,QAAQ,GAAG,4BAA4B,CAAC;AAC7C,eAAO,MAAM,4BAA4B,EAAG,uCAAgD,CAAC;AAC7F,eAAO,MAAM,4BAA4B,EAAG,uCAAgD,CAAC;AAM7F,KAAK,QAAQ,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,OAAO,4BAA4B,GAAG,OAAO,4BAA4B,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,qBAAqB,CAAA;CAAE,CAAC,CAAC;AAEpO;;;;;GAKG;AACH,qBAAa,wBAAwB;IAEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAS,OAAO,CAAC,QAAQ,CAAC,MAAM;IAAqB,OAAO,CAAC,QAAQ,CAAC,eAAe;IADtH,yGAAyG;gBAC5E,IAAI,EAAE,MAAM,EAAkB,MAAM,GAAC,MAAmB,EAAkB,eAAe,GAAC,CAAC,SAAS,EAAC,MAAM,KAAG,OAAO,CAAC,IAAI,CAAe;IACtK,gGAAgG;IAC1F,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,GAAG;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,qBAAqB,CAAA;KAAE,CAAC;IAW3H;;;;;;;;;OASG;IACG,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAE,qBAAgD,GAAG,OAAO,CAAC,QAAQ,CAAC;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAO5J;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,QAAQ,CAyB1F"}
|
|
@@ -2,13 +2,14 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { mkdir, open, readFile, rename, unlink } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { parseEngineBrokerResponse, parseEngineBrokerV1TerminalResponse } from "./engineBrokerProtocol.js";
|
|
5
|
+
import { ENGINE_BROKER_VERSION, parseEngineBrokerResponse, parseEngineBrokerV1TerminalResponse, parseEngineBrokerV2TerminalResponse, parseEngineBrokerV3TerminalResponse } from "./engineBrokerProtocol.js";
|
|
6
6
|
import { EMPTY_BROKER_TURN_LEDGER, parseBrokerTurnLedgerLines } from "./grokEngineBrokerLedger.js";
|
|
7
7
|
export const ENGINE_BROKER_TURN_RECORD_V1 = "noopolis.daimon.engine-broker-turn.v1";
|
|
8
8
|
export const ENGINE_BROKER_TURN_RECORD_V2 = "noopolis.daimon.engine-broker-turn.v2";
|
|
9
9
|
// The digest deliberately excludes `limits` and the protocol version, so a v1
|
|
10
|
-
// record written before the upgrade still identifies the same turn.
|
|
11
|
-
|
|
10
|
+
// record written before the upgrade still identifies the same unclocked turn.
|
|
11
|
+
// A supplied process clock changes execution and must conflict with any other value.
|
|
12
|
+
const digest = (request) => createHash("sha256").update(JSON.stringify([request.turnId, request.agentId, request.wakeId, request.prompt, request.mcpEndpoint, ...(request.processClock === undefined ? [] : [request.processClock])])).digest("hex");
|
|
12
13
|
const safe = (turnId) => `${createHash("sha256").update(turnId).digest("hex")}.json`;
|
|
13
14
|
/**
|
|
14
15
|
* Durable per-turn state. Record v2 stores the terminal response *with* its
|
|
@@ -97,7 +98,7 @@ export class EngineBrokerTurnRegistry {
|
|
|
97
98
|
}
|
|
98
99
|
/**
|
|
99
100
|
* Strict record parser. v2 accepts exactly `{version,digest,state,bootId}`
|
|
100
|
-
* plus `response` and its sealed `ledger` bytes when terminal, and the response
|
|
101
|
+
* plus `response` and its sealed `ledger` bytes when terminal, and the response may be a v2, v3 or v4 terminal frame (older frames upgrade on read).
|
|
101
102
|
* v1 records keep their historical looser shape and are upgraded on read: no
|
|
102
103
|
* usage (`null`), zero requests, `limitReason: "none"`, the declared model.
|
|
103
104
|
*/
|
|
@@ -126,7 +127,7 @@ export function parseEngineBrokerTurnRecord(text, model) {
|
|
|
126
127
|
throw new Error("broker turn registry unavailable");
|
|
127
128
|
}
|
|
128
129
|
const accounting = { outcome: legacy.kind, usage: null, model, requests: 0, limitReason: "none" };
|
|
129
|
-
const response = { ...legacy, ...accounting, version:
|
|
130
|
+
const response = { ...legacy, ...accounting, version: ENGINE_BROKER_VERSION };
|
|
130
131
|
return { version: ENGINE_BROKER_TURN_RECORD_V1, ...base, response };
|
|
131
132
|
}
|
|
132
133
|
if (input.version !== ENGINE_BROKER_TURN_RECORD_V2)
|
|
@@ -138,7 +139,7 @@ export function parseEngineBrokerTurnRecord(text, model) {
|
|
|
138
139
|
return { version: ENGINE_BROKER_TURN_RECORD_V2, ...base };
|
|
139
140
|
let response;
|
|
140
141
|
try {
|
|
141
|
-
response = parseEngineBrokerResponse(input.response);
|
|
142
|
+
response = input.response?.version === "noopolis.daimon.engine-broker.v2" ? parseEngineBrokerV2TerminalResponse(input.response) : input.response?.version === "noopolis.daimon.engine-broker.v3" ? parseEngineBrokerV3TerminalResponse(input.response) : parseEngineBrokerResponse(input.response);
|
|
142
143
|
}
|
|
143
144
|
catch {
|
|
144
145
|
throw new Error("broker turn registry unavailable");
|
|
@@ -11,6 +11,8 @@ export declare function startOrganizationRuntimeEngine(agent: OrganizationRuntim
|
|
|
11
11
|
export declare function grokSandboxProtectedPaths(currentAgentId: string, organizationAgents: readonly OrganizationRuntimeAgentConfig[], sharedProtectedPaths?: readonly string[]): readonly string[];
|
|
12
12
|
export declare function codexSandboxProtectedPaths(currentAgentId: string, currentAgent: OrganizationRuntimeAgentConfig, currentEngineHomePath: string, organizationAgents: readonly OrganizationRuntimeAgentConfig[], sharedProtectedPaths?: readonly string[]): readonly string[];
|
|
13
13
|
export declare function codexSandboxReadablePaths(currentAgent: OrganizationRuntimeAgentConfig): readonly string[];
|
|
14
|
+
/** @internal The same callback used by the production session; no native process clock enters the engine environment. */
|
|
15
|
+
export declare function grokBrokerTurnFor(agent: OrganizationRuntimeAgentConfig, grokBroker: EngineBrokerTurnClient, wakeEnvironmentContext: import("../pi/piAgentWakeSupport.js").PiWakeEnvironmentContextRef): (prompt: string, endpoint: string, signal: AbortSignal) => Promise<string>;
|
|
14
16
|
/**
|
|
15
17
|
* CLI engines do not consume Pi's resource loader. Frame the same immutable
|
|
16
18
|
* identity in JSON so arbitrary names/instructions cannot change its shape.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engineDispatcher.d.ts","sourceRoot":"","sources":["../../src/runtime/engineDispatcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engineDispatcher.d.ts","sourceRoot":"","sources":["../../src/runtime/engineDispatcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAQpD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,wBAAwB,CAAC;AAE/E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAM7E;;;GAGG;AACH,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,8BAA8B,EACrC,eAAe,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,UAAU,CAAC,gCAAgC,CAAC,UAAU,CAAC,CAAC,EAChE,aAAa,CAAC,EAAE,MAAM,EACtB,UAAU,CAAC,EAAE,sBAAsB,EACnC,kBAAkB,CAAC,EAAE,SAAS,8BAA8B,EAAE,EAC9D,oBAAoB,GAAE,SAAS,MAAM,EAAO,EAC5C,SAAS,CAAC,EAAE,iBAAiB,GAC5B,OAAO,CAAC,WAAW,CAAC,CAiDtB;AAED,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,SAAS,8BAA8B,EAAE,EAC7D,oBAAoB,GAAE,SAAS,MAAM,EAAO,GAC3C,SAAS,MAAM,EAAE,CAYnB;AAED,wBAAgB,0BAA0B,CACxC,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,8BAA8B,EAC5C,qBAAqB,EAAE,MAAM,EAC7B,kBAAkB,EAAE,SAAS,8BAA8B,EAAE,EAC7D,oBAAoB,GAAE,SAAS,MAAM,EAAO,GAC3C,SAAS,MAAM,EAAE,CAQnB;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,8BAA8B,GAC3C,SAAS,MAAM,EAAE,CAEnB;AAkDD,yHAAyH;AACzH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,8BAA8B,EAAE,UAAU,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,OAAO,6BAA6B,EAAE,2BAA2B,IAG5L,QAAQ,MAAM,EAAE,UAAU,MAAM,EAAE,QAAQ,WAAW,qBAI9D;AAED;;;GAGG;AACH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,8BAA8B,EAAE,gBAAgB,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAkBxH"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { brokerProcessClock } from "./grokBrokerTaskClock.js";
|
|
2
|
+
import { reportEngineTaskClockGap } from "../pi/engineTaskClock.js";
|
|
1
3
|
import { attentionTools } from "./attention.js";
|
|
4
|
+
import { readTaskClock } from "./taskClock.js";
|
|
5
|
+
import { memoryClockOptions } from "../pi/memoryClock.js";
|
|
2
6
|
import { grokDaimonToolName, grokMountedToolNamingRule } from "../contracts/grokWorkerContract.js";
|
|
3
7
|
import path from "node:path";
|
|
4
8
|
import { AGY_MAX_TOOL_TURNS, createCliSessionFactory, resolveCodexWakeTimeoutMs, resolveCodexWakeTokenCeiling, resolveEngineWakeLimitOverrides } from "../pi/cliSession.js";
|
|
@@ -14,6 +18,10 @@ import { recordCodexTurnRequests } from "./turnRequestLedger.js";
|
|
|
14
18
|
* existing one-agent harness. Configuration never carries a command or env.
|
|
15
19
|
*/
|
|
16
20
|
export async function startOrganizationRuntimeEngine(agent, controlTokenEnv, paths, agyBusAddress, grokBroker, organizationAgents, sharedProtectedPaths = [], attention) {
|
|
21
|
+
const clock = readTaskClock();
|
|
22
|
+
reportEngineTaskClockGap(agent.engine.kind);
|
|
23
|
+
if (agent.memory !== undefined)
|
|
24
|
+
memoryClockOptions(clock);
|
|
17
25
|
// A declared Grok model is enforced by the broker proxy and worker config;
|
|
18
26
|
// the direct path has neither, so it refuses rather than silently ignoring it.
|
|
19
27
|
if (agent.engine.kind === "grok" && agent.engine.model !== undefined && grokBroker === undefined)
|
|
@@ -137,10 +145,14 @@ function adapterFor(agent, controlTokenEnv, verifyExecutable, executablePath, en
|
|
|
137
145
|
} : {}) });
|
|
138
146
|
return cliHarness(agent, sessionFactory, [controlTokenEnv], productionTools, wakeEnvironmentContext);
|
|
139
147
|
}
|
|
140
|
-
|
|
148
|
+
/** @internal The same callback used by the production session; no native process clock enters the engine environment. */
|
|
149
|
+
export function grokBrokerTurnFor(agent, grokBroker, wakeEnvironmentContext) {
|
|
141
150
|
const limits = resolveEngineWakeLimitOverrides();
|
|
142
151
|
const options = { ...(limits === undefined ? {} : { limits }), ...(agent.engine.model === undefined ? {} : { model: agent.engine.model }) };
|
|
143
|
-
return (prompt, endpoint, signal) =>
|
|
152
|
+
return (prompt, endpoint, signal) => {
|
|
153
|
+
const processClock = brokerProcessClock();
|
|
154
|
+
return grokBroker.turn(agent.id, wakeEnvironmentContext.current ?? "wake", prompt, endpoint, signal, { ...options, ...(processClock === undefined ? {} : { processClock }) });
|
|
155
|
+
};
|
|
144
156
|
}
|
|
145
157
|
/**
|
|
146
158
|
* CLI engines do not consume Pi's resource loader. Frame the same immutable
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
2
|
import { lstat, open, realpath, stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { spawn } from "
|
|
4
|
+
import { spawnRealTime as spawn } from "./taskClockProcess.js";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { cliChildEnvironment } from "../pi/cliEnvironment.js";
|
|
7
7
|
import { hasRefreshablePortableCredential, portableCredentialSecretValues } from "./portableCredentialAuth.js";
|
|
@@ -9,6 +9,7 @@ export declare class DurableGrokBrokerCredentialAuthority {
|
|
|
9
9
|
private staleWrite;
|
|
10
10
|
private lastDigest;
|
|
11
11
|
private generation;
|
|
12
|
+
private ancestorDigests;
|
|
12
13
|
constructor(command: string, home: string, authFile?: string);
|
|
13
14
|
initialize(): Promise<void>;
|
|
14
15
|
accessToken(forceRefresh: boolean): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerCredentialAuthority.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerCredentialAuthority.ts"],"names":[],"mappings":"AAUA,qBAAa,oCAAoC;
|
|
1
|
+
{"version":3,"file":"grokBrokerCredentialAuthority.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerCredentialAuthority.ts"],"names":[],"mappings":"AAUA,qBAAa,oCAAoC;IAGnC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAU,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFtG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAAC,OAAO,CAAC,KAAK,CAAS;IAAA,OAAO,CAAC,WAAW,CAAO;IAAA,OAAO,CAAC,UAAU,CAAyB;IAAA,OAAO,CAAC,UAAU,CAAkB;IAAA,OAAO,CAAC,UAAU,CAAG;IAClR,OAAO,CAAC,eAAe,CAAyB;gBACnB,OAAO,EAAE,MAAM,EAAmB,IAAI,EAAE,MAAM,EAAmB,QAAQ,SAA+B;IAC/H,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,WAAW,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD,qBAAqB,CAAC,mBAAmB,EAAC,MAAM,GAAE,OAAO,CAAC,MAAM,CAAC;IACvE,OAAO,CAAC,OAAO;IAYT,YAAY,CAAC,mBAAmB,CAAC,EAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9D,OAAO,IAAG,OAAO;IACjB,OAAO,CAAC,SAAS;YACH,KAAK;CAKpB"}
|
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { readGrokBrokerCredential } from "./grokBrokerCredentialReader.js";
|
|
7
7
|
import { refreshGrokBrokerCredential } from "./grokBrokerRefresh.js";
|
|
8
8
|
import { EngineBrokerGenerationFence, EngineBrokerSingleflight } from "./engineBrokerSingleflight.js";
|
|
9
|
-
import { parseBrokerCredentialJournal, recoverBrokerCredentialJournal } from "./engineBrokerCredentialJournal.js";
|
|
9
|
+
import { BROKER_CREDENTIAL_MAX_ANCESTORS, parseBrokerCredentialJournal, recoverBrokerCredentialJournal } from "./engineBrokerCredentialJournal.js";
|
|
10
10
|
export class DurableGrokBrokerCredentialAuthority {
|
|
11
11
|
command;
|
|
12
12
|
home;
|
|
@@ -18,33 +18,52 @@ export class DurableGrokBrokerCredentialAuthority {
|
|
|
18
18
|
staleWrite;
|
|
19
19
|
lastDigest;
|
|
20
20
|
generation = 0;
|
|
21
|
+
ancestorDigests = [];
|
|
21
22
|
constructor(command, home, authFile = path.join(home, "auth.json")) {
|
|
22
23
|
this.command = command;
|
|
23
24
|
this.home = home;
|
|
24
25
|
this.authFile = authFile;
|
|
25
26
|
}
|
|
26
|
-
async initialize() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
async initialize() {
|
|
28
|
+
if (this.initialized)
|
|
29
|
+
return;
|
|
30
|
+
const credential = await readGrokBrokerCredential(this.authFile);
|
|
31
|
+
this.lastDigest = credential.digest;
|
|
32
|
+
const file = path.join(this.home, ".daimon-broker", "credential-journal.json");
|
|
33
|
+
let handle;
|
|
34
|
+
try {
|
|
35
|
+
handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
36
|
+
const stat = await handle.stat();
|
|
37
|
+
if (!stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 0o777) !== 0o600 || stat.size > 65536)
|
|
38
|
+
throw unavailable();
|
|
39
|
+
const journal = parseBrokerCredentialJournal(JSON.parse(await handle.readFile("utf8")));
|
|
34
40
|
this.generation = journal.generation;
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
if (recoverBrokerCredentialJournal(journal, credential.digest) === "stale") {
|
|
42
|
+
await this.markStale();
|
|
43
|
+
throw unavailable();
|
|
44
|
+
}
|
|
45
|
+
this.ancestorDigests = [...new Set([...(journal.ancestorDigests ?? []), journal.sourceDigest])]
|
|
46
|
+
.filter((digest) => digest !== credential.digest);
|
|
47
|
+
if (journal.state === "refreshing") {
|
|
48
|
+
// The durable credential still matches the pre-exchange source. Settle
|
|
49
|
+
// before serving it so writeback and drain need no subsequent refresh.
|
|
50
|
+
// No exchange completed: preserve the generation and existing lineage.
|
|
51
|
+
await this.write({ state: "promoted", generation: journal.generation,
|
|
52
|
+
sourceDigest: credential.digest, promotedDigest: credential.digest });
|
|
53
|
+
}
|
|
54
|
+
this.fence.restore(journal.generation);
|
|
37
55
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
catch (error) {
|
|
57
|
+
// Only a missing journal on open is an unjournaled bootstrap. A failed
|
|
58
|
+
// recovery write (including ENOENT) must never publish readiness.
|
|
59
|
+
if (handle !== undefined || error.code !== "ENOENT")
|
|
60
|
+
throw unavailable();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await handle?.close().catch(() => undefined);
|
|
64
|
+
}
|
|
65
|
+
this.initialized = true;
|
|
44
66
|
}
|
|
45
|
-
finally {
|
|
46
|
-
await handle?.close().catch(() => undefined);
|
|
47
|
-
} this.initialized = true; }
|
|
48
67
|
async accessToken(forceRefresh) {
|
|
49
68
|
if (!this.initialized)
|
|
50
69
|
await this.initialize();
|
|
@@ -64,6 +83,11 @@ export class DurableGrokBrokerCredentialAuthority {
|
|
|
64
83
|
const before = await readGrokBrokerCredential(this.authFile);
|
|
65
84
|
if (rejectedTokenDigest !== undefined && createHash("sha256").update(before.accessToken).digest("hex") !== rejectedTokenDigest)
|
|
66
85
|
return before.accessToken;
|
|
86
|
+
// Never spend a refresh whose lineage cannot be persisted. Advancing expiry
|
|
87
|
+
// normally clears the history, so this bound applies to one expiry epoch.
|
|
88
|
+
const ancestors = [...new Set([...this.ancestorDigests, before.digest])];
|
|
89
|
+
if (ancestors.length > BROKER_CREDENTIAL_MAX_ANCESTORS)
|
|
90
|
+
throw unavailable();
|
|
67
91
|
try {
|
|
68
92
|
await this.write({ state: "refreshing", generation, sourceDigest: before.digest });
|
|
69
93
|
await refreshGrokBrokerCredential(this.command, this.home);
|
|
@@ -72,7 +96,9 @@ export class DurableGrokBrokerCredentialAuthority {
|
|
|
72
96
|
throw unavailable();
|
|
73
97
|
const next = this.fence.promote(generation);
|
|
74
98
|
this.generation = next;
|
|
75
|
-
|
|
99
|
+
const ancestorDigests = before.expiresAt !== undefined && after.expiresAt !== undefined && after.expiresAt > before.expiresAt ? [] : ancestors;
|
|
100
|
+
await this.write({ state: "promoted", generation: next, sourceDigest: before.digest, promotedDigest: after.digest, ancestorDigests });
|
|
101
|
+
this.ancestorDigests = ancestorDigests;
|
|
76
102
|
this.lastDigest = after.digest;
|
|
77
103
|
return after.accessToken;
|
|
78
104
|
}
|
|
@@ -100,7 +126,7 @@ export class DurableGrokBrokerCredentialAuthority {
|
|
|
100
126
|
const temporary = `${file}.${process.pid}.${randomUUID()}.tmp`;
|
|
101
127
|
const handle = await open(temporary, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
|
|
102
128
|
try {
|
|
103
|
-
await handle.writeFile(`${JSON.stringify({ version: "noopolis.daimon.broker-credential-journal.v1", ...value })}\n`);
|
|
129
|
+
await handle.writeFile(`${JSON.stringify({ version: "noopolis.daimon.broker-credential-journal.v1", ancestorDigests: this.ancestorDigests, ...value })}\n`);
|
|
104
130
|
await handle.sync();
|
|
105
131
|
}
|
|
106
132
|
finally {
|