audit-tools 0.28.7 → 0.28.9
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/audit-code-wrapper-install-hosts.mjs +133 -27
- package/dist/audit/cli/confirmIntentStep.d.ts +1 -0
- package/dist/audit/cli/confirmIntentStep.d.ts.map +1 -1
- package/dist/audit/cli/confirmIntentStep.js +14 -10
- package/dist/audit/cli/confirmIntentStep.js.map +1 -1
- package/dist/audit/cli/dispatch/quotaPool.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/quotaPool.js +4 -3
- package/dist/audit/cli/dispatch/quotaPool.js.map +1 -1
- package/dist/audit/cli/dispatch.d.ts +15 -1
- package/dist/audit/cli/dispatch.d.ts.map +1 -1
- package/dist/audit/cli/dispatch.js +54 -19
- package/dist/audit/cli/dispatch.js.map +1 -1
- package/dist/audit/cli/hybridDispatch.d.ts +46 -0
- package/dist/audit/cli/hybridDispatch.d.ts.map +1 -0
- package/dist/audit/cli/hybridDispatch.js +77 -0
- package/dist/audit/cli/hybridDispatch.js.map +1 -0
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +111 -2
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/cli/quotaCommand.d.ts.map +1 -1
- package/dist/audit/cli/quotaCommand.js +20 -10
- package/dist/audit/cli/quotaCommand.js.map +1 -1
- package/dist/audit/cli/reviewRun.d.ts +8 -0
- package/dist/audit/cli/reviewRun.d.ts.map +1 -1
- package/dist/audit/cli/reviewRun.js +1 -1
- package/dist/audit/cli/reviewRun.js.map +1 -1
- package/dist/audit/cli/rollingAuditDispatch.d.ts +57 -4
- package/dist/audit/cli/rollingAuditDispatch.d.ts.map +1 -1
- package/dist/audit/cli/rollingAuditDispatch.js +137 -10
- package/dist/audit/cli/rollingAuditDispatch.js.map +1 -1
- package/dist/audit/cli/scoreAuditCommand.d.ts +16 -0
- package/dist/audit/cli/scoreAuditCommand.d.ts.map +1 -0
- package/dist/audit/cli/scoreAuditCommand.js +82 -0
- package/dist/audit/cli/scoreAuditCommand.js.map +1 -0
- package/dist/audit/cli/submitPacketCommand.d.ts.map +1 -1
- package/dist/audit/cli/submitPacketCommand.js +8 -1
- package/dist/audit/cli/submitPacketCommand.js.map +1 -1
- package/dist/audit/cli.d.ts.map +1 -1
- package/dist/audit/cli.js +5 -1
- package/dist/audit/cli.js.map +1 -1
- package/dist/audit/orchestrator/designReviewProjection.d.ts +9 -1
- package/dist/audit/orchestrator/designReviewProjection.d.ts.map +1 -1
- package/dist/audit/orchestrator/designReviewProjection.js +19 -1
- package/dist/audit/orchestrator/designReviewProjection.js.map +1 -1
- package/dist/audit/orchestrator/designReviewPrompt.d.ts +2 -0
- package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
- package/dist/audit/orchestrator/designReviewPrompt.js +11 -1
- package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
- package/dist/audit/orchestrator/executorRunners.js +1 -1
- package/dist/audit/orchestrator/executorRunners.js.map +1 -1
- package/dist/audit/orchestrator/intakeExecutors.d.ts +9 -1
- package/dist/audit/orchestrator/intakeExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/intakeExecutors.js +16 -3
- package/dist/audit/orchestrator/intakeExecutors.js.map +1 -1
- package/dist/audit/orchestrator/intentCheckpointExecutor.d.ts.map +1 -1
- package/dist/audit/orchestrator/intentCheckpointExecutor.js +3 -0
- package/dist/audit/orchestrator/intentCheckpointExecutor.js.map +1 -1
- package/dist/audit/orchestrator/intentInterpreter.d.ts +21 -7
- package/dist/audit/orchestrator/intentInterpreter.d.ts.map +1 -1
- package/dist/audit/orchestrator/intentInterpreter.js +30 -11
- package/dist/audit/orchestrator/intentInterpreter.js.map +1 -1
- package/dist/audit/orchestrator/intentScopeDisposition.d.ts +49 -0
- package/dist/audit/orchestrator/intentScopeDisposition.d.ts.map +1 -0
- package/dist/audit/orchestrator/intentScopeDisposition.js +57 -0
- package/dist/audit/orchestrator/intentScopeDisposition.js.map +1 -0
- package/dist/audit/orchestrator/rollingDispatch.d.ts +9 -0
- package/dist/audit/orchestrator/rollingDispatch.d.ts.map +1 -1
- package/dist/audit/orchestrator/rollingDispatch.js +10 -0
- package/dist/audit/orchestrator/rollingDispatch.js.map +1 -1
- package/dist/audit/orchestrator/scope.d.ts +1 -0
- package/dist/audit/orchestrator/scope.d.ts.map +1 -1
- package/dist/audit/orchestrator/scope.js +2 -7
- package/dist/audit/orchestrator/scope.js.map +1 -1
- package/dist/audit/quota/index.d.ts +5 -0
- package/dist/audit/quota/index.d.ts.map +1 -1
- package/dist/audit/reporting/scoreAudit.d.ts +161 -0
- package/dist/audit/reporting/scoreAudit.d.ts.map +1 -0
- package/dist/audit/reporting/scoreAudit.js +224 -0
- package/dist/audit/reporting/scoreAudit.js.map +1 -0
- package/dist/audit/types/activeDispatch.d.ts +29 -1
- package/dist/audit/types/activeDispatch.d.ts.map +1 -1
- package/dist/audit/types/activeDispatch.js.map +1 -1
- package/dist/audit/types/analyzerCapability.d.ts +6 -6
- package/dist/audit/validation/auditResults.d.ts +13 -0
- package/dist/audit/validation/auditResults.d.ts.map +1 -1
- package/dist/audit/validation/auditResults.js +35 -12
- package/dist/audit/validation/auditResults.js.map +1 -1
- package/dist/remediate/contractPipeline/changeClassification.d.ts +146 -0
- package/dist/remediate/contractPipeline/changeClassification.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/changeClassification.js +398 -0
- package/dist/remediate/contractPipeline/changeClassification.js.map +1 -0
- package/dist/remediate/contractPipeline/derive.d.ts.map +1 -1
- package/dist/remediate/contractPipeline/derive.js +9 -0
- package/dist/remediate/contractPipeline/derive.js.map +1 -1
- package/dist/remediate/intent/intentOrdering.d.ts +51 -0
- package/dist/remediate/intent/intentOrdering.d.ts.map +1 -0
- package/dist/remediate/intent/intentOrdering.js +150 -0
- package/dist/remediate/intent/intentOrdering.js.map +1 -0
- package/dist/remediate/phases/plan.d.ts.map +1 -1
- package/dist/remediate/phases/plan.js +14 -1
- package/dist/remediate/phases/plan.js.map +1 -1
- package/dist/remediate/providers/index.d.ts +32 -0
- package/dist/remediate/providers/index.d.ts.map +1 -1
- package/dist/remediate/providers/index.js +28 -1
- package/dist/remediate/providers/index.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.d.ts +15 -1
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +282 -14
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/dispatch.d.ts +56 -1
- package/dist/remediate/steps/dispatch.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch.js +120 -29
- package/dist/remediate/steps/dispatch.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts +53 -2
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +253 -81
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/providerNodeDispatch.d.ts +8 -1
- package/dist/remediate/steps/providerNodeDispatch.d.ts.map +1 -1
- package/dist/remediate/steps/providerNodeDispatch.js +7 -2
- package/dist/remediate/steps/providerNodeDispatch.js.map +1 -1
- package/dist/remediate/steps/rollingSession.d.ts +55 -1
- package/dist/remediate/steps/rollingSession.d.ts.map +1 -1
- package/dist/remediate/steps/rollingSession.js +128 -19
- package/dist/remediate/steps/rollingSession.js.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.d.ts +23 -8
- package/dist/remediate/validation/contractPipelineGates.d.ts.map +1 -1
- package/dist/remediate/validation/contractPipelineGates.js +43 -38
- package/dist/remediate/validation/contractPipelineGates.js.map +1 -1
- package/dist/shared/dispatch/coordinator.d.ts +170 -0
- package/dist/shared/dispatch/coordinator.d.ts.map +1 -0
- package/dist/shared/dispatch/coordinator.js +177 -0
- package/dist/shared/dispatch/coordinator.js.map +1 -0
- package/dist/shared/dispatch/hybridDispatch.d.ts +74 -0
- package/dist/shared/dispatch/hybridDispatch.d.ts.map +1 -0
- package/dist/shared/dispatch/hybridDispatch.js +54 -0
- package/dist/shared/dispatch/hybridDispatch.js.map +1 -0
- package/dist/shared/dispatch/settledPools.d.ts +21 -0
- package/dist/shared/dispatch/settledPools.d.ts.map +1 -0
- package/dist/shared/dispatch/settledPools.js +34 -0
- package/dist/shared/dispatch/settledPools.js.map +1 -0
- package/dist/shared/index.d.ts +16 -6
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +15 -3
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/intent/clauseInterpreter.d.ts +19 -0
- package/dist/shared/intent/clauseInterpreter.d.ts.map +1 -1
- package/dist/shared/intent/clauseInterpreter.js +19 -0
- package/dist/shared/intent/clauseInterpreter.js.map +1 -1
- package/dist/shared/io/json.d.ts +25 -0
- package/dist/shared/io/json.d.ts.map +1 -1
- package/dist/shared/io/json.js +67 -0
- package/dist/shared/io/json.js.map +1 -1
- package/dist/shared/providers/opencodeProvider.d.ts.map +1 -1
- package/dist/shared/providers/opencodeProvider.js +12 -0
- package/dist/shared/providers/opencodeProvider.js.map +1 -1
- package/dist/shared/providers/providerConfirmation.d.ts.map +1 -1
- package/dist/shared/providers/providerConfirmation.js +9 -1
- package/dist/shared/providers/providerConfirmation.js.map +1 -1
- package/dist/shared/providers/providerFactory.d.ts +1 -0
- package/dist/shared/providers/providerFactory.d.ts.map +1 -1
- package/dist/shared/providers/providerFactory.js +10 -8
- package/dist/shared/providers/providerFactory.js.map +1 -1
- package/dist/shared/providers/sharedProviderConfirmation.d.ts +134 -0
- package/dist/shared/providers/sharedProviderConfirmation.d.ts.map +1 -0
- package/dist/shared/providers/sharedProviderConfirmation.js +244 -0
- package/dist/shared/providers/sharedProviderConfirmation.js.map +1 -0
- package/dist/shared/quota/apiPool.d.ts +67 -0
- package/dist/shared/quota/apiPool.d.ts.map +1 -0
- package/dist/shared/quota/apiPool.js +139 -0
- package/dist/shared/quota/apiPool.js.map +1 -0
- package/dist/shared/quota/capacity.d.ts +29 -1
- package/dist/shared/quota/capacity.d.ts.map +1 -1
- package/dist/shared/quota/capacity.js +5 -0
- package/dist/shared/quota/capacity.js.map +1 -1
- package/dist/shared/quota/claimRegistry.d.ts +64 -0
- package/dist/shared/quota/claimRegistry.d.ts.map +1 -0
- package/dist/shared/quota/claimRegistry.js +157 -0
- package/dist/shared/quota/claimRegistry.js.map +1 -0
- package/dist/shared/quota/compositeQuotaSource.d.ts +10 -1
- package/dist/shared/quota/compositeQuotaSource.d.ts.map +1 -1
- package/dist/shared/quota/compositeQuotaSource.js +34 -6
- package/dist/shared/quota/compositeQuotaSource.js.map +1 -1
- package/dist/shared/quota/httpQuotaSource.d.ts +9 -1
- package/dist/shared/quota/httpQuotaSource.d.ts.map +1 -1
- package/dist/shared/quota/httpQuotaSource.js +33 -8
- package/dist/shared/quota/httpQuotaSource.js.map +1 -1
- package/dist/shared/quota/learnedQuotaSource.d.ts +7 -1
- package/dist/shared/quota/learnedQuotaSource.d.ts.map +1 -1
- package/dist/shared/quota/learnedQuotaSource.js +18 -7
- package/dist/shared/quota/learnedQuotaSource.js.map +1 -1
- package/dist/shared/quota/quotaSource.d.ts +41 -0
- package/dist/shared/quota/quotaSource.d.ts.map +1 -1
- package/dist/shared/quota/quotaSource.js +19 -0
- package/dist/shared/quota/quotaSource.js.map +1 -1
- package/dist/shared/types/contractPipeline/obligations.d.ts +42 -0
- package/dist/shared/types/contractPipeline/obligations.d.ts.map +1 -1
- package/dist/shared/types/contractPipeline.d.ts +1 -1
- package/dist/shared/types/contractPipeline.d.ts.map +1 -1
- package/dist/shared/types/contractPipeline.js.map +1 -1
- package/dist/shared/types/intentCheckpoint.d.ts +14 -0
- package/dist/shared/types/intentCheckpoint.d.ts.map +1 -1
- package/dist/shared/types/intentCheckpoint.js +10 -0
- package/dist/shared/types/intentCheckpoint.js.map +1 -1
- package/dist/shared/types/sessionConfig.d.ts +60 -0
- package/dist/shared/types/sessionConfig.d.ts.map +1 -1
- package/dist/shared/types/sessionConfig.js +13 -0
- package/dist/shared/types/sessionConfig.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { probeQuotaSource } from "./quotaSource.js";
|
|
2
|
+
import { buildProviderModelKey } from "./scheduler.js";
|
|
3
|
+
import { hasConfiguredOpenAiCompatible } from "../providers/providerFactory.js";
|
|
4
|
+
/**
|
|
5
|
+
* The stable id of a dispatchable source — its explicit `id`, or a
|
|
6
|
+
* `${provider}:${model ?? endpoint}` key so two sources of the same provider stay
|
|
7
|
+
* distinct as long as their model/endpoint differ. This is the CapacityPool id and
|
|
8
|
+
* the key learned quota is recorded under.
|
|
9
|
+
*/
|
|
10
|
+
export function dispatchableSourceId(source) {
|
|
11
|
+
return source.id ?? buildProviderModelKey(source.provider, source.model ?? source.endpoint ?? null);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Bridge a generic {@link DispatchableSource} to the concrete per-provider config
|
|
15
|
+
* block its provider constructor expects, so `createFreshSessionProvider` can build
|
|
16
|
+
* the right backend FROM the source (not the global block). `endpoint` + `parameters`
|
|
17
|
+
* are interpreted per provider: the API base_url + sampling params for
|
|
18
|
+
* `openai-compatible`; the launcher command + CLI args for the headless CLIs.
|
|
19
|
+
*/
|
|
20
|
+
export function sourceProviderConfig(source) {
|
|
21
|
+
const p = source.parameters ?? {};
|
|
22
|
+
switch (source.provider) {
|
|
23
|
+
case "openai-compatible":
|
|
24
|
+
return {
|
|
25
|
+
openai_compatible: {
|
|
26
|
+
base_url: source.endpoint,
|
|
27
|
+
model: source.model,
|
|
28
|
+
api_key_env: source.api_key_env,
|
|
29
|
+
api_key: source.api_key,
|
|
30
|
+
...p,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
case "codex":
|
|
34
|
+
return { codex: { command: source.endpoint, model: source.model, ...p } };
|
|
35
|
+
case "opencode":
|
|
36
|
+
return { opencode: { command: source.endpoint, ...p } };
|
|
37
|
+
case "subprocess-template":
|
|
38
|
+
return {
|
|
39
|
+
subprocess_template: {
|
|
40
|
+
command_template: p.command_template ?? [],
|
|
41
|
+
...p,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
case "local-subprocess":
|
|
45
|
+
// local-subprocess takes no construction config (host-dispatch default).
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Overlay a dispatchable source's per-provider config block onto the session config,
|
|
51
|
+
* so `createFreshSessionProvider` builds the backend FROM that source — the launch
|
|
52
|
+
* reads THIS source's `{endpoint, model, parameters}`, not the global block. This is
|
|
53
|
+
* what lets two sources of the same provider (e.g. two NIM endpoints) launch
|
|
54
|
+
* distinctly. A node on the host's own pool (no source) passes the config through.
|
|
55
|
+
*/
|
|
56
|
+
export function withSourceConfig(sessionConfig, source) {
|
|
57
|
+
return source ? { ...sessionConfig, ...sourceProviderConfig(source) } : sessionConfig;
|
|
58
|
+
}
|
|
59
|
+
/** Index the source-backed pools by their pool id, for per-node provider resolution. */
|
|
60
|
+
export function sourceByPoolId(pools) {
|
|
61
|
+
const map = new Map();
|
|
62
|
+
for (const pool of pools) {
|
|
63
|
+
if (pool.source)
|
|
64
|
+
map.set(pool.id, pool.source);
|
|
65
|
+
}
|
|
66
|
+
return map;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build one CapacityPool for a configured dispatchable backend source — generic over
|
|
70
|
+
* the source's provider. An independent backend pool: it does not draw on the host
|
|
71
|
+
* subagent budget (`hostConcurrencyLimit: null`); its rate limits come from the
|
|
72
|
+
* source's own `quota` (RPM/TPM/context/output) plus learned 429 state; it carries
|
|
73
|
+
* its real-time quota probe (degraded → the raw `quotaSignalDegraded` marker). The
|
|
74
|
+
* pool is TAGGED with its `source` so the dispatch worker rebuilds the provider from
|
|
75
|
+
* the source's `{endpoint, model, parameters}`, not the global per-provider block.
|
|
76
|
+
*/
|
|
77
|
+
export async function buildSourcePool(params) {
|
|
78
|
+
const { source, quotaSource, quotaEntries } = params;
|
|
79
|
+
const poolKey = dispatchableSourceId(source);
|
|
80
|
+
const probe = await probeQuotaSource(quotaSource, poolKey).catch(() => ({ snapshot: null, status: "degraded" }));
|
|
81
|
+
return {
|
|
82
|
+
id: poolKey,
|
|
83
|
+
providerName: source.provider,
|
|
84
|
+
hostModel: source.model ?? null,
|
|
85
|
+
hostConcurrencyLimit: null,
|
|
86
|
+
quotaStateEntry: quotaEntries[poolKey] ?? null,
|
|
87
|
+
// QuotaModelLimits is structurally a DiscoveredRateLimitsInput (RPM/TPM/context/
|
|
88
|
+
// output) — the operator-declared per-source rate limit feeds the S4 fold.
|
|
89
|
+
discoveredLimits: source.quota ?? null,
|
|
90
|
+
quotaSourceSnapshot: probe.snapshot,
|
|
91
|
+
...(probe.status === "degraded" ? { quotaSignalDegraded: true } : {}),
|
|
92
|
+
source,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Every dispatchable backend source configured for a run, in pool order: the explicit
|
|
97
|
+
* `sessionConfig.sources`, plus — for back-compat — a single implicit source folded in
|
|
98
|
+
* from a legacy `openai_compatible` block when it isn't the primary provider and isn't
|
|
99
|
+
* already covered by an explicit source of the same id.
|
|
100
|
+
*/
|
|
101
|
+
export function collectDispatchableSources(sessionConfig, primaryProviderName) {
|
|
102
|
+
const out = [...(sessionConfig.sources ?? [])];
|
|
103
|
+
if (primaryProviderName !== "openai-compatible" &&
|
|
104
|
+
hasConfiguredOpenAiCompatible(sessionConfig.openai_compatible)) {
|
|
105
|
+
const oc = sessionConfig.openai_compatible;
|
|
106
|
+
const legacy = {
|
|
107
|
+
provider: "openai-compatible",
|
|
108
|
+
endpoint: oc.base_url,
|
|
109
|
+
model: oc.model,
|
|
110
|
+
api_key_env: oc.api_key_env,
|
|
111
|
+
api_key: oc.api_key,
|
|
112
|
+
parameters: {
|
|
113
|
+
...(oc.temperature !== undefined ? { temperature: oc.temperature } : {}),
|
|
114
|
+
...(oc.headers !== undefined ? { headers: oc.headers } : {}),
|
|
115
|
+
...(oc.max_output_tokens !== undefined ? { max_output_tokens: oc.max_output_tokens } : {}),
|
|
116
|
+
...(oc.response_format_json !== undefined ? { response_format_json: oc.response_format_json } : {}),
|
|
117
|
+
...(oc.include_referenced_files !== undefined
|
|
118
|
+
? { include_referenced_files: oc.include_referenced_files }
|
|
119
|
+
: {}),
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const legacyId = dispatchableSourceId(legacy);
|
|
123
|
+
if (!out.some((s) => dispatchableSourceId(s) === legacyId))
|
|
124
|
+
out.push(legacy);
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Build the CapacityPool for every configured dispatchable backend source (the
|
|
130
|
+
* generalization of the former openai-compatible-only `buildConfiguredApiPool`): one
|
|
131
|
+
* pool per source, the IDENTICAL shape across audit + remediate, so the spill topology
|
|
132
|
+
* can't drift and the operator can configure ANY non-IDE source — multiple NIM/vLLM
|
|
133
|
+
* endpoints, a CLI pool, … — each with its own rate limit.
|
|
134
|
+
*/
|
|
135
|
+
export async function buildSourcePools(params) {
|
|
136
|
+
const sources = collectDispatchableSources(params.sessionConfig, params.primaryProviderName);
|
|
137
|
+
return Promise.all(sources.map((source) => buildSourcePool({ source, quotaSource: params.quotaSource, quotaEntries: params.quotaEntries })));
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=apiPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiPool.js","sourceRoot":"","sources":["../../../src/shared/quota/apiPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type { ResolvedProviderName, SessionConfig } from "../types/sessionConfig.js";
|
|
2
|
+
import type { ResolvedProviderName, SessionConfig, DispatchableSource } from "../types/sessionConfig.js";
|
|
3
3
|
import type { DispatchModelTier } from "../types/stepContract.js";
|
|
4
4
|
import type { HostConcurrencyLimit, QuotaStateEntry, WaveBindingCap, WaveSchedule } from "./types.js";
|
|
5
5
|
import type { QuotaUsageSnapshot } from "./quotaSource.js";
|
|
@@ -85,6 +85,24 @@ export interface CapacityPool {
|
|
|
85
85
|
discoveredLimits?: DiscoveredRateLimitsInput | null;
|
|
86
86
|
/** Real-time usage snapshot for this pool, if available. */
|
|
87
87
|
quotaSourceSnapshot?: QuotaUsageSnapshot | null;
|
|
88
|
+
/**
|
|
89
|
+
* Explicit silent-degrade marker: true when this pool's proactive quota source
|
|
90
|
+
* was queried and degraded to no snapshot (missing/expired creds, 401/5xx,
|
|
91
|
+
* network error, unmappable payload) — i.e. a live reading was EXPECTED but
|
|
92
|
+
* lost, which a bare `quotaSourceSnapshot: null` cannot distinguish from "no
|
|
93
|
+
* source applies here". This is a RAW per-pool signal for observability and the
|
|
94
|
+
* downstream fold; it is deliberately NOT pre-folded into a slot count here (the
|
|
95
|
+
* byte-estimate × safety-margin floor-1 degrade lives in `scheduleWave`, S4).
|
|
96
|
+
*/
|
|
97
|
+
quotaSignalDegraded?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* The generic dispatchable source this pool was built from, when it is a
|
|
100
|
+
* configured backend source (not the conversation host's own pool). The dispatch
|
|
101
|
+
* worker rebuilds the provider from THIS source's `{endpoint, model, parameters}`
|
|
102
|
+
* rather than the global per-provider config block — which is what lets two
|
|
103
|
+
* sources of the same provider (e.g. two NIM endpoints) launch distinctly.
|
|
104
|
+
*/
|
|
105
|
+
source?: DispatchableSource;
|
|
88
106
|
}
|
|
89
107
|
/** One pool's slice of the overall dispatch capacity. */
|
|
90
108
|
export interface PoolDispatchAllocation {
|
|
@@ -95,6 +113,12 @@ export interface PoolDispatchAllocation {
|
|
|
95
113
|
slots: number;
|
|
96
114
|
/** Full wave schedule for this pool (resolved limits, binding cap, cooldown). */
|
|
97
115
|
schedule: WaveSchedule;
|
|
116
|
+
/**
|
|
117
|
+
* Echo of {@link CapacityPool.quotaSignalDegraded} — the pool's proactive quota
|
|
118
|
+
* source was queried and silently degraded. Carried through unfolded so the
|
|
119
|
+
* summary/observability can surface it; never affects slot math here.
|
|
120
|
+
*/
|
|
121
|
+
quotaSignalDegraded?: boolean;
|
|
98
122
|
}
|
|
99
123
|
/** Compact, serializable view of one pool allocation for dispatch-quota files. */
|
|
100
124
|
export declare const DispatchCapacityPoolSummarySchema: z.ZodObject<{
|
|
@@ -161,6 +185,8 @@ export declare const DispatchCapacityPoolSummarySchema: z.ZodObject<{
|
|
|
161
185
|
captured_at: string;
|
|
162
186
|
source: string;
|
|
163
187
|
}>>>;
|
|
188
|
+
/** Raw silent-degrade marker for this pool (see CapacityPool.quotaSignalDegraded). */
|
|
189
|
+
quota_signal_degraded: z.ZodOptional<z.ZodBoolean>;
|
|
164
190
|
}, "strict", z.ZodTypeAny, {
|
|
165
191
|
confidence: "high" | "low" | "medium";
|
|
166
192
|
source: "default" | "explicit_config" | "discovered_capability" | "cli_flags" | "provider_default" | "learned";
|
|
@@ -191,6 +217,7 @@ export declare const DispatchCapacityPoolSummarySchema: z.ZodObject<{
|
|
|
191
217
|
captured_at: string;
|
|
192
218
|
source: string;
|
|
193
219
|
} | null | undefined;
|
|
220
|
+
quota_signal_degraded?: boolean | undefined;
|
|
194
221
|
}, {
|
|
195
222
|
confidence: "high" | "low" | "medium";
|
|
196
223
|
source: "default" | "explicit_config" | "discovered_capability" | "cli_flags" | "provider_default" | "learned";
|
|
@@ -221,6 +248,7 @@ export declare const DispatchCapacityPoolSummarySchema: z.ZodObject<{
|
|
|
221
248
|
captured_at: string;
|
|
222
249
|
source: string;
|
|
223
250
|
} | null | undefined;
|
|
251
|
+
quota_signal_degraded?: boolean | undefined;
|
|
224
252
|
}>;
|
|
225
253
|
export type DispatchCapacityPoolSummary = z.infer<typeof DispatchCapacityPoolSummarySchema>;
|
|
226
254
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capacity.d.ts","sourceRoot":"","sources":["../../../src/shared/quota/capacity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"capacity.d.ts","sourceRoot":"","sources":["../../../src/shared/quota/capacity.ts"],"names":[],"mappings":"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"}
|
|
@@ -57,6 +57,8 @@ export const DispatchCapacityPoolSummarySchema = z
|
|
|
57
57
|
estimated_wave_tokens: z.number().int().min(0),
|
|
58
58
|
binding_cap: WaveBindingCapSchema,
|
|
59
59
|
quota_source_snapshot: QuotaUsageSnapshotSchema.nullable().optional(),
|
|
60
|
+
/** Raw silent-degrade marker for this pool (see CapacityPool.quotaSignalDegraded). */
|
|
61
|
+
quota_signal_degraded: z.boolean().optional(),
|
|
60
62
|
})
|
|
61
63
|
.strict();
|
|
62
64
|
/** Higher number = more constraining; used to pick the binding cap across pools. */
|
|
@@ -256,6 +258,8 @@ function schedulePool(pool, sessionConfig, itemTokens) {
|
|
|
256
258
|
? Math.min(schedule.max_concurrent, itemTokens.length)
|
|
257
259
|
: schedule.max_concurrent,
|
|
258
260
|
schedule,
|
|
261
|
+
// Raw signal carried through unfolded — does not enter the slot math above.
|
|
262
|
+
...(pool.quotaSignalDegraded ? { quotaSignalDegraded: true } : {}),
|
|
259
263
|
};
|
|
260
264
|
}
|
|
261
265
|
function choosePrimaryAllocation(allocations) {
|
|
@@ -285,6 +289,7 @@ export function summarizeDispatchCapacityPools(capacity) {
|
|
|
285
289
|
estimated_wave_tokens: allocation.schedule.estimated_wave_tokens,
|
|
286
290
|
binding_cap: allocation.schedule.binding_cap ?? "none",
|
|
287
291
|
quota_source_snapshot: allocation.schedule.quota_source_snapshot ?? null,
|
|
292
|
+
...(allocation.quotaSignalDegraded ? { quota_signal_degraded: true } : {}),
|
|
288
293
|
}));
|
|
289
294
|
}
|
|
290
295
|
//# sourceMappingURL=capacity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../../src/shared/quota/capacity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAkC,MAAM,gBAAgB,CAAC;AA2B9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,OAI9B;IACC,MAAM,EAAE,UAAU,EAAE,0BAA0B,EAAE,eAAe,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IAEhF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,CAAC,wCAAwC;IACvD,CAAC;IAED,IAAI,0BAA0B,IAAI,eAAe,EAAE,CAAC;QAClD,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,YAAY,EAAE,CAAC,GAAG,UAAU,CAAC;SAC9B,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAqB;IAC1D,OAAO;QACL,MAAM,EAAE,YAAY;QACpB,YAAY,EAAE,CAAC,GAAG,WAAW,CAAC;KAC/B,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../../src/shared/quota/capacity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface ClaimRecord {
|
|
2
|
+
/** Opaque token minted at claim time; required to release or survive a reclaim. */
|
|
3
|
+
ownerToken: string;
|
|
4
|
+
/** Pool the claim was taken for (diagnostic / routing — not part of identity). */
|
|
5
|
+
poolId: string;
|
|
6
|
+
/** Epoch ms of the last heartbeat. Drives staleness against STALE_LOCK_MS. */
|
|
7
|
+
heartbeatAt: number;
|
|
8
|
+
}
|
|
9
|
+
export type ClaimResult = {
|
|
10
|
+
acquired: true;
|
|
11
|
+
ownerToken: string;
|
|
12
|
+
} | {
|
|
13
|
+
acquired: false;
|
|
14
|
+
heldBy: string;
|
|
15
|
+
};
|
|
16
|
+
type ClaimMap = Record<string, ClaimRecord>;
|
|
17
|
+
/**
|
|
18
|
+
* File-backed claim registry. The caller owns the path (and may point two
|
|
19
|
+
* coordinators at the same file — that is the whole point). Every mutating op
|
|
20
|
+
* runs its entire read-modify-write inside `withFileLock(registryPath + '.lock')`
|
|
21
|
+
* so concurrent loops are serialized and the single-grant invariant holds.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ClaimRegistry {
|
|
24
|
+
private readonly registryPath;
|
|
25
|
+
private readonly now;
|
|
26
|
+
private readonly lockPath;
|
|
27
|
+
constructor(registryPath: string, now?: () => number);
|
|
28
|
+
/**
|
|
29
|
+
* Attempt to claim `nodeId` for `poolId`. Granted when the node is unclaimed or
|
|
30
|
+
* the existing claim is stale (heartbeat older than STALE_LOCK_MS). Returns the
|
|
31
|
+
* fresh ownerToken on success, or `{ acquired: false, heldBy }` carrying the
|
|
32
|
+
* live owner's token when another loop holds it.
|
|
33
|
+
*/
|
|
34
|
+
claim(nodeId: string, poolId: string): Promise<ClaimResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Refresh the heartbeat on a claim we still hold. Token-checked: a no-op if the
|
|
37
|
+
* node is unclaimed or held under a different token. Returns whether the
|
|
38
|
+
* heartbeat was applied. This is how a long-running owner stays "live" and so
|
|
39
|
+
* survives a concurrent `reclaimStale()`.
|
|
40
|
+
*/
|
|
41
|
+
heartbeat(nodeId: string, ownerToken: string): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Release a claim we hold. Token-checked: only the owner can release, so a
|
|
44
|
+
* stale-observation racer can never drop a claim another loop legitimately
|
|
45
|
+
* holds. Returns whether a claim was removed.
|
|
46
|
+
*/
|
|
47
|
+
release(nodeId: string, ownerToken: string): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Reclaim every claim whose heartbeat is older than STALE_LOCK_MS, returning
|
|
50
|
+
* the freed nodeIds. A claim that was re-heartbeated since the staleness check
|
|
51
|
+
* is — by the same single-lock serialization — observed fresh here and left
|
|
52
|
+
* intact, so a live owner is never clobbered.
|
|
53
|
+
*/
|
|
54
|
+
reclaimStale(): Promise<string[]>;
|
|
55
|
+
/** Snapshot of all current claims, keyed by nodeId. Read under the lock. */
|
|
56
|
+
listClaims(): Promise<ClaimMap>;
|
|
57
|
+
/**
|
|
58
|
+
* Whether `nodeId` currently has a LIVE (non-stale) claim. A stale claim reads
|
|
59
|
+
* as not-claimed, since the next `claim()` would grant over it.
|
|
60
|
+
*/
|
|
61
|
+
isClaimed(nodeId: string): Promise<boolean>;
|
|
62
|
+
}
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=claimRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claimRegistry.d.ts","sourceRoot":"","sources":["../../../src/shared/quota/claimRegistry.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,WAAW;IAC1B,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,QAAQ,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAmD5C;;;;;GAKG;AACH,qBAAa,aAAa;IAItB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAGf,YAAY,EAAE,MAAM,EACpB,GAAG,GAAE,MAAM,MAAyB;IAKvD;;;;;OAKG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAejE;;;;;OAKG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrE;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWnE;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBvC,4EAA4E;IACtE,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC;IAIrC;;;OAGG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAOlD"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { withFileLock, STALE_LOCK_MS } from "./fileLock.js";
|
|
4
|
+
function mintOwnerToken() {
|
|
5
|
+
return `${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
6
|
+
}
|
|
7
|
+
function isClaimRecord(value) {
|
|
8
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
9
|
+
return false;
|
|
10
|
+
const obj = value;
|
|
11
|
+
return (typeof obj.ownerToken === "string" &&
|
|
12
|
+
typeof obj.poolId === "string" &&
|
|
13
|
+
typeof obj.heartbeatAt === "number" &&
|
|
14
|
+
Number.isFinite(obj.heartbeatAt));
|
|
15
|
+
}
|
|
16
|
+
// Read the registry, degrading ANY malformed/absent state to an empty map. A
|
|
17
|
+
// corrupt registry must never throw into the dispatch loop — at worst a claim is
|
|
18
|
+
// re-granted, which the lock-serialized write then makes consistent again. Only
|
|
19
|
+
// well-formed individual records are retained; junk entries are dropped silently.
|
|
20
|
+
async function readClaimMap(registryPath) {
|
|
21
|
+
let raw;
|
|
22
|
+
try {
|
|
23
|
+
raw = await readFile(registryPath, "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
36
|
+
return {};
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const [nodeId, record] of Object.entries(parsed)) {
|
|
39
|
+
if (isClaimRecord(record))
|
|
40
|
+
out[nodeId] = record;
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
async function writeClaimMap(registryPath, claims) {
|
|
45
|
+
await mkdir(dirname(registryPath), { recursive: true });
|
|
46
|
+
await writeFile(registryPath, `${JSON.stringify(claims, null, 2)}\n`, "utf8");
|
|
47
|
+
}
|
|
48
|
+
function isStale(record, now) {
|
|
49
|
+
return now - record.heartbeatAt > STALE_LOCK_MS;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* File-backed claim registry. The caller owns the path (and may point two
|
|
53
|
+
* coordinators at the same file — that is the whole point). Every mutating op
|
|
54
|
+
* runs its entire read-modify-write inside `withFileLock(registryPath + '.lock')`
|
|
55
|
+
* so concurrent loops are serialized and the single-grant invariant holds.
|
|
56
|
+
*/
|
|
57
|
+
export class ClaimRegistry {
|
|
58
|
+
registryPath;
|
|
59
|
+
now;
|
|
60
|
+
lockPath;
|
|
61
|
+
constructor(registryPath, now = () => Date.now()) {
|
|
62
|
+
this.registryPath = registryPath;
|
|
63
|
+
this.now = now;
|
|
64
|
+
this.lockPath = `${registryPath}.lock`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Attempt to claim `nodeId` for `poolId`. Granted when the node is unclaimed or
|
|
68
|
+
* the existing claim is stale (heartbeat older than STALE_LOCK_MS). Returns the
|
|
69
|
+
* fresh ownerToken on success, or `{ acquired: false, heldBy }` carrying the
|
|
70
|
+
* live owner's token when another loop holds it.
|
|
71
|
+
*/
|
|
72
|
+
async claim(nodeId, poolId) {
|
|
73
|
+
return withFileLock(this.lockPath, async () => {
|
|
74
|
+
const claims = await readClaimMap(this.registryPath);
|
|
75
|
+
const now = this.now();
|
|
76
|
+
const existing = claims[nodeId];
|
|
77
|
+
if (existing && !isStale(existing, now)) {
|
|
78
|
+
return { acquired: false, heldBy: existing.ownerToken };
|
|
79
|
+
}
|
|
80
|
+
const ownerToken = mintOwnerToken();
|
|
81
|
+
claims[nodeId] = { ownerToken, poolId, heartbeatAt: now };
|
|
82
|
+
await writeClaimMap(this.registryPath, claims);
|
|
83
|
+
return { acquired: true, ownerToken };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Refresh the heartbeat on a claim we still hold. Token-checked: a no-op if the
|
|
88
|
+
* node is unclaimed or held under a different token. Returns whether the
|
|
89
|
+
* heartbeat was applied. This is how a long-running owner stays "live" and so
|
|
90
|
+
* survives a concurrent `reclaimStale()`.
|
|
91
|
+
*/
|
|
92
|
+
async heartbeat(nodeId, ownerToken) {
|
|
93
|
+
return withFileLock(this.lockPath, async () => {
|
|
94
|
+
const claims = await readClaimMap(this.registryPath);
|
|
95
|
+
const existing = claims[nodeId];
|
|
96
|
+
if (!existing || existing.ownerToken !== ownerToken)
|
|
97
|
+
return false;
|
|
98
|
+
existing.heartbeatAt = this.now();
|
|
99
|
+
await writeClaimMap(this.registryPath, claims);
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Release a claim we hold. Token-checked: only the owner can release, so a
|
|
105
|
+
* stale-observation racer can never drop a claim another loop legitimately
|
|
106
|
+
* holds. Returns whether a claim was removed.
|
|
107
|
+
*/
|
|
108
|
+
async release(nodeId, ownerToken) {
|
|
109
|
+
return withFileLock(this.lockPath, async () => {
|
|
110
|
+
const claims = await readClaimMap(this.registryPath);
|
|
111
|
+
const existing = claims[nodeId];
|
|
112
|
+
if (!existing || existing.ownerToken !== ownerToken)
|
|
113
|
+
return false;
|
|
114
|
+
delete claims[nodeId];
|
|
115
|
+
await writeClaimMap(this.registryPath, claims);
|
|
116
|
+
return true;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Reclaim every claim whose heartbeat is older than STALE_LOCK_MS, returning
|
|
121
|
+
* the freed nodeIds. A claim that was re-heartbeated since the staleness check
|
|
122
|
+
* is — by the same single-lock serialization — observed fresh here and left
|
|
123
|
+
* intact, so a live owner is never clobbered.
|
|
124
|
+
*/
|
|
125
|
+
async reclaimStale() {
|
|
126
|
+
return withFileLock(this.lockPath, async () => {
|
|
127
|
+
const claims = await readClaimMap(this.registryPath);
|
|
128
|
+
const now = this.now();
|
|
129
|
+
const reclaimed = [];
|
|
130
|
+
for (const [nodeId, record] of Object.entries(claims)) {
|
|
131
|
+
if (isStale(record, now)) {
|
|
132
|
+
delete claims[nodeId];
|
|
133
|
+
reclaimed.push(nodeId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (reclaimed.length > 0)
|
|
137
|
+
await writeClaimMap(this.registryPath, claims);
|
|
138
|
+
return reclaimed;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/** Snapshot of all current claims, keyed by nodeId. Read under the lock. */
|
|
142
|
+
async listClaims() {
|
|
143
|
+
return withFileLock(this.lockPath, async () => readClaimMap(this.registryPath));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Whether `nodeId` currently has a LIVE (non-stale) claim. A stale claim reads
|
|
147
|
+
* as not-claimed, since the next `claim()` would grant over it.
|
|
148
|
+
*/
|
|
149
|
+
async isClaimed(nodeId) {
|
|
150
|
+
return withFileLock(this.lockPath, async () => {
|
|
151
|
+
const claims = await readClaimMap(this.registryPath);
|
|
152
|
+
const existing = claims[nodeId];
|
|
153
|
+
return existing !== undefined && !isStale(existing, this.now());
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=claimRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claimRegistry.js","sourceRoot":"","sources":["../../../src/shared/quota/claimRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { QuotaSource, QuotaUsageSnapshot } from "./quotaSource.js";
|
|
1
|
+
import type { QuotaProbeResult, QuotaSource, QuotaUsageSnapshot } from "./quotaSource.js";
|
|
2
2
|
import { RunLogger } from "../observability/runLog.js";
|
|
3
3
|
export interface BuildQuotaSourceOptions {
|
|
4
4
|
halfLifeHours?: number;
|
|
@@ -17,6 +17,15 @@ export declare class CompositeQuotaSource implements QuotaSource {
|
|
|
17
17
|
private runLogger;
|
|
18
18
|
constructor(sources: QuotaSource[], runLogger?: RunLogger);
|
|
19
19
|
queryCurrentUsage(providerModelKey: string): Promise<QuotaUsageSnapshot | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Probe the cascade with an aggregate status: the first source that returns a
|
|
22
|
+
* snapshot wins (`ok`); otherwise the result is `degraded` when any source
|
|
23
|
+
* that handles this provider was queried and silently degraded (or threw), and
|
|
24
|
+
* `not_applicable` only when no source ever applied. This is what lets a pool
|
|
25
|
+
* record that a live quota reading was expected but lost, instead of treating
|
|
26
|
+
* every empty cascade as "no source configured".
|
|
27
|
+
*/
|
|
28
|
+
probeUsage(providerModelKey: string): Promise<QuotaProbeResult>;
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
22
31
|
* Builds the standard runtime quota snapshot cascade.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compositeQuotaSource.d.ts","sourceRoot":"","sources":["../../../src/shared/quota/compositeQuotaSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"compositeQuotaSource.d.ts","sourceRoot":"","sources":["../../../src/shared/quota/compositeQuotaSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAO1F,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC;IAClC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CACnC;AAED,qBAAa,oBAAqB,YAAW,WAAW;IACtD,QAAQ,CAAC,IAAI,eAAe;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,SAAS,CAAY;gBAEjB,OAAO,EAAE,WAAW,EAAE,EAAE,SAAS,CAAC,EAAE,SAAS;IAKnD,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAIrF;;;;;;;OAOG;IACG,UAAU,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAgCtE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,uBAA4B,GAAG,WAAW,CAmBnF"}
|
|
@@ -14,15 +14,43 @@ export class CompositeQuotaSource {
|
|
|
14
14
|
this.runLogger = runLogger ?? RunLogger.disabled();
|
|
15
15
|
}
|
|
16
16
|
async queryCurrentUsage(providerModelKey) {
|
|
17
|
+
return (await this.probeUsage(providerModelKey)).snapshot;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Probe the cascade with an aggregate status: the first source that returns a
|
|
21
|
+
* snapshot wins (`ok`); otherwise the result is `degraded` when any source
|
|
22
|
+
* that handles this provider was queried and silently degraded (or threw), and
|
|
23
|
+
* `not_applicable` only when no source ever applied. This is what lets a pool
|
|
24
|
+
* record that a live quota reading was expected but lost, instead of treating
|
|
25
|
+
* every empty cascade as "no source configured".
|
|
26
|
+
*/
|
|
27
|
+
async probeUsage(providerModelKey) {
|
|
28
|
+
let sawDegraded = false;
|
|
17
29
|
for (const source of this.sources) {
|
|
18
30
|
try {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
31
|
+
// Invoke the source directly (not via the swallowing `probeQuotaSource`)
|
|
32
|
+
// so a throw propagates to the catch below, where it is BOTH logged and
|
|
33
|
+
// counted as a degrade — preserving the operator-visible failure event.
|
|
34
|
+
let result;
|
|
35
|
+
if (source.probeUsage) {
|
|
36
|
+
result = await source.probeUsage(providerModelKey);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// A bare `queryCurrentUsage` source can't distinguish a silent degrade
|
|
40
|
+
// from a non-match, so a null result is `not_applicable`; a throw falls
|
|
41
|
+
// through to the catch and is recorded as a degrade there.
|
|
42
|
+
const snapshot = await source.queryCurrentUsage(providerModelKey);
|
|
43
|
+
result = { snapshot, status: snapshot ? "ok" : "not_applicable" };
|
|
44
|
+
}
|
|
45
|
+
if (result.snapshot)
|
|
46
|
+
return result;
|
|
47
|
+
if (result.status === "degraded")
|
|
48
|
+
sawDegraded = true;
|
|
22
49
|
}
|
|
23
50
|
catch (err) {
|
|
24
|
-
//
|
|
25
|
-
//
|
|
51
|
+
// A throw is a degrade for that source — surface it so operators can
|
|
52
|
+
// detect a persistently failing quota source, then try the next one.
|
|
53
|
+
sawDegraded = true;
|
|
26
54
|
this.runLogger.event({
|
|
27
55
|
kind: "error",
|
|
28
56
|
phase: "quota",
|
|
@@ -30,7 +58,7 @@ export class CompositeQuotaSource {
|
|
|
30
58
|
});
|
|
31
59
|
}
|
|
32
60
|
}
|
|
33
|
-
return null;
|
|
61
|
+
return { snapshot: null, status: sawDegraded ? "degraded" : "not_applicable" };
|
|
34
62
|
}
|
|
35
63
|
}
|
|
36
64
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compositeQuotaSource.js","sourceRoot":"","sources":["../../../src/shared/quota/compositeQuotaSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAcvD,MAAM,OAAO,oBAAoB;IACtB,IAAI,GAAG,WAAW,CAAC;IACpB,OAAO,CAAgB;IACvB,SAAS,CAAY;IAE7B,YAAY,OAAsB,EAAE,SAAqB;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,gBAAwB;QAC9C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"compositeQuotaSource.js","sourceRoot":"","sources":["../../../src/shared/quota/compositeQuotaSource.ts"],"names":[],"mappings":"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"}
|