@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.
Files changed (261) hide show
  1. package/README.md +6 -0
  2. package/dist/contracts/attentionContract.d.ts +25 -0
  3. package/dist/contracts/attentionContract.d.ts.map +1 -1
  4. package/dist/contracts/attentionContract.js +8 -1
  5. package/dist/contracts/grokBrokerTaskClock.d.ts +18 -0
  6. package/dist/contracts/grokBrokerTaskClock.d.ts.map +1 -0
  7. package/dist/contracts/grokBrokerTaskClock.js +16 -0
  8. package/dist/contracts/organizationRuntimeContract.d.ts +76 -0
  9. package/dist/contracts/organizationRuntimeContract.d.ts.map +1 -1
  10. package/dist/contracts/organizationRuntimeContract.js +2 -0
  11. package/dist/contracts/runtimeContractManifest.d.ts +222 -15
  12. package/dist/contracts/runtimeContractManifest.d.ts.map +1 -1
  13. package/dist/contracts/runtimeContractManifest.js +35 -10
  14. package/dist/contracts/shellEnvironmentPolicy.d.ts +3 -0
  15. package/dist/contracts/shellEnvironmentPolicy.d.ts.map +1 -0
  16. package/dist/contracts/shellEnvironmentPolicy.js +5 -0
  17. package/dist/contracts/wakeMomentContract.d.ts +61 -0
  18. package/dist/contracts/wakeMomentContract.d.ts.map +1 -0
  19. package/dist/contracts/wakeMomentContract.js +27 -0
  20. package/dist/core/types.d.ts +2 -0
  21. package/dist/core/types.d.ts.map +1 -1
  22. package/dist/examples/jungianPlayAgent.d.ts +1 -0
  23. package/dist/examples/jungianPlayAgent.d.ts.map +1 -1
  24. package/dist/examples/jungianPlayAgent.js +6 -2
  25. package/dist/observability/causalEvents.d.ts +3 -3
  26. package/dist/observability/causalEvents.d.ts.map +1 -1
  27. package/dist/observability/causalEvents.js +4 -4
  28. package/dist/pi/cliEngineSpawn.d.ts +2 -2
  29. package/dist/pi/cliEngineSpawn.d.ts.map +1 -1
  30. package/dist/pi/cliEngineSpawn.js +7 -2
  31. package/dist/pi/cliEnvironment.d.ts.map +1 -1
  32. package/dist/pi/cliEnvironment.js +2 -0
  33. package/dist/pi/cliMcpRegistration.d.ts +1 -1
  34. package/dist/pi/cliMcpRegistration.d.ts.map +1 -1
  35. package/dist/pi/cliMcpRegistration.js +1 -1
  36. package/dist/pi/cliSession.d.ts +2 -0
  37. package/dist/pi/cliSession.d.ts.map +1 -1
  38. package/dist/pi/cliSession.js +3 -80
  39. package/dist/pi/cliSessionMcp.d.ts +9 -0
  40. package/dist/pi/cliSessionMcp.d.ts.map +1 -0
  41. package/dist/pi/cliSessionMcp.js +80 -0
  42. package/dist/pi/engineTaskClock.d.ts +9 -0
  43. package/dist/pi/engineTaskClock.d.ts.map +1 -0
  44. package/dist/pi/engineTaskClock.js +28 -0
  45. package/dist/pi/grokHomeMcpRegistration.d.ts.map +1 -1
  46. package/dist/pi/grokHomeMcpRegistration.js +2 -1
  47. package/dist/pi/grokSandbox.js +1 -1
  48. package/dist/pi/memoryClock.d.ts +25 -0
  49. package/dist/pi/memoryClock.d.ts.map +1 -0
  50. package/dist/pi/memoryClock.js +18 -0
  51. package/dist/pi/piAgentHandle.d.ts +3 -1
  52. package/dist/pi/piAgentHandle.d.ts.map +1 -1
  53. package/dist/pi/piAgentHandle.js +5 -2
  54. package/dist/pi/piHarness.d.ts +8 -2
  55. package/dist/pi/piHarness.d.ts.map +1 -1
  56. package/dist/pi/piHarness.js +28 -12
  57. package/dist/pi/taskClockProcess.d.ts +6 -0
  58. package/dist/pi/taskClockProcess.d.ts.map +1 -0
  59. package/dist/pi/taskClockProcess.js +8 -0
  60. package/dist/pi/turnCausal.d.ts +4 -2
  61. package/dist/pi/turnCausal.d.ts.map +1 -1
  62. package/dist/pi/turnCausal.js +4 -4
  63. package/dist/pi/wakeAcceptance.d.ts +1 -1
  64. package/dist/pi/wakeAcceptance.d.ts.map +1 -1
  65. package/dist/pi/wakeAcceptance.js +2 -2
  66. package/dist/runtime/agentSkillsDirectory.d.ts +25 -0
  67. package/dist/runtime/agentSkillsDirectory.d.ts.map +1 -0
  68. package/dist/runtime/agentSkillsDirectory.js +101 -0
  69. package/dist/runtime/agySubscriptionBootstrap.js +1 -1
  70. package/dist/runtime/agySubscriptionRealm.js +1 -1
  71. package/dist/runtime/attention.d.ts +5 -0
  72. package/dist/runtime/attention.d.ts.map +1 -1
  73. package/dist/runtime/attention.js +14 -1
  74. package/dist/runtime/attentionDispatcher.d.ts +14 -2
  75. package/dist/runtime/attentionDispatcher.d.ts.map +1 -1
  76. package/dist/runtime/attentionDispatcher.js +127 -33
  77. package/dist/runtime/cli.js +5 -0
  78. package/dist/runtime/contract-manifest.json +1 -1
  79. package/dist/runtime/contract-manifest.sha256 +1 -1
  80. package/dist/runtime/engineBrokerCapabilities.d.ts +10 -0
  81. package/dist/runtime/engineBrokerCapabilities.d.ts.map +1 -1
  82. package/dist/runtime/engineBrokerCapabilities.js +10 -0
  83. package/dist/runtime/engineBrokerControlClient.d.ts +12 -1
  84. package/dist/runtime/engineBrokerControlClient.d.ts.map +1 -1
  85. package/dist/runtime/engineBrokerControlClient.js +139 -43
  86. package/dist/runtime/engineBrokerCredentialJournal.d.ts +2 -0
  87. package/dist/runtime/engineBrokerCredentialJournal.d.ts.map +1 -1
  88. package/dist/runtime/engineBrokerCredentialJournal.js +9 -0
  89. package/dist/runtime/engineBrokerInferenceProtocol.d.ts +3 -2
  90. package/dist/runtime/engineBrokerInferenceProtocol.d.ts.map +1 -1
  91. package/dist/runtime/engineBrokerInferenceProtocol.js +4 -4
  92. package/dist/runtime/engineBrokerMcpCallLog.d.ts +11 -0
  93. package/dist/runtime/engineBrokerMcpCallLog.d.ts.map +1 -1
  94. package/dist/runtime/engineBrokerMcpCallLog.js +13 -1
  95. package/dist/runtime/engineBrokerMcpFacade.d.ts +5 -2
  96. package/dist/runtime/engineBrokerMcpFacade.d.ts.map +1 -1
  97. package/dist/runtime/engineBrokerMcpFacade.js +5 -2
  98. package/dist/runtime/engineBrokerNativeClient.js +2 -2
  99. package/dist/runtime/engineBrokerProtocol.d.ts +42 -10
  100. package/dist/runtime/engineBrokerProtocol.d.ts.map +1 -1
  101. package/dist/runtime/engineBrokerProtocol.js +97 -14
  102. package/dist/runtime/engineBrokerSealLedger.d.ts.map +1 -1
  103. package/dist/runtime/engineBrokerSealLedger.js +9 -0
  104. package/dist/runtime/engineBrokerService.d.ts +8 -2
  105. package/dist/runtime/engineBrokerService.d.ts.map +1 -1
  106. package/dist/runtime/engineBrokerService.js +95 -37
  107. package/dist/runtime/engineBrokerServiceCli.js +1 -1
  108. package/dist/runtime/engineBrokerServiceConfig.d.ts +15 -2
  109. package/dist/runtime/engineBrokerServiceConfig.d.ts.map +1 -1
  110. package/dist/runtime/engineBrokerServiceConfig.js +53 -11
  111. package/dist/runtime/engineBrokerTurnRegistry.d.ts +1 -1
  112. package/dist/runtime/engineBrokerTurnRegistry.d.ts.map +1 -1
  113. package/dist/runtime/engineBrokerTurnRegistry.js +7 -6
  114. package/dist/runtime/engineDispatcher.d.ts +2 -0
  115. package/dist/runtime/engineDispatcher.d.ts.map +1 -1
  116. package/dist/runtime/engineDispatcher.js +14 -2
  117. package/dist/runtime/engineReadiness.js +1 -1
  118. package/dist/runtime/grokBrokerCredentialAuthority.d.ts +1 -0
  119. package/dist/runtime/grokBrokerCredentialAuthority.d.ts.map +1 -1
  120. package/dist/runtime/grokBrokerCredentialAuthority.js +48 -22
  121. package/dist/runtime/grokBrokerCredentialReader.d.ts +1 -0
  122. package/dist/runtime/grokBrokerCredentialReader.d.ts.map +1 -1
  123. package/dist/runtime/grokBrokerCredentialReader.js +2 -1
  124. package/dist/runtime/grokBrokerProjection.d.ts +26 -2
  125. package/dist/runtime/grokBrokerProjection.d.ts.map +1 -1
  126. package/dist/runtime/grokBrokerProjection.js +18 -7
  127. package/dist/runtime/grokBrokerProviderClock.d.ts +26 -0
  128. package/dist/runtime/grokBrokerProviderClock.d.ts.map +1 -0
  129. package/dist/runtime/grokBrokerProviderClock.js +133 -0
  130. package/dist/runtime/grokBrokerProxy.d.ts +17 -3
  131. package/dist/runtime/grokBrokerProxy.d.ts.map +1 -1
  132. package/dist/runtime/grokBrokerProxy.js +73 -9
  133. package/dist/runtime/grokBrokerProxyJson.d.ts +10 -0
  134. package/dist/runtime/grokBrokerProxyJson.d.ts.map +1 -0
  135. package/dist/runtime/grokBrokerProxyJson.js +31 -0
  136. package/dist/runtime/grokBrokerProxyRequest.d.ts.map +1 -1
  137. package/dist/runtime/grokBrokerProxyRequest.js +17 -6
  138. package/dist/runtime/grokBrokerRealmLease.js +1 -1
  139. package/dist/runtime/grokBrokerRefresh.js +1 -1
  140. package/dist/runtime/grokBrokerRunBudget.d.ts +20 -0
  141. package/dist/runtime/grokBrokerRunBudget.d.ts.map +1 -0
  142. package/dist/runtime/grokBrokerRunBudget.js +85 -0
  143. package/dist/runtime/grokBrokerSlot.d.ts +6 -0
  144. package/dist/runtime/grokBrokerSlot.d.ts.map +1 -0
  145. package/dist/runtime/grokBrokerSlot.js +21 -0
  146. package/dist/runtime/grokBrokerTaskClock.d.ts +32 -0
  147. package/dist/runtime/grokBrokerTaskClock.d.ts.map +1 -0
  148. package/dist/runtime/grokBrokerTaskClock.js +120 -0
  149. package/dist/runtime/grokBrokerTurnMeter.d.ts +55 -3
  150. package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -1
  151. package/dist/runtime/grokBrokerTurnMeter.js +90 -4
  152. package/dist/runtime/grokBrokerWorkerConfig.d.ts +5 -2
  153. package/dist/runtime/grokBrokerWorkerConfig.d.ts.map +1 -1
  154. package/dist/runtime/grokBrokerWorkerConfig.js +22 -3
  155. package/dist/runtime/grokEngineBroker.d.ts +43 -3
  156. package/dist/runtime/grokEngineBroker.d.ts.map +1 -1
  157. package/dist/runtime/grokEngineBroker.js +159 -71
  158. package/dist/runtime/grokEngineBrokerTurn.d.ts +32 -8
  159. package/dist/runtime/grokEngineBrokerTurn.d.ts.map +1 -1
  160. package/dist/runtime/grokEngineBrokerTurn.js +204 -21
  161. package/dist/runtime/grokEngineBrokerTurnEnd.d.ts +88 -0
  162. package/dist/runtime/grokEngineBrokerTurnEnd.d.ts.map +1 -0
  163. package/dist/runtime/grokEngineBrokerTurnEnd.js +148 -0
  164. package/dist/runtime/grokInferenceProxy.d.ts.map +1 -1
  165. package/dist/runtime/grokInferenceProxy.js +3 -0
  166. package/dist/runtime/grokSubscriptionRealm.js +1 -1
  167. package/dist/runtime/grokWorkerAttestation.d.ts +12 -5
  168. package/dist/runtime/grokWorkerAttestation.d.ts.map +1 -1
  169. package/dist/runtime/grokWorkerAttestation.js +5 -3
  170. package/dist/runtime/grokWorkerHomeAttestation.d.ts +51 -5
  171. package/dist/runtime/grokWorkerHomeAttestation.d.ts.map +1 -1
  172. package/dist/runtime/grokWorkerHomeAttestation.js +103 -8
  173. package/dist/runtime/grokWorkerSkills.d.ts +86 -0
  174. package/dist/runtime/grokWorkerSkills.d.ts.map +1 -0
  175. package/dist/runtime/grokWorkerSkills.js +135 -0
  176. package/dist/runtime/index.d.ts +10 -2
  177. package/dist/runtime/index.d.ts.map +1 -1
  178. package/dist/runtime/index.js +8 -1
  179. package/dist/runtime/native/daimon-engine-broker +0 -0
  180. package/dist/runtime/organizationRuntime.d.ts +3 -0
  181. package/dist/runtime/organizationRuntime.d.ts.map +1 -1
  182. package/dist/runtime/organizationRuntimeAdmission.d.ts +6 -0
  183. package/dist/runtime/organizationRuntimeAdmission.d.ts.map +1 -0
  184. package/dist/runtime/organizationRuntimeAdmission.js +22 -0
  185. package/dist/runtime/organizationRuntimeControl.d.ts +9 -0
  186. package/dist/runtime/organizationRuntimeControl.d.ts.map +1 -1
  187. package/dist/runtime/organizationRuntimeControl.js +72 -24
  188. package/dist/runtime/organizationRuntimeHost.d.ts.map +1 -1
  189. package/dist/runtime/organizationRuntimeHost.js +13 -4
  190. package/dist/runtime/organizationRuntimeParsing.d.ts.map +1 -1
  191. package/dist/runtime/organizationRuntimeParsing.js +4 -1
  192. package/dist/runtime/organizationRuntimeReadiness.d.ts.map +1 -1
  193. package/dist/runtime/organizationRuntimeReadiness.js +8 -0
  194. package/dist/runtime/organizationRuntimeRecording.d.ts +7 -0
  195. package/dist/runtime/organizationRuntimeRecording.d.ts.map +1 -0
  196. package/dist/runtime/organizationRuntimeRecording.js +58 -0
  197. package/dist/runtime/physicalReadiness.d.ts +12 -0
  198. package/dist/runtime/physicalReadiness.d.ts.map +1 -1
  199. package/dist/runtime/physicalReadiness.js +43 -9
  200. package/dist/runtime/productionAgentTools.d.ts.map +1 -1
  201. package/dist/runtime/productionAgentTools.js +13 -5
  202. package/dist/runtime/relocateRuntimeConfig.d.ts +14 -0
  203. package/dist/runtime/relocateRuntimeConfig.d.ts.map +1 -0
  204. package/dist/runtime/relocateRuntimeConfig.js +38 -0
  205. package/dist/runtime/schedule.d.ts.map +1 -1
  206. package/dist/runtime/schedule.js +12 -7
  207. package/dist/runtime/storeCoordination.d.ts +10 -0
  208. package/dist/runtime/storeCoordination.d.ts.map +1 -1
  209. package/dist/runtime/storeCoordination.js +23 -0
  210. package/dist/runtime/taskClock.d.ts +42 -0
  211. package/dist/runtime/taskClock.d.ts.map +1 -0
  212. package/dist/runtime/taskClock.js +102 -0
  213. package/dist/runtime/taskClockProcess.d.ts +17 -0
  214. package/dist/runtime/taskClockProcess.d.ts.map +1 -0
  215. package/dist/runtime/taskClockProcess.js +58 -0
  216. package/dist/runtime/turnRequestLedger.d.ts +0 -5
  217. package/dist/runtime/turnRequestLedger.d.ts.map +1 -1
  218. package/dist/runtime/turnRequestLedger.js +23 -21
  219. package/dist/runtime/wakeAcceptanceClaimDiagnostics.d.ts +34 -0
  220. package/dist/runtime/wakeAcceptanceClaimDiagnostics.d.ts.map +1 -0
  221. package/dist/runtime/wakeAcceptanceClaimDiagnostics.js +79 -0
  222. package/dist/runtime/wakeAcceptanceIndex.d.ts +55 -0
  223. package/dist/runtime/wakeAcceptanceIndex.d.ts.map +1 -0
  224. package/dist/runtime/wakeAcceptanceIndex.js +158 -0
  225. package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts +9 -1
  226. package/dist/runtime/wakeAcceptanceProcessIdentity.d.ts.map +1 -1
  227. package/dist/runtime/wakeAcceptanceProcessIdentity.js +5 -1
  228. package/dist/runtime/wakeAcceptanceRecord.d.ts +2 -0
  229. package/dist/runtime/wakeAcceptanceRecord.d.ts.map +1 -1
  230. package/dist/runtime/wakeAcceptanceRecord.js +4 -2
  231. package/dist/runtime/wakeAcceptanceRetention.d.ts +25 -1
  232. package/dist/runtime/wakeAcceptanceRetention.d.ts.map +1 -1
  233. package/dist/runtime/wakeAcceptanceRetention.js +28 -2
  234. package/dist/runtime/wakeAcceptanceStore.d.ts +8 -8
  235. package/dist/runtime/wakeAcceptanceStore.d.ts.map +1 -1
  236. package/dist/runtime/wakeAcceptanceStore.js +66 -63
  237. package/dist/runtime/wakeFuse.d.ts +58 -3
  238. package/dist/runtime/wakeFuse.d.ts.map +1 -1
  239. package/dist/runtime/wakeFuse.js +106 -7
  240. package/dist/runtime/wakeMomentFs.d.ts +27 -0
  241. package/dist/runtime/wakeMomentFs.d.ts.map +1 -0
  242. package/dist/runtime/wakeMomentFs.js +223 -0
  243. package/dist/runtime/wakeMomentHistory.d.ts +26 -0
  244. package/dist/runtime/wakeMomentHistory.d.ts.map +1 -0
  245. package/dist/runtime/wakeMomentHistory.js +109 -0
  246. package/dist/runtime/wakeMomentIo.d.ts +22 -0
  247. package/dist/runtime/wakeMomentIo.d.ts.map +1 -0
  248. package/dist/runtime/wakeMomentIo.js +114 -0
  249. package/dist/runtime/wakeMomentRecorder.d.ts +33 -0
  250. package/dist/runtime/wakeMomentRecorder.d.ts.map +1 -0
  251. package/dist/runtime/wakeMomentRecorder.js +81 -0
  252. package/dist/runtime/wakeMomentRetention.d.ts +7 -0
  253. package/dist/runtime/wakeMomentRetention.d.ts.map +1 -0
  254. package/dist/runtime/wakeMomentRetention.js +143 -0
  255. package/dist/runtime/wakeMomentRows.d.ts +8 -0
  256. package/dist/runtime/wakeMomentRows.d.ts.map +1 -0
  257. package/dist/runtime/wakeMomentRows.js +66 -0
  258. package/dist/runtime/wakeMomentSnapshot.d.ts +56 -0
  259. package/dist/runtime/wakeMomentSnapshot.d.ts.map +1 -0
  260. package/dist/runtime/wakeMomentSnapshot.js +248 -0
  261. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"grokBrokerCredentialReader.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerCredentialReader.ts"],"names":[],"mappings":"AAIA,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAUvH"}
