@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,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from "
|
|
1
|
+
import { spawnRealTime as spawn } from "./taskClockProcess.js";
|
|
2
2
|
import { readChild } from "../pi/cliChildOutput.js";
|
|
3
3
|
import { terminateChild, trackCliChild } from "../pi/cliProcess.js";
|
|
4
4
|
export async function refreshGrokBrokerCredential(command, grokHome, timeoutMs = 15_000) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class GrokBrokerRunLimit extends Error {
|
|
2
|
+
constructor();
|
|
3
|
+
}
|
|
4
|
+
/** One broker realm lease owns this journal. Reserve durably BEFORE forwarding;
|
|
5
|
+
* failed calls and credential retries consume capacity, never refund it.
|
|
6
|
+
* Slot recycle must never remove this run-level file.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GrokBrokerRunBudget {
|
|
9
|
+
readonly maximum: number;
|
|
10
|
+
private readonly file;
|
|
11
|
+
private used;
|
|
12
|
+
private tail;
|
|
13
|
+
private failed;
|
|
14
|
+
private closed;
|
|
15
|
+
private constructor();
|
|
16
|
+
static open(maximum: number, file: string): Promise<GrokBrokerRunBudget>;
|
|
17
|
+
reserve(): Promise<void>;
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=grokBrokerRunBudget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokBrokerRunBudget.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerRunBudget.ts"],"names":[],"mappings":"AAIA,qBAAa,kBAAmB,SAAQ,KAAK;;CAE5C;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAIV,QAAQ,CAAC,OAAO,EAAE,MAAM;IAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAU,OAAO,CAAC,IAAI;IAHzF,OAAO,CAAC,IAAI,CAAoC;IAChD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO;WAEM,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAc9E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBlB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, open, readFile, rename, rm } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export class GrokBrokerRunLimit extends Error {
|
|
5
|
+
constructor() { super("run_request_limit"); }
|
|
6
|
+
}
|
|
7
|
+
/** One broker realm lease owns this journal. Reserve durably BEFORE forwarding;
|
|
8
|
+
* failed calls and credential retries consume capacity, never refund it.
|
|
9
|
+
* Slot recycle must never remove this run-level file.
|
|
10
|
+
*/
|
|
11
|
+
export class GrokBrokerRunBudget {
|
|
12
|
+
maximum;
|
|
13
|
+
file;
|
|
14
|
+
used;
|
|
15
|
+
tail = Promise.resolve();
|
|
16
|
+
failed = false;
|
|
17
|
+
closed = false;
|
|
18
|
+
constructor(maximum, file, used) {
|
|
19
|
+
this.maximum = maximum;
|
|
20
|
+
this.file = file;
|
|
21
|
+
this.used = used;
|
|
22
|
+
}
|
|
23
|
+
static async open(maximum, file) {
|
|
24
|
+
if (!Number.isSafeInteger(maximum) || maximum < 1)
|
|
25
|
+
throw new TypeError("invalid run request cap");
|
|
26
|
+
await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
27
|
+
let used = 0;
|
|
28
|
+
try {
|
|
29
|
+
const state = JSON.parse(await readFile(file, "utf8"));
|
|
30
|
+
if (state.schema !== "daimon.run-requests.v1" || state.maximum !== maximum ||
|
|
31
|
+
!Number.isSafeInteger(state.used) || state.used < 0 || state.used > maximum ||
|
|
32
|
+
Object.keys(state).length !== 3)
|
|
33
|
+
throw new Error("invalid run request checkpoint");
|
|
34
|
+
used = state.used;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error.code !== "ENOENT")
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
return new GrokBrokerRunBudget(maximum, file, used);
|
|
41
|
+
}
|
|
42
|
+
reserve() {
|
|
43
|
+
if (this.closed)
|
|
44
|
+
return Promise.reject(new Error("run request budget closed"));
|
|
45
|
+
const reservation = this.tail.then(async () => {
|
|
46
|
+
if (this.failed)
|
|
47
|
+
throw new Error("run request checkpoint unavailable");
|
|
48
|
+
if (this.used >= this.maximum)
|
|
49
|
+
throw new GrokBrokerRunLimit();
|
|
50
|
+
this.used += 1;
|
|
51
|
+
const temporary = `${this.file}.${randomUUID()}.tmp`;
|
|
52
|
+
try {
|
|
53
|
+
const handle = await open(temporary, "wx", 0o600);
|
|
54
|
+
try {
|
|
55
|
+
await handle.writeFile(JSON.stringify({ schema: "daimon.run-requests.v1", maximum: this.maximum, used: this.used }));
|
|
56
|
+
await handle.sync();
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await handle.close();
|
|
60
|
+
}
|
|
61
|
+
await rename(temporary, this.file);
|
|
62
|
+
const directory = await open(path.dirname(this.file), "r");
|
|
63
|
+
try {
|
|
64
|
+
await directory.sync();
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
await directory.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
this.failed = true;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
await rm(temporary, { force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this.tail = reservation.catch(() => undefined);
|
|
79
|
+
return reservation;
|
|
80
|
+
}
|
|
81
|
+
async close() {
|
|
82
|
+
this.closed = true;
|
|
83
|
+
await this.tail;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type GrokWorkerConfigVariant } from "../contracts/grokBrokerTaskClock.js";
|
|
2
|
+
/** Canonical path in both broker and worker views; never a caller-selected file. */
|
|
3
|
+
export declare function brokerTaskClockFileFor(slot: number): string;
|
|
4
|
+
/** The pinned strict base exposes /run; its deny mounts must hide every peer clock. */
|
|
5
|
+
export declare function assertBrokerTaskClockIsolation(variant: GrokWorkerConfigVariant, slot: number, slots: readonly number[], denyPaths: readonly string[]): void;
|
|
6
|
+
//# sourceMappingURL=grokBrokerSlot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokBrokerSlot.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerSlot.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE3G,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,uFAAuF;AACvF,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GACrG,IAAI,CAUN"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GROK_BROKER_TASK_CLOCK } from "../contracts/grokBrokerTaskClock.js";
|
|
2
|
+
/** Canonical path in both broker and worker views; never a caller-selected file. */
|
|
3
|
+
export function brokerTaskClockFileFor(slot) {
|
|
4
|
+
if (!Number.isSafeInteger(slot) || slot < 0)
|
|
5
|
+
throw new TypeError("invalid broker slot");
|
|
6
|
+
return `${GROK_BROKER_TASK_CLOCK.rootDirectoryPath}/slot-${slot}/faketime`;
|
|
7
|
+
}
|
|
8
|
+
/** The pinned strict base exposes /run; its deny mounts must hide every peer clock. */
|
|
9
|
+
export function assertBrokerTaskClockIsolation(variant, slot, slots, denyPaths) {
|
|
10
|
+
if (variant !== "clocked")
|
|
11
|
+
return;
|
|
12
|
+
const own = brokerTaskClockFileFor(slot);
|
|
13
|
+
const covers = (denied, file) => file === denied || file.startsWith(`${denied}/`);
|
|
14
|
+
if (denyPaths.some((denied) => covers(denied, own)))
|
|
15
|
+
throw new Error("own broker task clock is denied");
|
|
16
|
+
for (const peer of slots) {
|
|
17
|
+
if (peer !== slot && !denyPaths.some((denied) => covers(denied, brokerTaskClockFileFor(peer).slice(0, -"/faketime".length)))) {
|
|
18
|
+
throw new Error("sibling broker task clock is not denied");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Stats } from "node:fs";
|
|
2
|
+
import { type GrokWorkerConfigVariant } from "../contracts/grokBrokerTaskClock.js";
|
|
3
|
+
import type { GrokBrokerProviderClockObservation } from "./grokBrokerProviderClock.js";
|
|
4
|
+
import { type GrokWorkerConfigPins } from "./grokWorkerHomeAttestation.js";
|
|
5
|
+
/** Internal filesystem seam; tests wrap real handles to observe both fsyncs. */
|
|
6
|
+
export type BrokerTaskClockFs = Pick<typeof import("node:fs/promises"), "lstat" | "open" | "rename" | "unlink">;
|
|
7
|
+
export type BrokerShellClock = "task" | "real" | "gap";
|
|
8
|
+
export type BrokerShellClockObservation = Readonly<{
|
|
9
|
+
shellClock?: BrokerShellClock;
|
|
10
|
+
}>;
|
|
11
|
+
export type BrokerClockObservation = BrokerShellClockObservation & Readonly<{
|
|
12
|
+
providerClock?: GrokBrokerProviderClockObservation;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function brokerClockObservation(shellClock?: BrokerShellClock, providerClock?: GrokBrokerProviderClockObservation): BrokerClockObservation;
|
|
15
|
+
/** Relative seconds only: never a date, speed, loader path or arbitrary environment. */
|
|
16
|
+
export declare function parseBrokerProcessClock(value: unknown): string;
|
|
17
|
+
/** Daimon remains the offset owner; the broker uses its pinned library, not ambient preload. */
|
|
18
|
+
export declare function brokerProcessClock(): string | undefined;
|
|
19
|
+
/** Discovery only; selected slots still require full attestation before reconciliation. */
|
|
20
|
+
export declare function needsBrokerTaskClockReconciliation(profilePath: string, pins: GrokWorkerConfigPins, file?: string): Promise<boolean>;
|
|
21
|
+
/** Pure provisioning seam: only the broker can replace entries; every worker can read. */
|
|
22
|
+
export declare function assertBrokerTaskClockDirectory(entry: Pick<Stats, "uid" | "mode" | "isDirectory">, brokerUid?: number): void;
|
|
23
|
+
/**
|
|
24
|
+
* Root provisions a non-symlink broker-owned directory. Rename publishes a
|
|
25
|
+
* complete value before launch; binding the DIRECTORY (not the old file inode)
|
|
26
|
+
* into the worker view keeps subsequent turns visible. No native ABI changes.
|
|
27
|
+
* Paths/uid below are internal test seams, never control or service inputs.
|
|
28
|
+
*/
|
|
29
|
+
export declare function writeBrokerTaskClock(value: string | undefined, file?: string, brokerUid?: number, fs?: BrokerTaskClockFs): Promise<void>;
|
|
30
|
+
/** Unknown config is never called clocked: this runs only after byte attestation. */
|
|
31
|
+
export declare function prepareBrokerTaskClock(variant: GrokWorkerConfigVariant, value: string | undefined, write?: typeof writeBrokerTaskClock): Promise<BrokerShellClock>;
|
|
32
|
+
//# sourceMappingURL=grokBrokerTaskClock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokBrokerTaskClock.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTaskClock.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,KAAK,EAAE,MAAM,SAAS,CAAC;AAIhD,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE3G,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAA+B,KAAK,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAExG,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,cAAc,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAGhH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AACvD,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IAAE,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAAC;AACtF,MAAM,MAAM,sBAAsB,GAAG,2BAA2B,GAAG,QAAQ,CAAC;IAC1E,aAAa,CAAC,EAAE,kCAAkC,CAAC;CACpD,CAAC,CAAC;AAEH,wBAAgB,sBAAsB,CACpC,UAAU,CAAC,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,kCAAkC,GAChF,sBAAsB,CAKxB;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG9D;AAED,gGAAgG;AAChG,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD;AAED,2FAA2F;AAC3F,wBAAsB,kCAAkC,CACtD,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAC/C,IAAI,GAAE,MAAkC,GACvC,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAED,0FAA0F;AAC1F,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,aAAa,CAAC,EAAE,SAAS,GAAE,MAAwC,GAAG,IAAI,CAI5J;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,IAAI,GAAE,MAAkC,EACxC,SAAS,GAAE,MAAwC,EACnD,EAAE,GAAE,iBAA2B,GAC9B,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED,qFAAqF;AACrF,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,GAAE,OAAO,oBAA2C,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAS9L"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { brokerTaskClockFileFor } from "./grokBrokerSlot.js";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { constants } from "node:fs";
|
|
4
|
+
import { lstat, open, rename, unlink } from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { GROK_BROKER_TASK_CLOCK } from "../contracts/grokBrokerTaskClock.js";
|
|
7
|
+
import { readTaskClock, taskClockChildEnvironment } from "./taskClock.js";
|
|
8
|
+
import { assertGrokWorkerConfigBytes } from "./grokWorkerHomeAttestation.js";
|
|
9
|
+
const clockFs = { lstat, open, rename, unlink };
|
|
10
|
+
export function brokerClockObservation(shellClock, providerClock) {
|
|
11
|
+
return {
|
|
12
|
+
...(shellClock === undefined ? {} : { shellClock }),
|
|
13
|
+
...(providerClock === undefined ? {} : { providerClock })
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** Relative seconds only: never a date, speed, loader path or arbitrary environment. */
|
|
17
|
+
export function parseBrokerProcessClock(value) {
|
|
18
|
+
if (typeof value !== "string" || !/^[+-](?:0|[1-9][0-9]{0,12})(?:\.[0-9]{3})?$/u.test(value))
|
|
19
|
+
throw new TypeError("invalid broker process clock");
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
/** Daimon remains the offset owner; the broker uses its pinned library, not ambient preload. */
|
|
23
|
+
export function brokerProcessClock() {
|
|
24
|
+
const clock = readTaskClock();
|
|
25
|
+
clock?.now();
|
|
26
|
+
return taskClockChildEnvironment({}, clock, { LD_PRELOAD: GROK_BROKER_TASK_CLOCK.preloadPath }).FAKETIME;
|
|
27
|
+
}
|
|
28
|
+
/** Discovery only; selected slots still require full attestation before reconciliation. */
|
|
29
|
+
export async function needsBrokerTaskClockReconciliation(profilePath, pins, file = brokerTaskClockFileFor(0)) {
|
|
30
|
+
try {
|
|
31
|
+
// Even an unsafe directory entry must reach the fail-closed reconciliation.
|
|
32
|
+
await lstat(path.dirname(file));
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error.code !== "ENOENT")
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
let handle;
|
|
40
|
+
try {
|
|
41
|
+
handle = await open(path.join(path.dirname(profilePath), "config.toml"), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
42
|
+
const entry = await handle.stat();
|
|
43
|
+
if (!entry.isFile() || entry.size > 65_536)
|
|
44
|
+
return false;
|
|
45
|
+
return assertGrokWorkerConfigBytes(await handle.readFile(), pins) === "clocked";
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Missing or invalid unclocked provisioning is a per-turn attestation failure.
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
await handle?.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Pure provisioning seam: only the broker can replace entries; every worker can read. */
|
|
56
|
+
export function assertBrokerTaskClockDirectory(entry, brokerUid = GROK_BROKER_TASK_CLOCK.ownerUid) {
|
|
57
|
+
if (!entry.isDirectory() || entry.uid !== brokerUid || (entry.mode & 0o7777) !== GROK_BROKER_TASK_CLOCK.directoryMode) {
|
|
58
|
+
throw new Error("unsafe Grok broker task clock directory");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Root provisions a non-symlink broker-owned directory. Rename publishes a
|
|
63
|
+
* complete value before launch; binding the DIRECTORY (not the old file inode)
|
|
64
|
+
* into the worker view keeps subsequent turns visible. No native ABI changes.
|
|
65
|
+
* Paths/uid below are internal test seams, never control or service inputs.
|
|
66
|
+
*/
|
|
67
|
+
export async function writeBrokerTaskClock(value, file = brokerTaskClockFileFor(0), brokerUid = GROK_BROKER_TASK_CLOCK.ownerUid, fs = clockFs) {
|
|
68
|
+
const seconds = value === undefined ? "+0" : parseBrokerProcessClock(value);
|
|
69
|
+
const directory = path.dirname(file);
|
|
70
|
+
const before = await fs.lstat(directory);
|
|
71
|
+
assertBrokerTaskClockDirectory(before, brokerUid);
|
|
72
|
+
const parent = await fs.open(directory, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
|
|
73
|
+
const temporary = path.join(directory, `.faketime-${randomUUID()}.tmp`);
|
|
74
|
+
let created = false;
|
|
75
|
+
try {
|
|
76
|
+
const pinned = await parent.stat();
|
|
77
|
+
const verify = async () => {
|
|
78
|
+
const current = await fs.lstat(directory);
|
|
79
|
+
assertBrokerTaskClockDirectory(current, brokerUid);
|
|
80
|
+
if (current.dev !== pinned.dev || current.ino !== pinned.ino || before.dev !== pinned.dev || before.ino !== pinned.ino)
|
|
81
|
+
throw new Error("Grok broker task clock directory changed");
|
|
82
|
+
};
|
|
83
|
+
await verify();
|
|
84
|
+
const handle = await fs.open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, GROK_BROKER_TASK_CLOCK.fileMode);
|
|
85
|
+
created = true;
|
|
86
|
+
try {
|
|
87
|
+
const entry = await handle.stat();
|
|
88
|
+
if (entry.uid !== brokerUid || !entry.isFile() || entry.nlink !== 1)
|
|
89
|
+
throw new Error("unsafe Grok broker task clock file");
|
|
90
|
+
await handle.chmod(GROK_BROKER_TASK_CLOCK.fileMode); // restrictive broker umask must not hide the file from the worker
|
|
91
|
+
await handle.writeFile(`${seconds}\n`, "utf8");
|
|
92
|
+
await handle.sync();
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await handle.close();
|
|
96
|
+
}
|
|
97
|
+
await verify();
|
|
98
|
+
await fs.rename(temporary, file);
|
|
99
|
+
created = false;
|
|
100
|
+
await parent.sync();
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (created)
|
|
104
|
+
await fs.unlink(temporary).catch(() => undefined);
|
|
105
|
+
await parent.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Unknown config is never called clocked: this runs only after byte attestation. */
|
|
109
|
+
export async function prepareBrokerTaskClock(variant, value, write = writeBrokerTaskClock) {
|
|
110
|
+
if (value !== undefined)
|
|
111
|
+
parseBrokerProcessClock(value);
|
|
112
|
+
if (variant === "clocked") {
|
|
113
|
+
await write(value);
|
|
114
|
+
return value === undefined ? "real" : "task";
|
|
115
|
+
}
|
|
116
|
+
if (value === undefined)
|
|
117
|
+
return "real";
|
|
118
|
+
console.warn("daimon: task clock coverage gap engine=grok: attested broker worker config is unclocked; native tools remain on real time; wake allowed");
|
|
119
|
+
return "gap";
|
|
120
|
+
}
|
|
@@ -20,6 +20,27 @@ export type GrokBrokerTurnMeterSnapshot = Readonly<{
|
|
|
20
20
|
estimatedRequests: number;
|
|
21
21
|
timings: readonly GrokBrokerRequestTiming[];
|
|
22
22
|
}>;
|
|
23
|
+
/** The model's last answer when it called no tool: the turn's final reply, as the proxy saw it, and when it settled. */
|
|
24
|
+
export type GrokBrokerFinalReply = Readonly<{
|
|
25
|
+
index: number;
|
|
26
|
+
text: string;
|
|
27
|
+
at: number;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* The weight a cached prompt read carries against the token ceiling.
|
|
31
|
+
*
|
|
32
|
+
* The ceiling exists to bound spend, and a cached read is billed at a quarter
|
|
33
|
+
* of a fresh input token (xAI's published cached-input rate for the Grok 4
|
|
34
|
+
* family). Counting it at full weight made the ceiling a context-size limit
|
|
35
|
+
* instead: a writing or composing turn re-reads its whole conversation on
|
|
36
|
+
* every request, 85–90% of it from cache, and production turns died at a
|
|
37
|
+
* 1.1M "ceiling" having spent about a third of that. Fresh input, output and
|
|
38
|
+
* reasoning still count in full; the sealed usage and ledgers are unchanged
|
|
39
|
+
* and keep every cached token at its raw count.
|
|
40
|
+
*/
|
|
41
|
+
export declare const GROK_CACHED_INPUT_TOKEN_WEIGHT = 0.25;
|
|
42
|
+
/** What one request's usage costs against `maxTokens`: everything at full weight except cached reads. */
|
|
43
|
+
export declare const grokCeilingTokens: (usage: EngineBrokerTurnUsage) => number;
|
|
23
44
|
/**
|
|
24
45
|
* The proxy's per-turn spend gate.
|
|
25
46
|
*
|
|
@@ -33,8 +54,9 @@ export type GrokBrokerTurnMeterSnapshot = Readonly<{
|
|
|
33
54
|
* - `maxTokens`: checked against the running total of upstream-reported usage
|
|
34
55
|
* of the requests already answered. A request is admitted while that total is
|
|
35
56
|
* still below the ceiling, so the overshoot is bounded by exactly one
|
|
36
|
-
* request's usage — the last admitted one.
|
|
37
|
-
*
|
|
57
|
+
* request's usage — the last admitted one. Cached prompt reads count at
|
|
58
|
+
* {@link GROK_CACHED_INPUT_TOKEN_WEIGHT} ({@link grokCeilingTokens}); an
|
|
59
|
+
* uncached replay (P0 observed one at +55%) is fresh input and counts in full.
|
|
38
60
|
*
|
|
39
61
|
* The first limit that fires is sticky: every later request is refused with
|
|
40
62
|
* the same reason, and `onLimit` runs once.
|
|
@@ -58,6 +80,8 @@ export declare class GrokBrokerTurnMeter {
|
|
|
58
80
|
private tokens;
|
|
59
81
|
private reason;
|
|
60
82
|
private inFlight;
|
|
83
|
+
private final;
|
|
84
|
+
private activityAt;
|
|
61
85
|
constructor(limits: EngineBrokerTurnLimits, onLimit?: (reason: Exclude<EngineBrokerLimitReason, "none">) => void, now?: () => number);
|
|
62
86
|
/** Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight. */
|
|
63
87
|
admit(): Readonly<{
|
|
@@ -75,8 +99,20 @@ export declare class GrokBrokerTurnMeter {
|
|
|
75
99
|
* from the request body size, so a missing `usage` can never silently disable
|
|
76
100
|
* the token ceiling. `toolCalls` is observation only: it never affects
|
|
77
101
|
* admission, the running total, or any limit.
|
|
102
|
+
*
|
|
103
|
+
* `finalReply` is the answer text of a response that called no tool and
|
|
104
|
+
* stopped ({@link parseGrokFinalReply}). It is recorded only when the same
|
|
105
|
+
* response decoded to zero tool calls, and only for the request still the
|
|
106
|
+
* latest: it is what lets the broker end a turn whose worker has finished but
|
|
107
|
+
* not exited, and report finished work whose stdout the launcher refused.
|
|
78
108
|
*/
|
|
79
|
-
settle(index: number, usage: EngineBrokerTurnUsage | undefined, requestBytes: number, toolCalls?: readonly string[]): void;
|
|
109
|
+
settle(index: number, usage: EngineBrokerTurnUsage | undefined, requestBytes: number, toolCalls?: readonly string[], finalReply?: string): void;
|
|
110
|
+
/** The turn's final reply, while no later request has been admitted. */
|
|
111
|
+
finalReply(): GrokBrokerFinalReply | undefined;
|
|
112
|
+
/** Whether a model request is in flight right now. */
|
|
113
|
+
busy(): boolean;
|
|
114
|
+
/** When a model request last started or settled (the meter's construction before any). */
|
|
115
|
+
lastActivityAt(): number;
|
|
80
116
|
/** Trips a limit from outside the request path (the broker's wall-clock timer). */
|
|
81
117
|
trip(reason: Exclude<EngineBrokerLimitReason, "none">): void;
|
|
82
118
|
/** Aborts the in-flight upstream call, if any (limit trip, or the broker ending the turn). */
|
|
@@ -125,4 +161,20 @@ export declare const GROK_TOOL_CALL_TRUNCATED = "<truncated>";
|
|
|
125
161
|
* not a second attempt.
|
|
126
162
|
*/
|
|
127
163
|
export declare function parseGrokResponseToolNames(body: Uint8Array, contentType: string | undefined): readonly string[] | undefined;
|
|
164
|
+
/** The most of a final reply the broker reports; the rest is cut at a marker that says how much. */
|
|
165
|
+
export declare const GROK_FINAL_REPLY_MAX_BYTES: number;
|
|
166
|
+
/**
|
|
167
|
+
* The answer text of a response that *stopped*: every `delta.content` of a
|
|
168
|
+
* streamed response (or the `message.content` of a JSON one) in order, when
|
|
169
|
+
* some choice finished with `finish_reason: "stop"` and none with anything else.
|
|
170
|
+
*
|
|
171
|
+
* `undefined` means the response is not known to be final — undecodable, no
|
|
172
|
+
* finish reason, or one that asks for a tool. The caller additionally requires
|
|
173
|
+
* the same body to have decoded to zero tool calls. The text is bounded by
|
|
174
|
+
* {@link boundGrokFinalReply}, so a runaway answer can never make the turn's
|
|
175
|
+
* own report the thing that fails it.
|
|
176
|
+
*/
|
|
177
|
+
export declare function parseGrokFinalReply(body: Uint8Array, contentType: string | undefined): string | undefined;
|
|
178
|
+
/** `text` whole when it fits {@link GROK_FINAL_REPLY_MAX_BYTES}, else its head and a marker naming what was cut — never a failure. */
|
|
179
|
+
export declare function boundGrokFinalReply(text: string, maxBytes?: number): string;
|
|
128
180
|
//# sourceMappingURL=grokBrokerTurnMeter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerTurnMeter.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTurnMeter.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAElK;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AACxK,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,uBAAuB,CAAC;IAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAA;CAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"grokBrokerTurnMeter.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTurnMeter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
|
|
2
2
|
import { sumEngineBrokerTurnUsage } from "./engineBrokerTurnAccounting.js";
|
|
3
|
+
/**
|
|
4
|
+
* The weight a cached prompt read carries against the token ceiling.
|
|
5
|
+
*
|
|
6
|
+
* The ceiling exists to bound spend, and a cached read is billed at a quarter
|
|
7
|
+
* of a fresh input token (xAI's published cached-input rate for the Grok 4
|
|
8
|
+
* family). Counting it at full weight made the ceiling a context-size limit
|
|
9
|
+
* instead: a writing or composing turn re-reads its whole conversation on
|
|
10
|
+
* every request, 85–90% of it from cache, and production turns died at a
|
|
11
|
+
* 1.1M "ceiling" having spent about a third of that. Fresh input, output and
|
|
12
|
+
* reasoning still count in full; the sealed usage and ledgers are unchanged
|
|
13
|
+
* and keep every cached token at its raw count.
|
|
14
|
+
*/
|
|
15
|
+
export const GROK_CACHED_INPUT_TOKEN_WEIGHT = 0.25;
|
|
16
|
+
/** What one request's usage costs against `maxTokens`: everything at full weight except cached reads. */
|
|
17
|
+
export const grokCeilingTokens = (usage) => usage.total - usage.cacheRead + Math.ceil(usage.cacheRead * GROK_CACHED_INPUT_TOKEN_WEIGHT);
|
|
3
18
|
/**
|
|
4
19
|
* The proxy's per-turn spend gate.
|
|
5
20
|
*
|
|
@@ -13,8 +28,9 @@ import { sumEngineBrokerTurnUsage } from "./engineBrokerTurnAccounting.js";
|
|
|
13
28
|
* - `maxTokens`: checked against the running total of upstream-reported usage
|
|
14
29
|
* of the requests already answered. A request is admitted while that total is
|
|
15
30
|
* still below the ceiling, so the overshoot is bounded by exactly one
|
|
16
|
-
* request's usage — the last admitted one.
|
|
17
|
-
*
|
|
31
|
+
* request's usage — the last admitted one. Cached prompt reads count at
|
|
32
|
+
* {@link GROK_CACHED_INPUT_TOKEN_WEIGHT} ({@link grokCeilingTokens}); an
|
|
33
|
+
* uncached replay (P0 observed one at +55%) is fresh input and counts in full.
|
|
18
34
|
*
|
|
19
35
|
* The first limit that fires is sticky: every later request is refused with
|
|
20
36
|
* the same reason, and `onLimit` runs once.
|
|
@@ -38,11 +54,14 @@ export class GrokBrokerTurnMeter {
|
|
|
38
54
|
tokens = 0;
|
|
39
55
|
reason = "none";
|
|
40
56
|
inFlight;
|
|
57
|
+
final;
|
|
58
|
+
activityAt;
|
|
41
59
|
constructor(limits, onLimit = () => undefined, now = Date.now) {
|
|
42
60
|
this.limits = limits;
|
|
43
61
|
this.onLimit = onLimit;
|
|
44
62
|
this.now = now;
|
|
45
63
|
this.startedAt = now();
|
|
64
|
+
this.activityAt = this.startedAt;
|
|
46
65
|
}
|
|
47
66
|
/** Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight. */
|
|
48
67
|
admit() {
|
|
@@ -59,6 +78,9 @@ export class GrokBrokerTurnMeter {
|
|
|
59
78
|
if (this.inFlight !== undefined)
|
|
60
79
|
return { busy: true };
|
|
61
80
|
this.timings.push({ startedAt: new Date(this.now()).toISOString() });
|
|
81
|
+
// A new request means the previous answer was not the last one.
|
|
82
|
+
this.final = undefined;
|
|
83
|
+
this.activityAt = this.now();
|
|
62
84
|
const controller = new AbortController();
|
|
63
85
|
this.inFlight = { index: this.timings.length - 1, controller };
|
|
64
86
|
return { index: this.inFlight.index, signal: controller.signal };
|
|
@@ -70,8 +92,14 @@ export class GrokBrokerTurnMeter {
|
|
|
70
92
|
* from the request body size, so a missing `usage` can never silently disable
|
|
71
93
|
* the token ceiling. `toolCalls` is observation only: it never affects
|
|
72
94
|
* admission, the running total, or any limit.
|
|
95
|
+
*
|
|
96
|
+
* `finalReply` is the answer text of a response that called no tool and
|
|
97
|
+
* stopped ({@link parseGrokFinalReply}). It is recorded only when the same
|
|
98
|
+
* response decoded to zero tool calls, and only for the request still the
|
|
99
|
+
* latest: it is what lets the broker end a turn whose worker has finished but
|
|
100
|
+
* not exited, and report finished work whose stdout the launcher refused.
|
|
73
101
|
*/
|
|
74
|
-
settle(index, usage, requestBytes, toolCalls) {
|
|
102
|
+
settle(index, usage, requestBytes, toolCalls, finalReply) {
|
|
75
103
|
const timing = this.timings[index];
|
|
76
104
|
if (timing === undefined || timing.endedAt !== undefined)
|
|
77
105
|
return;
|
|
@@ -86,8 +114,17 @@ export class GrokBrokerTurnMeter {
|
|
|
86
114
|
timing.usage = usage;
|
|
87
115
|
if (toolCalls !== undefined)
|
|
88
116
|
timing.toolCalls = toolCalls;
|
|
89
|
-
this.tokens += timing.usage
|
|
117
|
+
this.tokens += grokCeilingTokens(timing.usage);
|
|
118
|
+
this.activityAt = this.now();
|
|
119
|
+
if (finalReply !== undefined && toolCalls !== undefined && toolCalls.length === 0 && index === this.timings.length - 1)
|
|
120
|
+
this.final = { index, text: finalReply, at: this.activityAt };
|
|
90
121
|
}
|
|
122
|
+
/** The turn's final reply, while no later request has been admitted. */
|
|
123
|
+
finalReply() { return this.final; }
|
|
124
|
+
/** Whether a model request is in flight right now. */
|
|
125
|
+
busy() { return this.inFlight !== undefined; }
|
|
126
|
+
/** When a model request last started or settled (the meter's construction before any). */
|
|
127
|
+
lastActivityAt() { return this.activityAt; }
|
|
91
128
|
/** Trips a limit from outside the request path (the broker's wall-clock timer). */
|
|
92
129
|
trip(reason) {
|
|
93
130
|
if (this.reason !== "none")
|
|
@@ -232,6 +269,55 @@ export function parseGrokResponseToolNames(body, contentType) {
|
|
|
232
269
|
}
|
|
233
270
|
return names.length > GROK_REQUEST_TOOL_CALLS_MAX ? [...names.slice(0, GROK_REQUEST_TOOL_CALLS_MAX - 1), GROK_TOOL_CALL_TRUNCATED] : names;
|
|
234
271
|
}
|
|
272
|
+
/** The most of a final reply the broker reports; the rest is cut at a marker that says how much. */
|
|
273
|
+
export const GROK_FINAL_REPLY_MAX_BYTES = 64 * 1024;
|
|
274
|
+
/**
|
|
275
|
+
* The answer text of a response that *stopped*: every `delta.content` of a
|
|
276
|
+
* streamed response (or the `message.content` of a JSON one) in order, when
|
|
277
|
+
* some choice finished with `finish_reason: "stop"` and none with anything else.
|
|
278
|
+
*
|
|
279
|
+
* `undefined` means the response is not known to be final — undecodable, no
|
|
280
|
+
* finish reason, or one that asks for a tool. The caller additionally requires
|
|
281
|
+
* the same body to have decoded to zero tool calls. The text is bounded by
|
|
282
|
+
* {@link boundGrokFinalReply}, so a runaway answer can never make the turn's
|
|
283
|
+
* own report the thing that fails it.
|
|
284
|
+
*/
|
|
285
|
+
export function parseGrokFinalReply(body, contentType) {
|
|
286
|
+
const candidates = decodeUpstreamResponse(body, contentType);
|
|
287
|
+
if (candidates === undefined)
|
|
288
|
+
return undefined;
|
|
289
|
+
let text = "", stopped = false;
|
|
290
|
+
for (const candidate of candidates) {
|
|
291
|
+
if (!isRecord(candidate) || !Array.isArray(candidate.choices))
|
|
292
|
+
continue;
|
|
293
|
+
for (const choice of candidate.choices) {
|
|
294
|
+
if (!isRecord(choice))
|
|
295
|
+
continue;
|
|
296
|
+
for (const source of [choice.delta, choice.message])
|
|
297
|
+
if (isRecord(source) && typeof source.content === "string")
|
|
298
|
+
text += source.content;
|
|
299
|
+
// Only `stop` is a finished answer: `length` was cut off mid-answer and
|
|
300
|
+
// `content_filter` withheld it, so neither is work done.
|
|
301
|
+
if (typeof choice.finish_reason === "string" && choice.finish_reason.length > 0) {
|
|
302
|
+
if (choice.finish_reason !== "stop")
|
|
303
|
+
return undefined;
|
|
304
|
+
stopped = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return stopped ? boundGrokFinalReply(text) : undefined;
|
|
309
|
+
}
|
|
310
|
+
/** `text` whole when it fits {@link GROK_FINAL_REPLY_MAX_BYTES}, else its head and a marker naming what was cut — never a failure. */
|
|
311
|
+
export function boundGrokFinalReply(text, maxBytes = GROK_FINAL_REPLY_MAX_BYTES) {
|
|
312
|
+
const bytes = Buffer.byteLength(text, "utf8");
|
|
313
|
+
if (bytes <= maxBytes)
|
|
314
|
+
return text;
|
|
315
|
+
const marker = (cut) => `\n[… ${cut} bytes truncated by the Daimon broker …]`;
|
|
316
|
+
const budget = Math.max(0, maxBytes - Buffer.byteLength(marker(bytes)));
|
|
317
|
+
// Cut on a code point: a byte-counted window must not leave half a character behind.
|
|
318
|
+
const head = new TextDecoder("utf-8", { fatal: false }).decode(Buffer.from(text, "utf8").subarray(0, budget)).replace(/\uFFFD$/u, "");
|
|
319
|
+
return `${head}${marker(bytes - Buffer.byteLength(head, "utf8"))}`;
|
|
320
|
+
}
|
|
235
321
|
function decodeOpenAiUsage(usage) {
|
|
236
322
|
const prompt = count(usage.prompt_tokens), completion = count(usage.completion_tokens);
|
|
237
323
|
if (prompt === undefined || completion === undefined)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type GrokWorkerConfigVariant } from "../contracts/grokBrokerTaskClock.js";
|
|
1
2
|
import { type GrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
|
|
2
3
|
export { DAIMON_GROK_SYSTEM_PROMPT, GROK_WORKER_MAX_TURNS, GROK_WORKER_TOOL_IDS, GROK_WORKER_VISIBLE_TOOLS } from "../contracts/grokWorkerContract.js";
|
|
3
4
|
/**
|
|
@@ -74,10 +75,12 @@ export declare const renderGrokLeanBaseConfig: () => string;
|
|
|
74
75
|
* default *and* its closed enum, so it reaches the request body and nothing
|
|
75
76
|
* else can be selected; the proxy then re-verifies it on every body.
|
|
76
77
|
*/
|
|
77
|
-
export declare function renderGrokBrokerWorkerConfig(policy?: Partial<GrokBrokerModelPolicy
|
|
78
|
+
export declare function renderGrokBrokerWorkerConfig(policy?: Partial<GrokBrokerModelPolicy>, variant?: GrokWorkerConfigVariant, slot?: number): string;
|
|
78
79
|
/** Explicit-endpoint variant for the local live probe; production bytes come only from the function above. */
|
|
79
80
|
export declare function renderGrokBrokerWorkerConfigWith(policy: GrokBrokerModelPolicy, endpoints: WorkerEndpoints): string;
|
|
80
|
-
export declare const grokBrokerWorkerConfigSha256: (policy?: Partial<GrokBrokerModelPolicy
|
|
81
|
+
export declare const grokBrokerWorkerConfigSha256: (policy?: Partial<GrokBrokerModelPolicy>, variant?: GrokWorkerConfigVariant, slot?: number) => string;
|
|
82
|
+
/** Validate the slot-zero template pin before deriving bytes for another canonical slot path. */
|
|
83
|
+
export declare function grokBrokerWorkerConfigPins(policy: GrokBrokerModelPolicy, slot?: number): Readonly<Record<GrokWorkerConfigVariant, string>>;
|
|
81
84
|
/**
|
|
82
85
|
* TypeScript mirror of the argv compiled into `native/engineBrokerLauncherCore.inc`.
|
|
83
86
|
* `native/launcherArgv.test.ts` parses the C source and fails on any divergence.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerWorkerConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerWorkerConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grokBrokerWorkerConfig.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerWorkerConfig.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAK3G,OAAO,EAA8B,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEpG,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAEvJ;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,gaAK5B,CAAC;AAEZ,wFAAwF;AACxF,eAAO,MAAM,2BAA2B,EAAG,oBAA6B,CAAC;AAEzE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gCAAgC,EAAG,+BAAwC,CAAC;AACzF,eAAO,MAAM,2BAA2B,EAAG,wBAAiC,CAAC;AAM7E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mCAAmC,EAAG,4BAAqC,CAAC;AAEzF,KAAK,eAAe,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAMvE;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,QAAO,MAQhC,CAAC;AAEb;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,OAAO,CAAC,qBAAqB,CAAM,EAAE,OAAO,GAAE,uBAAqC,EAAE,IAAI,SAAI,GAAG,MAAM,CAS1J;AAED,8GAA8G;AAC9G,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,qBAAqB,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAgBlH;AAED,eAAO,MAAM,4BAA4B,GAAI,SAAQ,OAAO,CAAC,qBAAqB,CAAM,EAAE,UAAS,uBAAqC,EAAE,aAAQ,KAAG,MACrD,CAAC;AAEjG,iGAAiG;AACjG,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,qBAAqB,EAAE,IAAI,SAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,CAKrI;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,YAAY,MAAM,EAAE,KAAK,MAAM,KAAG,SAAS,MAAM,EAU3F,CAAC"}
|