agent-relay-orchestrator 0.102.2 → 0.103.4
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/package.json +3 -2
- package/src/config.ts +16 -6
- package/src/control.ts +6 -9
- package/src/provider-probe.ts +19 -13
- package/src/quota-poller.ts +37 -16
- package/src/relay.ts +2 -2
- package/src/self-upgrade.ts +6 -8
- package/src/spawn/types.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-relay-orchestrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.103.4",
|
|
4
4
|
"description": "Agent Relay orchestrator — manages agent lifecycle across hosts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"test": "bun test"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"agent-relay-
|
|
20
|
+
"agent-relay-providers": "0.102.2",
|
|
21
|
+
"agent-relay-sdk": "0.2.87"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@types/bun": "latest",
|
package/src/config.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { homedir, hostname as osHostname } from "node:os";
|
|
3
3
|
import { join, dirname } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { getAllManifests, getManifest } from "agent-relay-providers";
|
|
5
|
+
import { DEFAULT_RELAY_URL, type SpawnProvider } from "agent-relay-sdk";
|
|
5
6
|
|
|
6
7
|
export interface OrchestratorConfig {
|
|
7
8
|
id: string;
|
|
8
9
|
hostname: string;
|
|
9
10
|
relayUrl: string;
|
|
10
11
|
token?: string;
|
|
11
|
-
providers:
|
|
12
|
+
providers: SpawnProvider[];
|
|
12
13
|
baseDir: string;
|
|
13
14
|
env: Record<string, string>;
|
|
14
15
|
heartbeatIntervalMs: number;
|
|
@@ -17,6 +18,7 @@ export interface OrchestratorConfig {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
const DEFAULT_CONFIG_PATH = join(homedir(), ".agent-relay", "orchestrator.json");
|
|
21
|
+
const DEFAULT_PROVIDER_IDS = getAllManifests().map((manifest) => manifest.id as SpawnProvider);
|
|
20
22
|
|
|
21
23
|
function envNumberOrDefault(name: string, fallback: number): number {
|
|
22
24
|
return Number(process.env[name]) || fallback;
|
|
@@ -42,8 +44,9 @@ export function bunBinFromEnv(): string | undefined {
|
|
|
42
44
|
return process.env.AGENT_RELAY_BUN_BIN;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
export function
|
|
46
|
-
|
|
47
|
+
export function providerCommandFromEnv(provider: string): string | undefined {
|
|
48
|
+
const prefix = getManifest(provider)?.home?.envPrefix ?? provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
49
|
+
return process.env[`AGENT_RELAY_${prefix}_COMMAND`];
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export function providerHomeRootFromEnv(): string {
|
|
@@ -104,6 +107,13 @@ interface RawConfig {
|
|
|
104
107
|
apiPort?: number;
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
function normalizeProviders(values: string[] | undefined): SpawnProvider[] {
|
|
111
|
+
const requested = values?.map((value) => value.trim()).filter(Boolean) ?? [];
|
|
112
|
+
const allowed = new Set(DEFAULT_PROVIDER_IDS);
|
|
113
|
+
const normalized = requested.filter((value): value is SpawnProvider => allowed.has(value as SpawnProvider));
|
|
114
|
+
return normalized.length > 0 ? normalized : [...DEFAULT_PROVIDER_IDS];
|
|
115
|
+
}
|
|
116
|
+
|
|
107
117
|
export function loadConfig(path?: string): OrchestratorConfig {
|
|
108
118
|
const configPath = path || process.env.AGENT_RELAY_ORCHESTRATOR_CONFIG || DEFAULT_CONFIG_PATH;
|
|
109
119
|
|
|
@@ -116,7 +126,7 @@ export function loadConfig(path?: string): OrchestratorConfig {
|
|
|
116
126
|
const hostname = raw.hostname || process.env.AGENT_RELAY_ORCHESTRATOR_HOSTNAME || osHostname();
|
|
117
127
|
const relayUrl = raw.relayUrl || process.env.AGENT_RELAY_URL || DEFAULT_RELAY_URL;
|
|
118
128
|
const token = raw.token || process.env.AGENT_RELAY_TOKEN || undefined;
|
|
119
|
-
const providers = (raw.providers || process.env.AGENT_RELAY_ORCHESTRATOR_PROVIDERS?.split(",")
|
|
129
|
+
const providers = normalizeProviders(raw.providers || process.env.AGENT_RELAY_ORCHESTRATOR_PROVIDERS?.split(","));
|
|
120
130
|
const baseDir = raw.baseDir || process.env.AGENT_RELAY_ORCHESTRATOR_BASE_DIR || join(homedir(), "projects");
|
|
121
131
|
const env = raw.env || {};
|
|
122
132
|
const heartbeatIntervalMs = raw.heartbeatIntervalMs || 30_000;
|
|
@@ -133,7 +143,7 @@ export function initConfigFile(config: Partial<RawConfig>): string {
|
|
|
133
143
|
id: osHostname().replace(/\./g, "-"),
|
|
134
144
|
hostname: osHostname(),
|
|
135
145
|
relayUrl: DEFAULT_RELAY_URL,
|
|
136
|
-
providers: [
|
|
146
|
+
providers: [...DEFAULT_PROVIDER_IDS],
|
|
137
147
|
baseDir: join(homedir(), "projects"),
|
|
138
148
|
apiPort: 4860,
|
|
139
149
|
env: {},
|
package/src/control.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { errMessage, isRecord, normalizeAgentLifecycle, normalizeWorkspaceMode } from "agent-relay-sdk";
|
|
2
|
+
import { getAllManifests, getManifest } from "agent-relay-providers";
|
|
2
3
|
import type { OrchestratorConfig } from "./config";
|
|
3
4
|
import type { ManagedAgentReport, RelayClient, RelayCommand } from "./relay";
|
|
4
5
|
import { handleSelfUpgrade } from "./self-upgrade";
|
|
@@ -264,17 +265,13 @@ function shutdownTimeoutMs(ctrl: Record<string, any>): number | undefined {
|
|
|
264
265
|
return Number.isSafeInteger(ctrl.timeoutMs) && ctrl.timeoutMs > 0 ? Math.min(ctrl.timeoutMs, 60_000) : undefined;
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
// Both the control-spawn and restart-source paths build SpawnOptions from a
|
|
268
|
-
// loose record in the same way. The two prior copies differed only in two
|
|
269
|
-
// immaterial spots, unified here to the safer form:
|
|
270
|
-
// - provider: `=== "codex" ? "codex" : "claude"` (SPAWN_PROVIDERS is exactly
|
|
271
|
-
// claude|codex, so this matches control's `|| "claude"` for every valid
|
|
272
|
-
// input and stays defensive against junk).
|
|
273
|
-
// - cwd: `source.cwd || baseDir` — an empty-string cwd now falls back to
|
|
274
|
-
// baseDir on the restart path too (was a latent bug; empty cwd is invalid).
|
|
275
268
|
function spawnOptionsFromRecord(source: Record<string, any>, config: OrchestratorConfig): SpawnOptions {
|
|
269
|
+
const fallbackProvider = config.providers[0] ?? (getAllManifests()[0]?.id ?? "claude");
|
|
270
|
+
const provider = typeof source.provider === "string" && getManifest(source.provider)
|
|
271
|
+
? source.provider
|
|
272
|
+
: fallbackProvider;
|
|
276
273
|
return {
|
|
277
|
-
provider
|
|
274
|
+
provider,
|
|
278
275
|
cwd: source.cwd || config.baseDir,
|
|
279
276
|
rig: typeof source.rig === "string" ? source.rig : undefined,
|
|
280
277
|
model: modelFromControl(source),
|
package/src/provider-probe.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { delimiter, join, resolve } from "node:path";
|
|
4
|
+
import { getManifest, type ProviderProbeFeatureCheck } from "agent-relay-providers";
|
|
4
5
|
import { providerCatalogList, type ProviderCatalogEntry } from "agent-relay-sdk/provider-catalog";
|
|
5
|
-
import { errMessage } from "agent-relay-sdk";
|
|
6
|
+
import { errMessage, type SpawnProvider } from "agent-relay-sdk";
|
|
6
7
|
import type { OrchestratorConfig } from "./config";
|
|
7
8
|
import { VERSION } from "./version";
|
|
8
9
|
|
|
@@ -15,7 +16,7 @@ interface ProviderProbeDetail {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
interface ProviderProbeResult {
|
|
18
|
-
name:
|
|
19
|
+
name: SpawnProvider;
|
|
19
20
|
available: boolean;
|
|
20
21
|
checkedAt: number;
|
|
21
22
|
reason?: string;
|
|
@@ -27,7 +28,7 @@ interface ProviderProbeResult {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
interface ProviderProbeSnapshot {
|
|
30
|
-
providers:
|
|
31
|
+
providers: SpawnProvider[];
|
|
31
32
|
providerStatus: ProviderProbeResult[];
|
|
32
33
|
providerCatalog: ProviderCatalogEntry[];
|
|
33
34
|
checkedAt: number;
|
|
@@ -62,11 +63,14 @@ export class ProviderProbeCache {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
export async function probeProvider(provider:
|
|
66
|
-
const
|
|
66
|
+
export async function probeProvider(provider: SpawnProvider, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<ProviderProbeResult> {
|
|
67
|
+
const manifest = getManifest(provider);
|
|
68
|
+
const cliCommand = manifest?.probe?.command ?? provider;
|
|
69
|
+
const cliArgs = manifest?.probe?.args ?? ["--version"];
|
|
70
|
+
const cli = await probeCommand(cliCommand, cliArgs, timeoutMs, cliCommand, (path) => isRelayProviderShim(path, provider));
|
|
67
71
|
const runner = await probeRunner(provider, timeoutMs);
|
|
68
72
|
const available = cli.ok && runner.ok;
|
|
69
|
-
const features = probeProviderFeatures(
|
|
73
|
+
const features = probeProviderFeatures(manifest?.probe?.featureChecks ?? []);
|
|
70
74
|
return {
|
|
71
75
|
name: provider,
|
|
72
76
|
available,
|
|
@@ -80,17 +84,19 @@ export async function probeProvider(provider: "claude" | "codex", timeoutMs = DE
|
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
function probeProviderFeatures(
|
|
87
|
+
function probeProviderFeatures(checks: ProviderProbeFeatureCheck[]): Record<string, boolean> {
|
|
84
88
|
const features: Record<string, boolean> = {};
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
+
for (const check of checks) {
|
|
90
|
+
const hasCommand = check.command ? !!resolveExecutable(check.command) : false;
|
|
91
|
+
const hasHomeDir = check.homeDir ? existsSync(join(homedir(), check.homeDir)) : false;
|
|
92
|
+
if (hasCommand || hasHomeDir) {
|
|
93
|
+
features[check.name] = true;
|
|
94
|
+
}
|
|
89
95
|
}
|
|
90
96
|
return features;
|
|
91
97
|
}
|
|
92
98
|
|
|
93
|
-
async function probeRunner(provider:
|
|
99
|
+
async function probeRunner(provider: SpawnProvider, timeoutMs: number): Promise<ProviderProbeDetail> {
|
|
94
100
|
const repoLauncher = resolve(import.meta.dir, "../../runner/src/index.ts");
|
|
95
101
|
if (existsSync(repoLauncher)) {
|
|
96
102
|
const bun = resolveExecutable("bun");
|
|
@@ -175,7 +181,7 @@ function isExecutable(path: string): boolean {
|
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
183
|
|
|
178
|
-
function isRelayProviderShim(path: string, provider:
|
|
184
|
+
function isRelayProviderShim(path: string, provider: SpawnProvider): boolean {
|
|
179
185
|
try {
|
|
180
186
|
const content = readFileSync(path, "utf8").slice(0, 1024);
|
|
181
187
|
return content.includes(`${provider}-relay ${provider}`);
|
package/src/quota-poller.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { homedir } from "node:os";
|
|
|
2
2
|
import { existsSync, readdirSync } from "node:fs";
|
|
3
3
|
import { createServer } from "node:net";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { getManifest, type ProviderQuotaPollDescriptor } from "agent-relay-providers";
|
|
5
6
|
import {
|
|
6
7
|
DEFAULT_PROVIDER_QUOTA_CONFIG,
|
|
7
8
|
QUOTA_FAILURE_LOG_INTERVAL_MS,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
} from "agent-relay-sdk/provider-quota";
|
|
18
19
|
import type { ProviderQuotaConfig, ProviderQuotaConfigMap, ProviderQuotaLeaseAcquireInput, ProviderQuotaUpdateInput } from "agent-relay-sdk";
|
|
19
20
|
import { errMessage } from "agent-relay-sdk";
|
|
20
|
-
import {
|
|
21
|
+
import { providerCommandFromEnv, providerHomeRootFromEnv, type OrchestratorConfig } from "./config";
|
|
21
22
|
|
|
22
23
|
const QUOTA_LEASE_TTL_MS = 90_000;
|
|
23
24
|
const QUOTA_LEASE_RENEW_MS = 30_000;
|
|
@@ -173,10 +174,11 @@ export class OrchestratorQuotaPoller {
|
|
|
173
174
|
// A disabled provider (#605) is collected from at all: no discovery → no
|
|
174
175
|
// polling/API calls, leases released by releaseRemovedCandidates, and no
|
|
175
176
|
// skip-marker row (disabled is intentional, not a credential failure).
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
for (const provider of this.config.providers) {
|
|
178
|
+
if (!this.configFor(provider).enabled) continue;
|
|
179
|
+
const found = await this.discoverProviderCandidates(provider);
|
|
178
180
|
candidates.push(...found.candidates);
|
|
179
|
-
if (found.skipReason) skips.push({ provider
|
|
181
|
+
if (found.skipReason) skips.push({ provider, reason: found.skipReason });
|
|
180
182
|
}
|
|
181
183
|
const deduped = new Map<string, QuotaCandidate>();
|
|
182
184
|
for (const candidate of candidates) {
|
|
@@ -185,20 +187,32 @@ export class OrchestratorQuotaPoller {
|
|
|
185
187
|
return { candidates: [...deduped.values()], skips };
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
private async
|
|
190
|
+
private async discoverProviderCandidates(provider: string): Promise<{ candidates: QuotaCandidate[]; skipReason?: string }> {
|
|
191
|
+
const manifest = getManifest(provider);
|
|
192
|
+
const quotaPoll = manifest?.quotaPoll;
|
|
193
|
+
if (!quotaPoll || quotaPoll.strategy === "none") return { candidates: [] };
|
|
194
|
+
if (quotaPoll.strategy === "codex-app-server") return this.discoverCodexCandidates(provider, quotaPoll);
|
|
195
|
+
return { candidates: [] };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private async discoverCodexCandidates(provider: string, _quotaPoll: ProviderQuotaPollDescriptor): Promise<{ candidates: QuotaCandidate[]; skipReason?: string }> {
|
|
199
|
+
const manifest = getManifest(provider);
|
|
200
|
+
const providerLabel = manifest?.label ?? provider;
|
|
201
|
+
const markerFile = manifest?.home?.quotaCredentialFile ?? "auth.json";
|
|
189
202
|
const homes = [
|
|
190
|
-
this.
|
|
191
|
-
...providerHomeConfigDirs(
|
|
203
|
+
this.providerHomeDir(provider),
|
|
204
|
+
...providerHomeConfigDirs(provider, markerFile),
|
|
192
205
|
];
|
|
193
|
-
const
|
|
206
|
+
const envPrefix = manifest?.home?.envPrefix ?? provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
207
|
+
const appServerUrl = this.config.env[`${envPrefix}_APP_SERVER_URL`] || process.env[`${envPrefix}_APP_SERVER_URL`];
|
|
194
208
|
const candidates: QuotaCandidate[] = [];
|
|
195
209
|
for (const codexHome of homes) {
|
|
196
210
|
const identity = await resolveStableCodexQuotaIdentityFromHome({ codexHome });
|
|
197
211
|
if (identity) candidates.push({ ...identity, codexHome, ...(appServerUrl ? { appServerUrl } : {}) });
|
|
198
212
|
}
|
|
199
213
|
if (candidates.length === 0) {
|
|
200
|
-
const reason =
|
|
201
|
-
this.logOnce(
|
|
214
|
+
const reason = `no ${providerLabel} account id found in ${markerFile}`;
|
|
215
|
+
this.logOnce(`${provider}:no-stable-auth`, `quota refresh skipped for ${provider}: ${reason}`);
|
|
202
216
|
return { candidates, skipReason: reason };
|
|
203
217
|
}
|
|
204
218
|
return { candidates };
|
|
@@ -319,14 +333,15 @@ export class OrchestratorQuotaPoller {
|
|
|
319
333
|
}
|
|
320
334
|
|
|
321
335
|
private async collect(candidate: QuotaCandidate): Promise<ProviderQuotaSample> {
|
|
322
|
-
|
|
336
|
+
const strategy = getManifest(candidate.provider)?.quotaPoll?.strategy;
|
|
337
|
+
if (strategy === "codex-app-server") {
|
|
323
338
|
return collectCodexQuotaSample({
|
|
324
339
|
agentId: this.sourceAgentId(),
|
|
325
340
|
rateLimitsRead: () => this.options.codexRateLimitsRead
|
|
326
341
|
? this.options.codexRateLimitsRead(candidate.appServerUrl ?? "")
|
|
327
342
|
: candidate.appServerUrl
|
|
328
343
|
? codexRateLimitsRead(candidate.appServerUrl)
|
|
329
|
-
: codexRateLimitsReadFromHome(candidate.codexHome),
|
|
344
|
+
: codexRateLimitsReadFromHome(candidate.provider, candidate.codexHome),
|
|
330
345
|
});
|
|
331
346
|
}
|
|
332
347
|
return {};
|
|
@@ -370,6 +385,12 @@ export class OrchestratorQuotaPoller {
|
|
|
370
385
|
this.logStates.set(key, { key, at: now });
|
|
371
386
|
this.log(message);
|
|
372
387
|
}
|
|
388
|
+
|
|
389
|
+
private providerHomeDir(provider: string): string {
|
|
390
|
+
const manifest = getManifest(provider);
|
|
391
|
+
const envPrefix = manifest?.home?.envPrefix ?? provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
392
|
+
return this.config.env[`${envPrefix}_HOME`] || process.env[`${envPrefix}_HOME`] || join(homedir(), manifest?.home?.configDir ?? `.${provider}`);
|
|
393
|
+
}
|
|
373
394
|
}
|
|
374
395
|
|
|
375
396
|
async function codexRateLimitsRead(appServerUrl: string, attempts = 1): Promise<unknown> {
|
|
@@ -387,10 +408,10 @@ async function codexRateLimitsRead(appServerUrl: string, attempts = 1): Promise<
|
|
|
387
408
|
}
|
|
388
409
|
}
|
|
389
410
|
|
|
390
|
-
async function codexRateLimitsReadFromHome(codexHome: string | undefined): Promise<unknown> {
|
|
391
|
-
if (!codexHome) throw new QuotaCollectionError("creds_not_ready",
|
|
411
|
+
async function codexRateLimitsReadFromHome(provider: string, codexHome: string | undefined): Promise<unknown> {
|
|
412
|
+
if (!codexHome) throw new QuotaCollectionError("creds_not_ready", `${provider} home is not configured`);
|
|
392
413
|
const appServerUrl = await freeLoopbackWsUrl();
|
|
393
|
-
const command =
|
|
414
|
+
const command = providerCommandFromEnv(provider) || getManifest(provider)?.probe?.command || provider;
|
|
394
415
|
const proc = Bun.spawn([command, "app-server", "--listen", appServerUrl], {
|
|
395
416
|
env: {
|
|
396
417
|
...process.env,
|
|
@@ -440,7 +461,7 @@ function providerHomeRoot(): string {
|
|
|
440
461
|
return providerHomeRootFromEnv();
|
|
441
462
|
}
|
|
442
463
|
|
|
443
|
-
function providerHomeConfigDirs(provider:
|
|
464
|
+
function providerHomeConfigDirs(provider: string, markerFile: string): string[] {
|
|
444
465
|
const root = join(providerHomeRoot(), provider);
|
|
445
466
|
const dirs: string[] = [];
|
|
446
467
|
for (const profile of safeReadDir(root)) {
|
package/src/relay.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { OrchestratorConfig } from "./config";
|
|
|
2
2
|
import type { ProviderProbeCache } from "./provider-probe";
|
|
3
3
|
import { detectSelfSupervision } from "./self-supervision";
|
|
4
4
|
import { GIT_SHA, ORCHESTRATOR_PROTOCOL_VERSION, VERSION, runtimeMetadata } from "./version";
|
|
5
|
-
import type { AgentLifecycle, ProviderQuotaConfigMap, ProviderQuotaLeaseAcquireInput, ProviderQuotaLeaseAcquireResult, ProviderQuotaUpdateInput, WorkspaceMetadata, WorkspaceMode, ManagedSessionExitDiagnostics as SdkManagedSessionExitDiagnostics } from "agent-relay-sdk";
|
|
5
|
+
import type { AgentLifecycle, ProviderQuotaConfigMap, ProviderQuotaLeaseAcquireInput, ProviderQuotaLeaseAcquireResult, ProviderQuotaUpdateInput, WorkspaceMetadata, WorkspaceMode, ManagedSessionExitDiagnostics as SdkManagedSessionExitDiagnostics, SpawnProvider } from "agent-relay-sdk";
|
|
6
6
|
import { ReconnectionManager, RelayHttpClient } from "agent-relay-sdk";
|
|
7
7
|
|
|
8
8
|
export interface RelayClient {
|
|
@@ -29,7 +29,7 @@ interface RunnerTokenRemint {
|
|
|
29
29
|
|
|
30
30
|
export interface ManagedAgentReport {
|
|
31
31
|
agentId: string;
|
|
32
|
-
provider:
|
|
32
|
+
provider: SpawnProvider;
|
|
33
33
|
model?: string;
|
|
34
34
|
effort?: string;
|
|
35
35
|
profile?: string;
|
package/src/self-upgrade.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
+
import { getAllManifests } from "agent-relay-providers";
|
|
4
5
|
import { runInstallWithRetry } from "agent-relay-sdk";
|
|
5
6
|
import type { OrchestratorConfig } from "./config";
|
|
6
7
|
import type { RelayClient, RelayCommand } from "./relay";
|
|
7
8
|
import { detectSelfSupervision, type SelfSupervision } from "./self-supervision";
|
|
8
9
|
|
|
9
|
-
const VALID_PROVIDERS = new Set(["auto", "all", "
|
|
10
|
+
const VALID_PROVIDERS = new Set(["auto", "all", "orchestrator", ...getAllManifests().map((manifest) => manifest.id)]);
|
|
10
11
|
const SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
11
12
|
|
|
12
13
|
interface SelfUpgradeOptions {
|
|
@@ -213,13 +214,10 @@ function packagesForProviders(targetVersion: string, providers: string[]): strin
|
|
|
213
214
|
if (includeAll || includeAuto || selected.has("orchestrator")) {
|
|
214
215
|
packages.add("agent-relay-orchestrator");
|
|
215
216
|
}
|
|
216
|
-
|
|
217
|
-
packages
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (includeAll || selected.has("claude")) {
|
|
221
|
-
packages.add("agent-relay-runner");
|
|
222
|
-
packages.add("agent-relay-plugin");
|
|
217
|
+
for (const manifest of getAllManifests()) {
|
|
218
|
+
if (!manifest.upgrade?.packages?.length) continue;
|
|
219
|
+
if (!includeAll && !selected.has(manifest.id)) continue;
|
|
220
|
+
for (const providerPackage of manifest.upgrade.packages) packages.add(providerPackage);
|
|
223
221
|
}
|
|
224
222
|
|
|
225
223
|
if (packages.size === 0) packages.add("agent-relay-orchestrator");
|
package/src/spawn/types.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { OrchestratorConfig } from "../config";
|
|
2
|
-
import type { AgentLifecycle, WorkspaceMetadata, WorkspaceMode } from "agent-relay-sdk";
|
|
2
|
+
import type { AgentLifecycle, SpawnProvider, WorkspaceMetadata, WorkspaceMode } from "agent-relay-sdk";
|
|
3
3
|
import type { ResumeWorkspaceTarget } from "../workspace-probe/types";
|
|
4
4
|
|
|
5
5
|
export interface SpawnOptions {
|
|
6
|
-
provider:
|
|
6
|
+
provider: SpawnProvider;
|
|
7
7
|
cwd: string;
|
|
8
8
|
rig?: string;
|
|
9
9
|
model?: string;
|