@noopolis/daimon 0.2.4 → 0.2.5
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/grokBrokerAdmission.d.ts +29 -0
- package/dist/runtime/grokBrokerAdmission.d.ts.map +1 -0
- package/dist/runtime/grokBrokerAdmission.js +39 -0
- package/dist/runtime/grokBrokerProxy.d.ts.map +1 -1
- package/dist/runtime/grokBrokerProxy.js +8 -6
- package/dist/runtime/grokBrokerTurnMeter.d.ts +22 -7
- package/dist/runtime/grokBrokerTurnMeter.d.ts.map +1 -1
- package/dist/runtime/grokBrokerTurnMeter.js +35 -7
- package/dist/runtime/grokInferenceProxy.d.ts.map +1 -1
- package/dist/runtime/grokInferenceProxy.js +5 -3
- package/dist/runtime/productionAgentTools.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
import type { GrokBrokerTurnMeter } from "./grokBrokerTurnMeter.js";
|
|
3
|
+
type Admission = ReturnType<GrokBrokerTurnMeter["admit"]>;
|
|
4
|
+
/** Admitted (index and upstream signal) or refused by a limit: never `busy`. */
|
|
5
|
+
export type GrokBrokerSettledAdmission = Exclude<Admission, Readonly<{
|
|
6
|
+
busy: true;
|
|
7
|
+
}>>;
|
|
8
|
+
/**
|
|
9
|
+
* Admits one request to a meter's single upstream lane, waiting its turn
|
|
10
|
+
* instead of refusing it while another request is in flight.
|
|
11
|
+
*
|
|
12
|
+
* A refusal there is not a spend control — the waiting request is admitted
|
|
13
|
+
* afresh, every limit re-checked against the total the in-flight answer just
|
|
14
|
+
* reported into — but it is fatal to the turn: the worker runs with
|
|
15
|
+
* `max_retries = 0`, so one 429 `turn request in flight` ends its turn. That is
|
|
16
|
+
* what killed Grok training pilots 52–54 (`grokBrokerTurnMeter.ts`): the proxy
|
|
17
|
+
* received two copies of one logically sequential request and refused the copy
|
|
18
|
+
* the worker was reading.
|
|
19
|
+
*
|
|
20
|
+
* - `gone`: the client closed its connection while waiting. The request is
|
|
21
|
+
* never admitted, counted or forwarded; nobody is left to read an answer.
|
|
22
|
+
* - `revoked`: `current()` turned false while waiting (the turn ended and was
|
|
23
|
+
* revoked). The caller refuses it exactly as a request that arrived late.
|
|
24
|
+
*/
|
|
25
|
+
export declare function admitWhenIdle(meter: GrokBrokerTurnMeter, response: ServerResponse, options: Readonly<{
|
|
26
|
+
keepFinal?: boolean;
|
|
27
|
+
}>, current?: () => boolean): Promise<GrokBrokerSettledAdmission | "gone" | "revoked">;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=grokBrokerAdmission.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokBrokerAdmission.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerAdmission.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,KAAK,SAAS,GAAG,UAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1D,gFAAgF;AAChF,MAAM,MAAM,0BAA0B,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAAC,CAAC;AAEtF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EAAE,OAAO,GAAE,MAAM,OAAoB,GACpI,OAAO,CAAC,0BAA0B,GAAG,MAAM,GAAG,SAAS,CAAC,CAe1D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admits one request to a meter's single upstream lane, waiting its turn
|
|
3
|
+
* instead of refusing it while another request is in flight.
|
|
4
|
+
*
|
|
5
|
+
* A refusal there is not a spend control — the waiting request is admitted
|
|
6
|
+
* afresh, every limit re-checked against the total the in-flight answer just
|
|
7
|
+
* reported into — but it is fatal to the turn: the worker runs with
|
|
8
|
+
* `max_retries = 0`, so one 429 `turn request in flight` ends its turn. That is
|
|
9
|
+
* what killed Grok training pilots 52–54 (`grokBrokerTurnMeter.ts`): the proxy
|
|
10
|
+
* received two copies of one logically sequential request and refused the copy
|
|
11
|
+
* the worker was reading.
|
|
12
|
+
*
|
|
13
|
+
* - `gone`: the client closed its connection while waiting. The request is
|
|
14
|
+
* never admitted, counted or forwarded; nobody is left to read an answer.
|
|
15
|
+
* - `revoked`: `current()` turned false while waiting (the turn ended and was
|
|
16
|
+
* revoked). The caller refuses it exactly as a request that arrived late.
|
|
17
|
+
*/
|
|
18
|
+
export async function admitWhenIdle(meter, response, options, current = () => true) {
|
|
19
|
+
let admission = meter.admit(options);
|
|
20
|
+
if (!("busy" in admission))
|
|
21
|
+
return admission;
|
|
22
|
+
let gone = false, onClose;
|
|
23
|
+
const closed = new Promise((resolve) => { onClose = () => { gone = true; resolve(); }; });
|
|
24
|
+
response.once("close", onClose);
|
|
25
|
+
try {
|
|
26
|
+
while ("busy" in admission) {
|
|
27
|
+
await Promise.race([meter.whenIdle(), closed]);
|
|
28
|
+
if (gone || response.destroyed)
|
|
29
|
+
return "gone";
|
|
30
|
+
if (!current())
|
|
31
|
+
return "revoked";
|
|
32
|
+
admission = meter.admit(options);
|
|
33
|
+
}
|
|
34
|
+
return admission;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
response.off("close", onClose);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"grokBrokerProxy.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGxF,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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GrokBrokerRunLimit } from "./grokBrokerRunBudget.js";
|
|
2
|
+
import { admitWhenIdle } from "./grokBrokerAdmission.js";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { createServer } from "node:http";
|
|
4
5
|
import { redactCredentialText } from "../core/credentialRedaction.js";
|
|
@@ -147,17 +148,18 @@ async function serve(request, response, authority, upstream, capabilities, guard
|
|
|
147
148
|
token = "";
|
|
148
149
|
// The spend gate runs after the body is proven a real lean worker request
|
|
149
150
|
// (a refused session-title body never counts) and before any upstream call.
|
|
150
|
-
|
|
151
|
+
// A request that meets another still in flight waits for it rather than being
|
|
152
|
+
// refused: one 429 ends the worker's turn (`grokBrokerAdmission.ts`).
|
|
153
|
+
const admission = await admitWhenIdle(turn.meter, response, { keepFinal: prepared.compaction === true }, () => turns.get(scope.turnId) === turn && guards.has(scope.turnId));
|
|
154
|
+
if (admission === "gone")
|
|
155
|
+
return;
|
|
156
|
+
if (admission === "revoked")
|
|
157
|
+
throw new GrokBrokerProxyRefusal("no_active_turn");
|
|
151
158
|
if ("refused" in admission) {
|
|
152
159
|
response.writeHead(429, { "content-type": "application/json", "cache-control": "no-store" });
|
|
153
160
|
response.end(JSON.stringify({ error: "turn limit reached", limit: admission.refused }));
|
|
154
161
|
return;
|
|
155
162
|
}
|
|
156
|
-
if ("busy" in admission) {
|
|
157
|
-
response.writeHead(429, { "content-type": "application/json", "cache-control": "no-store" });
|
|
158
|
-
response.end('{"error":"turn request in flight"}');
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
163
|
settle = (usage, toolCalls, finalReply) => { turn.meter.settle(admission.index, usage, body.byteLength, toolCalls, finalReply); settle = undefined; };
|
|
162
164
|
let result = await upstream(prepared, admission.signal);
|
|
163
165
|
if (result.status === 401) {
|
|
@@ -63,13 +63,20 @@ export declare const grokCeilingTokens: (usage: EngineBrokerTurnUsage) => number
|
|
|
63
63
|
*
|
|
64
64
|
* The token bound is only a bound if no request can be admitted on a total
|
|
65
65
|
* that an in-flight request has not yet reported into. So a turn has at most
|
|
66
|
-
* ONE upstream request in flight:
|
|
67
|
-
*
|
|
68
|
-
* limit
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
66
|
+
* ONE upstream request in flight: {@link admit} answers `busy` for a second
|
|
67
|
+
* request while the first is unsettled, without counting it or tripping a
|
|
68
|
+
* limit, and the proxy then waits on {@link whenIdle} and admits it afresh —
|
|
69
|
+
* every limit re-checked against a total that now includes the first answer.
|
|
70
|
+
* It is never refused for arriving early: Grok's loop is sequential, but the
|
|
71
|
+
* proxy does not see it that way. Training pilot run54 logged one
|
|
72
|
+
* `inference_start` for loop 17, yet two copies of that request reached the
|
|
73
|
+
* proxy 4 ms apart (`provider_clock.requests` 18 against 17 admitted); the
|
|
74
|
+
* first was admitted and answered upstream, the second was refused 429 `turn
|
|
75
|
+
* request in flight`, and that refusal was the copy Grok read, so the turn
|
|
76
|
+
* failed at the 10-minute idle bound with its work in progress. Runs 52 and 53
|
|
77
|
+
* died the same way. Tripping a limit (including the broker's timer) aborts
|
|
78
|
+
* that in-flight upstream call through its own `AbortSignal` rather than
|
|
79
|
+
* letting it run to completion, and wakes every waiter into its refusal.
|
|
73
80
|
*/
|
|
74
81
|
export declare class GrokBrokerTurnMeter {
|
|
75
82
|
readonly limits: EngineBrokerTurnLimits;
|
|
@@ -82,6 +89,7 @@ export declare class GrokBrokerTurnMeter {
|
|
|
82
89
|
private inFlight;
|
|
83
90
|
private final;
|
|
84
91
|
private activityAt;
|
|
92
|
+
private idleWaiters;
|
|
85
93
|
constructor(limits: EngineBrokerTurnLimits, onLimit?: (reason: Exclude<EngineBrokerLimitReason, "none">) => void, now?: () => number);
|
|
86
94
|
/**
|
|
87
95
|
* Returns the request index and its upstream abort signal when admitted, the limit that refused it, or `busy` while another request is in flight.
|
|
@@ -112,6 +120,13 @@ export declare class GrokBrokerTurnMeter {
|
|
|
112
120
|
* not exited, and report finished work whose stdout the launcher refused.
|
|
113
121
|
*/
|
|
114
122
|
settle(index: number, usage: EngineBrokerTurnUsage | undefined, requestBytes: number, toolCalls?: readonly string[], finalReply?: string): void;
|
|
123
|
+
/**
|
|
124
|
+
* Resolves once no request is in flight, or once a limit has tripped. A
|
|
125
|
+
* request that met `busy` waits here and calls {@link admit} again; it may
|
|
126
|
+
* meet `busy` once more if another waiter was admitted first.
|
|
127
|
+
*/
|
|
128
|
+
whenIdle(): Promise<void>;
|
|
129
|
+
private wakeIdle;
|
|
115
130
|
/** The turn's final reply, while no later request has been admitted. */
|
|
116
131
|
finalReply(): GrokBrokerFinalReply | undefined;
|
|
117
132
|
/** Whether a model request is in flight right now. */
|
|
@@ -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
|
|
1
|
+
{"version":3,"file":"grokBrokerTurnMeter.d.ts","sourceRoot":"","sources":["../../src/runtime/grokBrokerTurnMeter.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,13 +37,20 @@ export const grokCeilingTokens = (usage) => usage.total - usage.cacheRead + Math
|
|
|
37
37
|
*
|
|
38
38
|
* The token bound is only a bound if no request can be admitted on a total
|
|
39
39
|
* that an in-flight request has not yet reported into. So a turn has at most
|
|
40
|
-
* ONE upstream request in flight:
|
|
41
|
-
*
|
|
42
|
-
* limit
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
40
|
+
* ONE upstream request in flight: {@link admit} answers `busy` for a second
|
|
41
|
+
* request while the first is unsettled, without counting it or tripping a
|
|
42
|
+
* limit, and the proxy then waits on {@link whenIdle} and admits it afresh —
|
|
43
|
+
* every limit re-checked against a total that now includes the first answer.
|
|
44
|
+
* It is never refused for arriving early: Grok's loop is sequential, but the
|
|
45
|
+
* proxy does not see it that way. Training pilot run54 logged one
|
|
46
|
+
* `inference_start` for loop 17, yet two copies of that request reached the
|
|
47
|
+
* proxy 4 ms apart (`provider_clock.requests` 18 against 17 admitted); the
|
|
48
|
+
* first was admitted and answered upstream, the second was refused 429 `turn
|
|
49
|
+
* request in flight`, and that refusal was the copy Grok read, so the turn
|
|
50
|
+
* failed at the 10-minute idle bound with its work in progress. Runs 52 and 53
|
|
51
|
+
* died the same way. Tripping a limit (including the broker's timer) aborts
|
|
52
|
+
* that in-flight upstream call through its own `AbortSignal` rather than
|
|
53
|
+
* letting it run to completion, and wakes every waiter into its refusal.
|
|
47
54
|
*/
|
|
48
55
|
export class GrokBrokerTurnMeter {
|
|
49
56
|
limits;
|
|
@@ -56,6 +63,7 @@ export class GrokBrokerTurnMeter {
|
|
|
56
63
|
inFlight;
|
|
57
64
|
final;
|
|
58
65
|
activityAt;
|
|
66
|
+
idleWaiters = [];
|
|
59
67
|
constructor(limits, onLimit = () => undefined, now = Date.now) {
|
|
60
68
|
this.limits = limits;
|
|
61
69
|
this.onLimit = onLimit;
|
|
@@ -122,6 +130,25 @@ export class GrokBrokerTurnMeter {
|
|
|
122
130
|
this.activityAt = this.now();
|
|
123
131
|
if (finalReply !== undefined && toolCalls !== undefined && toolCalls.length === 0 && index === this.timings.length - 1)
|
|
124
132
|
this.final = { index, text: finalReply, at: this.activityAt };
|
|
133
|
+
// Waiters resume asynchronously, after this settle has added the answer's tokens.
|
|
134
|
+
if (this.inFlight === undefined)
|
|
135
|
+
this.wakeIdle();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolves once no request is in flight, or once a limit has tripped. A
|
|
139
|
+
* request that met `busy` waits here and calls {@link admit} again; it may
|
|
140
|
+
* meet `busy` once more if another waiter was admitted first.
|
|
141
|
+
*/
|
|
142
|
+
whenIdle() {
|
|
143
|
+
if (this.inFlight === undefined || this.reason !== "none")
|
|
144
|
+
return Promise.resolve();
|
|
145
|
+
return new Promise((resolve) => { this.idleWaiters.push(resolve); });
|
|
146
|
+
}
|
|
147
|
+
wakeIdle() {
|
|
148
|
+
const waiters = this.idleWaiters;
|
|
149
|
+
this.idleWaiters = [];
|
|
150
|
+
for (const wake of waiters)
|
|
151
|
+
wake();
|
|
125
152
|
}
|
|
126
153
|
/** The turn's final reply, while no later request has been admitted. */
|
|
127
154
|
finalReply() { return this.final; }
|
|
@@ -135,6 +162,7 @@ export class GrokBrokerTurnMeter {
|
|
|
135
162
|
return;
|
|
136
163
|
this.reason = reason;
|
|
137
164
|
this.abortInFlight();
|
|
165
|
+
this.wakeIdle();
|
|
138
166
|
this.onLimit(reason);
|
|
139
167
|
}
|
|
140
168
|
/** Aborts the in-flight upstream call, if any (limit trip, or the broker ending the turn). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokInferenceProxy.d.ts","sourceRoot":"","sources":["../../src/runtime/grokInferenceProxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"grokInferenceProxy.d.ts","sourceRoot":"","sources":["../../src/runtime/grokInferenceProxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIhD,OAAO,KAAK,EAAE,6BAA6B,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,MAAM,MAAM,uBAAuB,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,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEzK,yGAAyG;AACzG,eAAO,MAAM,8BAA8B,+BAA2B,CAAC;AAEvE;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,mBAAmB,EAAE,SAAS,EAAE,6BAA6B,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC1N"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GrokBrokerRunLimit } from "./grokBrokerRunBudget.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import { admitWhenIdle } from "./grokBrokerAdmission.js";
|
|
3
4
|
import { GrokBrokerProxyRefusal } from "./grokBrokerProxy.js";
|
|
4
5
|
import { parseGrokUpstreamUsage } from "./grokBrokerTurnMeter.js";
|
|
5
6
|
import { authorizeGrokInferenceProxyRequest } from "./grokInferenceProxyRequest.js";
|
|
@@ -37,11 +38,12 @@ export async function serveGrokInferenceGrant(input, response, grants, authority
|
|
|
37
38
|
const rejectedDigest = createHash("sha256").update(token).digest("hex");
|
|
38
39
|
prepared = withBearer(prepared, token);
|
|
39
40
|
token = "";
|
|
40
|
-
|
|
41
|
+
// Same lane rule as a turn: an overlapping request waits, a released grant trips its waiters into a refusal.
|
|
42
|
+
const admission = await admitWhenIdle(grant.meter, response, {});
|
|
43
|
+
if (admission === "gone" || admission === "revoked")
|
|
44
|
+
return;
|
|
41
45
|
if ("refused" in admission)
|
|
42
46
|
return json(response, 429, JSON.stringify({ error: "grant limit reached", limit: admission.refused }));
|
|
43
|
-
if ("busy" in admission)
|
|
44
|
-
return json(response, 429, '{"error":"grant request in flight"}');
|
|
45
47
|
settle = (usage) => { settle = undefined; grants.settle(grant, admission.index, usage, input.body.byteLength); };
|
|
46
48
|
let result = await upstream(prepared, admission.signal);
|
|
47
49
|
if (result.status === 401) {
|
|
@@ -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.5" });
|
|
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 }) })) })
|