@agentbean/daemon 0.1.26 → 0.1.28
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/dist/agent-instance.js +4 -1
- package/dist/connection.js +4 -1
- package/dist/device-daemon.js +68 -0
- package/dist/post-process.js +1 -1
- package/package.json +1 -1
package/dist/agent-instance.js
CHANGED
|
@@ -51,6 +51,9 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
51
51
|
.join('\n');
|
|
52
52
|
return `${prompt}\n\n用户随消息附加了以下本地文件,请在需要时读取并使用:\n${list}`;
|
|
53
53
|
}
|
|
54
|
+
function promptWithWorkspaceOutput(prompt, outputDir) {
|
|
55
|
+
return `${prompt}\n\n如果本次任务会生成图片、文档、数据或其他文件,请把最终产物保存到这个 AgentBean 输出目录:\n${outputDir}\n保存后在回复中说明文件名即可,系统会自动同步并在聊天中展示预览。`;
|
|
56
|
+
}
|
|
54
57
|
export class AgentInstance {
|
|
55
58
|
config;
|
|
56
59
|
adapter;
|
|
@@ -96,7 +99,7 @@ export class AgentInstance {
|
|
|
96
99
|
let archivedFiles = [];
|
|
97
100
|
try {
|
|
98
101
|
const downloadedAttachments = await downloadAttachments({ serverUrl, token, run, attachments: req.attachments });
|
|
99
|
-
const prompt = promptWithAttachments(req.prompt, downloadedAttachments);
|
|
102
|
+
const prompt = promptWithWorkspaceOutput(promptWithAttachments(req.prompt, downloadedAttachments), run.outputDir);
|
|
100
103
|
const rawBody = await this.adapter.ask({
|
|
101
104
|
prompt,
|
|
102
105
|
history: req.history ?? [],
|
package/dist/connection.js
CHANGED
|
@@ -50,6 +50,9 @@ function promptWithAttachments(prompt, attachments) {
|
|
|
50
50
|
.join('\n');
|
|
51
51
|
return `${prompt}\n\n用户随消息附加了以下本地文件,请在需要时读取并使用:\n${list}`;
|
|
52
52
|
}
|
|
53
|
+
function promptWithWorkspaceOutput(prompt, outputDir) {
|
|
54
|
+
return `${prompt}\n\n如果本次任务会生成图片、文档、数据或其他文件,请把最终产物保存到这个 AgentBean 输出目录:\n${outputDir}\n保存后在回复中说明文件名即可,系统会自动同步并在聊天中展示预览。`;
|
|
55
|
+
}
|
|
53
56
|
export function createConnection(cfg, adapter) {
|
|
54
57
|
let socket = null;
|
|
55
58
|
let heartbeatTimer = null;
|
|
@@ -112,7 +115,7 @@ export function createConnection(cfg, adapter) {
|
|
|
112
115
|
run,
|
|
113
116
|
attachments: req.attachments,
|
|
114
117
|
});
|
|
115
|
-
const prompt = promptWithAttachments(req.prompt, downloadedAttachments);
|
|
118
|
+
const prompt = promptWithWorkspaceOutput(promptWithAttachments(req.prompt, downloadedAttachments), run.outputDir);
|
|
116
119
|
const rawBody = await adapter.ask({
|
|
117
120
|
prompt,
|
|
118
121
|
history: req.history ?? [],
|
package/dist/device-daemon.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { io } from 'socket.io-client';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
2
3
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
import { homedir } from 'node:os';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
5
7
|
import { logger } from './log.js';
|
|
6
8
|
import { AgentInstance } from './agent-instance.js';
|
|
7
9
|
import { pickAdapter } from './adapters/factory.js';
|
|
8
10
|
import { scanRuntimes, scanAgentOSAgents, scanLocalAgents, collectSystemInfo } from './scanner.js';
|
|
9
11
|
import { syncWorkspaceArtifacts } from './workspace-sync.js';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
10
13
|
function errorMessage(err) {
|
|
11
14
|
if (err instanceof Error && err.message)
|
|
12
15
|
return err.message;
|
|
@@ -26,6 +29,55 @@ function agentSlug(name) {
|
|
|
26
29
|
function scannedAgentId(deviceId, name) {
|
|
27
30
|
return `scan-${deviceId}-${agentSlug(name)}`;
|
|
28
31
|
}
|
|
32
|
+
export function nativeDirectoryPickerCommands(platform = process.platform) {
|
|
33
|
+
if (platform === 'darwin') {
|
|
34
|
+
return [{ command: 'osascript', args: ['-e', 'POSIX path of (choose folder with prompt "选择项目目录")'] }];
|
|
35
|
+
}
|
|
36
|
+
if (platform === 'win32') {
|
|
37
|
+
return [{
|
|
38
|
+
command: 'powershell.exe',
|
|
39
|
+
args: [
|
|
40
|
+
'-NoProfile',
|
|
41
|
+
'-STA',
|
|
42
|
+
'-Command',
|
|
43
|
+
'Add-Type -AssemblyName System.Windows.Forms; $dialog = New-Object System.Windows.Forms.FolderBrowserDialog; if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $dialog.SelectedPath }',
|
|
44
|
+
],
|
|
45
|
+
}];
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
{ command: 'zenity', args: ['--file-selection', '--directory', '--title=选择项目目录'] },
|
|
49
|
+
{ command: 'kdialog', args: ['--getexistingdirectory', '.', '选择项目目录'] },
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
function isMissingCommandError(err) {
|
|
53
|
+
return err?.code === 'ENOENT';
|
|
54
|
+
}
|
|
55
|
+
function isDirectoryPickerCancel(err) {
|
|
56
|
+
const message = `${err?.message ?? ''}\n${err?.stderr ?? ''}`;
|
|
57
|
+
return err?.code === 1 || /cancel|canceled|cancelled|User canceled|No file selected/i.test(message);
|
|
58
|
+
}
|
|
59
|
+
export async function selectNativeDirectory(commands = nativeDirectoryPickerCommands()) {
|
|
60
|
+
let lastError = null;
|
|
61
|
+
for (const cmd of commands) {
|
|
62
|
+
try {
|
|
63
|
+
const { stdout } = await execFileAsync(cmd.command, cmd.args, { timeout: 120_000 });
|
|
64
|
+
const selected = stdout.trim();
|
|
65
|
+
if (selected)
|
|
66
|
+
return selected;
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (isMissingCommandError(err)) {
|
|
71
|
+
lastError = err;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (isDirectoryPickerCancel(err))
|
|
75
|
+
return null;
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
throw new Error(lastError ? `directory picker command not available: ${errorMessage(lastError)}` : 'directory picker command not available');
|
|
80
|
+
}
|
|
29
81
|
const CACHE_DIR = join(homedir(), '.agentbean');
|
|
30
82
|
const CACHE_FILE = join(CACHE_DIR, 'scanned-agents.json');
|
|
31
83
|
function isRuntimeEntry(entry) {
|
|
@@ -88,6 +140,7 @@ export function createDeviceSocketOptions(input) {
|
|
|
88
140
|
protocolVersion: 1,
|
|
89
141
|
capabilities: {
|
|
90
142
|
customAgentDispatch: true,
|
|
143
|
+
directoryPicker: true,
|
|
91
144
|
},
|
|
92
145
|
},
|
|
93
146
|
reconnection: true,
|
|
@@ -347,6 +400,21 @@ export function createDeviceDaemon(cfg, agents) {
|
|
|
347
400
|
}
|
|
348
401
|
logger.info({ agentId: payload.agentId, requestId: payload.requestId, cancelled, reason: payload.reason }, 'dispatch cancel requested');
|
|
349
402
|
});
|
|
403
|
+
socket.on('device:select-directory', async (_payload, ack) => {
|
|
404
|
+
try {
|
|
405
|
+
const selected = await selectNativeDirectory();
|
|
406
|
+
if (!selected) {
|
|
407
|
+
ack?.({ ok: false, error: 'CANCELLED' });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
ack?.({ ok: true, path: selected });
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
const message = errorMessage(err);
|
|
414
|
+
logger.warn({ err: message }, 'failed to select directory on device');
|
|
415
|
+
ack?.({ ok: false, error: message });
|
|
416
|
+
}
|
|
417
|
+
});
|
|
350
418
|
socket.on('agents:discover', async () => {
|
|
351
419
|
await scanAndRegister(socket, false);
|
|
352
420
|
});
|
package/dist/post-process.js
CHANGED
|
@@ -51,7 +51,7 @@ function normalizeCandidatePath(raw) {
|
|
|
51
51
|
function extractMentionedFiles(reply, workspace, dispatchStart) {
|
|
52
52
|
const candidates = new Set();
|
|
53
53
|
const markdownLinkRe = /!?\[[^\]]*]\(([^)\s]+)\)/g;
|
|
54
|
-
const plainPathRe = /(?:^|[\s"'`(
|
|
54
|
+
const plainPathRe = /(?:^|[\s"'`(<::])((?:~?\/|\.{1,2}\/)?[\w@%+=:,./-]+\.(?:png|jpe?g|gif|webp|svg|pdf|txt|csv|json|md|mp4|mov|zip))(?:$|[\s"'`)>.,;::])/gim;
|
|
55
55
|
let match;
|
|
56
56
|
while ((match = markdownLinkRe.exec(reply)) !== null) {
|
|
57
57
|
const normalized = normalizeCandidatePath(match[1]);
|