@noopolis/daimon 0.2.0 → 0.2.1
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/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 +5 -0
- package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -1
- package/dist/runtime/engineBrokerServiceConfig.js +47 -9
- 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 +9 -1
- package/dist/runtime/grokBrokerProjection.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProjection.js +11 -4
- 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 +9 -4
- package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerAttestation.js +2 -2
- package/dist/runtime/grokWorkerHomeAttestation.d.ts +4 -2
- package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -1
- package/dist/runtime/grokWorkerHomeAttestation.js +10 -4
- package/dist/runtime/index.d.ts +7 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +5 -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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { parseBrokerProcessClock } from "./grokBrokerTaskClock.js";
|
|
2
|
+
import { parseGrokBrokerProxyJson } from "./grokBrokerProxyJson.js";
|
|
3
|
+
export class GrokBrokerProviderClockRefusal extends Error {
|
|
4
|
+
reason;
|
|
5
|
+
constructor(reason) {
|
|
6
|
+
super(`grok broker proxy refused: ${reason}`);
|
|
7
|
+
this.reason = reason;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const DATE = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/u;
|
|
11
|
+
const DATE_LINE = /^Today's date: ([0-9]{4}-[0-9]{2}-[0-9]{2})$/u;
|
|
12
|
+
const DATE_LIKE = /today['’]?s\s+date\b/iu;
|
|
13
|
+
const MAX_TASK_MS = 253_402_300_799_999;
|
|
14
|
+
/** One processClock, owned by one turn; never reads the broker's ambient TZ. */
|
|
15
|
+
export class GrokBrokerProviderClock {
|
|
16
|
+
now;
|
|
17
|
+
offsetMs;
|
|
18
|
+
observation = {
|
|
19
|
+
requests: 0, linesRewritten: 0, requestsWithoutDateLine: 0, linesIgnored: 0,
|
|
20
|
+
injectedDate: null, taskDate: null
|
|
21
|
+
};
|
|
22
|
+
constructor(processClock, now = () => Date.now()) {
|
|
23
|
+
this.now = now;
|
|
24
|
+
this.offsetMs = Math.round(Number(parseBrokerProcessClock(processClock)) * 1000);
|
|
25
|
+
}
|
|
26
|
+
rewrite(body) {
|
|
27
|
+
this.observation = { ...this.observation, requests: this.observation.requests + 1 };
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = parseGrokBrokerProxyJson(body);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
throw new GrokBrokerProviderClockRefusal("request_body_rejected");
|
|
34
|
+
}
|
|
35
|
+
const taskMs = this.now() + this.offsetMs;
|
|
36
|
+
if (!Number.isSafeInteger(taskMs) || taskMs < 0 || taskMs > MAX_TASK_MS) {
|
|
37
|
+
throw new GrokBrokerProviderClockRefusal("task_clock_date_range");
|
|
38
|
+
}
|
|
39
|
+
// The native launcher pins TZ=UTC. Compute once per request, including
|
|
40
|
+
// history resends; a long turn may cross midnight between requests.
|
|
41
|
+
const taskDate = new Date(taskMs).toISOString().slice(0, 10);
|
|
42
|
+
let lines = 0;
|
|
43
|
+
let ignored = 0;
|
|
44
|
+
let injectedDate = null;
|
|
45
|
+
const countIgnored = (text) => text.split(/\r\n|\r|\n/u).filter((line) => DATE_LIKE.test(line)).length;
|
|
46
|
+
const rewriteText = (text, injected) => {
|
|
47
|
+
const block = injected ? /<user_info>([\s\S]*?)<\/user_info>/u.exec(text) : null;
|
|
48
|
+
if (block === null) {
|
|
49
|
+
ignored += countIgnored(text);
|
|
50
|
+
return text;
|
|
51
|
+
}
|
|
52
|
+
const before = text.slice(0, block.index), after = text.slice(block.index + block[0].length);
|
|
53
|
+
ignored += countIgnored(before) + countIgnored(after);
|
|
54
|
+
const rewritten = block[1].split(/(\r\n|\r|\n)/u).map((line) => {
|
|
55
|
+
if (!DATE_LIKE.test(line))
|
|
56
|
+
return line;
|
|
57
|
+
const match = DATE_LINE.exec(line);
|
|
58
|
+
if (match === null)
|
|
59
|
+
throw new GrokBrokerProviderClockRefusal("task_clock_date_format");
|
|
60
|
+
lines++;
|
|
61
|
+
injectedDate = match[1];
|
|
62
|
+
return `Today's date: ${taskDate}`;
|
|
63
|
+
}).join("");
|
|
64
|
+
return `${before}<user_info>${rewritten}</user_info>${after}`;
|
|
65
|
+
};
|
|
66
|
+
if (Array.isArray(parsed.value.messages)) {
|
|
67
|
+
let firstUser = true;
|
|
68
|
+
for (const message of parsed.value.messages) {
|
|
69
|
+
if (!isRecord(message))
|
|
70
|
+
continue;
|
|
71
|
+
const injected = message.role === "user" && firstUser;
|
|
72
|
+
if (message.role === "user")
|
|
73
|
+
firstUser = false;
|
|
74
|
+
if (typeof message.content === "string") {
|
|
75
|
+
message.content = rewriteText(message.content, injected);
|
|
76
|
+
}
|
|
77
|
+
else if (Array.isArray(message.content)) {
|
|
78
|
+
const parts = message.content.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string");
|
|
79
|
+
// A block or date can straddle text parts. Replacements have exactly
|
|
80
|
+
// the same width, so slicing restores every original part boundary.
|
|
81
|
+
const rewritten = rewriteText(parts.map((part) => part.text).join(""), injected);
|
|
82
|
+
let start = 0;
|
|
83
|
+
for (const part of parts) {
|
|
84
|
+
const end = start + part.text.length;
|
|
85
|
+
part.text = rewritten.slice(start, end);
|
|
86
|
+
start = end;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Commit only after the entire body passes: a refused request rewrites no
|
|
92
|
+
// lines upstream, even when an earlier line had the recognized format.
|
|
93
|
+
this.observation = {
|
|
94
|
+
requests: this.observation.requests,
|
|
95
|
+
linesRewritten: this.observation.linesRewritten + lines,
|
|
96
|
+
requestsWithoutDateLine: this.observation.requestsWithoutDateLine + (lines === 0 ? 1 : 0),
|
|
97
|
+
linesIgnored: (this.observation.linesIgnored ?? 0) + ignored,
|
|
98
|
+
injectedDate: lines === 0 ? this.observation.injectedDate : injectedDate,
|
|
99
|
+
taskDate: lines === 0 ? this.observation.taskDate : taskDate
|
|
100
|
+
};
|
|
101
|
+
return lines === 0 ? parsed.body : Buffer.from(JSON.stringify(parsed.value));
|
|
102
|
+
}
|
|
103
|
+
snapshot() {
|
|
104
|
+
return { ...this.observation };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
108
|
+
/** Closed, dates-only observation on the v3 terminal frame and durable seal. */
|
|
109
|
+
export function parseGrokBrokerProviderClockObservation(value) {
|
|
110
|
+
if (!isRecord(value))
|
|
111
|
+
throw new TypeError("invalid broker frame");
|
|
112
|
+
const fields = ["requests", "linesRewritten", "requestsWithoutDateLine", "injectedDate", "taskDate"];
|
|
113
|
+
if (Object.keys(value).some((key) => !fields.includes(key) && key !== "linesIgnored") ||
|
|
114
|
+
fields.some((key) => !Object.hasOwn(value, key))) {
|
|
115
|
+
throw new TypeError("invalid broker frame");
|
|
116
|
+
}
|
|
117
|
+
for (const key of [...fields.slice(0, 3), ...(Object.hasOwn(value, "linesIgnored") ? ["linesIgnored"] : [])]) {
|
|
118
|
+
if (!Number.isSafeInteger(value[key]) || value[key] < 0) {
|
|
119
|
+
throw new TypeError("invalid broker frame");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const result = value;
|
|
123
|
+
if (result.requestsWithoutDateLine > result.requests ||
|
|
124
|
+
(result.linesRewritten > 0 && result.requestsWithoutDateLine === result.requests)) {
|
|
125
|
+
throw new TypeError("invalid broker frame");
|
|
126
|
+
}
|
|
127
|
+
for (const date of [result.injectedDate, result.taskDate]) {
|
|
128
|
+
if (result.linesRewritten === 0 ? date !== null : typeof date !== "string" || !DATE.test(date)) {
|
|
129
|
+
throw new TypeError("invalid broker frame");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { ...result };
|
|
133
|
+
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { type GrokBrokerRunBudget } from "./grokBrokerRunBudget.js";
|
|
2
|
+
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
1
3
|
import { EngineBrokerCapabilities } from "./engineBrokerCapabilities.js";
|
|
2
4
|
import { type GrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
|
|
3
5
|
import { authorizeGrokBrokerProxyRequest } from "./grokBrokerProxyRequest.js";
|
|
4
6
|
import { type GrokBrokerTurnMeter } from "./grokBrokerTurnMeter.js";
|
|
5
7
|
import type { GrokInferenceGrants } from "./grokInferenceGrants.js";
|
|
8
|
+
import { type GrokBrokerProviderClock } from "./grokBrokerProviderClock.js";
|
|
6
9
|
/** One running turn as the proxy sees it: its declared model/effort and its spend gate. */
|
|
7
10
|
export type GrokBrokerProxyTurn = Readonly<{
|
|
8
11
|
policy: GrokBrokerModelPolicy;
|
|
9
12
|
meter: GrokBrokerTurnMeter;
|
|
13
|
+
clock?: GrokBrokerProviderClock;
|
|
10
14
|
}>;
|
|
11
15
|
export type GrokBrokerCredentialAuthority = Readonly<{
|
|
12
16
|
accessToken(forceRefresh: boolean): Promise<string>;
|
|
@@ -30,15 +34,25 @@ export type GrokBrokerUpstream = (request: ReturnType<typeof authorizeGrokBroker
|
|
|
30
34
|
* `grokInferenceProxy.ts`; every other bearer is looked up only among turn
|
|
31
35
|
* capabilities. Without `grants` a prefixed bearer is simply refused.
|
|
32
36
|
*/
|
|
33
|
-
export declare function startGrokBrokerProxy(authority: GrokBrokerCredentialAuthority, upstream?: GrokBrokerUpstream, policy?: GrokBrokerModelPolicy, listenPort?: number, grants?: GrokInferenceGrants): Promise<
|
|
37
|
+
export declare function startGrokBrokerProxy(authority: GrokBrokerCredentialAuthority, upstream?: GrokBrokerUpstream, policy?: GrokBrokerModelPolicy, listenPort?: number, grants?: GrokInferenceGrants, runBudget?: GrokBrokerRunBudget): Promise<{
|
|
34
38
|
port: number;
|
|
39
|
+
close: () => Promise<void>;
|
|
35
40
|
capabilities: EngineBrokerCapabilities;
|
|
36
41
|
registerIsolationGuard(turnId: string, guard: () => Promise<void>): void;
|
|
37
42
|
revokeIsolationGuard(turnId: string): void;
|
|
38
43
|
registerTurn(turnId: string, turn: GrokBrokerProxyTurn): void;
|
|
39
44
|
revokeTurn(turnId: string): void;
|
|
40
|
-
|
|
41
|
-
}
|
|
45
|
+
serve: (request: IncomingMessage, response: ServerResponse) => Promise<void>;
|
|
46
|
+
}>;
|
|
47
|
+
/** @internal The production request handler, usable without opening a socket. */
|
|
48
|
+
export declare function createGrokBrokerProxyHandler(authority: GrokBrokerCredentialAuthority, upstream?: GrokBrokerUpstream, policy?: GrokBrokerModelPolicy, grants?: GrokInferenceGrants, runBudget?: GrokBrokerRunBudget): {
|
|
49
|
+
capabilities: EngineBrokerCapabilities;
|
|
50
|
+
registerIsolationGuard(turnId: string, guard: () => Promise<void>): void;
|
|
51
|
+
revokeIsolationGuard(turnId: string): void;
|
|
52
|
+
registerTurn(turnId: string, turn: GrokBrokerProxyTurn): void;
|
|
53
|
+
revokeTurn(turnId: string): void;
|
|
54
|
+
serve: (request: IncomingMessage, response: ServerResponse) => Promise<void>;
|
|
55
|
+
};
|
|
42
56
|
/**
|
|
43
57
|
* A refusal the caller must not retry.
|
|
44
58
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerProxy.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grokBrokerProxy.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAIpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,OAAO,EAAgE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACtI,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAE9E,OAAO,EAA2E,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG7I,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAkC,KAAK,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE5G,2FAA2F;AAC3F,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IAAE,WAAW,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,qBAAqB,CAAC,CAAC,mBAAmB,EAAC,MAAM,GAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,CAAC,mBAAmB,CAAC,EAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,OAAO,CAAC,IAAI,OAAO,CAAA;CAAE,CAAC,CAAC;AACjQ,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,+BAA+B,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC,CAAC;AAE3N;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,6BAA6B,EAAE,QAAQ,GAAE,kBAAoC,EACxF,MAAM,GAAE,qBAAwD,EAAE,UAAU,SAAS,EACrF,MAAM,CAAC,EAAE,mBAAmB,EAAE,SAAS,CAAC,EAAE,mBAAmB;;;;mCAoC5B,MAAM,SAAS,MAAM,OAAO,CAAC,IAAI,CAAC;iCACpC,MAAM;yBACd,MAAM,QAAQ,mBAAmB;uBAMnC,MAAM;qBACR,eAAe,YAAY,cAAc;GA5B7D;AAED,iFAAiF;AACjF,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,6BAA6B,EAAE,QAAQ,GAAE,kBAAoC,EACxF,MAAM,GAAE,qBAAwD,EAAE,MAAM,CAAC,EAAE,mBAAmB,EAAE,SAAS,CAAC,EAAE,mBAAmB;;mCAc9F,MAAM,SAAS,MAAM,OAAO,CAAC,IAAI,CAAC;iCACpC,MAAM;yBACd,MAAM,QAAQ,mBAAmB;uBAMnC,MAAM;qBACR,eAAe,YAAY,cAAc;EAI7D;AAED;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CACpC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GrokBrokerRunLimit } from "./grokBrokerRunBudget.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { createServer } from "node:http";
|
|
3
4
|
import { redactCredentialText } from "../core/credentialRedaction.js";
|
|
@@ -7,9 +8,10 @@ import { ENGINE_BROKER_AUTH_STALE } from "./engineBrokerProtocol.js";
|
|
|
7
8
|
import { DEFAULT_GROK_BROKER_MODEL_POLICY, parseGrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
|
|
8
9
|
import { authorizeGrokBrokerProxyRequest } from "./grokBrokerProxyRequest.js";
|
|
9
10
|
import { GROK_SESSION_TITLE_SINK_KEY } from "./grokBrokerWorkerConfig.js";
|
|
10
|
-
import { parseGrokResponseToolNames, parseGrokUpstreamUsage } from "./grokBrokerTurnMeter.js";
|
|
11
|
+
import { parseGrokFinalReply, parseGrokResponseToolNames, parseGrokUpstreamUsage } from "./grokBrokerTurnMeter.js";
|
|
11
12
|
import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
|
|
12
13
|
import { serveGrokInferenceGrant } from "./grokInferenceProxy.js";
|
|
14
|
+
import { GrokBrokerProviderClockRefusal } from "./grokBrokerProviderClock.js";
|
|
13
15
|
/**
|
|
14
16
|
* `policy` is the fallback declared model/effort (closed list); a registered
|
|
15
17
|
* turn's own policy wins. A request whose turn has no registered meter is
|
|
@@ -21,15 +23,48 @@ import { serveGrokInferenceGrant } from "./grokInferenceProxy.js";
|
|
|
21
23
|
* `grokInferenceProxy.ts`; every other bearer is looked up only among turn
|
|
22
24
|
* capabilities. Without `grants` a prefixed bearer is simply refused.
|
|
23
25
|
*/
|
|
24
|
-
export async function startGrokBrokerProxy(authority, upstream = defaultUpstream, policy = DEFAULT_GROK_BROKER_MODEL_POLICY, listenPort = 43_123, grants) {
|
|
26
|
+
export async function startGrokBrokerProxy(authority, upstream = defaultUpstream, policy = DEFAULT_GROK_BROKER_MODEL_POLICY, listenPort = 43_123, grants, runBudget) {
|
|
27
|
+
const handler = createGrokBrokerProxyHandler(authority, upstream, policy, grants, runBudget);
|
|
28
|
+
const server = createServer((request, response) => { void handler.serve(request, response); });
|
|
29
|
+
await new Promise((resolve, reject) => {
|
|
30
|
+
server.once("error", reject);
|
|
31
|
+
server.listen(listenPort, "127.0.0.1", () => { server.off("error", reject); resolve(); });
|
|
32
|
+
});
|
|
33
|
+
const address = server.address();
|
|
34
|
+
return {
|
|
35
|
+
...handler, port: address.port,
|
|
36
|
+
close: () => new Promise((resolve, reject) => {
|
|
37
|
+
server.close((error) => error === undefined ? resolve() : reject(error));
|
|
38
|
+
// A worker's idle pooled socket otherwise leaves close() without a bound.
|
|
39
|
+
server.closeAllConnections();
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** @internal The production request handler, usable without opening a socket. */
|
|
44
|
+
export function createGrokBrokerProxyHandler(authority, upstream = defaultUpstream, policy = DEFAULT_GROK_BROKER_MODEL_POLICY, grants, runBudget) {
|
|
45
|
+
const admittedUpstream = async (request, signal) => {
|
|
46
|
+
signal?.throwIfAborted();
|
|
47
|
+
await runBudget?.reserve();
|
|
48
|
+
signal?.throwIfAborted();
|
|
49
|
+
return upstream(request, signal);
|
|
50
|
+
};
|
|
25
51
|
const declared = parseGrokBrokerModelPolicy(policy);
|
|
26
52
|
const capabilities = new EngineBrokerCapabilities();
|
|
27
53
|
const guards = new Map();
|
|
28
54
|
const turns = new Map();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
return {
|
|
56
|
+
capabilities,
|
|
57
|
+
registerIsolationGuard(turnId, guard) { guards.set(turnId, guard); },
|
|
58
|
+
revokeIsolationGuard(turnId) { guards.delete(turnId); },
|
|
59
|
+
registerTurn(turnId, turn) {
|
|
60
|
+
turns.set(turnId, {
|
|
61
|
+
policy: parseGrokBrokerModelPolicy(turn.policy), meter: turn.meter,
|
|
62
|
+
...(turn.clock === undefined ? {} : { clock: turn.clock })
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
revokeTurn(turnId) { turns.delete(turnId); },
|
|
66
|
+
serve: (request, response) => serve(request, response, authority, admittedUpstream, capabilities, guards, turns, declared, grants)
|
|
67
|
+
};
|
|
33
68
|
}
|
|
34
69
|
/**
|
|
35
70
|
* A refusal the caller must not retry.
|
|
@@ -55,7 +90,7 @@ async function serve(request, response, authority, upstream, capabilities, guard
|
|
|
55
90
|
// child and launcher diagnostics are. Nothing reads them but {@link brokerFaultCause}.
|
|
56
91
|
const secrets = [];
|
|
57
92
|
try {
|
|
58
|
-
|
|
93
|
+
let body = await readBody(request);
|
|
59
94
|
const headers = Object.fromEntries(Object.entries(request.headers).map(([key, value]) => [key, Array.isArray(value) ? value[0] : value]));
|
|
60
95
|
titleSink = headers.authorization === `Bearer ${GROK_SESSION_TITLE_SINK_KEY}`;
|
|
61
96
|
const match = headers.authorization?.match(/^Bearer ([A-Za-z0-9_-]{40,})$/u);
|
|
@@ -78,6 +113,17 @@ async function serve(request, response, authority, upstream, capabilities, guard
|
|
|
78
113
|
catch (error) {
|
|
79
114
|
throw new GrokBrokerProxyRefusal("worker_isolation_unverified");
|
|
80
115
|
}
|
|
116
|
+
// Neutralize engine context before the existing body gate or bearer read.
|
|
117
|
+
// The clock belongs to this turn, never to the slot's installed variant.
|
|
118
|
+
try {
|
|
119
|
+
if (turn.clock !== undefined)
|
|
120
|
+
body = Buffer.from(turn.clock.rewrite(body));
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (error instanceof GrokBrokerProviderClockRefusal)
|
|
124
|
+
throw new GrokBrokerProxyRefusal(error.reason);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
81
127
|
// A fenced realm is not a transient fault: the credential is gone until an
|
|
82
128
|
// operator re-logs in, and 503 made Grok blind-retry it (observed: fifteen
|
|
83
129
|
// retries over five minutes, $0 spent, nothing learned). Named, 400, and
|
|
@@ -102,7 +148,7 @@ async function serve(request, response, authority, upstream, capabilities, guard
|
|
|
102
148
|
response.end('{"error":"turn request in flight"}');
|
|
103
149
|
return;
|
|
104
150
|
}
|
|
105
|
-
settle = (usage, toolCalls) => { turn.meter.settle(admission.index, usage, body.byteLength, toolCalls); settle = undefined; };
|
|
151
|
+
settle = (usage, toolCalls, finalReply) => { turn.meter.settle(admission.index, usage, body.byteLength, toolCalls, finalReply); settle = undefined; };
|
|
106
152
|
let result = await upstream(prepared, admission.signal);
|
|
107
153
|
if (result.status === 401) {
|
|
108
154
|
token = authority.refreshAfterRejection ? await authority.refreshAfterRejection(rejectedDigest) : await authority.accessToken(true);
|
|
@@ -118,12 +164,21 @@ async function serve(request, response, authority, upstream, capabilities, guard
|
|
|
118
164
|
// is already buffered here for its usage block, so what the model tried to
|
|
119
165
|
// call is in hand. A decoder fault records no attempt rather than a false
|
|
120
166
|
// empty one, and never disturbs the turn.
|
|
121
|
-
|
|
167
|
+
// A successful answer that called nothing and stopped is the turn's final
|
|
168
|
+
// reply: the broker ends a worker that finished but did not exit on it
|
|
169
|
+
// (`grokEngineBrokerTurnEnd.ts`), and reports it when the launcher refused
|
|
170
|
+
// the worker's stdout. Observation only, exactly like the tool names.
|
|
171
|
+
settle?.(usageOrEstimate(result.body, result.headers["content-type"]), toolCallsOrNothing(result.body, result.headers["content-type"]), result.status === 200 ? finalReplyOrNothing(result.body, result.headers["content-type"]) : undefined);
|
|
122
172
|
response.writeHead(result.status, { "content-type": result.headers["content-type"] ?? "application/json", "cache-control": "no-store" });
|
|
123
173
|
response.end(result.body);
|
|
124
174
|
}
|
|
125
175
|
catch (error) {
|
|
126
176
|
settle?.(undefined);
|
|
177
|
+
if (error instanceof GrokBrokerRunLimit) {
|
|
178
|
+
response.writeHead(429, { "content-type": "application/json", "cache-control": "no-store" });
|
|
179
|
+
response.end('{"error":"run_request_limit"}');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
127
182
|
// Name the refusal on the broker's own stderr (reason code only, never a body
|
|
128
183
|
// or a token) so a failing turn is diagnosable without a stub harness —
|
|
129
184
|
// except for the two requests every healthy turn makes anyway.
|
|
@@ -243,6 +298,15 @@ const toolCallsOrNothing = (body, contentType) => {
|
|
|
243
298
|
return undefined;
|
|
244
299
|
}
|
|
245
300
|
};
|
|
301
|
+
/** Instrumentation must never fail a turn: a throwing decoder reports no final reply. */
|
|
302
|
+
const finalReplyOrNothing = (body, contentType) => {
|
|
303
|
+
try {
|
|
304
|
+
return parseGrokFinalReply(body, contentType);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
246
310
|
/** The body gate, refused non-retryably: a rejected body is a policy miss, never a transient fault. */
|
|
247
311
|
function authorizeRequestOrRefuse(...args) {
|
|
248
312
|
try {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preserve ordinary JSON bytes, including whitespace and escaping. Ambiguous
|
|
3
|
+
* duplicate members still normalize to the validated values, as the spend gate
|
|
4
|
+
* requires: an upstream parser must never select a different model or tool set.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseGrokBrokerProxyJson(body: Uint8Array): {
|
|
7
|
+
value: Record<string, unknown>;
|
|
8
|
+
body: Uint8Array;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=grokBrokerProxyJson.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokBrokerProxyJson.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxyJson.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG;IAC1D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,UAAU,CAAC;CAClB,CAuBA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preserve ordinary JSON bytes, including whitespace and escaping. Ambiguous
|
|
3
|
+
* duplicate members still normalize to the validated values, as the spend gate
|
|
4
|
+
* requires: an upstream parser must never select a different model or tool set.
|
|
5
|
+
*/
|
|
6
|
+
export function parseGrokBrokerProxyJson(body) {
|
|
7
|
+
const source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(body);
|
|
8
|
+
let properties = 0;
|
|
9
|
+
const value = JSON.parse(source, (key, entry) => {
|
|
10
|
+
if (key === "__proto__")
|
|
11
|
+
throw new Error("broker proxy request rejected");
|
|
12
|
+
if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) {
|
|
13
|
+
properties += Object.keys(entry).length;
|
|
14
|
+
}
|
|
15
|
+
return entry;
|
|
16
|
+
});
|
|
17
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
18
|
+
throw new Error("broker proxy request rejected");
|
|
19
|
+
}
|
|
20
|
+
// JSON.parse established the grammar. Match whole string tokens (including
|
|
21
|
+
// escaped quotes), so a colon inside message content cannot count as a key.
|
|
22
|
+
let sourceProperties = 0;
|
|
23
|
+
for (const token of source.matchAll(/"(?:[^"\\]|\\[\s\S])*"\s*(:)?/gu)) {
|
|
24
|
+
if (token[1] !== undefined)
|
|
25
|
+
sourceProperties++;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
value: value,
|
|
29
|
+
body: sourceProperties === properties ? body : Buffer.from(JSON.stringify(value))
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokBrokerProxyRequest.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxyRequest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAgE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGtI,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC9L,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,qDAAqD,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAE9K;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,qBAAwD,GAAG,yBAAyB,
|
|
1
|
+
{"version":3,"file":"grokBrokerProxyRequest.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxyRequest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAgE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGtI,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAC9L,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,qDAAqD,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,CAAC;AAE9K;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,qBAAwD,GAAG,yBAAyB,CAmChO;AASD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAStD"}
|
|
@@ -34,8 +34,11 @@ export function authorizeGrokBrokerProxyRequest(input, capabilities, bearer, pol
|
|
|
34
34
|
// `__proto__` is refused at any depth: JSON.parse makes it an ordinary own
|
|
35
35
|
// member, but an upstream JavaScript parser may treat it as a prototype.
|
|
36
36
|
try {
|
|
37
|
-
parsed = JSON.parse(Buffer.from(input.body).toString("utf8"), (key, value) => {
|
|
38
|
-
|
|
37
|
+
parsed = JSON.parse(Buffer.from(input.body).toString("utf8"), (key, value) => {
|
|
38
|
+
if (key === "__proto__")
|
|
39
|
+
throw new Error("broker proxy request rejected");
|
|
40
|
+
return value;
|
|
41
|
+
});
|
|
39
42
|
}
|
|
40
43
|
catch {
|
|
41
44
|
throw new Error("broker proxy request rejected");
|
|
@@ -48,10 +51,18 @@ export function authorizeGrokBrokerProxyRequest(input, capabilities, bearer, pol
|
|
|
48
51
|
throw new Error("broker proxy request rejected");
|
|
49
52
|
if (Object.keys(parsed).some((key) => !LEAN_BODY_MEMBERS.has(key)) || !validStreamOptions(parsed.stream_options))
|
|
50
53
|
throw new Error("broker proxy request rejected");
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
return {
|
|
54
|
+
// Keep origin/main's production handling: UTF-8 replacement decoding, then
|
|
55
|
+
// serialize the validated object (including last-member-wins duplicates).
|
|
56
|
+
// Only a clocked turn takes the stricter date rewrite before this gate.
|
|
57
|
+
return {
|
|
58
|
+
url: "https://cli-chat-proxy.grok.com/v1/chat/completions",
|
|
59
|
+
headers: {
|
|
60
|
+
authorization: `Bearer ${bearer}`, "content-type": "application/json",
|
|
61
|
+
"x-xai-token-auth": "xai-grok-cli", "x-grok-model-override": declared.model,
|
|
62
|
+
"x-grok-client-version": clientVersion, "x-grok-client-identifier": "grok-shell"
|
|
63
|
+
},
|
|
64
|
+
body: Buffer.from(JSON.stringify(parsed))
|
|
65
|
+
};
|
|
55
66
|
}
|
|
56
67
|
/** Top-level members of a Grok 1.0.34 lean worker chat-completions body (live stub capture). */
|
|
57
68
|
const LEAN_BODY_MEMBERS = new Set(["messages", "model", "reasoning_effort", "stream", "stream_options", "tools"]);
|
|
@@ -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"}
|