@tokenfactory/acc-runner 0.40.1 → 0.40.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ClaudeUsage } from "./cost-pricing.js";
|
|
2
|
+
/** Claude subscription capacity window: 5 hours, rolling. // keep in sync */
|
|
3
|
+
export declare const CLAUDE_WINDOW_MS: number;
|
|
4
|
+
/** Tokens per capacity unit (window-pressure measure, not price). // keep in sync */
|
|
5
|
+
export declare const CAPACITY_UNIT_TOKENS = 1000;
|
|
6
|
+
export type CapacityLimitKind = "none" | "rate_limit" | "session_limit" | "usage_limit";
|
|
7
|
+
export interface RunnerCapacityWindow {
|
|
8
|
+
kind: "rolling" | "fixed";
|
|
9
|
+
windowMs: number;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RunnerLimitInput {
|
|
13
|
+
exitCode?: number | null;
|
|
14
|
+
stdout?: string;
|
|
15
|
+
stderr?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RunnerLimitSignal {
|
|
18
|
+
hitLimit: boolean;
|
|
19
|
+
kind: CapacityLimitKind;
|
|
20
|
+
status: number | null;
|
|
21
|
+
/** Absolute reset instant (epoch ms) when derivable, else null. */
|
|
22
|
+
resetAtMs: number | null;
|
|
23
|
+
detail: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RunnerMeterInput {
|
|
26
|
+
usage: ClaudeUsage | null | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface RunnerCapacityPlugin {
|
|
29
|
+
readonly provider: string;
|
|
30
|
+
window(): RunnerCapacityWindow;
|
|
31
|
+
classifyLimit(input: RunnerLimitInput, nowMs?: number): RunnerLimitSignal;
|
|
32
|
+
estimateResetAt(signal: RunnerLimitSignal, nowMs: number): number | null;
|
|
33
|
+
/** Capacity units this turn drew against the window. */
|
|
34
|
+
capacityUnits(input: RunnerMeterInput): number;
|
|
35
|
+
}
|
|
36
|
+
export declare const claudeRunnerCapacityPlugin: RunnerCapacityPlugin;
|
|
37
|
+
/** The wire payload the runner reports to the server capacity endpoint. */
|
|
38
|
+
export interface CapacityReport {
|
|
39
|
+
identity_id: string;
|
|
40
|
+
provider: string;
|
|
41
|
+
hit_limit: boolean;
|
|
42
|
+
kind: CapacityLimitKind;
|
|
43
|
+
status: number | null;
|
|
44
|
+
/** ISO reset instant when known, else null. */
|
|
45
|
+
reset_at: string | null;
|
|
46
|
+
detail: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the capacity report the runner POSTs when it hits (or clears) a limit.
|
|
50
|
+
* `estimateResetAt` fills a window-projected reset when Claude stated none, so
|
|
51
|
+
* the server always has a concrete probe-again time for an exhausted window.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildCapacityReport(identityId: string, signal: RunnerLimitSignal, plugin: RunnerCapacityPlugin, nowMs?: number): CapacityReport;
|
|
54
|
+
//# sourceMappingURL=capacity-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity-plugin.d.ts","sourceRoot":"","sources":["../src/capacity-plugin.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErE,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,QAAqB,CAAC;AACnD,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,YAAY,GAAG,eAAe,GAAG,aAAa,CAAC;AAExF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,MAAM,IAAI,oBAAoB,CAAC;IAC/B,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAC1E,eAAe,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACzE,wDAAwD;IACxD,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAAC;CAChD;AAQD,eAAO,MAAM,0BAA0B,EAAE,oBAwCxC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,oBAAoB,EAC5B,KAAK,SAAa,GACjB,cAAc,CAWhB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CC-3A CAPACITY-PLUGINS — the runner side of the per-provider capacity plugin.
|
|
3
|
+
*
|
|
4
|
+
* The runner is where a Claude 429 / session-limit is first SEEN, so it owns the
|
|
5
|
+
* 429/limit classifier that "feeds capacity_state" (the server folds the report
|
|
6
|
+
* through the capacity_state machine — see api/_lib/capacity/apply-capacity-signal.ts).
|
|
7
|
+
*
|
|
8
|
+
* This module wraps the runner's existing failure-classifier (isCapacityExhausted /
|
|
9
|
+
* parseApiErrorStatus / extractResetTime) in the CapacityPlugin shape. The shape
|
|
10
|
+
* is DUPLICATED from api/_lib/capacity/provider-plugin.ts on purpose: the runner
|
|
11
|
+
* is a standalone published package and MUST NOT import from api/_lib (the
|
|
12
|
+
* cost-pricing.ts precedent). The two shapes are kept in sync by hand. // keep in sync
|
|
13
|
+
*/
|
|
14
|
+
import { extractResetTime, isCapacityExhausted, parseApiErrorStatus, } from "./failure-classifier.js";
|
|
15
|
+
import { normalizeUsage } from "./cost-pricing.js";
|
|
16
|
+
/** Claude subscription capacity window: 5 hours, rolling. // keep in sync */
|
|
17
|
+
export const CLAUDE_WINDOW_MS = 5 * 60 * 60 * 1000;
|
|
18
|
+
/** Tokens per capacity unit (window-pressure measure, not price). // keep in sync */
|
|
19
|
+
export const CAPACITY_UNIT_TOKENS = 1_000;
|
|
20
|
+
// Hard billing wall = quarantine, never a recoverable window. Kept disjoint from
|
|
21
|
+
// the recoverable-capacity path, mirroring failure-classifier. // keep in sync
|
|
22
|
+
const HARD_BILLING_WALL = /out of credits|credit balance (?:is )?too low|monthly spend limit|insufficient_quota|quota exceeded|check your (?:plan and )?billing|billing (?:hard )?limit|payment required/i;
|
|
23
|
+
const SESSION_LIMIT = /hit your (?:session|usage|account) limit|session limit|(?:session|usage|account|limit).*resets?\b/i;
|
|
24
|
+
export const claudeRunnerCapacityPlugin = {
|
|
25
|
+
provider: "anthropic",
|
|
26
|
+
window() {
|
|
27
|
+
return { kind: "rolling", windowMs: CLAUDE_WINDOW_MS, label: "5h rolling subscription window" };
|
|
28
|
+
},
|
|
29
|
+
classifyLimit(input, nowMs = Date.now()) {
|
|
30
|
+
const stdout = input.stdout ?? "";
|
|
31
|
+
const stderr = input.stderr ?? "";
|
|
32
|
+
const combined = `${stderr}\n${stdout}`;
|
|
33
|
+
const status = parseApiErrorStatus(stdout);
|
|
34
|
+
if (HARD_BILLING_WALL.test(combined)) {
|
|
35
|
+
return { hitLimit: false, kind: "usage_limit", status, resetAtMs: null, detail: "hard billing/quota wall — not recoverable" };
|
|
36
|
+
}
|
|
37
|
+
if (isCapacityExhausted(stdout, stderr)) {
|
|
38
|
+
const isSession = SESSION_LIMIT.test(combined);
|
|
39
|
+
return {
|
|
40
|
+
hitLimit: true,
|
|
41
|
+
kind: isSession ? "session_limit" : "rate_limit",
|
|
42
|
+
status: status === 429 ? 429 : status,
|
|
43
|
+
resetAtMs: extractResetTime(combined, nowMs),
|
|
44
|
+
detail: isSession ? "Claude session/usage capacity reached" : "Claude 429 rate limit",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { hitLimit: false, kind: "none", status, resetAtMs: null, detail: "no capacity limit" };
|
|
48
|
+
},
|
|
49
|
+
estimateResetAt(signal, nowMs) {
|
|
50
|
+
if (!signal.hitLimit)
|
|
51
|
+
return null;
|
|
52
|
+
if (signal.resetAtMs !== null && signal.resetAtMs > nowMs)
|
|
53
|
+
return signal.resetAtMs;
|
|
54
|
+
return nowMs + CLAUDE_WINDOW_MS;
|
|
55
|
+
},
|
|
56
|
+
capacityUnits(input) {
|
|
57
|
+
const u = normalizeUsage(input.usage);
|
|
58
|
+
const tokens = u.input_tokens + u.output_tokens + u.cache_read_tokens + u.cache_write_tokens;
|
|
59
|
+
return tokens / CAPACITY_UNIT_TOKENS;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Build the capacity report the runner POSTs when it hits (or clears) a limit.
|
|
64
|
+
* `estimateResetAt` fills a window-projected reset when Claude stated none, so
|
|
65
|
+
* the server always has a concrete probe-again time for an exhausted window.
|
|
66
|
+
*/
|
|
67
|
+
export function buildCapacityReport(identityId, signal, plugin, nowMs = Date.now()) {
|
|
68
|
+
const resetMs = plugin.estimateResetAt(signal, nowMs);
|
|
69
|
+
return {
|
|
70
|
+
identity_id: identityId,
|
|
71
|
+
provider: plugin.provider,
|
|
72
|
+
hit_limit: signal.hitLimit,
|
|
73
|
+
kind: signal.kind,
|
|
74
|
+
status: signal.status,
|
|
75
|
+
reset_at: resetMs === null ? null : new Date(resetMs).toISOString(),
|
|
76
|
+
detail: signal.detail,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=capacity-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity-plugin.js","sourceRoot":"","sources":["../src/capacity-plugin.ts"],"names":[],"mappings":"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"}
|