@openagents-org/agent-launcher 0.2.11 → 0.2.13
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 +1 -1
- package/src/adapters/openclaw.js +62 -130
package/package.json
CHANGED
package/src/adapters/openclaw.js
CHANGED
|
@@ -36,23 +36,13 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
36
36
|
this.openclawAgentId = opts.openclawAgentId || 'main';
|
|
37
37
|
this.disabledModules = opts.disabledModules || new Set();
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
// Activated when LLM_API_KEY + LLM_BASE_URL are in agent env.
|
|
41
|
-
const env = opts.agentEnv || {};
|
|
42
|
-
this._directApiKey = env.OPENAI_API_KEY || env.LLM_API_KEY || '';
|
|
43
|
-
this._directBaseUrl = (env.OPENAI_BASE_URL || env.LLM_BASE_URL || '').replace(/\/+$/, '');
|
|
44
|
-
this._directModel = env.OPENCLAW_MODEL || env.LLM_MODEL || 'gpt-4o';
|
|
45
|
-
this._directMode = !!(this._directApiKey && this._directBaseUrl);
|
|
46
|
-
|
|
47
|
-
// Find the openclaw binary
|
|
39
|
+
// Find the openclaw binary — always use CLI/gateway mode for full tool support
|
|
48
40
|
this._openclawBinary = this._findOpenclawBinary();
|
|
49
41
|
|
|
50
|
-
if (this.
|
|
51
|
-
this._log(`Using direct LLM API mode (${this._directBaseUrl}, model=${this._directModel})`);
|
|
52
|
-
} else if (this._openclawBinary) {
|
|
42
|
+
if (this._openclawBinary) {
|
|
53
43
|
this._log(`Using OpenClaw CLI mode (${this._openclawBinary})`);
|
|
54
44
|
} else {
|
|
55
|
-
this._log('OpenClaw binary not found
|
|
45
|
+
this._log('OpenClaw binary not found — agent will not be able to process messages');
|
|
56
46
|
}
|
|
57
47
|
|
|
58
48
|
// Install workspace skill
|
|
@@ -161,12 +151,7 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
161
151
|
await this.sendStatus(msgChannel, 'thinking...');
|
|
162
152
|
|
|
163
153
|
try {
|
|
164
|
-
|
|
165
|
-
if (this._directMode) {
|
|
166
|
-
responseText = await this._runDirectApi(content, msgChannel);
|
|
167
|
-
} else {
|
|
168
|
-
responseText = await this._runCliAgent(content, msgChannel);
|
|
169
|
-
}
|
|
154
|
+
const responseText = await this._runCliAgent(content, msgChannel);
|
|
170
155
|
|
|
171
156
|
if (responseText) {
|
|
172
157
|
await this.sendResponse(msgChannel, responseText);
|
|
@@ -271,80 +256,18 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
271
256
|
});
|
|
272
257
|
});
|
|
273
258
|
}
|
|
274
|
-
// ------------------------------------------------------------------
|
|
275
|
-
// Direct API mode (bypass OpenClaw CLI, call LLM directly)
|
|
276
|
-
// ------------------------------------------------------------------
|
|
277
|
-
|
|
278
|
-
async _runDirectApi(userMessage, channel) {
|
|
279
|
-
const https = require('https');
|
|
280
|
-
const http = require('http');
|
|
281
|
-
const url = new URL(this._directBaseUrl + '/chat/completions');
|
|
282
|
-
const transport = url.protocol === 'https:' ? https : http;
|
|
283
|
-
|
|
284
|
-
// Build system prompt from workspace skill
|
|
285
|
-
const { buildOpenclawSystemPrompt } = require('./workspace-prompt');
|
|
286
|
-
const systemPrompt = buildOpenclawSystemPrompt({
|
|
287
|
-
workspaceId: this.workspaceId,
|
|
288
|
-
agentName: this.agentName,
|
|
289
|
-
channelName: channel,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
// Simple conversation (no history for now)
|
|
293
|
-
const messages = [
|
|
294
|
-
{ role: 'system', content: systemPrompt || 'You are a helpful assistant.' },
|
|
295
|
-
{ role: 'user', content: userMessage },
|
|
296
|
-
];
|
|
297
|
-
|
|
298
|
-
const body = JSON.stringify({
|
|
299
|
-
model: this._directModel,
|
|
300
|
-
messages,
|
|
301
|
-
stream: false,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
this._log(`Direct API: ${url.hostname} model=${this._directModel} msg=${userMessage.slice(0, 50)}...`);
|
|
305
|
-
|
|
306
|
-
return new Promise((resolve, reject) => {
|
|
307
|
-
const req = transport.request(url, {
|
|
308
|
-
method: 'POST',
|
|
309
|
-
headers: {
|
|
310
|
-
'Content-Type': 'application/json',
|
|
311
|
-
'Authorization': `Bearer ${this._directApiKey}`,
|
|
312
|
-
'Content-Length': Buffer.byteLength(body),
|
|
313
|
-
},
|
|
314
|
-
timeout: 120000,
|
|
315
|
-
}, (res) => {
|
|
316
|
-
let data = '';
|
|
317
|
-
res.on('data', (chunk) => { data += chunk; });
|
|
318
|
-
res.on('end', () => {
|
|
319
|
-
try {
|
|
320
|
-
if (res.statusCode !== 200) {
|
|
321
|
-
reject(new Error(`${res.statusCode} ${data.slice(0, 200)}`));
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
const result = JSON.parse(data);
|
|
325
|
-
const text = result.choices?.[0]?.message?.content || '';
|
|
326
|
-
this._log(`Direct API response: ${text.slice(0, 80)}...`);
|
|
327
|
-
resolve(text);
|
|
328
|
-
} catch (e) {
|
|
329
|
-
reject(new Error(`Parse error: ${e.message}`));
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
req.on('error', reject);
|
|
334
|
-
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
335
|
-
req.write(body);
|
|
336
|
-
req.end();
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
259
|
// ------------------------------------------------------------------
|
|
341
260
|
// Static: configure OpenClaw's native auth from LLM env vars
|
|
342
261
|
// ------------------------------------------------------------------
|
|
343
262
|
|
|
344
263
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
264
|
+
* Configure OpenClaw's native auth and model from user-provided
|
|
265
|
+
* LLM_API_KEY / LLM_BASE_URL / LLM_MODEL values.
|
|
347
266
|
* Called by the Launcher's saveAgentEnv when type === 'openclaw'.
|
|
267
|
+
*
|
|
268
|
+
* For standard providers (OpenAI, Anthropic), uses auth-profiles.json.
|
|
269
|
+
* For custom endpoints, uses models.providers in openclaw.json which
|
|
270
|
+
* gives full tool support via the CLI gateway mode.
|
|
348
271
|
*/
|
|
349
272
|
static configureNativeAuth(env) {
|
|
350
273
|
const apiKey = env.LLM_API_KEY;
|
|
@@ -352,51 +275,60 @@ class OpenClawAdapter extends BaseAdapter {
|
|
|
352
275
|
const model = env.LLM_MODEL || 'gpt-4o';
|
|
353
276
|
if (!apiKey) return;
|
|
354
277
|
|
|
355
|
-
// Determine provider: if baseUrl is openai.com, use 'openai'; otherwise 'openai-compatible'
|
|
356
278
|
const isOpenAI = baseUrl.includes('api.openai.com');
|
|
357
279
|
const isAnthropic = baseUrl.includes('api.anthropic.com');
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
280
|
+
const configFile = path.join(OPENCLAW_STATE_DIR, 'openclaw.json');
|
|
281
|
+
|
|
282
|
+
if (isOpenAI || isAnthropic) {
|
|
283
|
+
// Standard provider — use auth-profiles.json
|
|
284
|
+
const provider = isAnthropic ? 'anthropic' : 'openai';
|
|
285
|
+
const profileId = `${provider}:manual`;
|
|
286
|
+
const agentDir = path.join(OPENCLAW_STATE_DIR, 'agents', 'main', 'agent');
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
290
|
+
const authFile = path.join(agentDir, 'auth-profiles.json');
|
|
291
|
+
let authData = { version: 1, profiles: {} };
|
|
292
|
+
try { authData = JSON.parse(fs.readFileSync(authFile, 'utf-8')); } catch {}
|
|
293
|
+
authData.profiles = authData.profiles || {};
|
|
294
|
+
authData.profiles[profileId] = { type: 'token', provider, token: apiKey };
|
|
295
|
+
authData.lastGood = authData.lastGood || {};
|
|
296
|
+
authData.lastGood[provider] = profileId;
|
|
297
|
+
fs.writeFileSync(authFile, JSON.stringify(authData, null, 2), 'utf-8');
|
|
298
|
+
} catch {}
|
|
299
|
+
|
|
300
|
+
// Set model
|
|
301
|
+
try {
|
|
302
|
+
let config = {};
|
|
303
|
+
try { config = JSON.parse(fs.readFileSync(configFile, 'utf-8')); } catch {}
|
|
304
|
+
config.agents = config.agents || {};
|
|
305
|
+
config.agents.defaults = config.agents.defaults || {};
|
|
306
|
+
config.agents.defaults.model = { primary: `${provider}/${model}` };
|
|
307
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf-8');
|
|
308
|
+
} catch {}
|
|
309
|
+
} else {
|
|
310
|
+
// Custom endpoint — use models.providers for full gateway/tool support
|
|
311
|
+
// This is the proper way to add custom LLM endpoints to OpenClaw.
|
|
312
|
+
// See: https://docs.openclaw.ai/concepts/model-providers
|
|
313
|
+
try {
|
|
314
|
+
let config = {};
|
|
315
|
+
try { config = JSON.parse(fs.readFileSync(configFile, 'utf-8')); } catch {}
|
|
316
|
+
|
|
317
|
+
config.models = config.models || {};
|
|
318
|
+
config.models.providers = config.models.providers || {};
|
|
319
|
+
config.models.providers.custom = {
|
|
320
|
+
baseUrl: baseUrl.replace(/\/+$/, ''),
|
|
321
|
+
apiKey,
|
|
322
|
+
api: 'openai-completions',
|
|
323
|
+
models: [{ id: model, name: model }],
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
config.agents = config.agents || {};
|
|
327
|
+
config.agents.defaults = config.agents.defaults || {};
|
|
328
|
+
config.agents.defaults.model = { primary: `custom/${model}` };
|
|
329
|
+
|
|
330
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2), 'utf-8');
|
|
331
|
+
} catch {}
|
|
400
332
|
}
|
|
401
333
|
}
|
|
402
334
|
}
|