lody 0.84.0 → 0.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/grok-acp.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createInterface } from "node:readline";
2
- import { r as runtimeManifest } from "./chunks/runtime-manifest-Fr5DEH54.js";
2
+ import { r as runtimeManifest } from "./chunks/runtime-manifest-ByWJfM07.js";
3
+ import { L as LODY_EXTENSION_METHODS } from "./chunks/methods-CvEDMahD.js";
3
4
  import { spawn } from "node:child_process";
4
5
  const contract = runtimeManifest.privateWireContract;
5
6
  const PERMISSION_MODES = {
@@ -16,12 +17,17 @@ const INTERACTION_FROM_RUNTIME = { default: "agent", plan: "plan", ask: "plan" }
16
17
  const LEGACY_INTERACTION_ALIASES = { ask: "plan" };
17
18
  const INTERNAL_REQUESTS = {
18
19
  context: { contractKey: "sessionInfoRequest", params: (sessionId) => ({ sessionId }) },
19
- billing: { contractKey: "billingRequest", params: () => ({}) }
20
+ billing: { contractKey: "billingRequest", params: () => ({}) },
21
+ rateLimits: { contractKey: "billingRequest", params: () => ({}) }
20
22
  };
21
23
  const USD_TICKS_PER_USD = 1e10;
22
24
  const MAX_TRACKED_PROMPTS = 256;
23
- const FIVE_HOUR_WINDOW_MINS = 5 * 60;
24
- const SEVEN_DAY_WINDOW_MINS = 7 * 24 * 60;
25
+ const GROK_LODY_CAPABILITIES = {
26
+ usage: { version: 1 },
27
+ rateLimits: { version: 1, query: true }
28
+ };
29
+ const SEVEN_DAY_WINDOW_SECONDS = 7 * 24 * 60 * 60;
30
+ const GROK_MODEL_SNAPSHOT_SETTLE_TIMEOUT_MS = 2e3;
25
31
  function logicalExtensionMethod(method) {
26
32
  return typeof method === "string" && method.startsWith("_") ? method.slice(1) : method;
27
33
  }
@@ -31,6 +37,9 @@ function wireExtensionMethod(method) {
31
37
  function extensionNotification(contractKey, params) {
32
38
  return { jsonrpc: "2.0", method: wireExtensionMethod(contract[contractKey]), params };
33
39
  }
40
+ function lodyNotification(method, params) {
41
+ return { jsonrpc: "2.0", method, params };
42
+ }
34
43
  function optionalNonnegativeNumber(value) {
35
44
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
36
45
  }
@@ -53,20 +62,18 @@ function billingUsagePercent(config, period) {
53
62
  if (hasOfficialZeroUsage) return 0;
54
63
  return void 0;
55
64
  }
56
- function rateLimitsPayload(planName, window) {
57
- const isFiveHour = window?.windowDurationMins === FIVE_HOUR_WINDOW_MINS;
58
- const isSevenDay = window?.windowDurationMins === SEVEN_DAY_WINDOW_MINS;
65
+ function rateLimitsPayload(planName, window, now = Date.now()) {
59
66
  return {
60
- schemaVersion: 2,
61
- planName,
62
- limitName: "Grok Build",
63
- limitId: "grok",
64
- windows: window ? [window] : [],
65
- fiveHour: isFiveHour ? window.usedPercent : null,
66
- sevenDay: isSevenDay ? window.usedPercent : null,
67
- fiveHourResetAt: isFiveHour ? window.resetsAt : null,
68
- sevenDayResetAt: isSevenDay ? window.resetsAt : null,
69
- ...window ? {} : { apiUnavailable: true }
67
+ rateLimits: window ? [
68
+ {
69
+ limitId: "grok",
70
+ scope: { providerId: "grok" },
71
+ planName,
72
+ limitName: "Grok Build",
73
+ windows: [window]
74
+ }
75
+ ] : [],
76
+ fetchedAtEpochSeconds: Math.floor(now / 1e3)
70
77
  };
71
78
  }
72
79
  function normalizeUsageModel(usage, usageIsIncomplete) {
@@ -105,9 +112,9 @@ function normalizePromptUsage(promptUsage) {
105
112
  ...Object.keys(modelUsage).length ? { modelUsage } : {}
106
113
  };
107
114
  }
108
- function usageNotification(promptUsage) {
115
+ function usageNotification(sessionId, promptUsage) {
109
116
  const params = normalizePromptUsage(promptUsage);
110
- return params && extensionNotification("lodyUsageNotification", params);
117
+ return params && lodyNotification(LODY_EXTENSION_METHODS.sessionUsageUpdate, { sessionId, ...params });
111
118
  }
112
119
  function normalizeBillingRateLimits(billing) {
113
120
  if (!billing || typeof billing !== "object") return void 0;
@@ -121,20 +128,25 @@ function normalizeBillingRateLimits(billing) {
121
128
  const end = period?.end ?? period?.billingPeriodEnd ?? config.billingPeriodEnd;
122
129
  const startMs = typeof start === "string" ? Date.parse(start) : Number.NaN;
123
130
  const endMs = typeof end === "string" ? Date.parse(end) : Number.NaN;
124
- const measuredWindowDurationMins = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs ? Math.round((endMs - startMs) / 6e4) : null;
125
- const windowDurationMins = period?.type === contract.weeklyUsagePeriodType ? SEVEN_DAY_WINDOW_MINS : measuredWindowDurationMins;
126
- const resetsAt = Number.isFinite(endMs) ? endMs : null;
131
+ const measuredWindowDurationSeconds = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs ? Math.round((endMs - startMs) / 1e3) : null;
132
+ const windowDurationSeconds = period?.type === contract.weeklyUsagePeriodType ? SEVEN_DAY_WINDOW_SECONDS : measuredWindowDurationSeconds;
133
+ const resetsAtEpochSeconds = Number.isFinite(endMs) ? Math.floor(endMs / 1e3) : null;
127
134
  const tier = billing.subscriptionTier ?? billing.subscription_tier;
128
135
  const planName = typeof tier === "string" && tier.trim() ? tier : null;
129
136
  if (usedPercent === void 0) {
130
- if (!planName && windowDurationMins === null && resetsAt === null) return void 0;
137
+ if (!planName && windowDurationSeconds === null && resetsAtEpochSeconds === null)
138
+ return void 0;
131
139
  return rateLimitsPayload(planName, null);
132
140
  }
133
- return rateLimitsPayload(planName, { usedPercent, windowDurationMins, resetsAt });
141
+ return rateLimitsPayload(planName, {
142
+ usedPercent,
143
+ windowDurationSeconds,
144
+ resetsAtEpochSeconds
145
+ });
134
146
  }
135
147
  function rateLimitsNotification(billing) {
136
148
  const params = normalizeBillingRateLimits(billing);
137
- return params && extensionNotification("lodyRateLimitsNotification", params);
149
+ return params && lodyNotification(LODY_EXTENSION_METHODS.rateLimitsUpdate, params);
138
150
  }
139
151
  function contextUsageNotification(sessionId, context) {
140
152
  const size = nonnegativeNumber(context?.total);
@@ -184,6 +196,24 @@ function readReasoningEfforts(model) {
184
196
  if (!Array.isArray(raw)) return [];
185
197
  return raw.map((item) => typeof item === "string" ? item : item?.id ?? item?.reasoningEffort).filter((item) => typeof item === "string");
186
198
  }
199
+ function readModelSnapshot(params) {
200
+ if (!params || typeof params !== "object" || !Array.isArray(params.availableModels)) {
201
+ return void 0;
202
+ }
203
+ if (params.availableModels.length === 0 || params.availableModels.some(
204
+ (model) => !model || typeof model !== "object" || typeof model.modelId !== "string"
205
+ )) {
206
+ return void 0;
207
+ }
208
+ const currentModelId = params.currentModelId;
209
+ if (typeof currentModelId !== "string" || !params.availableModels.some((model) => model.modelId === currentModelId)) {
210
+ return void 0;
211
+ }
212
+ return {
213
+ currentModelId,
214
+ availableModels: params.availableModels
215
+ };
216
+ }
187
217
  function selectOption(id, name, description, currentValue, options, category) {
188
218
  return {
189
219
  id,
@@ -200,18 +230,147 @@ function permissionNotification(clientIdentifier, mode) {
200
230
  if (!mapped) return void 0;
201
231
  return extensionNotification("permissionNotification", { clientIdentifier, ...mapped });
202
232
  }
233
+ function stripLodySessionConfig(meta) {
234
+ if (!meta || typeof meta !== "object") return meta;
235
+ const lody = meta.lody;
236
+ if (!lody || typeof lody !== "object" || !Object.hasOwn(lody, "sessionConfig")) return meta;
237
+ const { sessionConfig: _sessionConfig, ...remainingLody } = lody;
238
+ const { lody: _lody, ...remainingMeta } = meta;
239
+ return Object.keys(remainingLody).length > 0 ? { ...remainingMeta, lody: remainingLody } : remainingMeta;
240
+ }
241
+ function readLodySessionConfigOption(meta, configId) {
242
+ if (!meta || typeof meta !== "object") return void 0;
243
+ const sessionConfig = meta.lody?.sessionConfig;
244
+ if (!sessionConfig || typeof sessionConfig !== "object" || sessionConfig.version !== 1 || !sessionConfig.configOptionValues || typeof sessionConfig.configOptionValues !== "object") {
245
+ return void 0;
246
+ }
247
+ const value = sessionConfig.configOptionValues[configId];
248
+ return typeof value === "string" || typeof value === "boolean" ? value : void 0;
249
+ }
250
+ function translateSessionStart(message) {
251
+ const params = message.params ?? {};
252
+ const permissionMode = readLodySessionConfigOption(params._meta, "permission_mode");
253
+ const mapped = typeof permissionMode === "string" ? PERMISSION_MODES[permissionMode] : void 0;
254
+ if (!mapped) return { message, permissionMode: void 0, notification: void 0 };
255
+ const clientIdentifier = params._meta?.clientIdentifier;
256
+ const translated = {
257
+ ...message,
258
+ params: {
259
+ ...params,
260
+ _meta: {
261
+ ...stripLodySessionConfig(params._meta),
262
+ yoloMode: mapped.yolo_mode
263
+ }
264
+ }
265
+ };
266
+ return {
267
+ message: translated,
268
+ permissionMode,
269
+ notification: mapped.auto_mode && typeof clientIdentifier === "string" ? permissionNotification(clientIdentifier, permissionMode) : void 0
270
+ };
271
+ }
203
272
  class GrokAcpCompatibilityProxy {
204
- constructor() {
273
+ constructor({ deferSessionResponseUntilModelSnapshot = false } = {}) {
205
274
  this.sessions = /* @__PURE__ */ new Map();
206
275
  this.pending = /* @__PURE__ */ new Map();
276
+ this.pendingSessionResponses = /* @__PURE__ */ new Map();
277
+ this.clientVisibleSessions = /* @__PURE__ */ new Set();
278
+ this.latestModelSnapshot = void 0;
279
+ this.latestModelSnapshotFingerprint = void 0;
280
+ this.deferSessionResponseUntilModelSnapshot = deferSessionResponseUntilModelSnapshot;
207
281
  this.permissionModes = /* @__PURE__ */ new Map();
208
282
  this.nextInternalRequestId = Number.MAX_SAFE_INTEGER;
209
283
  }
210
- internalRequest(kind, sessionId) {
284
+ applyModelSnapshot(state, snapshot) {
285
+ const previousModelId = state.currentModelId;
286
+ const previousReasoningEffort = state.reasoningEffort;
287
+ const currentModel = snapshot.availableModels.find(
288
+ (model) => model.modelId === snapshot.currentModelId
289
+ );
290
+ const reasoningEfforts = readReasoningEfforts(currentModel);
291
+ const metadataReasoningEffort = currentModel?._meta?.reasoningEffort ?? currentModel?._meta?.reasoning_effort;
292
+ state.currentModelId = snapshot.currentModelId;
293
+ state.models = snapshot.availableModels;
294
+ state.reasoningEfforts = reasoningEfforts;
295
+ state.reasoningEffort = previousModelId === snapshot.currentModelId && reasoningEfforts.includes(previousReasoningEffort) ? previousReasoningEffort : typeof metadataReasoningEffort === "string" && reasoningEfforts.includes(metadataReasoningEffort) ? metadataReasoningEffort : reasoningEfforts[0];
296
+ }
297
+ sessionResponseWithState(message, state) {
298
+ const models = typeof state.currentModelId === "string" && state.models.length > 0 ? {
299
+ currentModelId: state.currentModelId,
300
+ availableModels: state.models
301
+ } : message.result?.models;
302
+ return {
303
+ ...message,
304
+ result: {
305
+ ...message.result,
306
+ ...models ? { models } : {},
307
+ configOptions: this.configOptions(state)
308
+ }
309
+ };
310
+ }
311
+ exposePendingSessionResponse(id) {
312
+ const pending = this.pendingSessionResponses.get(id);
313
+ if (!pending) return { toRuntime: [], toClient: [] };
314
+ this.pendingSessionResponses.delete(id);
315
+ const state = this.sessions.get(pending.sessionId);
316
+ if (!state) return { toRuntime: [], toClient: [pending.message] };
317
+ this.clientVisibleSessions.add(pending.sessionId);
318
+ return {
319
+ toRuntime: [],
320
+ toClient: [this.sessionResponseWithState(pending.message, state)]
321
+ };
322
+ }
323
+ flushPendingSessionResponse(id) {
324
+ return this.exposePendingSessionResponse(id);
325
+ }
326
+ handleModelSnapshot(message) {
327
+ const snapshot = readModelSnapshot(message.params);
328
+ if (!snapshot) return { toRuntime: [], toClient: [message] };
329
+ const fingerprint = JSON.stringify(snapshot);
330
+ if (fingerprint === this.latestModelSnapshotFingerprint) {
331
+ return { toRuntime: [], toClient: [] };
332
+ }
333
+ this.latestModelSnapshot = snapshot;
334
+ this.latestModelSnapshotFingerprint = fingerprint;
335
+ for (const state of this.sessions.values()) {
336
+ this.applyModelSnapshot(state, snapshot);
337
+ }
338
+ const toClient = [];
339
+ const pendingSessionIds = /* @__PURE__ */ new Set();
340
+ const settledSessionResponseIds = [];
341
+ for (const id of [...this.pendingSessionResponses.keys()]) {
342
+ const pending = this.pendingSessionResponses.get(id);
343
+ if (pending) pendingSessionIds.add(pending.sessionId);
344
+ toClient.push(...this.exposePendingSessionResponse(id).toClient);
345
+ settledSessionResponseIds.push(id);
346
+ }
347
+ for (const sessionId of this.clientVisibleSessions) {
348
+ if (pendingSessionIds.has(sessionId)) continue;
349
+ const state = this.sessions.get(sessionId);
350
+ if (!state) continue;
351
+ toClient.push({
352
+ jsonrpc: "2.0",
353
+ method: "session/update",
354
+ params: {
355
+ sessionId,
356
+ update: {
357
+ sessionUpdate: "config_option_update",
358
+ configOptions: this.configOptions(state)
359
+ }
360
+ }
361
+ });
362
+ }
363
+ return {
364
+ toRuntime: [],
365
+ toClient,
366
+ ...settledSessionResponseIds.length > 0 ? { settledSessionResponseIds } : {}
367
+ };
368
+ }
369
+ internalRequest(kind, sessionId, responseId) {
211
370
  while (this.pending.has(this.nextInternalRequestId)) this.nextInternalRequestId -= 1;
212
371
  const id = this.nextInternalRequestId;
213
372
  this.nextInternalRequestId -= 1;
214
- this.pending.set(id, { kind, sessionId });
373
+ this.pending.set(id, { kind, sessionId, responseId });
215
374
  const { contractKey, params } = INTERNAL_REQUESTS[kind];
216
375
  return {
217
376
  jsonrpc: "2.0",
@@ -228,7 +387,7 @@ class GrokAcpCompatibilityProxy {
228
387
  return this.usageRefreshRequests(state.sessionId);
229
388
  }
230
389
  usageForPrompt(state, promptId, promptUsage) {
231
- const notification = usageNotification(promptUsage);
390
+ const notification = usageNotification(state.sessionId, promptUsage);
232
391
  if (!notification) return void 0;
233
392
  if (!rememberPrompt(state.usagePromptIds, promptId)) return void 0;
234
393
  return notification;
@@ -236,8 +395,22 @@ class GrokAcpCompatibilityProxy {
236
395
  handleClient(message) {
237
396
  if (!message || typeof message !== "object") return { toRuntime: [message], toClient: [] };
238
397
  const params = message.params ?? {};
239
- if (message.method === "session/new" || message.method === "session/load" || message.method === "session/resume") {
398
+ if (message.method === "initialize" && message.id !== void 0) {
399
+ this.pending.set(message.id, { kind: "initialize" });
400
+ return { toRuntime: [message], toClient: [] };
401
+ }
402
+ if (message.method === LODY_EXTENSION_METHODS.rateLimitsGet) {
403
+ return {
404
+ toRuntime: [this.internalRequest("rateLimits", void 0, message.id)],
405
+ toClient: []
406
+ };
407
+ }
408
+ if (message.method === "session/new" || message.method === "session/load" || message.method === "session/resume" || message.method === "session/fork") {
240
409
  const clientIdentifier = params._meta?.clientIdentifier;
410
+ const translated2 = translateSessionStart(message);
411
+ if (translated2.permissionMode && typeof clientIdentifier === "string") {
412
+ this.permissionModes.set(clientIdentifier, translated2.permissionMode);
413
+ }
241
414
  if (message.id !== void 0) {
242
415
  this.pending.set(message.id, {
243
416
  kind: "session",
@@ -246,7 +419,10 @@ class GrokAcpCompatibilityProxy {
246
419
  clientIdentifier
247
420
  });
248
421
  }
249
- return { toRuntime: [message], toClient: [] };
422
+ return {
423
+ toRuntime: translated2.notification ? [translated2.notification, translated2.message] : [translated2.message],
424
+ toClient: []
425
+ };
250
426
  }
251
427
  if (message.method === "session/prompt") {
252
428
  if (message.id !== void 0) {
@@ -358,27 +534,68 @@ class GrokAcpCompatibilityProxy {
358
534
  };
359
535
  }
360
536
  if (pending.kind === "billing") {
361
- const notification = message.error ? extensionNotification("lodyRateLimitsNotification", rateLimitsPayload(null, null)) : rateLimitsNotification(unwrapExtensionResult(message.result));
537
+ const notification = message.error ? lodyNotification(LODY_EXTENSION_METHODS.rateLimitsUpdate, rateLimitsPayload(null, null)) : rateLimitsNotification(unwrapExtensionResult(message.result));
362
538
  return {
363
539
  toRuntime: [],
364
540
  toClient: notification ? [notification] : []
365
541
  };
366
542
  }
543
+ if (pending.kind === "rateLimits") {
544
+ const result = message.error ? rateLimitsPayload(null, null) : normalizeBillingRateLimits(unwrapExtensionResult(message.result)) ?? rateLimitsPayload(null, null);
545
+ return {
546
+ toRuntime: [],
547
+ toClient: [{ jsonrpc: "2.0", id: pending.responseId, result }]
548
+ };
549
+ }
550
+ if (pending.kind === "initialize") {
551
+ if (message.error) return { toRuntime: [], toClient: [message] };
552
+ const result = message.result ?? {};
553
+ const agentCapabilities = result.agentCapabilities ?? {};
554
+ return {
555
+ toRuntime: [],
556
+ toClient: [
557
+ {
558
+ ...message,
559
+ result: {
560
+ ...result,
561
+ agentCapabilities: {
562
+ ...agentCapabilities,
563
+ _meta: {
564
+ ...agentCapabilities._meta ?? {},
565
+ lody: GROK_LODY_CAPABILITIES
566
+ }
567
+ }
568
+ }
569
+ }
570
+ ]
571
+ };
572
+ }
367
573
  if (message.error) return { toRuntime: [], toClient: [message] };
368
574
  if (pending.kind === "session") {
369
575
  const result = message.result ?? {};
370
576
  const sessionId = result.sessionId ?? pending.sessionId;
371
577
  if (!sessionId) return { toRuntime: [], toClient: [message] };
372
578
  const state2 = this.stateFromSessionResponse(sessionId, pending.clientIdentifier, result);
579
+ if (this.latestModelSnapshot) {
580
+ this.applyModelSnapshot(state2, this.latestModelSnapshot);
581
+ }
373
582
  this.sessions.set(sessionId, state2);
583
+ const sessionResponse = this.sessionResponseWithState(message, state2);
584
+ if (this.deferSessionResponseUntilModelSnapshot && !this.latestModelSnapshot && message.id !== void 0) {
585
+ this.pendingSessionResponses.set(message.id, {
586
+ message: sessionResponse,
587
+ sessionId
588
+ });
589
+ return {
590
+ toRuntime: this.usageRefreshRequests(sessionId),
591
+ toClient: [],
592
+ deferredSessionResponseIds: [message.id]
593
+ };
594
+ }
595
+ this.clientVisibleSessions.add(sessionId);
374
596
  return {
375
597
  toRuntime: this.usageRefreshRequests(sessionId),
376
- toClient: [
377
- {
378
- ...message,
379
- result: { ...result, configOptions: this.configOptions(state2) }
380
- }
381
- ]
598
+ toClient: [sessionResponse]
382
599
  };
383
600
  }
384
601
  if (pending.kind === "prompt") {
@@ -410,11 +627,14 @@ class GrokAcpCompatibilityProxy {
410
627
  }
411
628
  handleRuntimeMethod(message) {
412
629
  const passthrough = { toRuntime: [], toClient: [message] };
630
+ const logicalMethod = logicalExtensionMethod(message.method);
631
+ if (logicalMethod === contract.modelsUpdateNotification) {
632
+ return this.handleModelSnapshot(message);
633
+ }
413
634
  const sessionId = message.params?.sessionId;
414
635
  const update = message.params?.update;
415
636
  const state = this.sessions.get(sessionId);
416
637
  if (!state) return passthrough;
417
- const logicalMethod = logicalExtensionMethod(message.method);
418
638
  if (logicalMethod === contract.sessionUpdateNotification && update?.sessionUpdate === contract.turnCompletedUpdate) {
419
639
  if (message.params?._meta?.isReplay === true) return passthrough;
420
640
  const promptId = update.prompt_id ?? update.promptId;
@@ -565,16 +785,36 @@ if (!grokPath) {
565
785
  process.exit(1);
566
786
  }
567
787
  const child = spawnGrokRuntime(grokPath);
568
- const proxy = new GrokAcpCompatibilityProxy();
788
+ const proxy = new GrokAcpCompatibilityProxy({
789
+ deferSessionResponseUntilModelSnapshot: true
790
+ });
791
+ const deferredResponseTimers = /* @__PURE__ */ new Map();
569
792
  function write(stream, message) {
570
793
  stream.write(`${JSON.stringify(message)}
571
794
  `);
572
795
  }
796
+ function dispatch(output) {
797
+ for (const id of output.settledSessionResponseIds ?? []) {
798
+ const timer = deferredResponseTimers.get(id);
799
+ if (timer) clearTimeout(timer);
800
+ deferredResponseTimers.delete(id);
801
+ }
802
+ for (const message of output.toRuntime) write(child.stdin, message);
803
+ for (const message of output.toClient) write(process.stdout, message);
804
+ for (const id of output.deferredSessionResponseIds ?? []) {
805
+ const existingTimer = deferredResponseTimers.get(id);
806
+ if (existingTimer) clearTimeout(existingTimer);
807
+ const timer = setTimeout(() => {
808
+ deferredResponseTimers.delete(id);
809
+ dispatch(proxy.flushPendingSessionResponse(id));
810
+ }, GROK_MODEL_SNAPSHOT_SETTLE_TIMEOUT_MS);
811
+ deferredResponseTimers.set(id, timer);
812
+ timer.unref();
813
+ }
814
+ }
573
815
  createInterface({ input: process.stdin }).on("line", (line) => {
574
816
  try {
575
- const output = proxy.handleClient(JSON.parse(line));
576
- for (const message of output.toRuntime) write(child.stdin, message);
577
- for (const message of output.toClient) write(process.stdout, message);
817
+ dispatch(proxy.handleClient(JSON.parse(line)));
578
818
  } catch (error) {
579
819
  console.error(
580
820
  `Invalid ACP client message: ${error instanceof Error ? error.message : String(error)}`
@@ -583,9 +823,7 @@ createInterface({ input: process.stdin }).on("line", (line) => {
583
823
  });
584
824
  createInterface({ input: child.stdout }).on("line", (line) => {
585
825
  try {
586
- const output = proxy.handleRuntime(JSON.parse(line));
587
- for (const message of output.toRuntime) write(child.stdin, message);
588
- for (const message of output.toClient) write(process.stdout, message);
826
+ dispatch(proxy.handleRuntime(JSON.parse(line)));
589
827
  } catch (error) {
590
828
  console.error(
591
829
  `Invalid Grok runtime message: ${error instanceof Error ? error.message : String(error)}`