@next-open-ai/openbot 0.3.2 → 0.6.8
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/README.md +46 -7
- package/apps/desktop/renderer/dist/assets/index-LCp1YPVA.css +10 -0
- package/apps/desktop/renderer/dist/assets/index-l5fpDsHs.js +89 -0
- package/apps/desktop/renderer/dist/index.html +2 -2
- package/dist/core/agent/agent-manager.d.ts +15 -7
- package/dist/core/agent/agent-manager.js +52 -21
- package/dist/core/agent/run.js +2 -2
- package/dist/core/config/desktop-config.d.ts +24 -0
- package/dist/core/config/desktop-config.js +19 -1
- package/dist/core/session-current-agent.d.ts +34 -0
- package/dist/core/session-current-agent.js +32 -0
- package/dist/core/tools/create-agent-tool.d.ts +6 -0
- package/dist/core/tools/create-agent-tool.js +97 -0
- package/dist/core/tools/index.d.ts +3 -0
- package/dist/core/tools/index.js +3 -0
- package/dist/core/tools/list-agents-tool.d.ts +5 -0
- package/dist/core/tools/list-agents-tool.js +45 -0
- package/dist/core/tools/switch-agent-tool.d.ts +6 -0
- package/dist/core/tools/switch-agent-tool.js +54 -0
- package/dist/gateway/channel/adapters/dingtalk.d.ts +11 -0
- package/dist/gateway/channel/adapters/dingtalk.js +190 -0
- package/dist/gateway/channel/adapters/feishu.d.ts +11 -0
- package/dist/gateway/channel/adapters/feishu.js +218 -0
- package/dist/gateway/channel/adapters/telegram.d.ts +14 -0
- package/dist/gateway/channel/adapters/telegram.js +197 -0
- package/dist/gateway/channel/channel-core.d.ts +9 -0
- package/dist/gateway/channel/channel-core.js +135 -0
- package/dist/gateway/channel/registry.d.ts +16 -0
- package/dist/gateway/channel/registry.js +54 -0
- package/dist/gateway/channel/run-agent.d.ts +26 -0
- package/dist/gateway/channel/run-agent.js +137 -0
- package/dist/gateway/channel/session-persistence.d.ts +36 -0
- package/dist/gateway/channel/session-persistence.js +46 -0
- package/dist/gateway/channel/types.d.ts +74 -0
- package/dist/gateway/channel/types.js +4 -0
- package/dist/gateway/channel-handler.d.ts +3 -4
- package/dist/gateway/channel-handler.js +8 -2
- package/dist/gateway/methods/agent-chat.js +30 -12
- package/dist/gateway/methods/run-scheduled-task.js +4 -2
- package/dist/gateway/server.js +84 -1
- package/dist/server/agent-config/agent-config.controller.d.ts +6 -1
- package/dist/server/agent-config/agent-config.service.d.ts +12 -1
- package/dist/server/agent-config/agent-config.service.js +10 -3
- package/dist/server/agents/agents.controller.d.ts +10 -0
- package/dist/server/agents/agents.controller.js +35 -1
- package/dist/server/agents/agents.gateway.js +18 -4
- package/dist/server/agents/agents.service.d.ts +4 -0
- package/dist/server/agents/agents.service.js +17 -1
- package/dist/server/config/config.controller.d.ts +2 -0
- package/dist/server/config/config.service.d.ts +3 -0
- package/dist/server/config/config.service.js +3 -1
- package/dist/server/saved-items/saved-items.controller.d.ts +32 -1
- package/dist/server/saved-items/saved-items.controller.js +154 -3
- package/dist/server/saved-items/saved-items.module.js +3 -1
- package/dist/server/workspace/workspace.service.d.ts +11 -0
- package/dist/server/workspace/workspace.service.js +40 -1
- package/package.json +3 -1
- package/apps/desktop/renderer/dist/assets/index-DKtaRFW4.js +0 -89
- package/apps/desktop/renderer/dist/assets/index-QHuqXpWQ.css +0 -10
|
@@ -10,17 +10,114 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
|
-
import { Controller, Get, Post, Delete, Body, Param, Query, HttpException, HttpStatus, } from '@nestjs/common';
|
|
13
|
+
import { Controller, Get, Post, Delete, Body, Param, Query, Res, HttpException, HttpStatus, } from '@nestjs/common';
|
|
14
|
+
import { readFile } from 'fs/promises';
|
|
15
|
+
import { resolve } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
import { existsSync } from 'fs';
|
|
14
18
|
import { SavedItemsService } from './saved-items.service.js';
|
|
19
|
+
import { WorkspaceService } from '../workspace/workspace.service.js';
|
|
20
|
+
import { ConfigService } from '../config/config.service.js';
|
|
21
|
+
import { getOpenbotWorkspaceDir } from '../../core/agent/agent-dir.js';
|
|
22
|
+
const IMAGE_EXT_MIME = {
|
|
23
|
+
jpg: 'image/jpeg',
|
|
24
|
+
jpeg: 'image/jpeg',
|
|
25
|
+
png: 'image/png',
|
|
26
|
+
gif: 'image/gif',
|
|
27
|
+
webp: 'image/webp',
|
|
28
|
+
svg: 'image/svg+xml',
|
|
29
|
+
bmp: 'image/bmp',
|
|
30
|
+
ico: 'image/x-icon',
|
|
31
|
+
};
|
|
32
|
+
function mimeFromPath(filePath) {
|
|
33
|
+
const ext = filePath.split('.').pop()?.toLowerCase() || '';
|
|
34
|
+
return IMAGE_EXT_MIME[ext] || 'application/octet-stream';
|
|
35
|
+
}
|
|
36
|
+
function safeFilenameFromUrl(url, contentType) {
|
|
37
|
+
try {
|
|
38
|
+
const u = new URL(url);
|
|
39
|
+
const pathname = u.pathname || '';
|
|
40
|
+
const segment = pathname.split('/').filter(Boolean).pop() || '';
|
|
41
|
+
const decoded = decodeURIComponent(segment);
|
|
42
|
+
const base = decoded.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 180);
|
|
43
|
+
if (base)
|
|
44
|
+
return base;
|
|
45
|
+
}
|
|
46
|
+
catch (_) { }
|
|
47
|
+
const ct = (contentType || '').split(';')[0].trim().toLowerCase();
|
|
48
|
+
let ext = 'bin';
|
|
49
|
+
if (ct.includes('image/'))
|
|
50
|
+
ext = ct.replace('image/', '').trim() || 'png';
|
|
51
|
+
else if (ct.includes('text/html'))
|
|
52
|
+
ext = 'html';
|
|
53
|
+
else if (ct.includes('text/plain'))
|
|
54
|
+
ext = 'txt';
|
|
55
|
+
return `download_${Date.now()}.${ext}`;
|
|
56
|
+
}
|
|
15
57
|
let SavedItemsController = class SavedItemsController {
|
|
16
58
|
savedItemsService;
|
|
17
|
-
|
|
59
|
+
workspaceService;
|
|
60
|
+
configService;
|
|
61
|
+
constructor(savedItemsService, workspaceService, configService) {
|
|
18
62
|
this.savedItemsService = savedItemsService;
|
|
63
|
+
this.workspaceService = workspaceService;
|
|
64
|
+
this.configService = configService;
|
|
19
65
|
}
|
|
20
66
|
async list(tagId, workspace) {
|
|
21
67
|
const data = await this.savedItemsService.findAll({ tagId, workspace });
|
|
22
68
|
return { success: true, data };
|
|
23
69
|
}
|
|
70
|
+
async imageProxy(url, res) {
|
|
71
|
+
if (!url?.trim())
|
|
72
|
+
throw new HttpException('url is required', HttpStatus.BAD_REQUEST);
|
|
73
|
+
const decoded = decodeURIComponent(url.trim());
|
|
74
|
+
if (decoded.startsWith('file://') || decoded.startsWith('file:/')) {
|
|
75
|
+
try {
|
|
76
|
+
let pathPart;
|
|
77
|
+
try {
|
|
78
|
+
const u = new URL(decoded);
|
|
79
|
+
pathPart = (u.pathname || decoded).replace(/^\/([a-z]:)/i, '$1');
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
pathPart = decoded.replace(/^file:\/+/, '').replace(/^\/([a-z]:)/i, '$1');
|
|
83
|
+
}
|
|
84
|
+
const absolutePath = resolve(pathPart);
|
|
85
|
+
const home = homedir();
|
|
86
|
+
const workspaceRoot = getOpenbotWorkspaceDir();
|
|
87
|
+
if (!absolutePath.startsWith(resolve(home)) &&
|
|
88
|
+
!absolutePath.startsWith(resolve(workspaceRoot))) {
|
|
89
|
+
throw new HttpException('Local file path not allowed', HttpStatus.FORBIDDEN);
|
|
90
|
+
}
|
|
91
|
+
if (!existsSync(absolutePath)) {
|
|
92
|
+
throw new HttpException('File not found', HttpStatus.NOT_FOUND);
|
|
93
|
+
}
|
|
94
|
+
const buffer = await readFile(absolutePath);
|
|
95
|
+
const contentType = mimeFromPath(absolutePath);
|
|
96
|
+
res.setHeader('Content-Type', contentType);
|
|
97
|
+
res.send(buffer);
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
if (e instanceof HttpException)
|
|
101
|
+
throw e;
|
|
102
|
+
throw new HttpException('Local file read failed', HttpStatus.BAD_GATEWAY);
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const resFetch = await fetch(decoded, { redirect: 'follow' });
|
|
108
|
+
if (!resFetch.ok)
|
|
109
|
+
throw new HttpException('Upstream failed', HttpStatus.BAD_GATEWAY);
|
|
110
|
+
const contentType = resFetch.headers.get('content-type') || 'application/octet-stream';
|
|
111
|
+
res.setHeader('Content-Type', contentType);
|
|
112
|
+
const arr = new Uint8Array(await resFetch.arrayBuffer());
|
|
113
|
+
res.send(Buffer.from(arr));
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
if (e instanceof HttpException)
|
|
117
|
+
throw e;
|
|
118
|
+
throw new HttpException('Proxy failed', HttpStatus.BAD_GATEWAY);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
24
121
|
async get(id) {
|
|
25
122
|
const data = await this.savedItemsService.findById(id);
|
|
26
123
|
if (!data)
|
|
@@ -41,6 +138,42 @@ let SavedItemsController = class SavedItemsController {
|
|
|
41
138
|
await this.savedItemsService.delete(id);
|
|
42
139
|
return { success: true };
|
|
43
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Download the saved item URL to workspace .favorite or to a user-chosen directory.
|
|
143
|
+
* Body: { workspace?: string, targetDir?: string }.
|
|
144
|
+
* If targetDir (absolute path) is provided, file is written there; otherwise to workspace/.favorite.
|
|
145
|
+
*/
|
|
146
|
+
async downloadToWorkspace(id, body) {
|
|
147
|
+
const item = await this.savedItemsService.findById(id);
|
|
148
|
+
if (!item)
|
|
149
|
+
throw new HttpException('Saved item not found', HttpStatus.NOT_FOUND);
|
|
150
|
+
const workspace = (body?.workspace ?? '').trim() ||
|
|
151
|
+
this.configService.getDefaultAgentId(await this.configService.getConfig());
|
|
152
|
+
let buffer;
|
|
153
|
+
let contentType;
|
|
154
|
+
try {
|
|
155
|
+
const res = await fetch(item.url, { redirect: 'follow' });
|
|
156
|
+
if (!res.ok) {
|
|
157
|
+
throw new HttpException(`Failed to fetch URL: ${res.status} ${res.statusText}`, HttpStatus.BAD_GATEWAY);
|
|
158
|
+
}
|
|
159
|
+
contentType = res.headers.get('content-type') || undefined;
|
|
160
|
+
const arr = new Uint8Array(await res.arrayBuffer());
|
|
161
|
+
buffer = Buffer.from(arr);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (err instanceof HttpException)
|
|
165
|
+
throw err;
|
|
166
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
167
|
+
throw new HttpException(`Download failed: ${msg}`, HttpStatus.BAD_GATEWAY);
|
|
168
|
+
}
|
|
169
|
+
const filename = safeFilenameFromUrl(item.url, contentType);
|
|
170
|
+
if ((body?.targetDir ?? '').trim()) {
|
|
171
|
+
const absolutePath = await this.workspaceService.writeFileToDir(body.targetDir.trim(), filename, buffer);
|
|
172
|
+
return { success: true, data: { absolutePath, targetDir: body.targetDir.trim() } };
|
|
173
|
+
}
|
|
174
|
+
const relativePath = await this.workspaceService.writeFileInFavorite(workspace, filename, buffer);
|
|
175
|
+
return { success: true, data: { relativePath, workspace } };
|
|
176
|
+
}
|
|
44
177
|
};
|
|
45
178
|
__decorate([
|
|
46
179
|
Get(),
|
|
@@ -50,6 +183,14 @@ __decorate([
|
|
|
50
183
|
__metadata("design:paramtypes", [String, String]),
|
|
51
184
|
__metadata("design:returntype", Promise)
|
|
52
185
|
], SavedItemsController.prototype, "list", null);
|
|
186
|
+
__decorate([
|
|
187
|
+
Get('image-proxy'),
|
|
188
|
+
__param(0, Query('url')),
|
|
189
|
+
__param(1, Res({ passthrough: false })),
|
|
190
|
+
__metadata("design:type", Function),
|
|
191
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
192
|
+
__metadata("design:returntype", Promise)
|
|
193
|
+
], SavedItemsController.prototype, "imageProxy", null);
|
|
53
194
|
__decorate([
|
|
54
195
|
Get(':id'),
|
|
55
196
|
__param(0, Param('id')),
|
|
@@ -71,8 +212,18 @@ __decorate([
|
|
|
71
212
|
__metadata("design:paramtypes", [String]),
|
|
72
213
|
__metadata("design:returntype", Promise)
|
|
73
214
|
], SavedItemsController.prototype, "delete", null);
|
|
215
|
+
__decorate([
|
|
216
|
+
Post(':id/download-to-workspace'),
|
|
217
|
+
__param(0, Param('id')),
|
|
218
|
+
__param(1, Body()),
|
|
219
|
+
__metadata("design:type", Function),
|
|
220
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
221
|
+
__metadata("design:returntype", Promise)
|
|
222
|
+
], SavedItemsController.prototype, "downloadToWorkspace", null);
|
|
74
223
|
SavedItemsController = __decorate([
|
|
75
224
|
Controller('saved-items'),
|
|
76
|
-
__metadata("design:paramtypes", [SavedItemsService
|
|
225
|
+
__metadata("design:paramtypes", [SavedItemsService,
|
|
226
|
+
WorkspaceService,
|
|
227
|
+
ConfigService])
|
|
77
228
|
], SavedItemsController);
|
|
78
229
|
export { SavedItemsController };
|
|
@@ -6,6 +6,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Module } from '@nestjs/common';
|
|
8
8
|
import { DatabaseModule } from '../database/database.module.js';
|
|
9
|
+
import { ConfigModule } from '../config/config.module.js';
|
|
10
|
+
import { WorkspaceModule } from '../workspace/workspace.module.js';
|
|
9
11
|
import { TagsService } from './tags.service.js';
|
|
10
12
|
import { TagsController } from './tags.controller.js';
|
|
11
13
|
import { SavedItemsService } from './saved-items.service.js';
|
|
@@ -14,7 +16,7 @@ let SavedItemsModule = class SavedItemsModule {
|
|
|
14
16
|
};
|
|
15
17
|
SavedItemsModule = __decorate([
|
|
16
18
|
Module({
|
|
17
|
-
imports: [DatabaseModule],
|
|
19
|
+
imports: [DatabaseModule, ConfigModule, WorkspaceModule],
|
|
18
20
|
controllers: [TagsController, SavedItemsController],
|
|
19
21
|
providers: [TagsService, SavedItemsService],
|
|
20
22
|
exports: [TagsService, SavedItemsService],
|
|
@@ -22,4 +22,15 @@ export declare class WorkspaceService {
|
|
|
22
22
|
/** Delete a file or directory (recursive) under workspace. Returns true if deleted. skills 与 .skills 目录禁止删除。 */
|
|
23
23
|
deletePath(workspaceName: string, relativePath: string): Promise<boolean>;
|
|
24
24
|
private safeRelativePath;
|
|
25
|
+
/** Ensure workspace/.favorite directory exists. */
|
|
26
|
+
ensureFavoriteDir(workspaceName: string): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Write buffer to workspace/.favorite/{filename}. Returns relative path (e.g. .favorite/xxx).
|
|
29
|
+
*/
|
|
30
|
+
writeFileInFavorite(workspaceName: string, filename: string, buffer: Buffer): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Write buffer to a user-chosen directory. targetDir must be absolute and under homedir or workspace root.
|
|
33
|
+
* Returns the full path of the written file.
|
|
34
|
+
*/
|
|
35
|
+
writeFileToDir(targetDir: string, filename: string, buffer: Buffer): Promise<string>;
|
|
25
36
|
}
|
|
@@ -5,9 +5,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { Injectable } from '@nestjs/common';
|
|
8
|
-
import { readdir, stat, rm } from 'fs/promises';
|
|
8
|
+
import { readdir, stat, rm, mkdir, writeFile } from 'fs/promises';
|
|
9
9
|
import { join, resolve, relative } from 'path';
|
|
10
10
|
import { existsSync } from 'fs';
|
|
11
|
+
import { homedir } from 'os';
|
|
11
12
|
import { getOpenbotWorkspaceDir } from '../../core/agent/agent-dir.js';
|
|
12
13
|
let WorkspaceService = class WorkspaceService {
|
|
13
14
|
getWorkspaceRoot(name) {
|
|
@@ -96,6 +97,44 @@ let WorkspaceService = class WorkspaceService {
|
|
|
96
97
|
const parts = normalized.split('/').filter((p) => p !== '..' && p !== '.');
|
|
97
98
|
return parts.join('/');
|
|
98
99
|
}
|
|
100
|
+
/** Ensure workspace/.favorite directory exists. */
|
|
101
|
+
async ensureFavoriteDir(workspaceName) {
|
|
102
|
+
const root = resolve(this.getWorkspaceRoot(workspaceName));
|
|
103
|
+
const favoriteDir = join(root, '.favorite');
|
|
104
|
+
if (!existsSync(favoriteDir)) {
|
|
105
|
+
await mkdir(favoriteDir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
return favoriteDir;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Write buffer to workspace/.favorite/{filename}. Returns relative path (e.g. .favorite/xxx).
|
|
111
|
+
*/
|
|
112
|
+
async writeFileInFavorite(workspaceName, filename, buffer) {
|
|
113
|
+
const dir = await this.ensureFavoriteDir(workspaceName);
|
|
114
|
+
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 200) || 'download';
|
|
115
|
+
const absolutePath = join(dir, safeName);
|
|
116
|
+
await writeFile(absolutePath, buffer);
|
|
117
|
+
return `.favorite/${safeName}`;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Write buffer to a user-chosen directory. targetDir must be absolute and under homedir or workspace root.
|
|
121
|
+
* Returns the full path of the written file.
|
|
122
|
+
*/
|
|
123
|
+
async writeFileToDir(targetDir, filename, buffer) {
|
|
124
|
+
const home = homedir();
|
|
125
|
+
const workspaceRoot = getOpenbotWorkspaceDir();
|
|
126
|
+
const normalized = resolve(targetDir);
|
|
127
|
+
if (!normalized.startsWith(resolve(home)) && !normalized.startsWith(resolve(workspaceRoot))) {
|
|
128
|
+
throw new Error('Target directory must be under user home or workspace root');
|
|
129
|
+
}
|
|
130
|
+
if (!existsSync(normalized)) {
|
|
131
|
+
await mkdir(normalized, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 200) || 'download';
|
|
134
|
+
const absolutePath = join(normalized, safeName);
|
|
135
|
+
await writeFile(absolutePath, buffer);
|
|
136
|
+
return absolutePath;
|
|
137
|
+
}
|
|
99
138
|
};
|
|
100
139
|
WorkspaceService = __decorate([
|
|
101
140
|
Injectable()
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.6.8",
|
|
7
7
|
"description": "CLI and library to run prompts with skill paths (Agent Skills style). Use as npm package or openbot CLI.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "dist/index.js",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"openbot": "./dist/cli/cli.js"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@larksuiteoapi/node-sdk": "^1.59.0",
|
|
28
29
|
"@mariozechner/pi-ai": "^0.51.2",
|
|
29
30
|
"@mariozechner/pi-coding-agent": "^0.51.2",
|
|
30
31
|
"@nestjs/common": "^10.3.0",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"agent-browser": "^0.8.5",
|
|
38
39
|
"commander": "^14.0.2",
|
|
39
40
|
"croner": "^9.1.0",
|
|
41
|
+
"dingtalk-stream": "^2.1.4",
|
|
40
42
|
"multer": "^1.4.5-lts.1",
|
|
41
43
|
"reflect-metadata": "^0.2.1",
|
|
42
44
|
"rxjs": "^7.8.1",
|