@openagents-org/agent-connector 0.1.10 → 0.1.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 +1 -1
- package/src/daemon.js +78 -62
package/package.json
CHANGED
package/src/daemon.js
CHANGED
|
@@ -372,6 +372,11 @@ class Daemon {
|
|
|
372
372
|
// Send initial heartbeat
|
|
373
373
|
try { await wsClient.heartbeat(network.id, name, network.token); } catch {}
|
|
374
374
|
|
|
375
|
+
// Install workspace skill into OpenClaw's skills directory
|
|
376
|
+
try { this._installWorkspaceSkill(agentCfg, network); } catch (e) {
|
|
377
|
+
this._log(`${name} skill install failed: ${e.message}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
375
380
|
info.state = 'running';
|
|
376
381
|
info.startedAt = new Date().toISOString();
|
|
377
382
|
this._writeStatus();
|
|
@@ -504,36 +509,74 @@ class Daemon {
|
|
|
504
509
|
return { binary: process.env.COMSPEC || 'cmd.exe', prefix: ['/C', binary] };
|
|
505
510
|
}
|
|
506
511
|
|
|
507
|
-
|
|
512
|
+
/**
|
|
513
|
+
* Install a SKILL.md into OpenClaw's workspace skills directory.
|
|
514
|
+
* OpenClaw auto-discovers skills from <workspace>/skills/ and injects
|
|
515
|
+
* them into the system prompt — same mechanism as the Python adapter.
|
|
516
|
+
*/
|
|
517
|
+
_installWorkspaceSkill(agentCfg, network) {
|
|
508
518
|
const baseUrl = 'https://workspace-endpoint.openagents.org';
|
|
509
519
|
const h = `Authorization: Bearer ${network.token}`;
|
|
510
520
|
const wsId = network.id;
|
|
511
521
|
const name = agentCfg.name;
|
|
522
|
+
const agentId = agentCfg.openclaw_agent_id || 'main';
|
|
523
|
+
|
|
524
|
+
const home = IS_WINDOWS ? process.env.USERPROFILE : process.env.HOME;
|
|
525
|
+
const openclawDir = path.join(home, '.openclaw');
|
|
526
|
+
const wsDir = agentId && agentId !== 'main'
|
|
527
|
+
? path.join(openclawDir, `workspace-${agentId}`)
|
|
528
|
+
: path.join(openclawDir, 'workspace');
|
|
512
529
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
530
|
+
if (!fs.existsSync(wsDir)) {
|
|
531
|
+
this._log(`OpenClaw workspace not found at ${wsDir}, skipping skill install`);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const skillName = `openagents-workspace-${name}`;
|
|
536
|
+
const skillDir = path.join(wsDir, 'skills', skillName);
|
|
537
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
538
|
+
|
|
539
|
+
const content = [
|
|
540
|
+
'---',
|
|
541
|
+
'name: openagents-workspace',
|
|
542
|
+
'description: "Share files, browse websites, and collaborate with other agents in an OpenAgents workspace. Use when: (1) sharing results or reports, (2) browsing a website, (3) reading shared files, (4) checking who else is in the workspace."',
|
|
543
|
+
'metadata:',
|
|
544
|
+
' {"openclaw": {"always": true, "emoji": "\\U0001F310"}}',
|
|
545
|
+
'---',
|
|
546
|
+
'',
|
|
547
|
+
`You are agent "${name}" in workspace "${network.slug || network.name || wsId}".`,
|
|
548
|
+
'',
|
|
549
|
+
'## Workspace Tools (MANDATORY)',
|
|
517
550
|
'',
|
|
518
|
-
'
|
|
519
|
-
'
|
|
520
|
-
|
|
521
|
-
`Read page: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/snapshot`,
|
|
522
|
-
`Screenshot: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/screenshot`,
|
|
523
|
-
`Navigate: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/navigate -H "${h}" -H "Content-Type: application/json" -d '{"url":"URL"}'`,
|
|
524
|
-
`Click: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/click -H "${h}" -H "Content-Type: application/json" -d '{"selector":"CSS_SELECTOR"}'`,
|
|
525
|
-
`Type: curl -s -X POST ${baseUrl}/v1/browser/tabs/TAB_ID/type -H "${h}" -H "Content-Type: application/json" -d '{"selector":"CSS_SELECTOR","text":"TEXT"}'`,
|
|
526
|
-
`Close: curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID`,
|
|
527
|
-
`List tabs: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs?network=${wsId}`,
|
|
528
|
-
'(Replace TAB_ID with the id from the open response)',
|
|
551
|
+
'Use your `exec` tool to run the `curl` commands below.',
|
|
552
|
+
'Do NOT use native browsing tools for workspace browser tasks — use `exec` + `curl`.',
|
|
553
|
+
'The workspace browser is a *shared* browser visible to all users and agents.',
|
|
529
554
|
'',
|
|
530
|
-
'
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
`
|
|
534
|
-
|
|
555
|
+
'### Shared Browser',
|
|
556
|
+
'',
|
|
557
|
+
'**To browse a website**, exec these steps:',
|
|
558
|
+
`Step 1 — open tab: curl -s -X POST ${baseUrl}/v1/browser/tabs -H "${h}" -H "Content-Type: application/json" -d '{"url":"https://example.com","network":"${wsId}","source":"openagents:${name}"}'`,
|
|
559
|
+
`Step 2 — read content: curl -s -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID/snapshot`,
|
|
560
|
+
`Step 3 — close tab: curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/TAB_ID`,
|
|
561
|
+
'(Replace TAB_ID with the id from step 1 response)',
|
|
562
|
+
'',
|
|
563
|
+
`List tabs: \`curl -s -H "${h}" ${baseUrl}/v1/browser/tabs?network=${wsId}\``,
|
|
564
|
+
`Navigate: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/navigate -d '{"url":"URL"}'\``,
|
|
565
|
+
`Click: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/click -d '{"selector":"CSS"}'\``,
|
|
566
|
+
`Type: \`curl -s -X POST -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/browser/tabs/{tab_id}/type -d '{"selector":"CSS","text":"TEXT"}'\``,
|
|
567
|
+
`Close: \`curl -s -X DELETE -H "${h}" ${baseUrl}/v1/browser/tabs/{tab_id}\``,
|
|
568
|
+
'',
|
|
569
|
+
'### Workspace Files',
|
|
570
|
+
'',
|
|
571
|
+
`List: \`curl -s -H "${h}" ${baseUrl}/v1/files?network=${wsId}\``,
|
|
572
|
+
`Read: \`curl -s -H "${h}" ${baseUrl}/v1/files/FILE_PATH?network=${wsId}\``,
|
|
573
|
+
`Write: \`curl -s -X PUT -H "${h}" -H "Content-Type: application/json" ${baseUrl}/v1/files/FILE_PATH -d '{"content":"...","network":"${wsId}"}'\``,
|
|
535
574
|
'',
|
|
536
575
|
].join('\n');
|
|
576
|
+
|
|
577
|
+
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
578
|
+
fs.writeFileSync(skillPath, content, 'utf-8');
|
|
579
|
+
this._log(`Installed workspace skill at ${skillPath}`);
|
|
537
580
|
}
|
|
538
581
|
|
|
539
582
|
_runCliAgent(binary, message, channel, agentCfg, network, env) {
|
|
@@ -541,45 +584,10 @@ class Daemon {
|
|
|
541
584
|
const sessionKey = `openagents-${network.id.slice(0, 8)}-${channel.slice(-8)}`;
|
|
542
585
|
const agentId = agentCfg.openclaw_agent_id || 'main';
|
|
543
586
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
let fullMessage = message;
|
|
547
|
-
if (!this._sessionContextSent) this._sessionContextSent = new Set();
|
|
548
|
-
if (!this._sessionContextSent.has(contextKey)) {
|
|
549
|
-
fullMessage = this._buildWorkspaceContext(agentCfg, network) + message;
|
|
550
|
-
this._sessionContextSent.add(contextKey);
|
|
551
|
-
}
|
|
587
|
+
const args = ['agent', '--local', '--agent', agentId,
|
|
588
|
+
'--session-id', sessionKey, '--message', message, '--json'];
|
|
552
589
|
|
|
553
|
-
|
|
554
|
-
const msgFile = path.join(this.config.configDir, `msg-${Date.now()}.tmp`);
|
|
555
|
-
fs.writeFileSync(msgFile, fullMessage, 'utf-8');
|
|
556
|
-
|
|
557
|
-
// Use a small node wrapper to read the message file and exec openclaw
|
|
558
|
-
// This avoids all cmd.exe quoting/length issues
|
|
559
|
-
const wrapperCode = [
|
|
560
|
-
`const msg = require("fs").readFileSync(${JSON.stringify(msgFile)}, "utf-8");`,
|
|
561
|
-
`const cp = require("child_process");`,
|
|
562
|
-
`const path = require("path");`,
|
|
563
|
-
`const args = ${JSON.stringify(['agent', '--local', '--agent', agentId, '--session-id', sessionKey, '--json'])};`,
|
|
564
|
-
`args.push("--message", msg);`,
|
|
565
|
-
// Resolve the .cmd shim to find the actual JS entry point
|
|
566
|
-
`let bin = ${JSON.stringify(binary)};`,
|
|
567
|
-
`try {`,
|
|
568
|
-
` const w = cp.execSync("where " + bin, { encoding: "utf-8", timeout: 5000 }).split(/\\r?\\n/)[0].trim();`,
|
|
569
|
-
` if (w.endsWith(".cmd")) {`,
|
|
570
|
-
` const c = require("fs").readFileSync(w, "utf-8");`,
|
|
571
|
-
` const m = c.match(/"([^"]+\\.js)"/);`,
|
|
572
|
-
` if (m) { args.unshift(m[1].replace("%~dp0\\\\", path.dirname(w) + "\\\\")); bin = process.execPath; }`,
|
|
573
|
-
` }`,
|
|
574
|
-
`} catch {}`,
|
|
575
|
-
`const r = cp.spawnSync(bin, args, { stdio: ["ignore", "pipe", "pipe"], env: process.env, timeout: 600000 });`,
|
|
576
|
-
`try { require("fs").unlinkSync(${JSON.stringify(msgFile)}); } catch {}`,
|
|
577
|
-
`if (r.stdout) process.stdout.write(r.stdout);`,
|
|
578
|
-
`if (r.stderr) process.stderr.write(r.stderr);`,
|
|
579
|
-
`process.exit(r.status || 0);`,
|
|
580
|
-
].join('\n');
|
|
581
|
-
|
|
582
|
-
this._log(`${agentCfg.name} CLI: ${binary} agent --local --agent ${agentId} ... (via wrapper, msg ${fullMessage.length} chars)`);
|
|
590
|
+
this._log(`${agentCfg.name} CLI: ${binary} ${args.slice(0, 5).join(' ')} ...`);
|
|
583
591
|
|
|
584
592
|
const spawnEnv = { ...env };
|
|
585
593
|
if (IS_WINDOWS) {
|
|
@@ -589,14 +597,22 @@ class Daemon {
|
|
|
589
597
|
}
|
|
590
598
|
}
|
|
591
599
|
|
|
592
|
-
|
|
593
|
-
|
|
600
|
+
// On Windows, use cmd.exe /C for .cmd shim resolution
|
|
601
|
+
let spawnBinary = binary;
|
|
602
|
+
let spawnArgs = args;
|
|
594
603
|
const spawnOpts = {
|
|
595
604
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
596
605
|
env: spawnEnv,
|
|
597
|
-
timeout:
|
|
606
|
+
timeout: 600000,
|
|
598
607
|
};
|
|
599
608
|
|
|
609
|
+
if (IS_WINDOWS) {
|
|
610
|
+
spawnBinary = process.env.COMSPEC || 'cmd.exe';
|
|
611
|
+
const quotedArgs = args.map((a) => a.includes(' ') ? `"${a}"` : a);
|
|
612
|
+
spawnArgs = ['/C', binary, ...quotedArgs];
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
|
|
600
616
|
const proc = spawn(spawnBinary, spawnArgs, spawnOpts);
|
|
601
617
|
let stdout = '';
|
|
602
618
|
let stderr = '';
|