1
+ {"version":3,"file":"grokBrokerCredentialReader.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerCredentialReader.ts"],"names":[],"mappings":"AAIA,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAW3I"}
@@ -22,7 +22,8 @@ export async function readGrokBrokerCredential(file) {
22
22
  const rows = Object.values(root).filter((value) => value !== null && typeof value === "object" && !Array.isArray(value));
23
23
  if (rows.length !== 1 || typeof rows[0].key !== "string" || rows[0].key.length < 32 || typeof rows[0].refresh_token !== "string" || rows[0].refresh_token.length < 16)
24
24
  throw new Error();
25
- return { accessToken: rows[0].key, digest: createHash("sha256").update(bytes).digest("hex") };
25
+ const expiresAt = typeof rows[0].expires_at === "string" ? Date.parse(rows[0].expires_at) : NaN;
26
+ return { accessToken: rows[0].key, digest: createHash("sha256").update(bytes).digest("hex"), ...(Number.isFinite(expiresAt) ? { expiresAt } : {}) };
26
27
  }
27
28
  catch {
28
29
  throw new Error("Grok broker credential authority unavailable");
@@ -1,8 +1,10 @@
1
+ import { GROK_BROKER_TASK_CLOCK, type GrokWorkerConfigVariant } from "../contracts/grokBrokerTaskClock.js";
1
2
  import { type EngineBrokerServiceRegistration } from "./engineBrokerServiceConfig.js";
2
3
  import { type EngineBrokerTurnLimits } from "./engineBrokerTurnAccounting.js";
3
4
  import type { GrokBrokerModel, GrokBrokerReasoningEffort } from "./grokBrokerModelPolicy.js";
5
+ import { type AgentSkill } from "./grokWorkerSkills.js";
4
6
  import { GROK_WORKER_SANDBOX_PROFILE } from "./grokWorkerSandboxProfile.js";
5
- export declare const GROK_BROKER_PROJECTION_VERSION: "noopolis.daimon.grok-broker-projection.v1";
7
+ export declare const GROK_BROKER_PROJECTION_VERSION: "noopolis.daimon.grok-broker-projection.v3";
6
8
  /**
7
9
  * Everything a consumer (Spawnfile provisioning, Paideia's native adapter, the
8
10
  * root slot supervisor) needs to know about one brokered Grok agent's slot,
@@ -20,7 +22,19 @@ export type OrganizationGrokBrokerProjection = Readonly<{
20
22
  profileSha256: string;
21
23
  denyPaths: readonly string[];
22
24
  workerConfigSha256: string;
25
+ workerConfigVariant: GrokWorkerConfigVariant;
26
+ taskClock?: Omit<typeof GROK_BROKER_TASK_CLOCK, "directoryPath" | "timestampFilePath"> & Readonly<{
27
+ directoryPath: string;
28
+ timestampFilePath: string;
29
+ }>;
23
30
  systemPromptSha256: string;
31
+ /**
32
+ * Digest of the declared skills rendered into `$GROK_HOME/skills`
33
+ * (`grokWorkerSkillsSha256`). Present only when the agent declares at least
34
+ * one skill, so a skill-less projection is byte-identical to one computed
35
+ * before skills existed.
36
+ */
37
+ skillsSha256?: string;
24
38
  grokCliVersion: string;
25
39
  grokExecutableSha256: string;
26
40
  nativeAbiVersion: number;
@@ -40,6 +54,8 @@ export type OrganizationGrokBrokerProjection = Readonly<{
40
54
  }>;
41
55
  }>;
