@openagents-org/agent-launcher 0.2.9 → 0.2.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-launcher",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "OpenAgents Launcher — install, configure, and run AI coding agents from your terminal",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -36,12 +36,23 @@ class OpenClawAdapter extends BaseAdapter {
36
36
  this.openclawAgentId = opts.openclawAgentId || 'main';
37
37
  this.disabledModules = opts.disabledModules || new Set();
38
38
 
39
+ // Direct API mode: call LLM via HTTP (no OpenClaw CLI needed).
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
+
39
47
  // Find the openclaw binary
40
48
  this._openclawBinary = this._findOpenclawBinary();
41
- if (this._openclawBinary) {
49
+
50
+ if (this._directMode) {
51
+ this._log(`Using direct LLM API mode (${this._directBaseUrl}, model=${this._directModel})`);
52
+ } else if (this._openclawBinary) {
42
53
  this._log(`Using OpenClaw CLI mode (${this._openclawBinary})`);
43
54
  } else {
44
- this._log('OpenClaw binary not found — agent will not be able to process messages');
55
+ this._log('OpenClaw binary not found and no direct API config — agent will not be able to process messages');
45
56
  }
46
57
 
47
58
  // Install workspace skill
@@ -150,7 +161,12 @@ class OpenClawAdapter extends BaseAdapter {
150
161
  await this.sendStatus(msgChannel, 'thinking...');
151
162
 
152
163
  try {
153
- const responseText = await this._runCliAgent(content, msgChannel);
164
+ let responseText;
165
+ if (this._directMode) {
166
+ responseText = await this._runDirectApi(content, msgChannel);
167
+ } else {
168
+ responseText = await this._runCliAgent(content, msgChannel);
169
+ }
154
170
 
155
171
  if (responseText) {
156
172
  await this.sendResponse(msgChannel, responseText);
@@ -255,6 +271,72 @@ class OpenClawAdapter extends BaseAdapter {
255
271
  });
256
272
  });
257
273
  }
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
+
258
340
  // ------------------------------------------------------------------
259
341
  // Static: configure OpenClaw's native auth from LLM env vars
260
342
  // ------------------------------------------------------------------
@@ -161,7 +161,7 @@ class WorkspaceClient {
161
161
  async pollPending(workspaceId, agentName, token, { after, limit = 50 } = {}) {
162
162
  const params = new URLSearchParams({
163
163
  network: workspaceId,
164
- type: 'workspace.message',
164
+ type: 'workspace.message.posted',
165
165
  limit: String(limit),
166
166
  });
167
167
  if (after) params.set('after', after);