@agentbean/daemon 0.1.12 → 0.1.14
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 +38 -1
- package/dist/connection.js +43 -2
- package/dist/scanner.js +11 -0
- package/dist/workspace-manager.js +3 -1
- package/package.json +1 -1
package/dist/agent-instance.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
1
3
|
import { logger } from './log.js';
|
|
2
4
|
import { uploadArtifact } from './uploader.js';
|
|
3
5
|
import { postProcess } from './post-process.js';
|
|
@@ -16,6 +18,39 @@ function errorMessage(err) {
|
|
|
16
18
|
catch { }
|
|
17
19
|
return 'unknown error';
|
|
18
20
|
}
|
|
21
|
+
function safeFilename(value) {
|
|
22
|
+
return basename(value).replace(/[^a-zA-Z0-9._-]/g, '-').replace(/^-+|-+$/g, '') || 'attachment';
|
|
23
|
+
}
|
|
24
|
+
async function downloadAttachments(input) {
|
|
25
|
+
const downloaded = [];
|
|
26
|
+
for (const attachment of input.attachments ?? []) {
|
|
27
|
+
const sep = attachment.downloadUrl.includes('?') ? '&' : '?';
|
|
28
|
+
const url = `${input.serverUrl}${attachment.downloadUrl}${sep}token=${encodeURIComponent(input.token)}`;
|
|
29
|
+
try {
|
|
30
|
+
const resp = await fetch(url);
|
|
31
|
+
if (!resp.ok) {
|
|
32
|
+
logger.warn({ id: attachment.id, status: resp.status }, 'attachment download rejected');
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const bytes = Buffer.from(await resp.arrayBuffer());
|
|
36
|
+
const localPath = join(input.run.inputDir, `${attachment.id}-${safeFilename(attachment.filename)}`);
|
|
37
|
+
writeFileSync(localPath, bytes);
|
|
38
|
+
downloaded.push({ ...attachment, localPath });
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger.warn({ id: attachment.id, err: err?.message }, 'attachment download failed');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return downloaded;
|
|
45
|
+
}
|
|
46
|
+
function promptWithAttachments(prompt, attachments) {
|
|
47
|
+
if (attachments.length === 0)
|
|
48
|
+
return prompt;
|
|
49
|
+
const list = attachments
|
|
50
|
+
.map((file) => `- ${file.filename} (${file.mimeType}, ${file.sizeBytes} bytes): ${file.localPath}`)
|
|
51
|
+
.join('\n');
|
|
52
|
+
return `${prompt}\n\n用户随消息附加了以下本地文件,请在需要时读取并使用:\n${list}`;
|
|
53
|
+
}
|
|
19
54
|
export class AgentInstance {
|
|
20
55
|
config;
|
|
21
56
|
adapter;
|
|
@@ -58,8 +93,10 @@ export class AgentInstance {
|
|
|
58
93
|
});
|
|
59
94
|
let archivedFiles = [];
|
|
60
95
|
try {
|
|
96
|
+
const downloadedAttachments = await downloadAttachments({ serverUrl, token, run, attachments: req.attachments });
|
|
97
|
+
const prompt = promptWithAttachments(req.prompt, downloadedAttachments);
|
|
61
98
|
const rawBody = await this.adapter.ask({
|
|
62
|
-
prompt
|
|
99
|
+
prompt,
|
|
63
100
|
history: req.history ?? [],
|
|
64
101
|
systemPrompt: this.config.adapter.systemPrompt,
|
|
65
102
|
workspace: projectWorkspace,
|
package/dist/connection.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { io } from 'socket.io-client';
|
|
2
|
+
import { writeFileSync } from 'node:fs';
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
2
4
|
import { logger } from './log.js';
|
|
3
5
|
import { uploadArtifact } from './uploader.js';
|
|
4
6
|
import { postProcess } from './post-process.js';
|
|
@@ -16,6 +18,38 @@ function errorMessage(err) {
|
|
|
16
18
|
catch { }
|
|
17
19
|
return 'unknown error';
|
|
18
20
|
}
|
|
21
|
+
function safeFilename(value) {
|
|
22
|
+
return basename(value).replace(/[^a-zA-Z0-9._-]/g, '-').replace(/^-+|-+$/g, '') || 'attachment';
|
|
23
|
+
}
|
|
24
|
+
async function downloadAttachments(input) {
|
|
25
|
+
const downloaded = [];
|
|
26
|
+
for (const attachment of input.attachments ?? []) {
|
|
27
|
+
const sep = attachment.downloadUrl.includes('?') ? '&' : '?';
|
|
28
|
+
const url = `${input.serverUrl}${attachment.downloadUrl}${sep}token=${encodeURIComponent(input.token)}`;
|
|
29
|
+
try {
|
|
30
|
+
const resp = await fetch(url);
|
|
31
|
+
if (!resp.ok) {
|
|
32
|
+
logger.warn({ id: attachment.id, status: resp.status }, 'attachment download rejected');
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const localPath = join(input.run.inputDir, `${attachment.id}-${safeFilename(attachment.filename)}`);
|
|
36
|
+
writeFileSync(localPath, Buffer.from(await resp.arrayBuffer()));
|
|
37
|
+
downloaded.push({ ...attachment, localPath });
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
logger.warn({ id: attachment.id, err: err?.message }, 'attachment download failed');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return downloaded;
|
|
44
|
+
}
|
|
45
|
+
function promptWithAttachments(prompt, attachments) {
|
|
46
|
+
if (attachments.length === 0)
|
|
47
|
+
return prompt;
|
|
48
|
+
const list = attachments
|
|
49
|
+
.map((file) => `- ${file.filename} (${file.mimeType}, ${file.sizeBytes} bytes): ${file.localPath}`)
|
|
50
|
+
.join('\n');
|
|
51
|
+
return `${prompt}\n\n用户随消息附加了以下本地文件,请在需要时读取并使用:\n${list}`;
|
|
52
|
+
}
|
|
19
53
|
export function createConnection(cfg, adapter) {
|
|
20
54
|
let socket = null;
|
|
21
55
|
let heartbeatTimer = null;
|
|
@@ -69,8 +103,16 @@ export function createConnection(cfg, adapter) {
|
|
|
69
103
|
});
|
|
70
104
|
let archivedFiles = [];
|
|
71
105
|
try {
|
|
106
|
+
const httpBase = cfg.server.url.replace(/\/agent$/, '');
|
|
107
|
+
const downloadedAttachments = await downloadAttachments({
|
|
108
|
+
serverUrl: httpBase,
|
|
109
|
+
token: cfg.server.token,
|
|
110
|
+
run,
|
|
111
|
+
attachments: req.attachments,
|
|
112
|
+
});
|
|
113
|
+
const prompt = promptWithAttachments(req.prompt, downloadedAttachments);
|
|
72
114
|
const rawBody = await adapter.ask({
|
|
73
|
-
prompt
|
|
115
|
+
prompt,
|
|
74
116
|
history: req.history ?? [],
|
|
75
117
|
systemPrompt: cfg.adapter.systemPrompt,
|
|
76
118
|
workspace: cfg.adapter.workspace,
|
|
@@ -84,7 +126,6 @@ export function createConnection(cfg, adapter) {
|
|
|
84
126
|
finishAgentWorkspaceRun(run, { replyText, files: archivedFiles, status: 'completed' });
|
|
85
127
|
const artifactIds = [];
|
|
86
128
|
if (archivedFiles.length > 0) {
|
|
87
|
-
const httpBase = cfg.server.url.replace(/\/agent$/, '');
|
|
88
129
|
for (const file of archivedFiles) {
|
|
89
130
|
try {
|
|
90
131
|
const result = await uploadArtifact({
|
package/dist/scanner.js
CHANGED
|
@@ -4,6 +4,16 @@ import { join } from "node:path";
|
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import * as os from "node:os";
|
|
6
6
|
import { logger } from "./log.js";
|
|
7
|
+
function readDaemonVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
10
|
+
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return "unknown";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const DAEMON_VERSION = readDaemonVersion();
|
|
7
17
|
function isExecutableFile(path) {
|
|
8
18
|
try {
|
|
9
19
|
return existsSync(path) && statSync(path).isFile();
|
|
@@ -374,5 +384,6 @@ export function collectSystemInfo() {
|
|
|
374
384
|
totalMemoryGB: Math.round((totalMem / 1024 / 1024 / 1024) * 10) / 10,
|
|
375
385
|
freeMemoryGB: Math.round((freeMem / 1024 / 1024 / 1024) * 10) / 10,
|
|
376
386
|
nodeVersion: process.version,
|
|
387
|
+
daemonVersion: DAEMON_VERSION,
|
|
377
388
|
};
|
|
378
389
|
}
|
|
@@ -49,6 +49,7 @@ export function beginAgentWorkspaceRun(input) {
|
|
|
49
49
|
const teamDir = ensureDir(join(rootDir(), 'teams', teamId));
|
|
50
50
|
const agentDir = ensureDir(join(teamDir, 'agents', agentId));
|
|
51
51
|
const runDir = ensureDir(join(agentDir, 'runs', runId));
|
|
52
|
+
const inputDir = ensureDir(join(runDir, 'inputs'));
|
|
52
53
|
const outputDir = ensureDir(join(runDir, 'outputs'));
|
|
53
54
|
const intermediateDir = ensureDir(join(runDir, 'intermediates'));
|
|
54
55
|
const logDir = ensureDir(join(runDir, 'logs'));
|
|
@@ -72,7 +73,7 @@ export function beginAgentWorkspaceRun(input) {
|
|
|
72
73
|
createdAt: new Date().toISOString(),
|
|
73
74
|
files: [],
|
|
74
75
|
});
|
|
75
|
-
return { teamId: input.teamId, agentId: input.agentId, runId: input.runId, agentDir, runDir, outputDir, intermediateDir, logDir };
|
|
76
|
+
return { teamId: input.teamId, agentId: input.agentId, runId: input.runId, agentDir, runDir, inputDir, outputDir, intermediateDir, logDir };
|
|
76
77
|
}
|
|
77
78
|
export function workspaceEnv(run) {
|
|
78
79
|
return {
|
|
@@ -80,6 +81,7 @@ export function workspaceEnv(run) {
|
|
|
80
81
|
AGENTBEAN_AGENT_ID: run.agentId,
|
|
81
82
|
AGENTBEAN_RUN_ID: run.runId,
|
|
82
83
|
AGENTBEAN_WORKSPACE: run.agentDir,
|
|
84
|
+
AGENTBEAN_INPUT_DIR: run.inputDir,
|
|
83
85
|
AGENTBEAN_OUTPUT_DIR: run.outputDir,
|
|
84
86
|
AGENTBEAN_INTERMEDIATE_DIR: run.intermediateDir,
|
|
85
87
|
AGENT_BEAN_OUTPUT_DIRS: [run.outputDir, run.intermediateDir].join(','),
|