agl 40.4.0 → 40.5.0
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/changelog.md +27 -0
- package/dist_serve/bundle.js +2228 -2177
- package/dist_serve/bundle.js.map +2 -2
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/aglapi/aglapisurface.document.js +2 -2
- package/dist_ts/classes.accountsactions.d.ts +11 -1
- package/dist_ts/classes.accountsactions.js +59 -2
- package/dist_ts/classes.controller.js +5 -5
- package/dist_ts/classes.flexaccountaccess.js +3 -2
- package/dist_ts/classes.harnessreleases.d.ts +14 -4
- package/dist_ts/classes.harnessreleases.js +28 -4
- package/dist_ts/classes.inferencegateway.d.ts +28 -3
- package/dist_ts/classes.inferencegateway.js +177 -61
- package/dist_ts/classes.inferenceplacement.d.ts +5 -3
- package/dist_ts/classes.inferenceplacement.js +2 -2
- package/dist_ts/classes.inferencerouter.d.ts +349 -91
- package/dist_ts/classes.inferencerouter.js +804 -297
- package/dist_ts/classes.inferenceservice.d.ts +14 -2
- package/dist_ts/classes.inferenceservice.js +53 -14
- package/dist_ts/classes.inferencespend.d.ts +339 -0
- package/dist_ts/classes.inferencespend.js +815 -0
- package/dist_ts/classes.inferenceusagecache.d.ts +8 -0
- package/dist_ts/classes.inferenceusagecache.js +9 -5
- package/dist_ts/classes.inferenceusagetap.d.ts +50 -9
- package/dist_ts/classes.inferenceusagetap.js +185 -31
- package/dist_ts/classes.proxycontrol.d.ts +3 -2
- package/dist_ts/classes.proxycontrol.js +1 -2
- package/dist_ts/classes.proxydaemon.js +3 -2
- package/dist_ts/classes.proxystore.d.ts +6 -0
- package/dist_ts/classes.proxystore.js +11 -2
- package/dist_ts/fleet/classes.claudeworkers.d.ts +5 -4
- package/dist_ts/fleet/classes.claudeworkers.js +10 -9
- package/dist_ts/functions.claudecoderelease.d.ts +12 -6
- package/dist_ts/functions.claudecoderelease.js +13 -7
- package/dist_ts/functions.inferencecli.js +12 -8
- package/dist_ts/interfaces.auth.d.ts +1 -1
- package/dist_ts/interfaces.auth.js +3 -1
- package/dist_ts/plugins.d.ts +3 -1
- package/dist_ts/plugins.js +7 -2
- package/dist_ts_authswitch/authority-apikeys.d.ts +32 -0
- package/dist_ts_authswitch/authority-apikeys.js +65 -0
- package/dist_ts_authswitch/authority-contract.d.ts +142 -28
- package/dist_ts_authswitch/authority-contract.js +48 -1
- package/dist_ts_authswitch/authority-overview.js +8 -1
- package/dist_ts_authswitch/authority-placement.d.ts +7 -2
- package/dist_ts_authswitch/authority-placement.js +10 -3
- package/dist_ts_authswitch/authority-runtime-contract.d.ts +2 -2
- package/dist_ts_authswitch/authority-spend.d.ts +103 -0
- package/dist_ts_authswitch/authority-spend.js +110 -0
- package/dist_ts_authswitch/authority-subscription.d.ts +12 -1
- package/dist_ts_authswitch/authority-subscription.js +24 -1
- package/dist_ts_authswitch/authority-usagelimit.d.ts +7 -4
- package/dist_ts_authswitch/authority-usagelimit.js +89 -39
- package/dist_ts_authswitch/authority-usagewindows.d.ts +4 -1
- package/dist_ts_authswitch/authority-usagewindows.js +41 -16
- package/dist_ts_authswitch/classes.authoritybroker.d.ts +30 -19
- package/dist_ts_authswitch/classes.authoritybroker.js +152 -61
- package/dist_ts_authswitch/classes.authoritycli.d.ts +9 -4
- package/dist_ts_authswitch/classes.authoritycli.js +94 -29
- package/dist_ts_authswitch/classes.authorityclient.d.ts +24 -7
- package/dist_ts_authswitch/classes.authorityclient.js +31 -11
- package/dist_ts_authswitch/classes.authoritydaemon.js +39 -12
- package/dist_ts_authswitch/classes.authoritydatabase.d.ts +28 -5
- package/dist_ts_authswitch/classes.authoritydatabase.js +171 -9
- package/dist_ts_authswitch/classes.authorityimport.js +2 -2
- package/dist_ts_authswitch/classes.authoritymodels.d.ts +71 -3
- package/dist_ts_authswitch/classes.authoritymodels.js +249 -20
- package/dist_ts_authswitch/classes.authorityregistry.js +4 -2
- package/dist_ts_authswitch/classes.authorityusage.d.ts +69 -7
- package/dist_ts_authswitch/classes.authorityusage.js +118 -4
- package/dist_ts_authswitch/classes.claudenative.d.ts +16 -7
- package/dist_ts_authswitch/classes.claudenative.js +29 -16
- package/dist_ts_authswitch/classes.claudesignin.js +5 -2
- package/dist_ts_authswitch/testsupport.d.ts +24 -5
- package/dist_ts_authswitch/testsupport.js +56 -12
- package/dist_ts_authswitch/ts_migration/0011_account_api_key_fields.d.ts +12 -0
- package/dist_ts_authswitch/ts_migration/0011_account_api_key_fields.js +21 -0
- package/dist_ts_authswitch/ts_migration/index.js +3 -1
- package/dist_ts_interfaces/functions.authorityscope.d.ts +18 -7
- package/dist_ts_interfaces/functions.authorityscope.js +35 -8
- package/dist_ts_interfaces/interfaces.d.ts +1 -1
- package/dist_ts_interfaces/interfaces.js +1 -1
- package/dist_ts_interfaces/plugins.d.ts +2 -1
- package/dist_ts_interfaces/plugins.js +7 -4
- package/dist_ts_interfaces/requests.accounts.d.ts +56 -0
- package/dist_ts_interfaces/requests.accounts.js +11 -1
- package/dist_ts_interfaces/requests.d.ts +2 -2
- package/dist_ts_interfaces/requests.js +1 -1
- package/docs/authswitch.md +75 -12
- package/package.json +5 -5
- package/readme.md +198 -21
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/aglapi/aglapisurface.document.ts +2 -2
- package/ts/classes.accountsactions.ts +75 -1
- package/ts/classes.controller.ts +4 -4
- package/ts/classes.flexaccountaccess.ts +2 -1
- package/ts/classes.harnessreleases.ts +25 -4
- package/ts/classes.inferencegateway.ts +184 -64
- package/ts/classes.inferenceplacement.ts +6 -4
- package/ts/classes.inferencerouter.ts +1026 -314
- package/ts/classes.inferenceservice.ts +56 -13
- package/ts/classes.inferencespend.ts +870 -0
- package/ts/classes.inferenceusagecache.ts +16 -4
- package/ts/classes.inferenceusagetap.ts +159 -34
- package/ts/classes.proxycontrol.ts +3 -3
- package/ts/classes.proxydaemon.ts +2 -1
- package/ts/classes.proxystore.ts +11 -1
- package/ts/fleet/classes.claudeworkers.ts +9 -8
- package/ts/functions.claudecoderelease.ts +13 -6
- package/ts/functions.inferencecli.ts +11 -7
- package/ts/interfaces.auth.ts +2 -0
- package/ts/plugins.ts +7 -0
- package/ts_authswitch/authority-apikeys.ts +85 -0
- package/ts_authswitch/authority-contract.ts +167 -29
- package/ts_authswitch/authority-overview.ts +7 -0
- package/ts_authswitch/authority-placement.ts +12 -4
- package/ts_authswitch/authority-runtime-contract.ts +2 -2
- package/ts_authswitch/authority-spend.ts +168 -0
- package/ts_authswitch/authority-subscription.ts +28 -1
- package/ts_authswitch/authority-usagelimit.ts +95 -40
- package/ts_authswitch/authority-usagewindows.ts +42 -17
- package/ts_authswitch/classes.authoritybroker.ts +161 -68
- package/ts_authswitch/classes.authoritycli.ts +108 -32
- package/ts_authswitch/classes.authorityclient.ts +41 -10
- package/ts_authswitch/classes.authoritydaemon.ts +43 -13
- package/ts_authswitch/classes.authoritydatabase.ts +178 -8
- package/ts_authswitch/classes.authorityimport.ts +1 -1
- package/ts_authswitch/classes.authoritymodels.ts +165 -19
- package/ts_authswitch/classes.authorityregistry.ts +3 -0
- package/ts_authswitch/classes.authorityusage.ts +171 -10
- package/ts_authswitch/classes.claudenative.ts +28 -15
- package/ts_authswitch/classes.claudesignin.ts +4 -1
- package/ts_authswitch/native-contracts.md +81 -20
- package/ts_authswitch/readme.md +1 -1
- package/ts_authswitch/testsupport.ts +58 -11
- package/ts_authswitch/ts_migration/0011_account_api_key_fields.ts +20 -0
- package/ts_authswitch/ts_migration/index.ts +2 -0
- package/ts_interfaces/functions.authorityscope.ts +43 -8
- package/ts_interfaces/interfaces.ts +1 -1
- package/ts_interfaces/plugins.ts +6 -3
- package/ts_interfaces/requests.accounts.ts +48 -0
- package/ts_interfaces/requests.ts +4 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/accounts.plugins.ts +3 -1
- package/ts_web/accounts.templates.ts +20 -11
- package/ts_web/classes.accountsreadmodel.ts +322 -70
- package/ts_web/elements.accounts.ts +219 -20
- package/ts_web/elements.codexconnections.ts +3 -1
- package/ts_web/plugins.ts +4 -2
|
@@ -2,9 +2,10 @@ import * as plugins from './plugins.js';
|
|
|
2
2
|
import { AuthorityState } from './classes.authoritystate.js';
|
|
3
3
|
import type { IAuthoritySocketPaths } from './classes.authorityclient.js';
|
|
4
4
|
import { FlexAccountAccess } from './classes.flexaccountaccess.js';
|
|
5
|
-
import { InferenceRouter, InferenceRoutingError,
|
|
6
|
-
type IInferenceRoutingPolicy } from './classes.inferencerouter.js';
|
|
5
|
+
import { InferenceRouter, InferenceRoutingError, inferencePaymentReportOptions, type IInferenceAccount,
|
|
6
|
+
type IInferenceAccountStatus, type IInferenceRoutingPolicy } from './classes.inferencerouter.js';
|
|
7
7
|
import { InferenceUsageCache } from './classes.inferenceusagecache.js';
|
|
8
|
+
import { InferenceSpendOutbox, type IInferenceSpendStore } from './classes.inferencespend.js';
|
|
8
9
|
import { InferenceUsageObserver, type IInferenceUsageObserverStatus } from './classes.inferenceusageobserver.js';
|
|
9
10
|
import { InferenceGateway, type IInferenceGatewayClientOptions, type IInferenceGatewayGrant, type IInferenceGatewayLease,
|
|
10
11
|
type IInferenceGatewayLimits, type IInferenceGatewayRestoredLease, type IInferenceGatewayStatus } from './classes.inferencegateway.js';
|
|
@@ -12,7 +13,8 @@ import type { IInferenceAffinityStore } from './classes.inferenceaffinity.js';
|
|
|
12
13
|
import type { IInferencePlacementJournal, IInferencePlacementStatus } from './classes.inferenceplacement.js';
|
|
13
14
|
import type { IInferenceUsageLedger } from './classes.inferenceusage.js';
|
|
14
15
|
import type { TInferenceProvider } from './functions.proxycontract.js';
|
|
15
|
-
import { findAuthorityGatewayLogin, findInferencePool, isAuthorityInstallationId,
|
|
16
|
+
import { findAuthorityApiKeyLogin, findAuthorityGatewayLogin, findInferencePool, isAuthorityInstallationId,
|
|
17
|
+
parseAuthorityScope } from '../ts_interfaces/index.js';
|
|
16
18
|
|
|
17
19
|
export interface IInferenceServiceOptions {
|
|
18
20
|
authorityPaths: IAuthoritySocketPaths;
|
|
@@ -25,6 +27,11 @@ export interface IInferenceServiceOptions {
|
|
|
25
27
|
placements: IInferencePlacementJournal;
|
|
26
28
|
/** Where the tokens of every answer are recorded for the usage metrics. */
|
|
27
29
|
usageLedger: IInferenceUsageLedger;
|
|
30
|
+
/**
|
|
31
|
+
* Where the spend of the answers relayed on API keys is kept until the account service acknowledged it: the proxy's
|
|
32
|
+
* own database (`ProxyStore.spend`).
|
|
33
|
+
*/
|
|
34
|
+
spendStore: IInferenceSpendStore;
|
|
28
35
|
providerFetch?: typeof fetch;
|
|
29
36
|
limits?: IInferenceGatewayLimits;
|
|
30
37
|
}
|
|
@@ -45,6 +52,11 @@ export class InferenceService {
|
|
|
45
52
|
* to the authority, whose answer the cache holds.
|
|
46
53
|
*/
|
|
47
54
|
private readonly observer: InferenceUsageObserver;
|
|
55
|
+
/**
|
|
56
|
+
* The spend of the answers relayed on API keys until the account service acknowledged it: counted against each key's
|
|
57
|
+
* limit in the readings the cache hands out, and reported to the account service.
|
|
58
|
+
*/
|
|
59
|
+
private readonly spend: InferenceSpendOutbox;
|
|
48
60
|
private readonly abort = new AbortController();
|
|
49
61
|
private ready = false;
|
|
50
62
|
private started = false;
|
|
@@ -66,6 +78,21 @@ export class InferenceService {
|
|
|
66
78
|
// Routing needs a reading: an account added a moment ago is routed on once its first read landed.
|
|
67
79
|
return client.getUsage(accountIdArg, login.id, signalArg, { waitForFirstRead: true });
|
|
68
80
|
},
|
|
81
|
+
// A key's reading counts the answers whose spend the account service has not acknowledged yet.
|
|
82
|
+
view: (accountIdArg, snapshotArg) => this.spend.judged(accountIdArg, snapshotArg),
|
|
83
|
+
});
|
|
84
|
+
this.spend = new InferenceSpendOutbox({
|
|
85
|
+
store: options.spendStore,
|
|
86
|
+
// Reported on the login each answer was served on, which the outbox keeps with it: also once the key was removed.
|
|
87
|
+
report: async (accountIdArg, loginIdArg, answersArg, signalArg) => {
|
|
88
|
+
const client = this.authority.readyClient();
|
|
89
|
+
if (!this.ready || !client) throw new Error('The account service is unavailable.');
|
|
90
|
+
return client.recordSpend(accountIdArg, loginIdArg, answersArg, signalArg);
|
|
91
|
+
},
|
|
92
|
+
// The account service's answer counts the report's answers: it replaces the held reading as they leave the outbox.
|
|
93
|
+
acknowledged: (accountIdArg, usageArg) => this.usage.accept(accountIdArg, usageArg),
|
|
94
|
+
// An answer recorded without a login is reported on the key's live login, or the removed key's.
|
|
95
|
+
attribute: (accountIdArg) => findAuthorityApiKeyLogin(this.authority.getProjection(), accountIdArg)?.id,
|
|
69
96
|
});
|
|
70
97
|
this.observer = new InferenceUsageObserver({
|
|
71
98
|
send: async (accountIdArg, reportArg, signalArg) => {
|
|
@@ -89,15 +116,22 @@ export class InferenceService {
|
|
|
89
116
|
},
|
|
90
117
|
usage: (accountIdArg, signalArg) => this.usage.get(accountIdArg, signalArg),
|
|
91
118
|
// The account service holds a payment problem on the account's usage, which the cache then routes on.
|
|
92
|
-
reportPaymentProblem: async (accountIdArg, observedAtArg) => {
|
|
119
|
+
reportPaymentProblem: async (accountIdArg, observedAtArg, causeArg) => {
|
|
93
120
|
const client = this.authority.readyClient();
|
|
94
121
|
const login = findAuthorityGatewayLogin(this.authority.getProjection(), accountIdArg);
|
|
95
122
|
if (!this.ready || !client || typeof login === 'string') throw new Error('The account login is unavailable.');
|
|
96
|
-
const usage = await client.reportPaymentProblem(accountIdArg, login.id, observedAtArg, this.abort.signal
|
|
123
|
+
const usage = await client.reportPaymentProblem(accountIdArg, login.id, observedAtArg, this.abort.signal,
|
|
124
|
+
inferencePaymentReportOptions(causeArg));
|
|
97
125
|
this.usage.accept(accountIdArg, usage);
|
|
98
126
|
},
|
|
99
127
|
resolveAccess: (accountIdArg, signalArg, rejectedGenerationArg) => this.access.resolveGateway(
|
|
100
128
|
accountIdArg, AbortSignal.any([signalArg, this.abort.signal]), rejectedGenerationArg),
|
|
129
|
+
// Recorded on the login the route was served on, as the pool was read when the request was placed.
|
|
130
|
+
spend: {
|
|
131
|
+
record: (accountIdArg, loginIdArg, recordArg) => this.spend.record(accountIdArg, loginIdArg, recordArg),
|
|
132
|
+
held: (accountIdArg) => this.spend.held(accountIdArg),
|
|
133
|
+
uncounted: (accountIdArg, modelArg) => this.spend.uncounted(accountIdArg, modelArg),
|
|
134
|
+
},
|
|
101
135
|
});
|
|
102
136
|
this.gateway = new InferenceGateway({ router: this.router, signatureKey: options.signatureKey,
|
|
103
137
|
affinity: options.affinity, placements: options.placements, usageLedger: options.usageLedger, port: options.port,
|
|
@@ -114,8 +148,10 @@ export class InferenceService {
|
|
|
114
148
|
if (!this.ready || projection.state !== 'ready' || !projection.snapshot) return undefined;
|
|
115
149
|
return projection.snapshot.accounts.flatMap((account) => {
|
|
116
150
|
const pool = findInferencePool(projection, account.id);
|
|
151
|
+
const login = findAuthorityGatewayLogin(projection, account.id);
|
|
117
152
|
return pool ? [{ id: account.id, label: account.label, revision: String(account.revision), providerId: pool.provider,
|
|
118
|
-
credential: pool.credential, maxUsagePercent: account.maxUsagePercent, reserveLiftUntil: account.reserveLiftUntil, lapsesAt: account.lapsesAt
|
|
153
|
+
credential: pool.credential, maxUsagePercent: account.maxUsagePercent, reserveLiftUntil: account.reserveLiftUntil, lapsesAt: account.lapsesAt,
|
|
154
|
+
spendLimitMicroUsd: account.spendLimitMicroUsd, loginId: typeof login === 'string' ? null : login.id }] : [];
|
|
119
155
|
});
|
|
120
156
|
}
|
|
121
157
|
|
|
@@ -143,6 +179,8 @@ export class InferenceService {
|
|
|
143
179
|
incarnationId: binding.incarnationId, expectedRevision: binding.revision }, signal);
|
|
144
180
|
}
|
|
145
181
|
this.ready = true;
|
|
182
|
+
// The answers a run before left unacknowledged count from the start, before any request is placed, and are sent.
|
|
183
|
+
await this.spend.start(signal);
|
|
146
184
|
return this.baseUrl;
|
|
147
185
|
} catch (errorArg) {
|
|
148
186
|
await this.stop();
|
|
@@ -165,20 +203,21 @@ export class InferenceService {
|
|
|
165
203
|
/**
|
|
166
204
|
* The gateway's state, each pool account judged on the usage reading a request would route on now -- the account
|
|
167
205
|
* service's answer from its own cache (`InferenceUsageCache.current`), so a pool no request used since the proxy
|
|
168
|
-
* started is judged as its next request would judge it -- the
|
|
169
|
-
*
|
|
206
|
+
* started is judged as its next request would judge it -- the account each provider's next new session of a client
|
|
207
|
+
* that names no credential goes to (a subscription while one takes it, else an API key), and the latest placements the
|
|
208
|
+
* journal holds.
|
|
170
209
|
*/
|
|
171
210
|
public async status(signalArg: AbortSignal): Promise<IInferenceGatewayStatus & { baseUrl: string;
|
|
172
211
|
authority: 'ready' | 'unavailable'; accounts: IInferenceAccountStatus[]; usageObservations: IInferenceUsageObserverStatus;
|
|
173
212
|
nextPlacement: Record<TInferenceProvider, string | null>; recentPlacements: IInferencePlacementStatus[] }> {
|
|
174
213
|
const pool = this.poolAccounts() ?? [];
|
|
175
|
-
|
|
214
|
+
// A key's usage is its month's spend, with the payment problem the account service holds on it.
|
|
215
|
+
const readings = new Map(await Promise.all(pool
|
|
176
216
|
.map(async (accountArg) => [accountArg.id, await this.usage.current(accountArg.id, signalArg)] as const)));
|
|
177
217
|
const accounts = this.router.accountStatus(pool, (accountIdArg) => readings.get(accountIdArg));
|
|
178
218
|
const recent = await this.options.placements.recent(recentPlacementCount, signalArg);
|
|
179
219
|
const next = (providerArg: TInferenceProvider): string | null =>
|
|
180
|
-
accounts.find((accountArg) => accountArg.provider === providerArg && accountArg.
|
|
181
|
-
&& accountArg.placementRank === 1)?.id ?? null;
|
|
220
|
+
accounts.find((accountArg) => accountArg.provider === providerArg && accountArg.placementRank === 1)?.id ?? null;
|
|
182
221
|
return { ...this.gateway.status(), baseUrl: this.baseUrl ?? '', usageObservations: this.observer.status(),
|
|
183
222
|
authority: this.ready && this.authority.getProjection().state === 'ready' ? 'ready' : 'unavailable',
|
|
184
223
|
accounts,
|
|
@@ -193,9 +232,13 @@ export class InferenceService {
|
|
|
193
232
|
this.usage.stop();
|
|
194
233
|
try { await this.gateway.stop(); }
|
|
195
234
|
finally {
|
|
196
|
-
// Hand-overs in flight end before the authority connection closes under them
|
|
235
|
+
// Hand-overs in flight end before the authority connection closes under them; the answers the gateway ended are
|
|
236
|
+
// in the outbox, which keeps what it holds for the next start.
|
|
197
237
|
try { await this.observer.stop(); }
|
|
198
|
-
finally {
|
|
238
|
+
finally {
|
|
239
|
+
try { await this.spend.stop(); }
|
|
240
|
+
finally { try { await this.access.stop(); } finally { await this.authority.stop(); } }
|
|
241
|
+
}
|
|
199
242
|
}
|
|
200
243
|
})();
|
|
201
244
|
}
|