agl 41.0.0 → 41.1.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 +18 -0
- package/dist_serve/bundle.js +881 -881
- package/dist_serve/bundle.js.map +2 -2
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/aglapi/aglapisurface.document.js +6 -2
- package/dist_ts/classes.authmodels.d.ts +15 -0
- package/dist_ts/classes.authmodels.js +78 -7
- package/dist_ts/classes.authstore.js +23 -6
- package/dist_ts/classes.cli.js +8 -3
- package/dist_ts/classes.controller.d.ts +13 -0
- package/dist_ts/classes.controller.js +52 -15
- package/dist_ts/classes.controllermanagement.d.ts +53 -6
- package/dist_ts/classes.controllermanagement.js +180 -72
- package/dist_ts/classes.inferencegateway.d.ts +6 -6
- package/dist_ts/classes.inferencegateway.js +25 -13
- package/dist_ts/classes.mcpreexec.js +4 -4
- package/dist_ts/classes.processinspection.d.ts +3 -1
- package/dist_ts/classes.processinspection.js +4 -2
- package/dist_ts/classes.proxycontrol.d.ts +22 -7
- package/dist_ts/classes.proxycontrol.js +5 -3
- package/dist_ts/classes.proxycontrolclient.d.ts +4 -3
- package/dist_ts/classes.proxycontrolclient.js +7 -5
- package/dist_ts/classes.proxydaemon.d.ts +6 -4
- package/dist_ts/classes.proxydaemon.js +42 -17
- package/dist_ts/classes.proxyleaseholder.d.ts +11 -2
- package/dist_ts/classes.proxyleaseholder.js +25 -2
- package/dist_ts/classes.proxystore.d.ts +3 -2
- package/dist_ts/classes.proxystore.js +5 -2
- package/dist_ts/classes.upgradecoordinator.d.ts +2 -1
- package/dist_ts/classes.upgradecoordinator.js +13 -10
- package/dist_ts/classes.upgradetransaction.d.ts +6 -0
- package/dist_ts/classes.upgradetransaction.js +38 -13
- package/dist_ts/classes.workercallers.d.ts +2 -0
- package/dist_ts/classes.workercallers.js +11 -8
- package/dist_ts/functions.controllermanagementsurface.d.ts +37 -0
- package/dist_ts/functions.controllermanagementsurface.js +110 -0
- package/dist_ts/functions.inferencecli.d.ts +6 -3
- package/dist_ts/functions.inferencecli.js +9 -5
- package/dist_ts/functions.inferencecliarguments.d.ts +1 -1
- package/dist_ts/functions.inferencecliarguments.js +19 -7
- package/dist_ts/functions.inferencelaunch.d.ts +30 -9
- package/dist_ts/functions.inferencelaunch.js +49 -23
- package/dist_ts/functions.workerprocessproof.d.ts +12 -3
- package/dist_ts/functions.workerprocessproof.js +17 -6
- package/dist_ts/interfaces.auth.d.ts +14 -3
- package/dist_ts/interfaces.auth.js +4 -3
- package/dist_ts_interfaces/index.d.ts +1 -0
- package/dist_ts_interfaces/index.js +2 -1
- package/dist_ts_interfaces/interfaces.d.ts +5 -0
- package/dist_ts_interfaces/interfaces.js +1 -1
- package/dist_ts_interfaces/management.d.ts +33 -0
- package/dist_ts_interfaces/management.js +35 -0
- package/package.json +2 -1
- package/readme.md +118 -31
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/aglapi/aglapisurface.document.ts +5 -1
- package/ts/classes.authmodels.ts +74 -5
- package/ts/classes.authstore.ts +24 -4
- package/ts/classes.cli.ts +9 -2
- package/ts/classes.controller.ts +99 -60
- package/ts/classes.controllermanagement.ts +284 -107
- package/ts/classes.inferencegateway.ts +28 -17
- package/ts/classes.mcpreexec.ts +3 -3
- package/ts/classes.processinspection.ts +2 -1
- package/ts/classes.proxycontrol.ts +25 -9
- package/ts/classes.proxycontrolclient.ts +7 -4
- package/ts/classes.proxydaemon.ts +43 -17
- package/ts/classes.proxyleaseholder.ts +36 -7
- package/ts/classes.proxystore.ts +8 -3
- package/ts/classes.upgradecoordinator.ts +20 -11
- package/ts/classes.upgradetransaction.ts +53 -2
- package/ts/classes.workercallers.ts +12 -7
- package/ts/functions.controllermanagementsurface.ts +149 -0
- package/ts/functions.inferencecli.ts +15 -7
- package/ts/functions.inferencecliarguments.ts +16 -6
- package/ts/functions.inferencelaunch.ts +57 -23
- package/ts/functions.workerprocessproof.ts +17 -3
- package/ts/interfaces.auth.ts +14 -3
- package/ts_interfaces/index.ts +1 -0
- package/ts_interfaces/interfaces.ts +5 -0
- package/ts_interfaces/management.ts +52 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
|
@@ -72,6 +72,8 @@ export interface IAglProxyStatus {
|
|
|
72
72
|
export interface IAglProxyConfinedRunStatus {
|
|
73
73
|
/** The run's id: the first 12 hex characters of its credential's SHA-256 digest, never the credential. */
|
|
74
74
|
id: string;
|
|
75
|
+
/** The pool the run is served from: Claude accounts (`anthropic`) or ChatGPT accounts (`openai`). */
|
|
76
|
+
provider: TInferenceProvider;
|
|
75
77
|
createdAt: string;
|
|
76
78
|
/** False while a restarted proxy serves the credential for its reclaim window, waiting for its holder to take it back. */
|
|
77
79
|
held: boolean;
|
|
@@ -148,24 +150,35 @@ export interface IReq_AglProxyReclaim extends ITypedRequest {
|
|
|
148
150
|
|
|
149
151
|
/**
|
|
150
152
|
* A confined run's credential: accepted on the confined listener alone, never on the loopback one, and served there from
|
|
151
|
-
* the Claude pool exactly as the loopback listener serves
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
153
|
+
* the pool `provider` names -- the Claude pool when it names none -- exactly as the loopback listener serves Claude Code on
|
|
154
|
+
* that pool, its sessions those of the client `aglProxyConfinedClient` on that pool. A ChatGPT-pool run is served by the
|
|
155
|
+
* pool's ChatGPT accounts alone, since a translated Messages request never goes to an API key. Like a lease it lives as
|
|
156
|
+
* long as the connection that asked for it, a restarted proxy keeps it for its holder to take back
|
|
157
|
+
* (`agl.proxy.reclaim`), and the proxy keeps only its digest. `agl.proxy.confined.end` ends it at once.
|
|
155
158
|
*/
|
|
156
159
|
export interface IReq_AglProxyConfined extends ITypedRequest {
|
|
157
160
|
method: 'agl.proxy.confined';
|
|
158
|
-
request
|
|
161
|
+
/** An empty request asks for a Claude-pool run, as every proxy since confined runs takes it. */
|
|
162
|
+
request: { provider?: TInferenceProvider };
|
|
159
163
|
response: IAglProxyConfinedGrant;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* What a confined run is given: its id, its pool, its credential, the confined listener's socket and the origin to name
|
|
168
|
+
* with it, and, for a ChatGPT-pool run, the pool's models as the proxy read them when it issued the credential, which the
|
|
169
|
+
* launcher configures Claude Code with as `agl proxy run claude --provider openai` does. A Claude-pool run gets none:
|
|
170
|
+
* Claude Code reads that pool's models through the confined listener.
|
|
171
|
+
*/
|
|
163
172
|
export interface IAglProxyConfinedGrant {
|
|
164
173
|
/** See `IAglProxyConfinedRunStatus.id`. */
|
|
165
174
|
id: string;
|
|
175
|
+
/** The run's pool; a proxy older than ChatGPT-pool runs names none, and issues Claude-pool runs alone. */
|
|
176
|
+
provider?: TInferenceProvider;
|
|
166
177
|
token: string;
|
|
167
178
|
socketPath: string;
|
|
168
179
|
baseUrl: string;
|
|
180
|
+
/** A ChatGPT-pool run's models, the pool's default among them; absent for a Claude-pool run. */
|
|
181
|
+
models?: TInferenceModel[];
|
|
169
182
|
}
|
|
170
183
|
|
|
171
184
|
/**
|
|
@@ -207,7 +220,7 @@ export interface IAglProxyControlHandlers {
|
|
|
207
220
|
catalog(requestArg: IReq_AglProxyCatalog['request'], connectionArg: IAglProxyConnection): Promise<IReq_AglProxyCatalog['response']>;
|
|
208
221
|
lease(requestArg: IReq_AglProxyLease['request'], connectionArg: IAglProxyConnection): Promise<IReq_AglProxyLease['response']>;
|
|
209
222
|
reclaim(requestArg: IReq_AglProxyReclaim['request'], connectionArg: IAglProxyConnection): Promise<IReq_AglProxyReclaim['response']>;
|
|
210
|
-
confined(connectionArg: IAglProxyConnection): Promise<IReq_AglProxyConfined['response']>;
|
|
223
|
+
confined(requestArg: IReq_AglProxyConfined['request'], connectionArg: IAglProxyConnection): Promise<IReq_AglProxyConfined['response']>;
|
|
211
224
|
confinedEnd(requestArg: IReq_AglProxyConfinedEnd['request']): Promise<IReq_AglProxyConfinedEnd['response']>;
|
|
212
225
|
usage(requestArg: IReq_AglProxyUsage['request'], connectionArg: IAglProxyConnection): Promise<IReq_AglProxyUsage['response']>;
|
|
213
226
|
}
|
|
@@ -303,8 +316,11 @@ export class AglProxyControlServer {
|
|
|
303
316
|
return this.handlers!.reclaim(requestArg, connectionArg);
|
|
304
317
|
}));
|
|
305
318
|
this.router.addTypedHandler(handler<IReq_AglProxyConfined>('agl.proxy.confined', (requestArg, connectionArg) => {
|
|
306
|
-
if (!isRecord(requestArg) || Object.keys(requestArg).
|
|
307
|
-
|
|
319
|
+
if (!isRecord(requestArg) || Object.keys(requestArg).some((keyArg) => keyArg !== 'provider')
|
|
320
|
+
|| (requestArg.provider !== undefined && !inferenceProviders.includes(requestArg.provider))) {
|
|
321
|
+
throw new AglProxyControlRefusal('Invalid proxy confined request.');
|
|
322
|
+
}
|
|
323
|
+
return this.handlers!.confined(requestArg, connectionArg);
|
|
308
324
|
}));
|
|
309
325
|
this.router.addTypedHandler(handler<IReq_AglProxyConfinedEnd>('agl.proxy.confined.end', (requestArg) => {
|
|
310
326
|
if (!isRecord(requestArg) || typeof requestArg.id !== 'string' || !aglProxyConfinedIdPattern.test(requestArg.id)
|
|
@@ -190,12 +190,15 @@ export class AglProxyControlClient {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* A confined run's credential, the confined listener's socket and the origin to name
|
|
194
|
-
* long as the returned connection (see `IReq_AglProxyConfined`).
|
|
193
|
+
* A confined run's credential on the pool `providerArg` names, the confined listener's socket and the origin to name
|
|
194
|
+
* with it; the credential lives as long as the returned connection (see `IReq_AglProxyConfined`). A Claude-pool run is
|
|
195
|
+
* asked for with the empty request every proxy since confined runs takes.
|
|
195
196
|
*/
|
|
196
|
-
public async confined(
|
|
197
|
+
public async confined(providerArg: TInferenceProvider,
|
|
198
|
+
signalArg: AbortSignal): Promise<IReq_AglProxyConfined['response'] & IAglProxyLeaseConnection> {
|
|
197
199
|
let held: { socket: net.Socket; rest: Buffer } | undefined;
|
|
198
|
-
const
|
|
200
|
+
const request: IReq_AglProxyConfined['request'] = providerArg === 'anthropic' ? {} : { provider: providerArg };
|
|
201
|
+
const response = await exchange<IReq_AglProxyConfined['response']>(this.socketPath, 'agl.proxy.confined', request,
|
|
199
202
|
signalArg, (socketArg, restArg) => { held = { socket: socketArg, rest: restArg }; });
|
|
200
203
|
return { ...response, ...leaseConnection(held) };
|
|
201
204
|
}
|
|
@@ -8,7 +8,7 @@ import { InferenceRoutingError, type IInferenceRoutingPolicy } from './classes.i
|
|
|
8
8
|
import { aglProxyConfinedClient, aglProxyConfinedOrigin, proxyClientNamePattern, type TInferenceProvider,
|
|
9
9
|
type TProxyCredentialDelivery } from './functions.proxycontract.js';
|
|
10
10
|
import { AglProxyControlRefusal, AglProxyControlServer, type IAglProxyConfinedGrant, type IAglProxyConnection,
|
|
11
|
-
type IAglProxyStatus, type IReq_AglProxyCatalog, type IReq_AglProxyReclaim,
|
|
11
|
+
type IAglProxyStatus, type IReq_AglProxyCatalog, type IReq_AglProxyConfined, type IReq_AglProxyReclaim,
|
|
12
12
|
type TAglProxyLeaseCatalog } from './classes.proxycontrol.js';
|
|
13
13
|
import { ProxyStore, type IProxySecretCodec } from './classes.proxystore.js';
|
|
14
14
|
import type { InferenceUsageStore } from './classes.inferenceusage.js';
|
|
@@ -51,8 +51,16 @@ const catalogRefusal = (errorArg: unknown): AglProxyControlRefusal => new AglPro
|
|
|
51
51
|
errorArg instanceof InferenceRoutingError ? errorArg.code : undefined,
|
|
52
52
|
);
|
|
53
53
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* The policy of a confined run's credential, by its pool: the pool, unrestricted, as Claude Code's own lease on the Claude
|
|
56
|
+
* pool and `agl proxy run claude --provider openai`'s on the ChatGPT pool.
|
|
57
|
+
*/
|
|
58
|
+
const confinedPolicies: Readonly<Record<TInferenceProvider, IInferenceRoutingPolicy>> = Object.freeze({
|
|
59
|
+
anthropic: Object.freeze({ provider: 'anthropic' }),
|
|
60
|
+
// A ChatGPT-pool run's policy is the one `agl proxy run claude --provider openai` leases: its translated Messages
|
|
61
|
+
// requests go to the pool's ChatGPT accounts alone, never to an API key (see `IReq_AglProxyConfined`).
|
|
62
|
+
openai: Object.freeze({ provider: 'openai' }),
|
|
63
|
+
});
|
|
56
64
|
|
|
57
65
|
/** A confined run's id, as the operator names it: the first 12 hex characters of its credential's digest. */
|
|
58
66
|
const confinedRunId = (digestArg: string): string => digestArg.slice(0, 12);
|
|
@@ -61,6 +69,8 @@ const confinedRunId = (digestArg: string): string => digestArg.slice(0, 12);
|
|
|
61
69
|
interface IHeldLease {
|
|
62
70
|
grant: IInferenceGatewayGrant;
|
|
63
71
|
route: TInferenceGatewayRoute;
|
|
72
|
+
/** The pool the lease is served from; a policy that names none is the ChatGPT pool's, as the router reads it. */
|
|
73
|
+
provider: TInferenceProvider;
|
|
64
74
|
createdAt: Date;
|
|
65
75
|
/** The connection the lease lives as long as, while a holder has it. */
|
|
66
76
|
holder?: IAglProxyConnection;
|
|
@@ -146,7 +156,7 @@ export class AglProxyDaemon {
|
|
|
146
156
|
catalog: (requestArg, connectionArg) => this.catalog(requestArg, connectionArg),
|
|
147
157
|
lease: (requestArg, connectionArg) => this.lease(requestArg.policy, requestArg.client, connectionArg),
|
|
148
158
|
reclaim: async (requestArg, connectionArg) => this.reclaim(requestArg.token, connectionArg),
|
|
149
|
-
confined: (connectionArg) => this.confined(connectionArg),
|
|
159
|
+
confined: (requestArg, connectionArg) => this.confined(requestArg, connectionArg),
|
|
150
160
|
confinedEnd: async (requestArg) => this.confinedEnd(requestArg.id),
|
|
151
161
|
usage: async (requestArg, connectionArg) => 'since' in requestArg ? this.usage!.changes(requestArg)
|
|
152
162
|
: await this.usage!.snapshot(requestArg, connectionArg.signal),
|
|
@@ -168,8 +178,8 @@ export class AglProxyDaemon {
|
|
|
168
178
|
recentPlacements: status.recentPlacements, confinedSocketPath: this.options.confinedSocketPath ?? null,
|
|
169
179
|
confinedRuns: [...this.leases].filter(([, heldArg]) => heldArg.route === 'confined')
|
|
170
180
|
.sort(([, left], [, right]) => left.createdAt.getTime() - right.createdAt.getTime())
|
|
171
|
-
.map(([digestArg, heldArg]) => ({ id: confinedRunId(digestArg),
|
|
172
|
-
held: heldArg.reclaimTimer === undefined })),
|
|
181
|
+
.map(([digestArg, heldArg]) => ({ id: confinedRunId(digestArg), provider: heldArg.provider,
|
|
182
|
+
createdAt: heldArg.createdAt.toISOString(), held: heldArg.reclaimTimer === undefined })),
|
|
173
183
|
};
|
|
174
184
|
}
|
|
175
185
|
|
|
@@ -289,7 +299,8 @@ export class AglProxyDaemon {
|
|
|
289
299
|
// The lease continues the sessions of the client it is taken for (see `IReq_AglProxyLease`).
|
|
290
300
|
try { lease = await service.open(policyArg, { sessionScope: clientArg }); }
|
|
291
301
|
catch (errorArg) { throw new AglProxyControlRefusal(errorArg instanceof Error ? errorArg.message : 'The lease could not be opened.'); }
|
|
292
|
-
const held: IHeldLease = { grant: lease, route: 'loopback', createdAt: new Date(),
|
|
302
|
+
const held: IHeldLease = { grant: lease, route: 'loopback', provider: policyArg.provider ?? 'openai', createdAt: new Date(),
|
|
303
|
+
holder: connectionArg };
|
|
293
304
|
this.leases.set(lease.digest, held);
|
|
294
305
|
try {
|
|
295
306
|
await this.trackLeaseWrite(this.store!.recordLease({ digest: lease.digest, client: clientArg, policy: policyArg,
|
|
@@ -319,30 +330,45 @@ export class AglProxyDaemon {
|
|
|
319
330
|
* proves the caller holds the credential the lease was issued with.
|
|
320
331
|
*/
|
|
321
332
|
/**
|
|
322
|
-
* A confined run's credential (see `IReq_AglProxyConfined`): a lease of the
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
333
|
+
* A confined run's credential (see `IReq_AglProxyConfined`): a lease of the pool the request names -- the Claude pool
|
|
334
|
+
* when it names none -- that continues the confined client's sessions on that pool and is accepted on the confined
|
|
335
|
+
* listener alone. It is kept, as its digest, before it is handed out, and ends when its holder's connection closes or
|
|
336
|
+
* the operator ends it (`confinedEnd`). A Claude-pool run gets no model list: Claude Code reads the pool's models
|
|
337
|
+
* through the confined listener, and the pool is judged at each request. A ChatGPT-pool run gets the pool's models, as
|
|
338
|
+
* an `agl proxy run` lease does, for its launcher to configure Claude Code with.
|
|
326
339
|
*/
|
|
327
|
-
private async confined(
|
|
340
|
+
private async confined(requestArg: IReq_AglProxyConfined['request'],
|
|
341
|
+
connectionArg: IAglProxyConnection): Promise<IAglProxyConfinedGrant> {
|
|
328
342
|
const socketPath = this.options.confinedSocketPath;
|
|
329
343
|
if (socketPath === undefined) throw new AglProxyControlRefusal('This AGL proxy has no confined listener.');
|
|
344
|
+
const provider = requestArg.provider ?? 'anthropic';
|
|
345
|
+
const policy = confinedPolicies[provider];
|
|
346
|
+
const service = this.service!;
|
|
330
347
|
let lease: IInferenceGatewayLease;
|
|
331
|
-
try { lease = await
|
|
348
|
+
try { lease = await service.open(policy, { sessionScope: aglProxyConfinedClient, route: 'confined' }); }
|
|
332
349
|
catch (errorArg) {
|
|
333
350
|
throw new AglProxyControlRefusal(errorArg instanceof Error ? errorArg.message : 'The confined credential could not be issued.');
|
|
334
351
|
}
|
|
335
|
-
const held: IHeldLease = { grant: lease, route: 'confined', createdAt: new Date(), holder: connectionArg };
|
|
352
|
+
const held: IHeldLease = { grant: lease, route: 'confined', provider, createdAt: new Date(), holder: connectionArg };
|
|
336
353
|
this.leases.set(lease.digest, held);
|
|
337
354
|
try {
|
|
338
355
|
await this.trackLeaseWrite(this.store!.recordLease({ digest: lease.digest, client: aglProxyConfinedClient,
|
|
339
|
-
policy
|
|
356
|
+
policy, createdAt: held.createdAt, route: 'confined' }));
|
|
340
357
|
} catch (errorArg) {
|
|
341
358
|
this.endLease(lease.digest, held);
|
|
342
359
|
throw new AglProxyControlRefusal(errorArg instanceof Error ? errorArg.message : 'The confined credential could not be recorded.');
|
|
343
360
|
}
|
|
344
361
|
connectionArg.onClose(() => this.endLease(lease.digest, held));
|
|
345
|
-
|
|
362
|
+
const grant: IAglProxyConfinedGrant = { id: confinedRunId(lease.digest), provider, token: lease.token, socketPath,
|
|
363
|
+
baseUrl: aglProxyConfinedOrigin };
|
|
364
|
+
if (provider === 'anthropic') return grant;
|
|
365
|
+
try {
|
|
366
|
+
// A launcher that goes away stops the model list read it asked for.
|
|
367
|
+
return { ...grant, models: await service.router.models(policy, AbortSignal.any([connectionArg.signal, AbortSignal.timeout(60_000)])) };
|
|
368
|
+
} catch (errorArg) {
|
|
369
|
+
this.endLease(lease.digest, held);
|
|
370
|
+
throw catalogRefusal(errorArg);
|
|
371
|
+
}
|
|
346
372
|
}
|
|
347
373
|
|
|
348
374
|
/**
|
|
@@ -414,7 +440,7 @@ export class AglProxyDaemon {
|
|
|
414
440
|
await this.forgetLease(kept.digest);
|
|
415
441
|
continue;
|
|
416
442
|
}
|
|
417
|
-
const held: IHeldLease = { grant, route: kept.route, createdAt: kept.createdAt };
|
|
443
|
+
const held: IHeldLease = { grant, route: kept.route, provider: kept.policy.provider ?? 'openai', createdAt: kept.createdAt };
|
|
418
444
|
held.reclaimTimer = setTimeout(() => this.endLease(kept.digest, held), Math.max(0, deadline - Date.now()));
|
|
419
445
|
this.leases.set(kept.digest, held);
|
|
420
446
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
-
import type { IInferenceRoutingPolicy } from './classes.inferencerouter.js';
|
|
3
|
-
import type { IReq_AglProxyReclaim, TAglProxyLeaseCatalog } from './classes.proxycontrol.js';
|
|
2
|
+
import type { IInferenceRoutingPolicy, TInferenceModel } from './classes.inferencerouter.js';
|
|
3
|
+
import type { IAglProxyConfinedGrant, IReq_AglProxyReclaim, TAglProxyLeaseCatalog } from './classes.proxycontrol.js';
|
|
4
|
+
import type { TInferenceProvider } from './functions.proxycontract.js';
|
|
4
5
|
import { AglProxyControlClient, AglProxyRefusedError, type IAglProxyLeaseConnection } from './classes.proxycontrolclient.js';
|
|
5
6
|
|
|
6
7
|
/** The delays between attempts to take a lease back from a restarting proxy; the last one repeats. */
|
|
@@ -159,28 +160,56 @@ export class AglProxyLeaseHolder extends AglProxyHeldCredential {
|
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
|
|
163
|
+
export interface IAglProxyConfinedHolderOptions extends IAglProxyHolderOptions {
|
|
164
|
+
/** The run's pool: Claude accounts (`anthropic`) or, translated, the ChatGPT accounts (`openai`). */
|
|
165
|
+
provider: TInferenceProvider;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Why a confined grant does not serve the pool it was asked for, or `undefined` when it does: a proxy older than
|
|
170
|
+
* ChatGPT-pool runs names no pool and issues Claude-pool runs alone, and a ChatGPT-pool run comes with the pool's models.
|
|
171
|
+
*/
|
|
172
|
+
const confinedGrantMismatch = (providerArg: TInferenceProvider, grantArg: IAglProxyConfinedGrant): string | undefined => {
|
|
173
|
+
if (providerArg === 'anthropic') {
|
|
174
|
+
return grantArg.provider === undefined || grantArg.provider === 'anthropic' ? undefined
|
|
175
|
+
: 'The AGL proxy issued a confined run of another pool than the Claude pool asked for.';
|
|
176
|
+
}
|
|
177
|
+
return grantArg.provider === 'openai' && Array.isArray(grantArg.models) ? undefined
|
|
178
|
+
: 'The AGL proxy issued no ChatGPT-pool confined run with the pool\'s models; it may run an AGL older than ChatGPT-pool runs.';
|
|
179
|
+
};
|
|
180
|
+
|
|
162
181
|
/**
|
|
163
182
|
* A confined run's credential (see `IReq_AglProxyConfined`), held for as long as its container runs. It is configured
|
|
164
183
|
* with the confined listener's socket, so one taken back on another socket cannot continue.
|
|
165
184
|
*/
|
|
166
185
|
export class AglProxyConfinedHolder extends AglProxyHeldCredential {
|
|
167
186
|
/** Takes a new confined run's credential of the proxy on `optionsArg.socketPath`, its control socket. */
|
|
168
|
-
public static async take(optionsArg:
|
|
187
|
+
public static async take(optionsArg: IAglProxyConfinedHolderOptions, signalArg: AbortSignal): Promise<AglProxyConfinedHolder> {
|
|
169
188
|
const control = new AglProxyControlClient(optionsArg.socketPath);
|
|
170
|
-
const grant = await control.confined(signalArg);
|
|
189
|
+
const grant = await control.confined(optionsArg.provider, signalArg);
|
|
190
|
+
const mismatch = confinedGrantMismatch(optionsArg.provider, grant);
|
|
191
|
+
if (mismatch !== undefined) {
|
|
192
|
+
grant.close();
|
|
193
|
+
throw new Error(mismatch);
|
|
194
|
+
}
|
|
171
195
|
return new AglProxyConfinedHolder(control, grant, optionsArg);
|
|
172
196
|
}
|
|
173
197
|
|
|
174
198
|
/** The run's id, as `agl proxy confined end` and `agl proxy status` name it. */
|
|
175
199
|
public readonly id: string;
|
|
200
|
+
/** The run's pool. */
|
|
201
|
+
public readonly provider: TInferenceProvider;
|
|
202
|
+
/** A ChatGPT-pool run's models as the proxy read them when it issued the credential; empty for a Claude-pool run. */
|
|
203
|
+
public readonly models: readonly TInferenceModel[];
|
|
176
204
|
/** The confined listener's socket, on the host. */
|
|
177
205
|
public readonly confinedSocketPath: string;
|
|
178
206
|
|
|
179
|
-
private constructor(controlArg: AglProxyControlClient,
|
|
180
|
-
|
|
181
|
-
optionsArg: IAglProxyHolderOptions) {
|
|
207
|
+
private constructor(controlArg: AglProxyControlClient, grantArg: IAglProxyConfinedGrant & IAglProxyLeaseConnection,
|
|
208
|
+
optionsArg: IAglProxyConfinedHolderOptions) {
|
|
182
209
|
super(controlArg, grantArg, optionsArg);
|
|
183
210
|
this.id = grantArg.id;
|
|
211
|
+
this.provider = optionsArg.provider;
|
|
212
|
+
this.models = grantArg.models ?? [];
|
|
184
213
|
this.confinedSocketPath = grantArg.socketPath;
|
|
185
214
|
}
|
|
186
215
|
|
package/ts/classes.proxystore.ts
CHANGED
|
@@ -151,8 +151,9 @@ export interface IProxyLeaseDocument {
|
|
|
151
151
|
*/
|
|
152
152
|
orphanedAt?: Date;
|
|
153
153
|
/**
|
|
154
|
-
* `confined` for a confined run's credential, accepted on the confined listener alone, with the
|
|
155
|
-
* and the confined client's sessions; absent for a
|
|
154
|
+
* `confined` for a confined run's credential, accepted on the confined listener alone, with the policy of its pool,
|
|
155
|
+
* the Claude pool's or the ChatGPT pool's, unrestricted, and the confined client's sessions on that pool; absent for a
|
|
156
|
+
* lease of the loopback listener.
|
|
156
157
|
*/
|
|
157
158
|
route?: 'confined';
|
|
158
159
|
}
|
|
@@ -174,6 +175,10 @@ const assertLeasePolicy = (valueArg: unknown): IProxyLeasePolicyDocument => {
|
|
|
174
175
|
return value;
|
|
175
176
|
};
|
|
176
177
|
|
|
178
|
+
/** A confined run's policy, as kept: one pool, unrestricted (see `IProxyLeaseDocument.route`). */
|
|
179
|
+
const confinedLeasePolicies: ReadonlySet<string> = new Set([JSON.stringify({ provider: 'anthropic' }),
|
|
180
|
+
JSON.stringify({ provider: 'openai' })]);
|
|
181
|
+
|
|
177
182
|
const assertLease: (valueArg: unknown) => asserts valueArg is IProxyLeaseDocument = (valueArg) => {
|
|
178
183
|
const value = valueArg as Partial<IProxyLeaseDocument> | null;
|
|
179
184
|
if (!value || typeof value !== 'object'
|
|
@@ -182,7 +187,7 @@ const assertLease: (valueArg: unknown) => asserts valueArg is IProxyLeaseDocumen
|
|
|
182
187
|
|| typeof value.client !== 'string' || !proxyClientNamePattern.test(value.client)
|
|
183
188
|
|| !isDate(value.createdAt) || (Object.hasOwn(value, 'orphanedAt') && !isDate(value.orphanedAt))
|
|
184
189
|
|| (Object.hasOwn(value, 'route') && (value.route !== 'confined' || value.client !== aglProxyConfinedClient
|
|
185
|
-
|| JSON.stringify(value.policy)
|
|
190
|
+
|| !confinedLeasePolicies.has(JSON.stringify(value.policy))))) {
|
|
186
191
|
throw new Error('Invalid proxy lease.');
|
|
187
192
|
}
|
|
188
193
|
assertLeasePolicy(value.policy);
|
|
@@ -85,6 +85,18 @@ interface IUpgradeSemver {
|
|
|
85
85
|
prerelease: string[];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
const upgradeOwnerCommands = [
|
|
89
|
+
'__serve', '__upgrade-worker', 'upgrade', 'start', 'restart', 'service', 'foreground', 'temp-password', 'config',
|
|
90
|
+
] as const;
|
|
91
|
+
/** The CLI commands this release runs under an upgrade lock or a start lease. */
|
|
92
|
+
type TUpgradeOwnerCommand = (typeof upgradeOwnerCommands)[number];
|
|
93
|
+
const upgradeOwnerCommandSet: ReadonlySet<string> = new Set(upgradeOwnerCommands);
|
|
94
|
+
/**
|
|
95
|
+
* A command a later release's CLI holds a start lease under (`agl remote` from 42 on), read back after a rollback:
|
|
96
|
+
* its owner is live while that command runs and stale once it ended, like any other.
|
|
97
|
+
*/
|
|
98
|
+
const laterReleaseStartCommandPattern = /^[a-z][a-z0-9-]{0,31}$/;
|
|
99
|
+
|
|
88
100
|
interface IUpgradeProcessOwner {
|
|
89
101
|
version: typeof coordinationVersion;
|
|
90
102
|
kind: TUpgradeOwnerKind;
|
|
@@ -94,7 +106,8 @@ interface IUpgradeProcessOwner {
|
|
|
94
106
|
processGroupId: number;
|
|
95
107
|
fingerprint: string;
|
|
96
108
|
cliPath: string;
|
|
97
|
-
|
|
109
|
+
/** A `TUpgradeOwnerCommand`, or for a start lease also a later release's command. */
|
|
110
|
+
command: string;
|
|
98
111
|
createdAt: number;
|
|
99
112
|
}
|
|
100
113
|
|
|
@@ -504,15 +517,11 @@ const parseOwner = (valueArg: unknown): IUpgradeProcessOwner => {
|
|
|
504
517
|
|| value.fingerprint.length > 256
|
|
505
518
|
|| typeof value.cliPath !== 'string'
|
|
506
519
|
|| !plugins.path.isAbsolute(value.cliPath)
|
|
507
|
-
||
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
&& value.
|
|
511
|
-
|
|
512
|
-
&& value.command !== 'temp-password'
|
|
513
|
-
&& value.command !== 'config'
|
|
514
|
-
&& value.command !== 'restart'
|
|
515
|
-
&& value.command !== 'service')
|
|
520
|
+
|| typeof value.command !== 'string'
|
|
521
|
+
|| (
|
|
522
|
+
!upgradeOwnerCommandSet.has(value.command)
|
|
523
|
+
&& (value.kind !== 'start' || !laterReleaseStartCommandPattern.test(value.command))
|
|
524
|
+
)
|
|
516
525
|
) {
|
|
517
526
|
throw new Error('Upgrade owner metadata is invalid.');
|
|
518
527
|
}
|
|
@@ -1330,7 +1339,7 @@ const ownerForCurrentProcess = async (
|
|
|
1330
1339
|
kindArg: TUpgradeOwnerKind,
|
|
1331
1340
|
tokenArg: string,
|
|
1332
1341
|
cliPathArg: string,
|
|
1333
|
-
commandArg:
|
|
1342
|
+
commandArg: TUpgradeOwnerCommand,
|
|
1334
1343
|
): Promise<IUpgradeProcessOwner> => {
|
|
1335
1344
|
const identity = await readControllerProcessIdentity(process.pid);
|
|
1336
1345
|
if (!identity) throw new Error('Unable to establish upgrade process ownership.');
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from '../ts_interfaces/index.js';
|
|
10
10
|
import { resolveAGLHomePaths } from './classes.aglhome.js';
|
|
11
11
|
import {
|
|
12
|
+
isControllerManagementProtocolVersion,
|
|
12
13
|
isLoopbackPortListening,
|
|
13
14
|
queryControllerStatus,
|
|
14
15
|
requestControllerUpgradeFinalize,
|
|
@@ -144,8 +145,22 @@ export interface IPnpmGlobalInstallation {
|
|
|
144
145
|
packageDirectory: string;
|
|
145
146
|
cliPath: string;
|
|
146
147
|
packageVersion: string;
|
|
148
|
+
/**
|
|
149
|
+
* The management protocol the installed `package.json` declares (`controllerManagementProtocolVersion`), which
|
|
150
|
+
* decides how the controller this package starts is reached before it reports its status; absent when it declares
|
|
151
|
+
* none, as every release older than the loopback management endpoint.
|
|
152
|
+
*/
|
|
153
|
+
managementProtocolVersion?: number;
|
|
147
154
|
}
|
|
148
155
|
|
|
156
|
+
/**
|
|
157
|
+
* What a `package.json` declares as `controllerManagementProtocolVersion`: `undefined` for no declaration, `false`
|
|
158
|
+
* for one that is not a safe integer of 1 or more, which makes the package metadata incompatible.
|
|
159
|
+
*/
|
|
160
|
+
const readDeclaredManagementProtocolVersion = (valueArg: unknown): number | undefined | false => (
|
|
161
|
+
valueArg === undefined ? undefined : isControllerManagementProtocolVersion(valueArg) ? valueArg : false
|
|
162
|
+
);
|
|
163
|
+
|
|
149
164
|
export interface IDetachedUpgradeWorker {
|
|
150
165
|
pid: number;
|
|
151
166
|
processGroupId: number;
|
|
@@ -597,15 +612,20 @@ export const resolvePnpmGlobalInstallation = async (): Promise<IPnpmGlobalInstal
|
|
|
597
612
|
version?: unknown;
|
|
598
613
|
bin?: unknown;
|
|
599
614
|
controllerUpgradeManagementVersion?: unknown;
|
|
615
|
+
controllerManagementProtocolVersion?: unknown;
|
|
600
616
|
};
|
|
601
617
|
const currentIdentity: { cliName: string; cliRelativePath: string; managementVersion: number } = (
|
|
602
618
|
currentPackageIdentity
|
|
603
619
|
);
|
|
620
|
+
const managementProtocolVersion = readDeclaredManagementProtocolVersion(
|
|
621
|
+
packageJson.controllerManagementProtocolVersion,
|
|
622
|
+
);
|
|
604
623
|
if (
|
|
605
624
|
packageJson.name !== controllerPackageName
|
|
606
625
|
|| packageJson.version !== dependency.version
|
|
607
626
|
|| packageJson.controllerUpgradeManagementVersion !== currentIdentity.managementVersion
|
|
608
627
|
|| Number(controllerUpgradeManagementVersion) !== currentIdentity.managementVersion
|
|
628
|
+
|| managementProtocolVersion === false
|
|
609
629
|
|| !declaresControllerCommands(packageJson.bin, currentIdentity)
|
|
610
630
|
) {
|
|
611
631
|
throw new Error(`The pnpm-global ${controllerPackageName} package metadata is incompatible.`);
|
|
@@ -621,6 +641,7 @@ export const resolvePnpmGlobalInstallation = async (): Promise<IPnpmGlobalInstal
|
|
|
621
641
|
packageDirectory,
|
|
622
642
|
cliPath,
|
|
623
643
|
packageVersion: dependency.version,
|
|
644
|
+
...(managementProtocolVersion === undefined ? {} : { managementProtocolVersion }),
|
|
624
645
|
};
|
|
625
646
|
};
|
|
626
647
|
|
|
@@ -749,10 +770,14 @@ const readExactGlobalPackage = async (
|
|
|
749
770
|
}
|
|
750
771
|
const manifest = packageJson as Record<string, unknown>;
|
|
751
772
|
const bin = manifest.bin;
|
|
773
|
+
const managementProtocolVersion = readDeclaredManagementProtocolVersion(
|
|
774
|
+
manifest.controllerManagementProtocolVersion,
|
|
775
|
+
);
|
|
752
776
|
if (
|
|
753
777
|
manifest.name !== identityArg.packageName
|
|
754
778
|
|| manifest.version !== identityArg.version
|
|
755
779
|
|| manifest.controllerUpgradeManagementVersion !== identityArg.managementVersion
|
|
780
|
+
|| managementProtocolVersion === false
|
|
756
781
|
|| !bin
|
|
757
782
|
|| typeof bin !== 'object'
|
|
758
783
|
|| Array.isArray(bin)
|
|
@@ -772,6 +797,7 @@ const readExactGlobalPackage = async (
|
|
|
772
797
|
packageDirectory,
|
|
773
798
|
cliPath,
|
|
774
799
|
packageVersion: identityArg.version,
|
|
800
|
+
...(managementProtocolVersion === undefined ? {} : { managementProtocolVersion }),
|
|
775
801
|
packageName: identityArg.packageName,
|
|
776
802
|
cliName: identityArg.cliName,
|
|
777
803
|
cliRelativePath: identityArg.cliRelativePath,
|
|
@@ -952,11 +978,15 @@ const resolveAuthoritativeRecoveryInstallation = async (
|
|
|
952
978
|
}
|
|
953
979
|
const manifest = packageJson as Record<string, unknown>;
|
|
954
980
|
const bin = manifest.bin;
|
|
981
|
+
const managementProtocolVersion = readDeclaredManagementProtocolVersion(
|
|
982
|
+
manifest.controllerManagementProtocolVersion,
|
|
983
|
+
);
|
|
955
984
|
if (
|
|
956
985
|
manifest.name !== currentIdentity.packageName
|
|
957
986
|
|| typeof manifest.version !== 'string'
|
|
958
987
|
|| !currentIdentity.versions.includes(manifest.version)
|
|
959
988
|
|| manifest.controllerUpgradeManagementVersion !== currentIdentity.managementVersion
|
|
989
|
+
|| managementProtocolVersion === false
|
|
960
990
|
|| !declaresControllerCommands(bin, currentIdentity)
|
|
961
991
|
) throw new Error('The authoritative recovery package identity is incompatible.');
|
|
962
992
|
if (!(await plugins.fs.promises.stat(cliPath)).isFile()) {
|
|
@@ -970,6 +1000,7 @@ const resolveAuthoritativeRecoveryInstallation = async (
|
|
|
970
1000
|
packageDirectory,
|
|
971
1001
|
cliPath,
|
|
972
1002
|
packageVersion: manifest.version,
|
|
1003
|
+
...(managementProtocolVersion === undefined ? {} : { managementProtocolVersion }),
|
|
973
1004
|
};
|
|
974
1005
|
};
|
|
975
1006
|
|
|
@@ -1956,6 +1987,10 @@ const grantControllerAction = async (
|
|
|
1956
1987
|
},
|
|
1957
1988
|
});
|
|
1958
1989
|
|
|
1990
|
+
/**
|
|
1991
|
+
* Reads the status of a controller the upgrade just started from `installationArg`, over the transport that
|
|
1992
|
+
* package's `package.json` declares.
|
|
1993
|
+
*/
|
|
1959
1994
|
const queryUpgradeManagedController = async (
|
|
1960
1995
|
portArg: number,
|
|
1961
1996
|
identityArg: {
|
|
@@ -1963,10 +1998,12 @@ const queryUpgradeManagedController = async (
|
|
|
1963
1998
|
packageVersion: string;
|
|
1964
1999
|
managementVersion: number;
|
|
1965
2000
|
},
|
|
2001
|
+
installationArg: IPnpmGlobalInstallation,
|
|
1966
2002
|
): Promise<IControllerStatus> => queryControllerStatus(portArg, {
|
|
1967
2003
|
packageName: identityArg.packageName,
|
|
1968
2004
|
packageVersion: identityArg.packageVersion,
|
|
1969
2005
|
upgradeManagementVersion: identityArg.managementVersion,
|
|
2006
|
+
managementProtocolVersion: installationArg.managementProtocolVersion,
|
|
1970
2007
|
});
|
|
1971
2008
|
|
|
1972
2009
|
const finalizeControllerUpgrade = async (
|
|
@@ -1980,7 +2017,7 @@ const finalizeControllerUpgrade = async (
|
|
|
1980
2017
|
try {
|
|
1981
2018
|
response = await requestControllerUpgradeFinalize(statusArg.controllerPid > 0
|
|
1982
2019
|
? (await coordinatorArg.readTransaction(tokenArg)).port
|
|
1983
|
-
: 0, tokenArg, modeArg);
|
|
2020
|
+
: 0, statusArg, tokenArg, modeArg);
|
|
1984
2021
|
} finally {
|
|
1985
2022
|
await coordinatorArg.removeControllerActionGrant('finalize', tokenArg);
|
|
1986
2023
|
}
|
|
@@ -2103,6 +2140,7 @@ export const prepareAndStopRunningController = async (
|
|
|
2103
2140
|
try {
|
|
2104
2141
|
await (dependenciesArg.requestPrepareBegin ?? requestControllerUpgradePrepareBegin)(
|
|
2105
2142
|
optionsArg.port,
|
|
2143
|
+
optionsArg.runningStatus,
|
|
2106
2144
|
optionsArg.token,
|
|
2107
2145
|
optionsArg.targetVersion,
|
|
2108
2146
|
optionsArg.gracePeriodMs,
|
|
@@ -2323,6 +2361,7 @@ const runPackageTransitionUpgradeWorker = async (optionsArg: {
|
|
|
2323
2361
|
packageVersion: initialTransaction.sourceVersion,
|
|
2324
2362
|
protocolVersion: controllerProtocolVersion,
|
|
2325
2363
|
upgradeManagementVersion: initialTransaction.sourceManagementVersion,
|
|
2364
|
+
managementProtocolVersion: currentInstallation.managementProtocolVersion,
|
|
2326
2365
|
});
|
|
2327
2366
|
assertExpectedController(runningStatus, payload.expectedController);
|
|
2328
2367
|
if (
|
|
@@ -2470,6 +2509,7 @@ const runPackageTransitionUpgradeWorker = async (optionsArg: {
|
|
|
2470
2509
|
const restoredStatus = await queryUpgradeManagedController(
|
|
2471
2510
|
payload.port,
|
|
2472
2511
|
sourceControllerIdentity(initialTransaction),
|
|
2512
|
+
sourceTopology.source,
|
|
2473
2513
|
);
|
|
2474
2514
|
await finalizeControllerUpgrade(
|
|
2475
2515
|
coordinator,
|
|
@@ -2520,6 +2560,7 @@ const runPackageTransitionUpgradeWorker = async (optionsArg: {
|
|
|
2520
2560
|
const targetStatus = await queryUpgradeManagedController(
|
|
2521
2561
|
payload.port,
|
|
2522
2562
|
targetControllerIdentity(initialTransaction),
|
|
2563
|
+
targetInstallation,
|
|
2523
2564
|
);
|
|
2524
2565
|
await updateWorkerProgress(
|
|
2525
2566
|
coordinator,
|
|
@@ -2728,6 +2769,7 @@ export async function runUpgradeWorker(
|
|
|
2728
2769
|
packageVersion: currentInstallation.packageVersion,
|
|
2729
2770
|
protocolVersion: controllerProtocolVersion,
|
|
2730
2771
|
upgradeManagementVersion: controllerUpgradeManagementVersion,
|
|
2772
|
+
managementProtocolVersion: currentInstallation.managementProtocolVersion,
|
|
2731
2773
|
});
|
|
2732
2774
|
assertExpectedController(runningStatus, payloadArg.expectedController);
|
|
2733
2775
|
if (
|
|
@@ -2812,6 +2854,7 @@ export async function runUpgradeWorker(
|
|
|
2812
2854
|
packageVersion: restored.packageVersion,
|
|
2813
2855
|
managementVersion: controllerUpgradeManagementVersion,
|
|
2814
2856
|
},
|
|
2857
|
+
restored,
|
|
2815
2858
|
);
|
|
2816
2859
|
await finalizeControllerUpgrade(
|
|
2817
2860
|
coordinator,
|
|
@@ -2851,7 +2894,7 @@ export async function runUpgradeWorker(
|
|
|
2851
2894
|
packageName: controllerPackageName,
|
|
2852
2895
|
packageVersion: latestVersion,
|
|
2853
2896
|
managementVersion: controllerUpgradeManagementVersion,
|
|
2854
|
-
});
|
|
2897
|
+
}, upgradedInstallation);
|
|
2855
2898
|
await updateWorkerProgress(
|
|
2856
2899
|
coordinator,
|
|
2857
2900
|
payloadArg.token,
|
|
@@ -2997,6 +3040,7 @@ const recoverPackageTransition = async (optionsArg: {
|
|
|
2997
3040
|
packageName: current.targetPackageName,
|
|
2998
3041
|
packageVersion: upgradeTransactionTargetVersion(current)!,
|
|
2999
3042
|
upgradeManagementVersion: current.targetManagementVersion,
|
|
3043
|
+
managementProtocolVersion: targetInstallation.managementProtocolVersion,
|
|
3000
3044
|
}).catch(() => undefined);
|
|
3001
3045
|
if (!status) {
|
|
3002
3046
|
if (await retainedUpgradeTargetIsAuthoritative({
|
|
@@ -3019,6 +3063,7 @@ const recoverPackageTransition = async (optionsArg: {
|
|
|
3019
3063
|
status = await queryUpgradeManagedController(
|
|
3020
3064
|
current.port,
|
|
3021
3065
|
targetControllerIdentity(current),
|
|
3066
|
+
targetInstallation,
|
|
3022
3067
|
);
|
|
3023
3068
|
}
|
|
3024
3069
|
await finalizeControllerUpgrade(
|
|
@@ -3051,6 +3096,7 @@ const recoverPackageTransition = async (optionsArg: {
|
|
|
3051
3096
|
packageName: transaction.sourcePackageName,
|
|
3052
3097
|
packageVersion: transaction.sourceVersion,
|
|
3053
3098
|
upgradeManagementVersion: transaction.sourceManagementVersion,
|
|
3099
|
+
managementProtocolVersion: sourceInstallation.managementProtocolVersion,
|
|
3054
3100
|
}).catch(() => undefined);
|
|
3055
3101
|
if (!status) {
|
|
3056
3102
|
await startRestoredController(
|
|
@@ -3062,6 +3108,7 @@ const recoverPackageTransition = async (optionsArg: {
|
|
|
3062
3108
|
status = await queryUpgradeManagedController(
|
|
3063
3109
|
transaction.port,
|
|
3064
3110
|
sourceControllerIdentity(transaction),
|
|
3111
|
+
sourceInstallation,
|
|
3065
3112
|
);
|
|
3066
3113
|
}
|
|
3067
3114
|
await finalizeControllerUpgrade(
|
|
@@ -3130,6 +3177,7 @@ const recoverStalledUpgradeUnderLock = async (optionsArg: {
|
|
|
3130
3177
|
packageName: controllerPackageName,
|
|
3131
3178
|
packageVersion: targetInstallation.packageVersion,
|
|
3132
3179
|
upgradeManagementVersion: controllerUpgradeManagementVersion,
|
|
3180
|
+
managementProtocolVersion: targetInstallation.managementProtocolVersion,
|
|
3133
3181
|
}).catch(() => undefined);
|
|
3134
3182
|
if (!status) {
|
|
3135
3183
|
if (await retainedUpgradeTargetIsAuthoritative({
|
|
@@ -3156,6 +3204,7 @@ const recoverStalledUpgradeUnderLock = async (optionsArg: {
|
|
|
3156
3204
|
packageVersion: targetInstallation.packageVersion,
|
|
3157
3205
|
managementVersion: controllerUpgradeManagementVersion,
|
|
3158
3206
|
},
|
|
3207
|
+
targetInstallation,
|
|
3159
3208
|
);
|
|
3160
3209
|
}
|
|
3161
3210
|
await finalizeControllerUpgrade(
|
|
@@ -3187,6 +3236,7 @@ const recoverStalledUpgradeUnderLock = async (optionsArg: {
|
|
|
3187
3236
|
packageName: controllerPackageName,
|
|
3188
3237
|
packageVersion: sourceInstallation.packageVersion,
|
|
3189
3238
|
upgradeManagementVersion: controllerUpgradeManagementVersion,
|
|
3239
|
+
managementProtocolVersion: sourceInstallation.managementProtocolVersion,
|
|
3190
3240
|
}).catch(() => undefined);
|
|
3191
3241
|
if (!status) {
|
|
3192
3242
|
await startRestoredController(
|
|
@@ -3202,6 +3252,7 @@ const recoverStalledUpgradeUnderLock = async (optionsArg: {
|
|
|
3202
3252
|
packageVersion: sourceInstallation.packageVersion,
|
|
3203
3253
|
managementVersion: controllerUpgradeManagementVersion,
|
|
3204
3254
|
},
|
|
3255
|
+
sourceInstallation,
|
|
3205
3256
|
);
|
|
3206
3257
|
}
|
|
3207
3258
|
await finalizeControllerUpgrade(
|