42
56
  export type OrganizationGrokBrokerProjectionOptions = Readonly<{
57
+ /** Clocked configs require an isolated clock directory per slot. Defaults to the unchanged production bytes. */
58
+ workerConfigVariant?: GrokWorkerConfigVariant;
43
59
  /** Deployment-assigned slot identity. */
44
60
  slot: number;
45
61
  workerUid: number;
@@ -70,6 +86,13 @@ export type OrganizationGrokBrokerProjectionOptions = Readonly<{
70
86
  seccompProfileSha256: string;
71
87
  /** When the caller already holds a rendered profile digest, it must equal Daimon's. */
72
88
  profileSha256?: string;
89
+ /**
90
+ * The agent's declared skills: the compiled workspace `.agents/skills` tree
91
+ * every engine is given (`readAgentSkillsDirectory`), which root provisioning
92
+ * renders into `$GROK_HOME/skills` (`renderGrokWorkerSkillsTree`). Omitted or
93
+ * empty means no skills.
94
+ */
95
+ skills?: readonly AgentSkill[];
73
96
  }>;
74
97
  /**
75
98
  * Resolve the public Grok broker projection for one agent.
@@ -90,7 +113,8 @@ export type OrganizationGrokBrokerProjectionOptions = Readonly<{
90
113
  * this agent (realm, bootstrap, peers, and the mask covering the acceptance
91
114
  * store) plus the caller's evaluator paths, sorted and deduplicated exactly as
92
115
  * the profile renderer does. A supplied `profileSha256` that differs is
93
- * refused.
116
+ * refused. Declared `skills` add `skillsSha256`, which the implied
117
+ * registration carries and the broker attests against `$GROK_HOME/skills`.
94
118
  */
95
119
  export declare function resolveOrganizationGrokBrokerProjection(config: unknown, agentId: string, options: OrganizationGrokBrokerProjectionOptions): OrganizationGrokBrokerProjection;
96
120
  /** sha256 over the projection's canonical JSON; what a slot preflight receipt binds. */
@@ -1 +1 @@
1
- {"version":3,"file":"grokBrokerProjection.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProjection.ts"],"names":[],"mappings":"AAOA,OAAO,EAAkC,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACtH,OAAO,EAA+B,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE3G,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,2BAA2B,EAA2F,MAAM,+BAA+B,CAAC;AAGrK,eAAO,MAAM,8BAA8B,6CAAuC,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC;IACtD,OAAO,EAAE,OAAO,8BAA8B,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,eAAe,EAAE,yBAAyB,CAAC;IAC3C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,yHAAyH;IACzH,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,gBAAgB,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,eAAe,EAAE,IAAI,CAAC;QAAC,WAAW,EAAE,OAAO,2BAA2B,CAAC;QAAC,cAAc,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjM,CAAC,CAAC;AAEH,MAAM,MAAM,uCAAuC,GAAG,QAAQ,CAAC;IAC7D,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,GAAG,KAAK,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,gFAAgF;IAChF,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uCAAuC,GAAG,gCAAgC,CA8B5K;AAED,wFAAwF;AACxF,eAAO,MAAM,0BAA0B,GAAI,YAAY,gCAAgC,KAAG,MACpB,CAAC;AAEvE,4HAA4H;AAC5H,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,gCAAgC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQhI;AAED;;;;GAIG;AACH,wBAAgB,6CAA6C,CAAC,YAAY,EAAE,+BAA+B,EAAE,UAAU,EAAE,gCAAgC,GAAG,IAAI,CAG/J"}
1
+ {"version":3,"file":"grokBrokerProjection.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProjection.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAQ3G,OAAO,EAAkC,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACtH,OAAO,EAA+B,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAE3G,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAA4C,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,EAAE,2BAA2B,EAA2F,MAAM,+BAA+B,CAAC;AAGrK,eAAO,MAAM,8BAA8B,6CAAuC,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC;IACtD,OAAO,EAAE,OAAO,8BAA8B,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO,sBAAsB,EAAE,eAAe,GAAG,mBAAmB,CAAC,GAAG,QAAQ,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxJ,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,eAAe,EAAE,yBAAyB,CAAC;IAC3C,MAAM,EAAE,sBAAsB,CAAC;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,yHAAyH;IACzH,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,gBAAgB,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAC;QAAC,eAAe,EAAE,IAAI,CAAC;QAAC,WAAW,EAAE,OAAO,2BAA2B,CAAC;QAAC,cAAc,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjM,CAAC,CAAC;AAEH,MAAM,MAAM,uCAAuC,GAAG,QAAQ,CAAC;IAC7D,gHAAgH;IAChH,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;IAC9C,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,GAAG,KAAK,CAAC;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,sBAAsB,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,gFAAgF;IAChF,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,uCAAuC,GAAG,gCAAgC,CAmC5K;AAED,wFAAwF;AACxF,eAAO,MAAM,0BAA0B,GAAI,YAAY,gCAAgC,KAAG,MACpB,CAAC;AAEvE,4HAA4H;AAC5H,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,gCAAgC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAShI;AAED;;;;GAIG;AACH,wBAAgB,6CAA6C,CAAC,YAAY,EAAE,+BAA+B,EAAE,UAAU,EAAE,gCAAgC,GAAG,IAAI,CAG/J"}
@@ -1,3 +1,5 @@
1
+ import { brokerTaskClockFileFor } from "./grokBrokerSlot.js";
2
+ import { GROK_BROKER_TASK_CLOCK } from "../contracts/grokBrokerTaskClock.js";
1
3
  import { createHash } from "node:crypto";
