@noopolis/daimon 0.2.2 → 0.2.3

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.
@@ -64,6 +64,13 @@ export declare function createGrokBrokerProxyHandler(authority: GrokBrokerCreden
64
64
  */
65
65
  export declare class GrokBrokerProxyRefusal extends Error {
66
66
  readonly reason: string;
67
- constructor(reason: string);
67
+ readonly check?: string | undefined;
68
+ readonly detail?: string | undefined;
69
+ /**
70
+ * `check` names which body-gate check failed and `detail` is the refused
71
+ * body's content-free shape ({@link grokBrokerProxyBodyShape}); both are for
72
+ * the broker's stderr line, and `check` also rides the 400 body.
73
+ */
74
+ constructor(reason: string, check?: string | undefined, detail?: string | undefined);
68
75
  }
69
76
  //# sourceMappingURL=grokBrokerProxy.d.ts.map
@@ -1 +1 @@
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
+ {"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,EAAmC,MAAM,6BAA6B,CAAC;AAG/G,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;IAMnC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IALtF;;;;OAIG;gBACkB,MAAM,EAAE,MAAM,EAAW,KAAK,CAAC,EAAE,MAAM,YAAA,EAAW,MAAM,CAAC,EAAE,MAAM,YAAA;CACvF"}
@@ -6,7 +6,8 @@ import { CLI_ENGINE_MAX_DIAGNOSTIC_BYTES } from "../pi/cliChildOutput.js";
6
6
  import { EngineBrokerCapabilities } from "./engineBrokerCapabilities.js";
7
7
  import { ENGINE_BROKER_AUTH_STALE } from "./engineBrokerProtocol.js";
8
8
  import { DEFAULT_GROK_BROKER_MODEL_POLICY, parseGrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
9
- import { authorizeGrokBrokerProxyRequest } from "./grokBrokerProxyRequest.js";
9
+ import { authorizeGrokBrokerProxyRequest, GrokBrokerProxyRequestRejection } from "./grokBrokerProxyRequest.js";
10
+ import { formatGrokBrokerProxyBodyShape, grokBrokerProxyBodyShape } from "./grokBrokerProxyBodyShape.js";
10
11
  import { GROK_SESSION_TITLE_SINK_KEY } from "./grokBrokerWorkerConfig.js";
11
12
  import { parseGrokFinalReply, parseGrokResponseToolNames, parseGrokUpstreamUsage } from "./grokBrokerTurnMeter.js";
12
13
  import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
@@ -77,9 +78,18 @@ export function createGrokBrokerProxyHandler(authority, upstream = defaultUpstre
77
78
  */
78
79
  export class GrokBrokerProxyRefusal extends Error {
79
80
  reason;
80
- constructor(reason) {
81
+ check;
82
+ detail;
83
+ /**
84
+ * `check` names which body-gate check failed and `detail` is the refused
85
+ * body's content-free shape ({@link grokBrokerProxyBodyShape}); both are for
86
+ * the broker's stderr line, and `check` also rides the 400 body.
87
+ */
88
+ constructor(reason, check, detail) {
81
89
  super(`grok broker proxy refused: ${reason}`);
82
90
  this.reason = reason;
91
+ this.check = check;
92
+ this.detail = detail;
83
93
  }
84
94
  }
85
95
  async function serve(request, response, authority, upstream, capabilities, guards, turns, fallback, grants) {
@@ -137,7 +147,7 @@ async function serve(request, response, authority, upstream, capabilities, guard
137
147
  token = "";
138
148
  // The spend gate runs after the body is proven a real lean worker request
139
149
  // (a refused session-title body never counts) and before any upstream call.
140
- const admission = turn.meter.admit();
150
+ const admission = turn.meter.admit({ keepFinal: prepared.compaction === true });
141
151
  if ("refused" in admission) {
142
152
  response.writeHead(429, { "content-type": "application/json", "cache-control": "no-store" });
143
153
  response.end(JSON.stringify({ error: "turn limit reached", limit: admission.refused }));
@@ -167,8 +177,9 @@ async function serve(request, response, authority, upstream, capabilities, guard
167
177
  // A successful answer that called nothing and stopped is the turn's final
168
178
  // reply: the broker ends a worker that finished but did not exit on it
169
179
  // (`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);
180
+ // the worker's stdout. Observation only, exactly like the tool names. A
181
+ // compaction summary also calls nothing and stops, and is never the reply.
182
+ settle?.(usageOrEstimate(result.body, result.headers["content-type"]), toolCallsOrNothing(result.body, result.headers["content-type"]), result.status === 200 && prepared.compaction !== true ? finalReplyOrNothing(result.body, result.headers["content-type"]) : undefined);
172
183
  response.writeHead(result.status, { "content-type": result.headers["content-type"] ?? "application/json", "cache-control": "no-store" });
173
184
  response.end(result.body);
174
185
  }
@@ -191,7 +202,8 @@ async function serve(request, response, authority, upstream, capabilities, guard
191
202
  // A named refusal is its own account; anything else used to reach the log as
192
203
  // the bare word `broker_unavailable`, which names nothing — so it carries the
193
204
  // fault's own class and message, and nothing else, beside it.
194
- const named = refused ? refusal : `${refusal} (${brokerFaultCause(error, secrets)})`;
205
+ const named = !refused ? `${refusal} (${brokerFaultCause(error, secrets)})`
206
+ : error instanceof GrokBrokerProxyRefusal && error.check !== undefined ? `${refusal} check=${error.check}${error.detail === undefined ? "" : ` ${error.detail}`}` : refusal;
195
207
  if (!titleSink && !expectedWorkerProbe(request))
196
208
  process.stderr.write(`[grok-proxy] refused: ${named}\n`);
197
209
  // Grok's own session-title call is refused by design, and keeps the transient
@@ -206,7 +218,7 @@ async function serve(request, response, authority, upstream, capabilities, guard
206
218
  }
207
219
  if (refused) {
208
220
  response.writeHead(400, { "content-type": "application/json", "cache-control": "no-store" });
209
- response.end(JSON.stringify({ error: "broker refused this request", reason: refusal }));
221
+ response.end(JSON.stringify({ error: "broker refused this request", reason: refusal, ...(error instanceof GrokBrokerProxyRefusal && error.check !== undefined ? { check: error.check } : {}) }));
210
222
  return;
211
223
  }
212
224
  response.writeHead(503, { "content-type": "application/json", "cache-control": "no-store" });
@@ -307,13 +319,19 @@ const finalReplyOrNothing = (body, contentType) => {
307
319
  return undefined;
308
320
  }
309
321
  };
310
- /** The body gate, refused non-retryably: a rejected body is a policy miss, never a transient fault. */
322
+ /**
323
+ * The body gate, refused non-retryably: a rejected body is a policy miss, never
324
+ * a transient fault. The refusal names the failed check and the body's
325
+ * content-free shape, because a bare `request_body_rejected` sent a live
326
+ * training pilot to a stub harness to learn which of a dozen checks fired.
327
+ */
311
328
  function authorizeRequestOrRefuse(...args) {
312
329
  try {
313
330
  return authorizeGrokBrokerProxyRequest(...args);
314
331
  }
315
- catch {
316
- throw new GrokBrokerProxyRefusal("request_body_rejected");
332
+ catch (error) {
333
+ const check = error instanceof GrokBrokerProxyRequestRejection ? error.check : "credential";
334
+ throw new GrokBrokerProxyRefusal("request_body_rejected", check, formatGrokBrokerProxyBodyShape(grokBrokerProxyBodyShape(args[0].body)));
317
335
  }
318
336
  }
319
337
  async function readBody(request) { const chunks = []; let bytes = 0; for await (const chunk of request) {
@@ -0,0 +1,24 @@
1
+ /**
2
+ * A content-free description of one refused worker body, for the broker's own
3
+ * stderr: byte length, top-level member names, offered tool names, message
4
+ * count and roles, and `tool_choice`. Never a message, a parameter schema, a
5
+ * value of any other member, a header or a token.
6
+ *
7
+ * Every name comes from a body the worker wrote, so each is admitted only as a
8
+ * plain short identifier (anything else is `<invalid>`) and every list is
9
+ * bounded with a `<truncated>` last entry. A body that is not a JSON object
10
+ * reports its byte length alone.
11
+ */
12
+ export type GrokBrokerProxyBodyShape = Readonly<{
13
+ bytes: number;
14
+ keys?: readonly string[];
15
+ tools?: readonly string[] | "absent" | "invalid";
16
+ messages?: number | "invalid";
17
+ roles?: readonly string[];
18
+ tool_choice?: string;
19
+ }>;
20
+ export declare const GROK_PROXY_BODY_SHAPE_LIST_MAX = 32;
21
+ export declare function grokBrokerProxyBodyShape(body: Uint8Array): GrokBrokerProxyBodyShape;
22
+ /** One line, `key=value` pairs, for the `[grok-proxy] refused:` log. */
23
+ export declare const formatGrokBrokerProxyBodyShape: (shape: GrokBrokerProxyBodyShape) => string;
24
+ //# sourceMappingURL=grokBrokerProxyBodyShape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grokBrokerProxyBodyShape.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxyBodyShape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAGH,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAqBjD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,wBAAwB,CAmBnF;AAED,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,GAAI,OAAO,wBAAwB,KAAG,MAOtE,CAAC"}
@@ -0,0 +1,60 @@
1
+ const NAME = /^[A-Za-z_][A-Za-z0-9_.-]{0,63}$/u;
2
+ export const GROK_PROXY_BODY_SHAPE_LIST_MAX = 32;
3
+ const safeName = (value) => typeof value === "string" && NAME.test(value) ? value : "<invalid>";
4
+ const bounded = (values) => values.length <= GROK_PROXY_BODY_SHAPE_LIST_MAX ? values : [...values.slice(0, GROK_PROXY_BODY_SHAPE_LIST_MAX - 1), "<truncated>"];
5
+ const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
6
+ /** Roles in order, with consecutive repeats collapsed to `role*n` so a long history stays short. */
7
+ const roleRuns = (messages) => {
8
+ const runs = [];
9
+ let last;
10
+ let count = 0;
11
+ const flush = () => { if (last !== undefined)
12
+ runs.push(count > 1 ? `${last}*${count}` : last); };
13
+ for (const message of messages) {
14
+ const role = isObject(message) ? safeName(message.role) : "<invalid>";
15
+ if (role === last) {
16
+ count++;
17
+ continue;
18
+ }
19
+ flush();
20
+ last = role;
21
+ count = 1;
22
+ }
23
+ flush();
24
+ return bounded(runs);
25
+ };
26
+ export function grokBrokerProxyBodyShape(body) {
27
+ let parsed;
28
+ try {
29
+ parsed = JSON.parse(new TextDecoder("utf-8", { fatal: false }).decode(body));
30
+ }
31
+ catch {
32
+ return { bytes: body.byteLength };
33
+ }
34
+ if (!isObject(parsed))
35
+ return { bytes: body.byteLength };
36
+ const tools = parsed.tools === undefined ? "absent" : Array.isArray(parsed.tools)
37
+ ? bounded(parsed.tools.map((tool) => isObject(tool) && isObject(tool.function) ? safeName(tool.function.name) : "<invalid>"))
38
+ : "invalid";
39
+ const choice = parsed.tool_choice;
40
+ return {
41
+ bytes: body.byteLength,
42
+ keys: bounded(Object.keys(parsed).map(safeName).sort()),
43
+ tools,
44
+ messages: Array.isArray(parsed.messages) ? parsed.messages.length : "invalid",
45
+ ...(Array.isArray(parsed.messages) ? { roles: roleRuns(parsed.messages) } : {}),
46
+ ...(choice === undefined ? {} : {
47
+ tool_choice: typeof choice === "string" ? safeName(choice)
48
+ : isObject(choice) ? `object:${isObject(choice.function) ? safeName(choice.function.name) : safeName(choice.type)}` : "<invalid>"
49
+ })
50
+ };
51
+ }
52
+ /** One line, `key=value` pairs, for the `[grok-proxy] refused:` log. */
53
+ export const formatGrokBrokerProxyBodyShape = (shape) => [
54
+ `bytes=${shape.bytes}`,
55
+ ...(shape.keys === undefined ? [] : [`keys=${shape.keys.join(",")}`]),
56
+ ...(shape.tools === undefined ? [] : [`tools=${Array.isArray(shape.tools) ? shape.tools.join(",") : shape.tools}`]),
57
+ ...(shape.messages === undefined ? [] : [`messages=${shape.messages}`]),
58
+ ...(shape.roles === undefined ? [] : [`roles=${shape.roles.join(",")}`]),
59
+ ...(shape.tool_choice === undefined ? [] : [`tool_choice=${shape.tool_choice}`])
60
+ ].join(" ");
@@ -1,5 +1,15 @@
1
1
  import type { EngineBrokerCapabilities } from "./engineBrokerCapabilities.js";
2
2
  import { type GrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
3
+ /**
4
+ * Which body-gate check refused a request: a closed, content-free code, so a
5
+ * refusal on the broker's stderr names its cause without a stub harness.
6
+ */
7
+ export type GrokBrokerProxyRejectionCheck = "route" | "body_size" | "bearer" | "scope" | "client_version" | "json" | "envelope" | "model" | "reasoning_effort" | "tools" | "members" | "stream_options";
8
+ /** A body-gate refusal. The message is the historic one; `check` names the failed check. */
9
+ export declare class GrokBrokerProxyRequestRejection extends Error {
10
+ readonly check: GrokBrokerProxyRejectionCheck;
11
+ constructor(check: GrokBrokerProxyRejectionCheck);
12
+ }
3
13
  export type GrokBrokerProxyInput = Readonly<{
4
14
  method: string;
5
15
  pathname: string;
@@ -8,10 +18,12 @@ export type GrokBrokerProxyInput = Readonly<{
8
18
  agentId?: string;
9
19
  turnId?: string;
10
20
  }>;
21
+ /** `compaction` marks a normalized auto-compaction summary request: its answer is a summary, never the turn's final reply. */
11
22
  export type GrokBrokerUpstreamRequest = Readonly<{
12
23
  url: "https://cli-chat-proxy.grok.com/v1/chat/completions";
13
24
  headers: Readonly<Record<string, string>>;
14
25
  body: Uint8Array;
26
+ compaction?: true;
15
27
  }>;
16
28
  /**
17
29
  * Authorizes one worker request and rebuilds it for the provider.
@@ -24,7 +36,24 @@ export type GrokBrokerUpstreamRequest = Readonly<{
24
36
  * - the offered tool names are exactly the lean visible set. Grok 1.0.34 turns
25
37
  * an unmappable `--tools` entry into its full 19-tool set, and its per-turn
26
38
  * `session_title` request carries a single forced tool; both are refused.
39
+ *
40
+ * One other shape is admitted, and only by normalizing it into the lean one:
41
+ * Grok 1.0.34's auto-compaction summary request ({@link normalizeGrokCompactionRequest}).
27
42
  */
28
43
  export declare function authorizeGrokBrokerProxyRequest(input: GrokBrokerProxyInput, capabilities: EngineBrokerCapabilities, bearer: string, policy?: GrokBrokerModelPolicy): GrokBrokerUpstreamRequest;
44
+ /**
45
+ * Rewrites, in place, exactly the captured compaction shape into the lean
46
+ * worker shape, and reports whether it did. The two extra members are each
47
+ * the provider's default value (`tool_choice: "auto"` with tools offered,
48
+ * `temperature: 1`), so removing them changes nothing the model is asked; the
49
+ * missing effort is set to the declared one, so the request cannot fall back
50
+ * to a provider default effort. Every other check — model, tools, stream
51
+ * options — then runs on the result exactly as for any worker request, and
52
+ * the forwarded body is indistinguishable from an ordinary lean request: the
53
+ * spend envelope is unchanged. Any other value of either member (a forced
54
+ * `tool_choice`, another temperature) or any other member set is left as is,
55
+ * and refused by the ordinary checks.
56
+ */
57
+ export declare function normalizeGrokCompactionRequest(parsed: Record<string, unknown>, reasoningEffort: string): boolean;
29
58
  export declare function exactLeanTools(tools: unknown): boolean;
30
59
  //# sourceMappingURL=grokBrokerProxyRequest.d.ts.map
@@ -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,CAmChO;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;AAItI;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,gBAAgB,CAAC;AAExM,4FAA4F;AAC5F,qBAAa,+BAAgC,SAAQ,KAAK;IAC5C,QAAQ,CAAC,KAAK,EAAE,6BAA6B;gBAApC,KAAK,EAAE,6BAA6B;CAC1D;AAED,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,8HAA8H;AAC9H,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,CAAC;IAAC,UAAU,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC;AAEjM;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,qBAAwD,GAAG,yBAAyB,CAwChO;AAcD;;;;;;;;;;;;GAYG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAOhH;AASD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAStD"}
@@ -2,6 +2,15 @@ import { GROK_ENGINE_BROKER } from "../contracts/runtimeContractManifest.js";
2
2
  import { GROK_WORKER_VISIBLE_TOOLS } from "../contracts/grokWorkerContract.js";
3
3
  import { DEFAULT_GROK_BROKER_MODEL_POLICY, parseGrokBrokerModelPolicy } from "./grokBrokerModelPolicy.js";
4
4
  const MAX_BODY = 2 * 1024 * 1024;
5
+ /** A body-gate refusal. The message is the historic one; `check` names the failed check. */
6
+ export class GrokBrokerProxyRequestRejection extends Error {
7
+ check;
8
+ constructor(check) {
9
+ super("broker proxy request rejected");
10
+ this.check = check;
11
+ }
12
+ }
13
+ function reject(check) { throw new GrokBrokerProxyRequestRejection(check); }
5
14
  /**
6
15
  * Authorizes one worker request and rebuilds it for the provider.
7
16
  *
@@ -13,23 +22,28 @@ const MAX_BODY = 2 * 1024 * 1024;
13
22
  * - the offered tool names are exactly the lean visible set. Grok 1.0.34 turns
14
23
  * an unmappable `--tools` entry into its full 19-tool set, and its per-turn
15
24
  * `session_title` request carries a single forced tool; both are refused.
25
+ *
26
+ * One other shape is admitted, and only by normalizing it into the lean one:
27
+ * Grok 1.0.34's auto-compaction summary request ({@link normalizeGrokCompactionRequest}).
16
28
  */
17
29
  export function authorizeGrokBrokerProxyRequest(input, capabilities, bearer, policy = DEFAULT_GROK_BROKER_MODEL_POLICY) {
18
30
  const declared = parseGrokBrokerModelPolicy(policy);
19
- if (input.method !== "POST" || input.pathname !== "/v1/chat/completions" || input.body.byteLength < 2 || input.body.byteLength > MAX_BODY)
20
- throw new Error("broker proxy request rejected");
31
+ if (input.method !== "POST" || input.pathname !== "/v1/chat/completions")
32
+ reject("route");
33
+ if (input.body.byteLength < 2 || input.body.byteLength > MAX_BODY)
34
+ reject("body_size");
21
35
  const authorization = input.headers.authorization;
22
36
  const match = authorization?.match(/^Bearer ([A-Za-z0-9_-]{40,})$/u);
23
37
  if (match === null || match === undefined)
24
- throw new Error("broker proxy request rejected");
38
+ return reject("bearer");
25
39
  const scope = capabilities.authorizeToken(match[1]);
26
40
  if (scope === undefined || (input.agentId !== undefined && scope.agentId !== input.agentId) || (input.turnId !== undefined && scope.turnId !== input.turnId))
27
- throw new Error("broker proxy request rejected");
41
+ reject("scope");
28
42
  if (!bearer || /[\r\n]/u.test(bearer))
29
43
  throw new Error("broker credential authority unavailable");
30
44
  const clientVersion = input.headers["x-grok-client-version"];
31
45
  if (clientVersion !== GROK_ENGINE_BROKER.grokCliVersion)
32
- throw new Error("broker proxy request rejected");
46
+ reject("client_version");
33
47
  let parsed;
34
48
  // `__proto__` is refused at any depth: JSON.parse makes it an ordinary own
35
49
  // member, but an upstream JavaScript parser may treat it as a prototype.
@@ -41,16 +55,21 @@ export function authorizeGrokBrokerProxyRequest(input, capabilities, bearer, pol
41
55
  });
42
56
  }
43
57
  catch {
44
- throw new Error("broker proxy request rejected");
58
+ return reject("json");
45
59
  }
46
60
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed) || parsed.stream !== true || !Array.isArray(parsed.messages))
47
- throw new Error("broker proxy request rejected");
48
- if (parsed.model !== declared.model || parsed.reasoning_effort !== declared.reasoningEffort)
49
- throw new Error("broker proxy request rejected");
61
+ reject("envelope");
62
+ const compaction = normalizeGrokCompactionRequest(parsed, declared.reasoningEffort);
63
+ if (parsed.model !== declared.model)
64
+ reject("model");
65
+ if (parsed.reasoning_effort !== declared.reasoningEffort)
66
+ reject("reasoning_effort");
50
67
  if (!exactLeanTools(parsed.tools))
51
- throw new Error("broker proxy request rejected");
52
- if (Object.keys(parsed).some((key) => !LEAN_BODY_MEMBERS.has(key)) || !validStreamOptions(parsed.stream_options))
53
- throw new Error("broker proxy request rejected");
68
+ reject("tools");
69
+ if (Object.keys(parsed).some((key) => !LEAN_BODY_MEMBERS.has(key)))
70
+ reject("members");
71
+ if (!validStreamOptions(parsed.stream_options))
72
+ reject("stream_options");
54
73
  // Keep origin/main's production handling: UTF-8 replacement decoding, then
55
74
  // serialize the validated object (including last-member-wins duplicates).
56
75
  // Only a clocked turn takes the stricter date rewrite before this gate.
@@ -61,9 +80,45 @@ export function authorizeGrokBrokerProxyRequest(input, capabilities, bearer, pol
61
80
  "x-xai-token-auth": "xai-grok-cli", "x-grok-model-override": declared.model,
62
81
  "x-grok-client-version": clientVersion, "x-grok-client-identifier": "grok-shell"
63
82
  },
64
- body: Buffer.from(JSON.stringify(parsed))
83
+ body: Buffer.from(JSON.stringify(parsed)),
84
+ ...(compaction ? { compaction: true } : {})
65
85
  };
66
86
  }
87
+ /**
88
+ * Top-level members of Grok 1.0.34's auto-compaction summary request (live stub
89
+ * capture against the pinned binary in the training image, 2026-10-21). When a
90
+ * session nears the model's `context_window`, Grok asks the same model for a
91
+ * summary — single-pass, or a second "two-pass" request — and sends it with
92
+ * the lean tool set, `tool_choice: "auto"` and `temperature: 1`, and *without*
93
+ * `reasoning_effort`. Refusing it does not stop the session: Grok gives up on
94
+ * compaction and carries the whole history forward, so every refusal was a
95
+ * wasted round trip and the context kept growing.
96
+ */
97
+ const COMPACTION_BODY_MEMBERS = new Set(["messages", "model", "stream", "stream_options", "temperature", "tool_choice", "tools"]);
98
+ /**
99
+ * Rewrites, in place, exactly the captured compaction shape into the lean
100
+ * worker shape, and reports whether it did. The two extra members are each
101
+ * the provider's default value (`tool_choice: "auto"` with tools offered,
102
+ * `temperature: 1`), so removing them changes nothing the model is asked; the
103
+ * missing effort is set to the declared one, so the request cannot fall back
104
+ * to a provider default effort. Every other check — model, tools, stream
105
+ * options — then runs on the result exactly as for any worker request, and
106
+ * the forwarded body is indistinguishable from an ordinary lean request: the
107
+ * spend envelope is unchanged. Any other value of either member (a forced
108
+ * `tool_choice`, another temperature) or any other member set is left as is,
109
+ * and refused by the ordinary checks.
110
+ */
111
+ export function normalizeGrokCompactionRequest(parsed, reasoningEffort) {
112
+ const keys = Object.keys(parsed);
113
+ if (keys.length !== COMPACTION_BODY_MEMBERS.size || keys.some((key) => !COMPACTION_BODY_MEMBERS.has(key)))
114
+ return false;
115
+ if (parsed.temperature !== 1 || parsed.tool_choice !== "auto")
116
+ return false;
117
+ delete parsed.temperature;
118
+ delete parsed.tool_choice;
119
+ parsed.reasoning_effort = reasoningEffort;
120
+ return true;
121
+ }
67
122
  /** Top-level members of a Grok 1.0.34 lean worker chat-completions body (live stub capture). */
68
123
  const LEAN_BODY_MEMBERS = new Set(["messages", "model", "reasoning_effort", "stream", "stream_options", "tools"]);
69
124
  /** Members of each lean tool `function` entry (live stub capture). */
@@ -83,8 +83,13 @@ export declare class GrokBrokerTurnMeter {
83
83
  private final;
84
84
  private activityAt;
85
85
  constructor(limits: EngineBrokerTurnLimits, onLimit?: (reason: Exclude<EngineBrokerLimitReason, "none">) => void, now?: () => number);
86
- /** Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight. */
87
- admit(): Readonly<{
86
+ /**
87
+ * Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight.
88
+ * `keepFinal` admits a request that cannot replace the answer (a compaction summary), so a final reply already recorded survives it.
89
+ */
90
+ admit(options?: Readonly<{
91
+ keepFinal?: boolean;
92
+ }>): Readonly<{
88
93
  index: number;
89
94
  signal: AbortSignal;
90
95
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"grokBrokerTurnMeter.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTurnMeter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grokBrokerTurnMeter.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTurnMeter.ts"],"names":[],"mappings":"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"}
@@ -63,8 +63,11 @@ export class GrokBrokerTurnMeter {
63
63
  this.startedAt = now();
64
64
  this.activityAt = this.startedAt;
65
65
  }
66
- /** Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight. */
67
- admit() {
66
+ /**
67
+ * Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight.
68
+ * `keepFinal` admits a request that cannot replace the answer (a compaction summary), so a final reply already recorded survives it.
69
+ */
70
+ admit(options = {}) {
68
71
  if (this.reason === "none") {
69
72
  if (this.now() - this.startedAt >= this.limits.timeoutMs)
70
73
  this.trip("timeout");
@@ -78,8 +81,9 @@ export class GrokBrokerTurnMeter {
78
81
  if (this.inFlight !== undefined)
79
82
  return { busy: true };
80
83
  this.timings.push({ startedAt: new Date(this.now()).toISOString() });
81
- // A new request means the previous answer was not the last one.
82
- this.final = undefined;
84
+ // A new sampling request means the previous answer was not the last one.
85
+ if (options.keepFinal !== true)
86
+ this.final = undefined;
83
87
  this.activityAt = this.now();
84
88
  const controller = new AbortController();
85
89
  this.inFlight = { index: this.timings.length - 1, controller };
@@ -226,7 +226,7 @@ function moltnetTool(agent, wakeContext) {
226
226
  }
227
227
  async function connect(agent, server) {
228
228
  taskClockChildEnvironment(server.env);
229
- const client = new Client({ name: "daimon-production", version: "0.2.2" });
229
+ const client = new Client({ name: "daimon-production", version: "0.2.3" });
230
230
  const headers = server.authSecretEnv === undefined ? {} : { authorization: `Bearer ${requiredSecret(server.authSecretEnv)}` };
231
231
  const transport = server.transport === "stdio"
232
232
  ? new StdioClientTransport({ command: server.command, args: [...server.args], env: stringEnvironment(readyTaskClockEnvironment({ ...server.env, ...cliChildEnvironment([], agent.runtimeHomePath, { executablePath: server.command }) })) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noopolis/daimon",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Noopolis native per-agent runtime harness built on Pi.",
5
5
  "license": "MIT",
6
6
  "type": "module",