@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.
- package/dist/runtime/grokBrokerProxy.d.ts +8 -1
- package/dist/runtime/grokBrokerProxy.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProxy.js +28 -10
- package/dist/runtime/grokBrokerProxyBodyShape.d.ts +24 -0
- package/dist/runtime/grokBrokerProxyBodyShape.d.ts.map +1 -0
- package/dist/runtime/grokBrokerProxyBodyShape.js +60 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts +29 -0
- package/dist/runtime/grokBrokerProxyRequest.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProxyRequest.js +68 -13
- package/dist/runtime/grokBrokerTurnMeter.d.ts +7 -2
- package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -1
- package/dist/runtime/grokBrokerTurnMeter.js +8 -4
- package/dist/runtime/productionAgentTools.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
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
|
-
/**
|
|
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
|
-
|
|
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;
|
|
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"
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
52
|
-
if (Object.keys(parsed).some((key) => !LEAN_BODY_MEMBERS.has(key))
|
|
53
|
-
|
|
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
|
-
/**
|
|
87
|
-
|
|
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":"AACA,OAAO,EAA4B,KAAK,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAElK;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AACxK,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,uBAAuB,CAAC;IAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,uBAAuB,EAAE,CAAA;CAAE,CAAC,CAAC;AAC5O,wHAAwH;AACxH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEzF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AACnD,yGAAyG;AACzG,eAAO,MAAM,iBAAiB,GAAI,OAAO,qBAAqB,KAAG,MAC4B,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,mBAAmB;IAQlB,QAAQ,CAAC,MAAM,EAAE,sBAAsB;IAAE,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAgF,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPjL,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiI;IACzJ,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,QAAQ,CAA6D;IAC7E,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,UAAU,CAAS;gBACN,MAAM,EAAE,sBAAsB,EAAmB,OAAO,GAAE,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,EAAE,MAAM,CAAC,KAAK,IAAsB,EAAmB,GAAG,GAAE,MAAM,MAAiB;IAK1M
|
|
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
|
-
/**
|
|
67
|
-
|
|
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
|
-
|
|
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.
|
|
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 }) })) })
|