2
4
  import path from "node:path";
3
5
  import { canonicalJson } from "../contracts/canonicalJson.js";
@@ -6,7 +8,8 @@ import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
6
8
  import { grokSandboxProtectedPaths } from "./engineDispatcher.js";
7
9
  import { parseEngineBrokerServiceConfig } from "./engineBrokerServiceConfig.js";
8
10
  import { parseEngineBrokerTurnLimits } from "./engineBrokerTurnAccounting.js";
9
- import { grokBrokerWorkerConfigSha256 } from "./grokBrokerWorkerConfig.js";
11
+ import { grokBrokerWorkerConfigPins, grokBrokerWorkerConfigSha256 } from "./grokBrokerWorkerConfig.js";
12
+ import { grokWorkerSkillsSha256, parseAgentSkills } from "./grokWorkerSkills.js";
10
13
  import { GROK_WORKER_SANDBOX_PROFILE, grokWorkerEventsPathFor, renderGrokWorkerSandboxProfile, grokWorkerSandboxProfileSha256 } from "./grokWorkerSandboxProfile.js";
11
14
  import { parseOrganizationRuntimeConfig } from "./organizationRuntime.js";
12
15
  export const GROK_BROKER_PROJECTION_VERSION = GROK_ENGINE_BROKER.projectionVersion;
