@hypercli.com/sdk 2026.3.13-2 → 2026.3.18
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/README.md +16 -3
- package/dist/agent.d.ts +12 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +49 -25
- package/dist/agent.js.map +1 -1
- package/dist/agents.d.ts +102 -4
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +446 -14
- package/dist/agents.js.map +1 -1
- package/dist/billing.d.ts +35 -1
- package/dist/billing.d.ts.map +1 -1
- package/dist/billing.js +45 -5
- package/dist/billing.js.map +1 -1
- package/dist/browser.d.ts +21 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +28 -0
- package/dist/browser.js.map +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -3
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +13 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +70 -13
- package/dist/config.js.map +1 -1
- package/dist/gateway.d.ts +23 -5
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +363 -86
- package/dist/gateway.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/user.d.ts +12 -0
- package/dist/user.d.ts.map +1 -1
- package/dist/user.js +11 -0
- package/dist/user.js.map +1 -1
- package/package.json +7 -3
package/dist/agents.js
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HyperClaw agents API - typed agent lifecycle, files, exec, and OpenClaw access.
|
|
3
|
+
*/
|
|
4
|
+
import { getAgentsApiBaseUrl, getConfigValue } from './config.js';
|
|
1
5
|
import { GatewayClient, } from './gateway.js';
|
|
2
6
|
const AGENTS_API_BASE = 'https://api.hypercli.com/agents';
|
|
3
7
|
const DEV_AGENTS_API_BASE = 'https://api.dev.hypercli.com/agents';
|
|
4
8
|
const DEPLOYMENTS_API_PREFIX = '/deployments';
|
|
5
9
|
const AGENTS_WS_URL = 'wss://api.agents.hypercli.com/ws';
|
|
6
10
|
const DEV_AGENTS_WS_URL = 'wss://api.agents.dev.hypercli.com/ws';
|
|
11
|
+
export const DEFAULT_OPENCLAW_IMAGE = 'ghcr.io/hypercli/hypercli-openclaw:prod';
|
|
7
12
|
function parseDate(value) {
|
|
8
13
|
if (typeof value !== 'string' || !value)
|
|
9
14
|
return null;
|
|
10
15
|
return new Date(value.replace('Z', '+00:00'));
|
|
11
16
|
}
|
|
17
|
+
function deepMergeConfig(base, patch) {
|
|
18
|
+
const merged = structuredClone(base);
|
|
19
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
20
|
+
if (value &&
|
|
21
|
+
typeof value === 'object' &&
|
|
22
|
+
!Array.isArray(value) &&
|
|
23
|
+
merged[key] &&
|
|
24
|
+
typeof merged[key] === 'object' &&
|
|
25
|
+
!Array.isArray(merged[key])) {
|
|
26
|
+
merged[key] = deepMergeConfig(merged[key], value);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
merged[key] = structuredClone(value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return merged;
|
|
33
|
+
}
|
|
34
|
+
function sleep(ms) {
|
|
35
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
36
|
+
}
|
|
12
37
|
function toWsBaseUrl(baseUrl) {
|
|
13
38
|
const base = (baseUrl || '').replace(/\/+$/, '');
|
|
14
39
|
if (!base)
|
|
@@ -30,21 +55,42 @@ export function resolveAgentsApiBase(apiBase) {
|
|
|
30
55
|
if (!raw)
|
|
31
56
|
return AGENTS_API_BASE;
|
|
32
57
|
const parsed = new URL(raw.includes('://') ? raw : `https://${raw}`);
|
|
58
|
+
const normalizedPath = parsed.pathname.replace(/\/+$/, '');
|
|
33
59
|
const host = parsed.host.toLowerCase();
|
|
34
|
-
if (
|
|
60
|
+
if (normalizedPath.endsWith('/agents')) {
|
|
61
|
+
return `${parsed.origin}${normalizedPath}`;
|
|
62
|
+
}
|
|
63
|
+
if (normalizedPath.endsWith('/api')) {
|
|
64
|
+
if (host === 'api.agents.hypercli.com') {
|
|
65
|
+
return AGENTS_API_BASE;
|
|
66
|
+
}
|
|
67
|
+
if (host === 'api.agents.dev.hypercli.com') {
|
|
68
|
+
return DEV_AGENTS_API_BASE;
|
|
69
|
+
}
|
|
70
|
+
return `${parsed.origin}${normalizedPath.slice(0, -4)}/agents`;
|
|
71
|
+
}
|
|
72
|
+
if (host === 'api.agents.hypercli.com' || host === 'api.hypercli.com' || host === 'api.hyperclaw.app') {
|
|
35
73
|
return AGENTS_API_BASE;
|
|
36
|
-
|
|
74
|
+
}
|
|
75
|
+
if (host === 'api.agents.dev.hypercli.com' ||
|
|
76
|
+
host === 'api.dev.hypercli.com' ||
|
|
77
|
+
host === 'api.dev.hyperclaw.app' ||
|
|
78
|
+
host === 'dev-api.hyperclaw.app') {
|
|
37
79
|
return DEV_AGENTS_API_BASE;
|
|
38
80
|
}
|
|
39
|
-
|
|
81
|
+
const normalized = raw.replace(/\/$/, '');
|
|
82
|
+
return `${normalized}/agents`;
|
|
40
83
|
}
|
|
41
84
|
function defaultAgentsWsUrl(apiBase) {
|
|
42
85
|
const resolvedApiBase = resolveAgentsApiBase(apiBase);
|
|
43
86
|
const parsed = new URL(resolvedApiBase.includes('://') ? resolvedApiBase : `https://${resolvedApiBase}`);
|
|
44
87
|
const host = parsed.host.toLowerCase();
|
|
45
|
-
if (host === 'api.hypercli.com' || host === 'api.hyperclaw.app')
|
|
88
|
+
if (host === 'api.agents.hypercli.com' || host === 'api.hypercli.com' || host === 'api.hyperclaw.app')
|
|
46
89
|
return AGENTS_WS_URL;
|
|
47
|
-
if (host === 'api.dev.hypercli.com' ||
|
|
90
|
+
if (host === 'api.agents.dev.hypercli.com' ||
|
|
91
|
+
host === 'api.dev.hypercli.com' ||
|
|
92
|
+
host === 'api.dev.hyperclaw.app' ||
|
|
93
|
+
host === 'dev-api.hyperclaw.app') {
|
|
48
94
|
return DEV_AGENTS_WS_URL;
|
|
49
95
|
}
|
|
50
96
|
return normalizeAgentsWsUrl(resolvedApiBase);
|
|
@@ -135,6 +181,30 @@ export function buildAgentConfig(config = {}, options = {}) {
|
|
|
135
181
|
prepared.registry_auth = options.registryAuth;
|
|
136
182
|
return { config: prepared, gatewayToken };
|
|
137
183
|
}
|
|
184
|
+
function defaultOpenClawImage(image, config) {
|
|
185
|
+
if (image !== undefined && image !== null)
|
|
186
|
+
return image;
|
|
187
|
+
const configured = String(config?.image ?? '').trim();
|
|
188
|
+
return configured || DEFAULT_OPENCLAW_IMAGE;
|
|
189
|
+
}
|
|
190
|
+
export function buildOpenClawRoutes(options = {}) {
|
|
191
|
+
const routes = {};
|
|
192
|
+
if (options.includeGateway ?? true) {
|
|
193
|
+
routes.openclaw = {
|
|
194
|
+
port: options.gatewayPort ?? 18789,
|
|
195
|
+
auth: options.gatewayAuth ?? false,
|
|
196
|
+
prefix: options.gatewayPrefix ?? '',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (options.includeDesktop ?? true) {
|
|
200
|
+
routes.desktop = {
|
|
201
|
+
port: options.desktopPort ?? 3000,
|
|
202
|
+
auth: options.desktopAuth ?? true,
|
|
203
|
+
prefix: options.desktopPrefix ?? 'desktop',
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return routes;
|
|
207
|
+
}
|
|
138
208
|
async function getFsPromises() {
|
|
139
209
|
return import('node:fs/promises');
|
|
140
210
|
}
|
|
@@ -196,11 +266,30 @@ export class Agent {
|
|
|
196
266
|
get publicUrl() {
|
|
197
267
|
return this.hostname ? `https://${this.hostname}` : null;
|
|
198
268
|
}
|
|
269
|
+
routePrefix(routeName, defaultPrefix = null) {
|
|
270
|
+
const route = this.routes[routeName] ?? {};
|
|
271
|
+
const prefix = route.prefix;
|
|
272
|
+
if (typeof prefix === 'undefined' || prefix === null) {
|
|
273
|
+
return defaultPrefix;
|
|
274
|
+
}
|
|
275
|
+
return String(prefix);
|
|
276
|
+
}
|
|
277
|
+
routeUrl(routeName, defaultPrefix = null) {
|
|
278
|
+
if (!this.hostname)
|
|
279
|
+
return null;
|
|
280
|
+
const prefix = this.routePrefix(routeName, defaultPrefix);
|
|
281
|
+
if (prefix === null)
|
|
282
|
+
return null;
|
|
283
|
+
return prefix === '' ? `https://${this.hostname}` : `https://${prefix}-${this.hostname}`;
|
|
284
|
+
}
|
|
285
|
+
get desktopUrl() {
|
|
286
|
+
return this.routeUrl('desktop', 'desktop');
|
|
287
|
+
}
|
|
199
288
|
get vncUrl() {
|
|
200
|
-
return this.
|
|
289
|
+
return this.desktopUrl;
|
|
201
290
|
}
|
|
202
291
|
get shellUrl() {
|
|
203
|
-
return this.
|
|
292
|
+
return this.routeUrl('shell');
|
|
204
293
|
}
|
|
205
294
|
get executorUrl() {
|
|
206
295
|
return this.shellUrl;
|
|
@@ -214,12 +303,22 @@ export class Agent {
|
|
|
214
303
|
}
|
|
215
304
|
return this._deployments;
|
|
216
305
|
}
|
|
306
|
+
routeRequiresAuth(routeName, defaultValue = true) {
|
|
307
|
+
const route = this.routes[routeName];
|
|
308
|
+
if (!route || typeof route.auth === 'undefined') {
|
|
309
|
+
return defaultValue;
|
|
310
|
+
}
|
|
311
|
+
return Boolean(route.auth);
|
|
312
|
+
}
|
|
217
313
|
async refreshToken() {
|
|
218
314
|
const data = await this.requireDeployments().refreshToken(this.id);
|
|
219
315
|
this.jwtToken = data.token ?? data.jwt ?? null;
|
|
220
316
|
this.jwtExpiresAt = parseDate(data.expires_at);
|
|
221
317
|
return data;
|
|
222
318
|
}
|
|
319
|
+
async waitRunning(timeoutMs = 300_000, pollIntervalMs = 5_000) {
|
|
320
|
+
return this.requireDeployments().waitRunning(this.id, timeoutMs, pollIntervalMs);
|
|
321
|
+
}
|
|
223
322
|
async env() {
|
|
224
323
|
const data = await this.requireDeployments().env(this.id);
|
|
225
324
|
return data.env ?? {};
|
|
@@ -269,7 +368,7 @@ export class OpenClawAgent extends Agent {
|
|
|
269
368
|
static fromDict(data) {
|
|
270
369
|
return new OpenClawAgent({
|
|
271
370
|
...agentStateFromDict(data),
|
|
272
|
-
gatewayUrl: data.openclaw_url ?? data.gateway_url ?? null,
|
|
371
|
+
gatewayUrl: data.openclaw_url ?? data.gateway_url ?? (data.hostname ? `wss://${data.hostname}` : null),
|
|
273
372
|
gatewayToken: data.gateway_token ?? null,
|
|
274
373
|
});
|
|
275
374
|
}
|
|
@@ -288,17 +387,28 @@ export class OpenClawAgent extends Agent {
|
|
|
288
387
|
if (!this.gatewayUrl) {
|
|
289
388
|
throw new Error('Agent has no OpenClaw gateway URL');
|
|
290
389
|
}
|
|
291
|
-
|
|
292
|
-
throw new Error('Agent has no JWT token');
|
|
293
|
-
}
|
|
390
|
+
const deployments = this.requireDeployments();
|
|
294
391
|
return new GatewayClient({
|
|
295
392
|
url: this.gatewayUrl,
|
|
296
|
-
token:
|
|
393
|
+
token: undefined,
|
|
297
394
|
gatewayToken: options.gatewayToken ?? this.gatewayToken ?? undefined,
|
|
395
|
+
deploymentId: options.deploymentId ?? this.id,
|
|
396
|
+
apiKey: options.apiKey ?? deployments.agentApiKey,
|
|
397
|
+
apiBase: options.apiBase ?? deployments.agentApiBase,
|
|
398
|
+
autoApprovePairing: options.autoApprovePairing ?? true,
|
|
298
399
|
clientId: options.clientId,
|
|
299
400
|
clientMode: options.clientMode,
|
|
401
|
+
clientDisplayName: options.clientDisplayName,
|
|
402
|
+
clientVersion: options.clientVersion,
|
|
403
|
+
platform: options.platform,
|
|
404
|
+
instanceId: options.instanceId,
|
|
405
|
+
caps: options.caps,
|
|
300
406
|
origin: options.origin,
|
|
301
407
|
timeout: options.timeout,
|
|
408
|
+
onHello: options.onHello,
|
|
409
|
+
onClose: options.onClose,
|
|
410
|
+
onGap: options.onGap,
|
|
411
|
+
onPairing: options.onPairing,
|
|
302
412
|
});
|
|
303
413
|
}
|
|
304
414
|
async connect(options = {}) {
|
|
@@ -319,6 +429,18 @@ export class OpenClawAgent extends Agent {
|
|
|
319
429
|
client.close();
|
|
320
430
|
}
|
|
321
431
|
}
|
|
432
|
+
async waitReady(timeoutMs = 300_000, options = {}) {
|
|
433
|
+
const client = this.gateway(options);
|
|
434
|
+
try {
|
|
435
|
+
return await client.waitReady(timeoutMs, {
|
|
436
|
+
retryIntervalMs: options.retryIntervalMs,
|
|
437
|
+
probe: options.probe,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
finally {
|
|
441
|
+
client.close();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
322
444
|
async configGet(options = {}) {
|
|
323
445
|
const client = await this.connect(options);
|
|
324
446
|
try {
|
|
@@ -337,6 +459,33 @@ export class OpenClawAgent extends Agent {
|
|
|
337
459
|
client.close();
|
|
338
460
|
}
|
|
339
461
|
}
|
|
462
|
+
async configPatch(patch, options = {}) {
|
|
463
|
+
const client = await this.connect(options);
|
|
464
|
+
try {
|
|
465
|
+
await client.configPatch(patch);
|
|
466
|
+
}
|
|
467
|
+
finally {
|
|
468
|
+
client.close();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async configApply(config, options = {}) {
|
|
472
|
+
const client = await this.connect(options);
|
|
473
|
+
try {
|
|
474
|
+
await client.configApply(config);
|
|
475
|
+
}
|
|
476
|
+
finally {
|
|
477
|
+
client.close();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
async modelsList(options = {}) {
|
|
481
|
+
const client = await this.connect(options);
|
|
482
|
+
try {
|
|
483
|
+
return await client.modelsList();
|
|
484
|
+
}
|
|
485
|
+
finally {
|
|
486
|
+
client.close();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
340
489
|
async sessionsList(options = {}) {
|
|
341
490
|
const client = await this.connect(options);
|
|
342
491
|
try {
|
|
@@ -357,6 +506,251 @@ export class OpenClawAgent extends Agent {
|
|
|
357
506
|
client.close();
|
|
358
507
|
}
|
|
359
508
|
}
|
|
509
|
+
async channelsStatus(options = {}) {
|
|
510
|
+
const client = await this.connect(options);
|
|
511
|
+
try {
|
|
512
|
+
return await client.channelsStatus(options.probe ?? false, options.timeoutMs);
|
|
513
|
+
}
|
|
514
|
+
finally {
|
|
515
|
+
client.close();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
async channelsLogout(channel, accountId, options = {}) {
|
|
519
|
+
const client = await this.connect(options);
|
|
520
|
+
try {
|
|
521
|
+
return await client.channelsLogout(channel, accountId);
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
client.close();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
async webLoginStart(options = {}) {
|
|
528
|
+
const client = await this.connect(options);
|
|
529
|
+
try {
|
|
530
|
+
return await client.webLoginStart({
|
|
531
|
+
force: options.force,
|
|
532
|
+
timeoutMs: options.timeoutMs,
|
|
533
|
+
verbose: options.verbose,
|
|
534
|
+
accountId: options.accountId,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
finally {
|
|
538
|
+
client.close();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
async webLoginWait(options = {}) {
|
|
542
|
+
const client = await this.connect(options);
|
|
543
|
+
try {
|
|
544
|
+
return await client.webLoginWait({
|
|
545
|
+
timeoutMs: options.timeoutMs,
|
|
546
|
+
accountId: options.accountId,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
finally {
|
|
550
|
+
client.close();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
async workspaceFiles(options = {}) {
|
|
554
|
+
const client = await this.connect(options);
|
|
555
|
+
try {
|
|
556
|
+
const agents = await client.agentsList();
|
|
557
|
+
const agentId = agents[0]?.id ?? 'main';
|
|
558
|
+
const files = await client.filesList(agentId);
|
|
559
|
+
return { agentId, files };
|
|
560
|
+
}
|
|
561
|
+
finally {
|
|
562
|
+
client.close();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
async fileGet(name, agentId, options = {}) {
|
|
566
|
+
const client = await this.connect(options);
|
|
567
|
+
try {
|
|
568
|
+
let resolvedAgentId;
|
|
569
|
+
if (agentId) {
|
|
570
|
+
resolvedAgentId = agentId;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
const agents = await client.agentsList();
|
|
574
|
+
resolvedAgentId = agents[0]?.id ?? 'main';
|
|
575
|
+
}
|
|
576
|
+
return await client.fileGet(resolvedAgentId, name);
|
|
577
|
+
}
|
|
578
|
+
finally {
|
|
579
|
+
client.close();
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async fileSet(name, content, agentId, options = {}) {
|
|
583
|
+
const client = await this.connect(options);
|
|
584
|
+
try {
|
|
585
|
+
let resolvedAgentId;
|
|
586
|
+
if (agentId) {
|
|
587
|
+
resolvedAgentId = agentId;
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
const agents = await client.agentsList();
|
|
591
|
+
resolvedAgentId = agents[0]?.id ?? 'main';
|
|
592
|
+
}
|
|
593
|
+
await client.fileSet(resolvedAgentId, name, content);
|
|
594
|
+
}
|
|
595
|
+
finally {
|
|
596
|
+
client.close();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
async chatHistory(sessionKey, limit = 50, options = {}) {
|
|
600
|
+
const client = await this.connect(options);
|
|
601
|
+
try {
|
|
602
|
+
return await client.chatHistory(sessionKey, limit);
|
|
603
|
+
}
|
|
604
|
+
finally {
|
|
605
|
+
client.close();
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async chatSendMessage(message, options = {}) {
|
|
609
|
+
const client = await this.connect(options);
|
|
610
|
+
try {
|
|
611
|
+
return await client.sendChat(message, options.sessionKey ?? 'main', options.agentId, options.attachments);
|
|
612
|
+
}
|
|
613
|
+
finally {
|
|
614
|
+
client.close();
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
async mutateConfig(mutator, options = {}) {
|
|
618
|
+
const config = structuredClone(await this.configGet(options));
|
|
619
|
+
await mutator(config);
|
|
620
|
+
await this.configApply(config, options);
|
|
621
|
+
return config;
|
|
622
|
+
}
|
|
623
|
+
async providerUpsert(providerId, providerConfig, gatewayOptions = {}) {
|
|
624
|
+
const { api, baseUrl, apiKey, models, ...extra } = providerConfig;
|
|
625
|
+
const config = await this.mutateConfig((next) => {
|
|
626
|
+
const modelsCfg = (next.models ??= {});
|
|
627
|
+
const providers = (modelsCfg.providers ??= {});
|
|
628
|
+
const provider = { ...(providers[providerId] ?? {}) };
|
|
629
|
+
provider.api = api;
|
|
630
|
+
provider.baseUrl = baseUrl;
|
|
631
|
+
if (apiKey !== undefined)
|
|
632
|
+
provider.apiKey = apiKey;
|
|
633
|
+
if (models !== undefined)
|
|
634
|
+
provider.models = structuredClone(models);
|
|
635
|
+
Object.assign(provider, extra);
|
|
636
|
+
providers[providerId] = provider;
|
|
637
|
+
}, gatewayOptions);
|
|
638
|
+
return config.models?.providers?.[providerId] ?? {};
|
|
639
|
+
}
|
|
640
|
+
async providerRemove(providerId, options = {}) {
|
|
641
|
+
const config = await this.mutateConfig((next) => {
|
|
642
|
+
if (next.models?.providers) {
|
|
643
|
+
delete next.models.providers[providerId];
|
|
644
|
+
}
|
|
645
|
+
}, options);
|
|
646
|
+
return config.models?.providers ?? {};
|
|
647
|
+
}
|
|
648
|
+
async modelUpsert(providerId, modelId, modelConfig = {}, gatewayOptions = {}) {
|
|
649
|
+
const config = await this.mutateConfig((next) => {
|
|
650
|
+
const providers = ((next.models ??= {}).providers ??= {});
|
|
651
|
+
const provider = { ...(providers[providerId] ?? {}) };
|
|
652
|
+
const models = Array.isArray(provider.models)
|
|
653
|
+
? provider.models.map((entry) => ({ ...entry }))
|
|
654
|
+
: [];
|
|
655
|
+
let model = models.find((entry) => entry.id === modelId);
|
|
656
|
+
if (!model) {
|
|
657
|
+
model = { id: modelId };
|
|
658
|
+
models.push(model);
|
|
659
|
+
}
|
|
660
|
+
Object.assign(model, modelConfig);
|
|
661
|
+
provider.models = models;
|
|
662
|
+
providers[providerId] = provider;
|
|
663
|
+
}, gatewayOptions);
|
|
664
|
+
return (config.models?.providers?.[providerId]?.models?.find((entry) => entry.id === modelId) ??
|
|
665
|
+
{});
|
|
666
|
+
}
|
|
667
|
+
async modelRemove(providerId, modelId, options = {}) {
|
|
668
|
+
const config = await this.mutateConfig((next) => {
|
|
669
|
+
const providers = ((next.models ??= {}).providers ??= {});
|
|
670
|
+
const provider = { ...(providers[providerId] ?? {}) };
|
|
671
|
+
provider.models = Array.isArray(provider.models)
|
|
672
|
+
? provider.models.filter((entry) => entry.id !== modelId)
|
|
673
|
+
: [];
|
|
674
|
+
providers[providerId] = provider;
|
|
675
|
+
}, options);
|
|
676
|
+
return config.models?.providers?.[providerId]?.models ?? [];
|
|
677
|
+
}
|
|
678
|
+
async setDefaultModel(providerId, modelId, options = {}) {
|
|
679
|
+
const primary = `${providerId}/${modelId}`;
|
|
680
|
+
await this.mutateConfig((next) => {
|
|
681
|
+
const defaults = ((next.agents ??= {}).defaults ??= {});
|
|
682
|
+
const model = (defaults.model ??= {});
|
|
683
|
+
model.primary = primary;
|
|
684
|
+
}, options);
|
|
685
|
+
return primary;
|
|
686
|
+
}
|
|
687
|
+
async setMemorySearch(memorySearchConfig, gatewayOptions = {}) {
|
|
688
|
+
const { provider, model, baseUrl, apiKey, ...extra } = memorySearchConfig;
|
|
689
|
+
const config = await this.mutateConfig((next) => {
|
|
690
|
+
const defaults = ((next.agents ??= {}).defaults ??= {});
|
|
691
|
+
const memorySearch = { ...(defaults.memorySearch ?? {}) };
|
|
692
|
+
memorySearch.provider = provider;
|
|
693
|
+
memorySearch.model = model;
|
|
694
|
+
const remote = { ...(memorySearch.remote ?? {}) };
|
|
695
|
+
if (baseUrl !== undefined)
|
|
696
|
+
remote.baseUrl = baseUrl;
|
|
697
|
+
if (apiKey !== undefined)
|
|
698
|
+
remote.apiKey = apiKey;
|
|
699
|
+
if (Object.keys(remote).length > 0)
|
|
700
|
+
memorySearch.remote = remote;
|
|
701
|
+
Object.assign(memorySearch, extra);
|
|
702
|
+
defaults.memorySearch = memorySearch;
|
|
703
|
+
}, gatewayOptions);
|
|
704
|
+
return config.agents?.defaults?.memorySearch ?? {};
|
|
705
|
+
}
|
|
706
|
+
async channelUpsert(channelId, channelConfig, options = {}) {
|
|
707
|
+
const { accountId, ...gatewayOptions } = options;
|
|
708
|
+
const config = await this.mutateConfig((next) => {
|
|
709
|
+
const channels = (next.channels ??= {});
|
|
710
|
+
const current = channels[channelId] && typeof channels[channelId] === 'object'
|
|
711
|
+
? structuredClone(channels[channelId])
|
|
712
|
+
: {};
|
|
713
|
+
if (accountId) {
|
|
714
|
+
const accounts = current.accounts && typeof current.accounts === 'object'
|
|
715
|
+
? structuredClone(current.accounts)
|
|
716
|
+
: {};
|
|
717
|
+
const currentAccount = accounts[accountId] && typeof accounts[accountId] === 'object'
|
|
718
|
+
? accounts[accountId]
|
|
719
|
+
: {};
|
|
720
|
+
accounts[accountId] = deepMergeConfig(currentAccount, channelConfig);
|
|
721
|
+
current.accounts = accounts;
|
|
722
|
+
channels[channelId] = current;
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
channels[channelId] = deepMergeConfig(current, channelConfig);
|
|
726
|
+
}, gatewayOptions);
|
|
727
|
+
const channel = config.channels?.[channelId] ?? {};
|
|
728
|
+
if (accountId) {
|
|
729
|
+
return channel.accounts?.[accountId] ?? {};
|
|
730
|
+
}
|
|
731
|
+
return channel;
|
|
732
|
+
}
|
|
733
|
+
async channelPatch(channelId, patch, options = {}) {
|
|
734
|
+
return await this.channelUpsert(channelId, patch, options);
|
|
735
|
+
}
|
|
736
|
+
async telegramUpsert(channelConfig, options = {}) {
|
|
737
|
+
return await this.channelUpsert('telegram', channelConfig, options);
|
|
738
|
+
}
|
|
739
|
+
async slackUpsert(channelConfig, options = {}) {
|
|
740
|
+
return await this.channelUpsert('slack', channelConfig, options);
|
|
741
|
+
}
|
|
742
|
+
async discordUpsert(channelConfig, options = {}) {
|
|
743
|
+
return await this.channelUpsert('discord', channelConfig, options);
|
|
744
|
+
}
|
|
745
|
+
async cronList(options = {}) {
|
|
746
|
+
const client = await this.connect(options);
|
|
747
|
+
try {
|
|
748
|
+
return await client.cronList();
|
|
749
|
+
}
|
|
750
|
+
finally {
|
|
751
|
+
client.close();
|
|
752
|
+
}
|
|
753
|
+
}
|
|
360
754
|
}
|
|
361
755
|
export class Deployments {
|
|
362
756
|
http;
|
|
@@ -366,8 +760,14 @@ export class Deployments {
|
|
|
366
760
|
constructor(http, agentApiKey, agentApiBase, agentsWsUrl) {
|
|
367
761
|
this.http = http;
|
|
368
762
|
this.apiKey = agentApiKey || http.apiKey;
|
|
369
|
-
this.apiBase = resolveAgentsApiBase(agentApiBase ||
|
|
370
|
-
this.agentsWsUrl = agentsWsUrl
|
|
763
|
+
this.apiBase = resolveAgentsApiBase(agentApiBase || getAgentsApiBaseUrl());
|
|
764
|
+
this.agentsWsUrl = normalizeAgentsWsUrl(agentsWsUrl || getConfigValue('AGENTS_WS_URL') || defaultAgentsWsUrl(this.apiBase));
|
|
765
|
+
}
|
|
766
|
+
get agentApiKey() {
|
|
767
|
+
return this.apiKey;
|
|
768
|
+
}
|
|
769
|
+
get agentApiBase() {
|
|
770
|
+
return this.apiBase;
|
|
371
771
|
}
|
|
372
772
|
hydrateAgent(data) {
|
|
373
773
|
const agent = data.openclaw_url || data.gateway_url
|
|
@@ -410,6 +810,14 @@ export class Deployments {
|
|
|
410
810
|
agent.entrypoint = [...(config.entrypoint ?? [])];
|
|
411
811
|
return agent;
|
|
412
812
|
}
|
|
813
|
+
async createOpenClaw(options = {}) {
|
|
814
|
+
const effectiveOptions = { ...options };
|
|
815
|
+
if (options.routes === undefined) {
|
|
816
|
+
effectiveOptions.routes = buildOpenClawRoutes(options.openClawRoutes ?? {});
|
|
817
|
+
}
|
|
818
|
+
effectiveOptions.image = defaultOpenClawImage(options.image, options.config ?? {});
|
|
819
|
+
return this.create(effectiveOptions);
|
|
820
|
+
}
|
|
413
821
|
async budget() {
|
|
414
822
|
return this.http.get(`${DEPLOYMENTS_API_PREFIX}/budget`);
|
|
415
823
|
}
|
|
@@ -428,6 +836,22 @@ export class Deployments {
|
|
|
428
836
|
const data = await this.http.get(`${DEPLOYMENTS_API_PREFIX}/${agentId}`);
|
|
429
837
|
return this.hydrateAgent(data);
|
|
430
838
|
}
|
|
839
|
+
async waitRunning(agentId, timeoutMs = 300_000, pollIntervalMs = 5_000) {
|
|
840
|
+
const deadline = Date.now() + timeoutMs;
|
|
841
|
+
let lastState = '';
|
|
842
|
+
while (Date.now() < deadline) {
|
|
843
|
+
const agent = await this.get(agentId);
|
|
844
|
+
lastState = String(agent.state || '');
|
|
845
|
+
if (lastState.toLowerCase() === 'running') {
|
|
846
|
+
return agent;
|
|
847
|
+
}
|
|
848
|
+
if (lastState.toLowerCase() === 'failed' || lastState.toLowerCase() === 'error') {
|
|
849
|
+
throw new Error(`Agent entered ${lastState} while waiting for RUNNING`);
|
|
850
|
+
}
|
|
851
|
+
await sleep(pollIntervalMs);
|
|
852
|
+
}
|
|
853
|
+
throw new Error(`Timed out waiting for agent ${agentId} to reach RUNNING (last=${lastState})`);
|
|
854
|
+
}
|
|
431
855
|
async start(agentId, options = {}) {
|
|
432
856
|
const { config, gatewayToken } = buildAgentConfig(options.config ?? {}, options);
|
|
433
857
|
const body = { config };
|
|
@@ -443,6 +867,14 @@ export class Deployments {
|
|
|
443
867
|
agent.entrypoint = [...(config.entrypoint ?? [])];
|
|
444
868
|
return agent;
|
|
445
869
|
}
|
|
870
|
+
async startOpenClaw(agentId, options = {}) {
|
|
871
|
+
const effectiveOptions = { ...options };
|
|
872
|
+
if (options.routes === undefined) {
|
|
873
|
+
effectiveOptions.routes = buildOpenClawRoutes(options.openClawRoutes ?? {});
|
|
874
|
+
}
|
|
875
|
+
effectiveOptions.image = defaultOpenClawImage(options.image, options.config ?? {});
|
|
876
|
+
return this.start(agentId, effectiveOptions);
|
|
877
|
+
}
|
|
446
878
|
async stop(agentId) {
|
|
447
879
|
const data = await this.http.post(`${DEPLOYMENTS_API_PREFIX}/${agentId}/stop`);
|
|
448
880
|
return this.hydrateAgent(data);
|