@@ -29,7 +32,8 @@ export const GROK_BROKER_PROJECTION_VERSION = GROK_ENGINE_BROKER.projectionVersi
29
32
  * this agent (realm, bootstrap, peers, and the mask covering the acceptance
30
33
  * store) plus the caller's evaluator paths, sorted and deduplicated exactly as
31
34
  * the profile renderer does. A supplied `profileSha256` that differs is
32
- * refused.
35
+ * refused. Declared `skills` add `skillsSha256`, which the implied
36
+ * registration carries and the broker attests against `$GROK_HOME/skills`.
33
37
  */
34
38
  export function resolveOrganizationGrokBrokerProjection(config, agentId, options) {
35
39
  const parsed = parseOrganizationRuntimeConfig(config);
@@ -50,19 +54,25 @@ export function resolveOrganizationGrokBrokerProjection(config, agentId, options
50
54
  const profileSha256 = grokWorkerSandboxProfileSha256(denyPaths);
51
55
  if (options.profileSha256 !== undefined && options.profileSha256 !== profileSha256)
52
56
  throw new Error("Grok broker projection profile digest mismatch");
53
- const workerConfigSha256 = grokBrokerWorkerConfigSha256({ model, reasoningEffort });
54
- if (workerConfigSha256 !== GROK_ENGINE_BROKER.worker.configSha256[model][reasoningEffort])
57
+ const workerConfigVariant = options.workerConfigVariant ?? "unclocked";
58
+ const workerConfigSha256 = grokBrokerWorkerConfigSha256({ model, reasoningEffort }, workerConfigVariant, options.slot);
59
+ const pin = grokBrokerWorkerConfigPins({ model, reasoningEffort }, options.slot)[workerConfigVariant];
60
+ if (workerConfigVariant === "clocked" && denyPaths.some((denied) => [brokerTaskClockFileFor(options.slot), GROK_BROKER_TASK_CLOCK.preloadPath].some((file) => file === denied || file.startsWith(`${denied}/`))))
61
+ throw new Error("Grok broker task clock path is denied");
62
+ if (workerConfigSha256 !== pin)
55
63
  throw new Error("Grok broker projection worker config drifted from the manifest");
56
64
  if (createHash("sha256").update(DAIMON_GROK_SYSTEM_PROMPT).digest("hex") !== GROK_ENGINE_BROKER.worker.systemPromptSha256)
57
65
  throw new Error("Grok broker projection system prompt drifted from the manifest");
58
66
  const artifact = GROK_ENGINE_BROKER.grokCliArtifacts[options.architecture];
59
67
  if (artifact === undefined)
60
68
  throw new Error("Grok broker projection requires a pinned architecture");
69
+ const skills = parseAgentSkills(options.skills ?? []);
61
70
  const profilePath = path.posix.join(options.workerHomePath, ".grok", "sandbox.toml");
62
71
  const projection = {
63
72
  version: GROK_BROKER_PROJECTION_VERSION, agentId, workspacePath: agent.workspacePath, runtimeHomePath: agent.runtimeHomePath,
64
- workerUid: options.workerUid, slot: options.slot, profilePath, profileSha256, denyPaths, workerConfigSha256,
65
- systemPromptSha256: GROK_ENGINE_BROKER.worker.systemPromptSha256, grokCliVersion: GROK_ENGINE_BROKER.grokCliVersion, grokExecutableSha256: artifact.sha256,
73
+ workerUid: options.workerUid, slot: options.slot, profilePath, profileSha256, denyPaths, workerConfigSha256, workerConfigVariant,
74
+ ...(workerConfigVariant === "clocked" ? { taskClock: { ...GROK_BROKER_TASK_CLOCK, directoryPath: path.posix.dirname(brokerTaskClockFileFor(options.slot)), timestampFilePath: brokerTaskClockFileFor(options.slot) } } : {}),
75
+ systemPromptSha256: GROK_ENGINE_BROKER.worker.systemPromptSha256, ...(skills.length === 0 ? {} : { skillsSha256: grokWorkerSkillsSha256(skills) }), grokCliVersion: GROK_ENGINE_BROKER.grokCliVersion, grokExecutableSha256: artifact.sha256,
66
76
  nativeAbiVersion: GROK_ENGINE_BROKER.nativeAbiVersion, model, reasoningEffort, limits: parseEngineBrokerTurnLimits(options.limits), usageLedgerPath: options.usageLedgerPath, seccompProfileSha256: options.seccompProfileSha256,
67
77
  attestation: { platform: "linux/landlock", enforced: true, restrictNetwork: true, profileName: GROK_WORKER_SANDBOX_PROFILE, sandboxRuntime: "bubblewrap", eventsPath: grokWorkerEventsPathFor(profilePath) }
68
78
  };
@@ -77,7 +87,8 @@ export function grokBrokerServiceRegistrationFor(projection) {
77
87
  const registration = {
78
88
  agentId: projection.agentId, slot: projection.slot, workerUid: projection.workerUid, workspace: projection.workspacePath,
79
89
  profilePath: projection.profilePath, eventsPath: projection.attestation.eventsPath, profileSha256: projection.profileSha256,
80
- usageLedgerPath: projection.usageLedgerPath, limits: projection.limits, model: { id: projection.model, reasoningEffort: projection.reasoningEffort }
90
+ usageLedgerPath: projection.usageLedgerPath, limits: projection.limits, model: { id: projection.model, reasoningEffort: projection.reasoningEffort },
91
+ ...(projection.skillsSha256 === undefined ? {} : { skillsSha256: projection.skillsSha256 })
81
92
  };
82
93
  parseEngineBrokerServiceConfig({ version: "noopolis.daimon.engine-broker-service.v2", credentialHome: GROK_ENGINE_BROKER.credentialHomePath, turnStore: GROK_ENGINE_BROKER.turnStorePath, registrations: [registration] });
83
94
  return registration;
@@ -0,0 +1,26 @@
1
+ export type GrokBrokerProviderClockObservation = Readonly<{
2
+ requests: number;
3
+ linesRewritten: number;
4
+ requestsWithoutDateLine: number;
5
+ /** Date-like message lines outside the injected block; absent on older seals. */
6
+ linesIgnored?: number;
7
+ /** The last rewritten line's dates; null until a line is rewritten. */
8
+ injectedDate: string | null;
9
+ taskDate: string | null;
10
+ }>;
11
+ export declare class GrokBrokerProviderClockRefusal extends Error {
12
+ readonly reason: "task_clock_date_format" | "task_clock_date_range" | "request_body_rejected";
13
+ constructor(reason: "task_clock_date_format" | "task_clock_date_range" | "request_body_rejected");
14
+ }
15
+ /** One processClock, owned by one turn; never reads the broker's ambient TZ. */
16
+ export declare class GrokBrokerProviderClock {
17
+ private readonly now;
18
+ private readonly offsetMs;
19
+ private observation;
20
+ constructor(processClock: string, now?: () => number);
21
+ rewrite(body: Uint8Array): Uint8Array;
22
+ snapshot(): GrokBrokerProviderClockObservation;
23
+ }
24
+ /** Closed, dates-only observation on the v3 terminal frame and durable seal. */
25
+ export declare function parseGrokBrokerProviderClockObservation(value: unknown): GrokBrokerProviderClockObservation;
26
+ //# sourceMappingURL=grokBrokerProviderClock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grokBrokerProviderClock.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProviderClock.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kCAAkC,GAAG,QAAQ,CAAC;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC,CAAC;AAEH,qBAAa,8BAA+B,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,wBAAwB,GAAG,uBAAuB,GAAG,uBAAuB;gBAApF,MAAM,EAAE,wBAAwB,GAAG,uBAAuB,GAAG,uBAAuB;CAG1G;AAOD,gFAAgF;AAChF,qBAAa,uBAAuB;IAOA,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,WAAW,CAGjB;gBAEU,YAAY,EAAE,MAAM,EAAmB,GAAG,GAAE,MAAM,MAAyB;IAIvF,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU;IAuErC,QAAQ,IAAI,kCAAkC;CAG/C;AAKD,gFAAgF;AAChF,wBAAgB,uCAAuC,CAAC,KAAK,EAAE,OAAO,GAAG,kCAAkC,CAuB1G"}
@@ -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<Readonly<{
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
- close(): Promise<void>;
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":"AAKA,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,EAAsD,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGxH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,2FAA2F;AAC3F,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IAAE,MAAM,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;AAE1G,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,CAAC,SAAS,EAAE,6BAA6B,EAAE,QAAQ,GAAE,kBAAoC,EAAE,MAAM,GAAE,qBAAwD,EAAE,UAAU,SAAS,EAAE,MAAM,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,wBAAwB,CAAC;IAAC,sBAAsB,CAAC,MAAM,EAAC,MAAM,EAAC,KAAK,EAAC,MAAI,OAAO,CAAC,IAAI,CAAC,GAAE,IAAI,CAAC;IAAC,oBAAoB,CAAC,MAAM,EAAC,MAAM,GAAE,IAAI,CAAC;IAAC,YAAY,CAAC,MAAM,EAAC,MAAM,EAAC,IAAI,EAAC,mBAAmB,GAAE,IAAI,CAAC;IAAC,UAAU,CAAC,MAAM,EAAC,MAAM,GAAE,IAAI,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAAC,CAMtiB;AAED;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CACpC"}
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
- const server = createServer((request, response) => { void serve(request, response, authority, upstream, capabilities, guards, turns, declared, grants); });
30
- await new Promise((resolve, reject) => { server.once("error", reject); server.listen(listenPort, "127.0.0.1", () => { server.off("error", reject); resolve(); }); });
31
- const address = server.address();
32
- return { port: address.port, capabilities, registerIsolationGuard(turnId, guard) { guards.set(turnId, guard); }, revokeIsolationGuard(turnId) { guards.delete(turnId); }, registerTurn(turnId, turn) { turns.set(turnId, { policy: parseGrokBrokerModelPolicy(turn.policy), meter: turn.meter }); }, revokeTurn(turnId) { turns.delete(turnId); }, close: () => new Promise((resolve, reject) => { server.close((error) => error === undefined ? resolve() : reject(error)); /* `close` waits for every open connection, and a worker keeps its client pool's socket to this proxy open with nothing here accounting for it — so that wait has no bound. Ending them is this listener's to do, exactly as the MCP facade does. */ /* `close` waits for every open connection, and a worker keeps its client pool's socket to this proxy open with nothing here accounting for it — so that wait has no bound. Ending them is this listener's to do, exactly as the MCP facade does. */ server.closeAllConnections(); }) };
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
- const body = await readBody(request);
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
- settle?.(usageOrEstimate(result.body, result.headers["content-type"]), toolCallsOrNothing(result.body, result.headers["content-type"]));
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,CAsBhO;AASD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAStD"}
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) => { if (key === "__proto__")
38
- throw new Error(); return value; });
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
- // Forward what was validated, never the worker's bytes: JSON.parse keeps the
52
- // last of duplicate keys, and an upstream that keeps the first would
53
- // otherwise see a different `tools`/`model`/`reasoning_effort` than the gate.
54
- return { url: "https://cli-chat-proxy.grok.com/v1/chat/completions", headers: { authorization: `Bearer ${bearer}`, "content-type": "application/json", "x-xai-token-auth": "xai-grok-cli", "x-grok-model-override": declared.model, "x-grok-client-version": clientVersion, "x-grok-client-identifier": "grok-shell" }, body: Buffer.from(JSON.stringify(parsed)) };
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"]);