@glodon-aiot/bot-client-sdk 3.26.0-alpha.4 → 3.26.0-alpha.5
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 +105 -76
- package/dist/es/Config.mjs +63 -85
- package/dist/es/builtinTools/browserRuntime/BrowserCommandRunner.mjs +201 -0
- package/dist/es/builtinTools/browserRuntime/PythonRunner.mjs +356 -0
- package/dist/es/builtinTools/browserRuntime/WorkspaceBashFs.mjs +350 -0
- package/dist/es/builtinTools/browserRuntime/assets.mjs +9 -0
- package/dist/es/builtinTools/browserRuntime/loadBash.mjs +17 -0
- package/dist/es/builtinTools/browserRuntime/pyodideRunner.py.mjs +96 -0
- package/dist/es/builtinTools/browserRuntime/pyodideWorker.mjs +242 -0
- package/dist/es/builtinTools/command.mjs +56 -0
- package/dist/es/builtinTools/constants.mjs +10 -0
- package/dist/es/builtinTools/createBuiltinToolsPlugin.mjs +236 -0
- package/dist/es/builtinTools/overview.mjs +77 -0
- package/dist/es/builtinTools/paths.mjs +63 -0
- package/dist/es/builtinTools/schemas.mjs +216 -0
- package/dist/es/builtinTools/tools.mjs +471 -0
- package/dist/es/index.mjs +49 -48
- package/dist/es/localFiles/adapters/FileSystemAccessAdapter.mjs +193 -103
- package/dist/es/localFiles/adapters/HostBridgeAdapter.mjs +138 -77
- package/dist/es/localFiles/adapters/MemoryWorkspaceAdapter.mjs +132 -97
- package/dist/es/localFiles/adapters/WorkspaceFileAdapter.mjs +32 -28
- package/dist/es/localFiles/constants.mjs +1 -1
- package/dist/es/localFiles/host/connectHostBridge.mjs +22 -18
- package/dist/es/localFiles/host/protocol.mjs +6 -5
- package/dist/es/localFiles/schemas.mjs +45 -60
- package/dist/es/localFiles/validate.mjs +37 -37
- package/dist/es/localFiles/workspace/LocalWorkspace.mjs +71 -52
- package/dist/es/package.json.mjs +33 -27
- package/dist/lib/index.js +372 -9
- package/dist/src/Config.d.ts +2 -2
- package/dist/src/builtinTools/browserRuntime/BrowserCommandRunner.d.ts +26 -0
- package/dist/src/builtinTools/browserRuntime/PythonRunner.d.ts +67 -0
- package/dist/src/builtinTools/browserRuntime/WorkspaceBashFs.d.ts +51 -0
- package/dist/src/builtinTools/browserRuntime/assets.d.ts +13 -0
- package/dist/src/builtinTools/browserRuntime/loadBash.d.ts +3 -0
- package/dist/src/builtinTools/browserRuntime/pyodideWorker.d.ts +44 -0
- package/dist/src/builtinTools/command.d.ts +26 -0
- package/dist/src/builtinTools/constants.d.ts +17 -0
- package/dist/src/builtinTools/createBuiltinToolsPlugin.d.ts +11 -0
- package/dist/src/builtinTools/overview.d.ts +5 -0
- package/dist/src/builtinTools/paths.d.ts +15 -0
- package/dist/src/builtinTools/schemas.d.ts +3 -0
- package/dist/src/builtinTools/tools.d.ts +60 -0
- package/dist/src/localFiles/adapters/FileSystemAccessAdapter.d.ts +4 -1
- package/dist/src/localFiles/adapters/HostBridgeAdapter.d.ts +20 -1
- package/dist/src/localFiles/adapters/MemoryWorkspaceAdapter.d.ts +4 -1
- package/dist/src/localFiles/adapters/WorkspaceFileAdapter.d.ts +14 -0
- package/dist/src/localFiles/adapters/fsaTypes.d.ts +2 -0
- package/dist/src/localFiles/constants.d.ts +2 -1
- package/dist/src/localFiles/host/protocol.d.ts +13 -0
- package/dist/src/localFiles/index.d.ts +3 -2
- package/dist/src/localFiles/schemas.d.ts +2 -3
- package/dist/src/localFiles/types.d.ts +14 -1
- package/dist/src/localFiles/workspace/LocalWorkspace.d.ts +12 -0
- package/package.json +8 -2
- package/dist/es/localFiles/createLocalPythonPlugin.mjs +0 -196
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
const e = `// Pyodide 专用 Worker。PythonRunner 用这份源码创建 Blob Module Worker,不经过集成方的打包器,
|
|
2
|
+
// 所以这里只能写浏览器直接能跑的 JS,不能有 import/export 语句和顶层 await。
|
|
3
|
+
//
|
|
4
|
+
// init { indexURL, packages, runner } → ready | failed { message }
|
|
5
|
+
// run { id, files, dirs, cwd, mode, target, argv, stdin } → result { id, exitCode, stdout, stderr, written, removed, createdDirs, removedDirs }
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const ROOTS = ['/workspace'];
|
|
9
|
+
const OUTPUT_LIMIT = 16 * 1024 * 1024;
|
|
10
|
+
|
|
11
|
+
let pyodide = null;
|
|
12
|
+
let runPython = null;
|
|
13
|
+
let sink = null;
|
|
14
|
+
|
|
15
|
+
/** Emscripten 的 ErrnoError 不是 Error,只带 errno 和 code。 */
|
|
16
|
+
function describe(error) {
|
|
17
|
+
if (error && error.message) return error.message;
|
|
18
|
+
if (error && (error.code || error.errno !== undefined)) return \`文件系统错误 \${error.code || \`errno \${error.errno}\`}\`;
|
|
19
|
+
return String(error);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function networkDenied(url) {
|
|
23
|
+
return new TypeError(\`浏览器里的 Python 不能访问网络:\${url}\`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 只放行 indexURL 下的资源(Pyodide 自身和白名单 wheel),其余请求一律拒绝。 */
|
|
27
|
+
function guardNetwork(indexURL) {
|
|
28
|
+
const realFetch = globalThis.fetch ? globalThis.fetch.bind(globalThis) : null;
|
|
29
|
+
const resolve = (input) => {
|
|
30
|
+
const raw = typeof input === 'string' || input instanceof URL ? String(input) : input && input.url;
|
|
31
|
+
try {
|
|
32
|
+
return new URL(raw, indexURL).href;
|
|
33
|
+
} catch {
|
|
34
|
+
return String(raw);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
globalThis.fetch = (input, init) => {
|
|
38
|
+
const url = resolve(input);
|
|
39
|
+
if (!realFetch || !url.startsWith(indexURL)) return Promise.reject(networkDenied(url));
|
|
40
|
+
return realFetch(input, init);
|
|
41
|
+
};
|
|
42
|
+
for (const name of ['XMLHttpRequest', 'WebSocket', 'EventSource']) {
|
|
43
|
+
globalThis[name] = class {
|
|
44
|
+
constructor(url) {
|
|
45
|
+
throw networkDenied(url === undefined ? name : resolve(url));
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function collector() {
|
|
52
|
+
const decoder = new TextDecoder();
|
|
53
|
+
let text = '';
|
|
54
|
+
let size = 0;
|
|
55
|
+
let dropped = false;
|
|
56
|
+
return {
|
|
57
|
+
write(bytes) {
|
|
58
|
+
if (dropped || size + bytes.length > OUTPUT_LIMIT) {
|
|
59
|
+
dropped = true;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
size += bytes.length;
|
|
63
|
+
text += decoder.decode(bytes, { stream: true });
|
|
64
|
+
},
|
|
65
|
+
finish() {
|
|
66
|
+
return text + decoder.decode() + (dropped ? '\\n…输出超过 16 MB,后面的内容已丢弃\\n' : '');
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function init({ indexURL, packages, runner }) {
|
|
72
|
+
guardNetwork(indexURL);
|
|
73
|
+
const { loadPyodide } = await import(indexURL + 'pyodide.mjs');
|
|
74
|
+
pyodide = await loadPyodide({ indexURL, env: { HOME: '/home/pyodide', MPLBACKEND: 'Agg' } });
|
|
75
|
+
const stream = (name) => ({
|
|
76
|
+
write(bytes) {
|
|
77
|
+
if (sink) sink[name].write(bytes);
|
|
78
|
+
return bytes.length;
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
pyodide.setStdout(stream('stdout'));
|
|
82
|
+
pyodide.setStderr(stream('stderr'));
|
|
83
|
+
runPython = pyodide.runPython(runner, { globals: pyodide.toPy({ PACKAGES: packages }) });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function dirname(path) {
|
|
87
|
+
const index = path.lastIndexOf('/');
|
|
88
|
+
return index <= 0 ? '/' : path.slice(0, index);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** 主脚本、\`-c\` 代码,以及主脚本目录和 cwd 下的 .py 文件里出现的 import。 */
|
|
92
|
+
function sourcesToScan({ files, cwd, mode, target }) {
|
|
93
|
+
const decoder = new TextDecoder();
|
|
94
|
+
const sources = mode === 'c' ? [target] : [];
|
|
95
|
+
const dirs = new Set([cwd]);
|
|
96
|
+
if (mode === 'file') dirs.add(dirname(target));
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
if (file.path.endsWith('.py') && (file.path === target || dirs.has(dirname(file.path)))) {
|
|
99
|
+
sources.push(decoder.decode(file.data));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return sources;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function loadPackages(sources, stderr) {
|
|
106
|
+
const encoder = new TextEncoder();
|
|
107
|
+
const report = (message) => stderr.write(encoder.encode(\`\${message}\\n\`));
|
|
108
|
+
for (const source of sources) {
|
|
109
|
+
try {
|
|
110
|
+
await pyodide.loadPackagesFromImports(source, { messageCallback() {}, errorCallback: report });
|
|
111
|
+
} catch (error) {
|
|
112
|
+
report(\`加载 Python 包失败:\${describe(error)}\`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function lstat(path) {
|
|
118
|
+
try {
|
|
119
|
+
return pyodide.FS.lstat(path);
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function removeTree(path) {
|
|
126
|
+
const { FS } = pyodide;
|
|
127
|
+
const stat = lstat(path);
|
|
128
|
+
if (!stat) return;
|
|
129
|
+
if (!FS.isDir(stat.mode)) {
|
|
130
|
+
FS.unlink(path);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const name of FS.readdir(path)) {
|
|
134
|
+
if (name !== '.' && name !== '..') removeTree(\`\${path}/\${name}\`);
|
|
135
|
+
}
|
|
136
|
+
FS.rmdir(path);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function walk(path, files, dirs) {
|
|
140
|
+
const { FS } = pyodide;
|
|
141
|
+
for (const name of FS.readdir(path)) {
|
|
142
|
+
if (name === '.' || name === '..') continue;
|
|
143
|
+
const child = \`\${path}/\${name}\`;
|
|
144
|
+
const stat = lstat(child);
|
|
145
|
+
if (!stat) continue;
|
|
146
|
+
if (FS.isDir(stat.mode)) {
|
|
147
|
+
dirs.add(child);
|
|
148
|
+
walk(child, files, dirs);
|
|
149
|
+
} else if (FS.isFile(stat.mode)) {
|
|
150
|
+
files.set(child, FS.readFile(child));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function sameBytes(a, b) {
|
|
156
|
+
if (a.length !== b.length) return false;
|
|
157
|
+
for (let index = 0; index < a.length; index += 1) if (a[index] !== b[index]) return false;
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function execute(message) {
|
|
162
|
+
const { FS } = pyodide;
|
|
163
|
+
const output = { stdout: collector(), stderr: collector() };
|
|
164
|
+
await loadPackages(sourcesToScan(message), output.stderr);
|
|
165
|
+
|
|
166
|
+
const before = new Map();
|
|
167
|
+
const beforeDirs = new Set(ROOTS);
|
|
168
|
+
// 上次运行停在某个根目录里时,Emscripten 不允许删除当前目录。
|
|
169
|
+
FS.chdir('/');
|
|
170
|
+
for (const root of ROOTS) {
|
|
171
|
+
removeTree(root);
|
|
172
|
+
FS.mkdirTree(root);
|
|
173
|
+
}
|
|
174
|
+
for (const dir of message.dirs) {
|
|
175
|
+
FS.mkdirTree(dir);
|
|
176
|
+
beforeDirs.add(dir);
|
|
177
|
+
}
|
|
178
|
+
for (const file of message.files) {
|
|
179
|
+
FS.mkdirTree(dirname(file.path));
|
|
180
|
+
FS.writeFile(file.path, file.data);
|
|
181
|
+
before.set(file.path, file.data);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
sink = output;
|
|
185
|
+
let exitCode;
|
|
186
|
+
const argv = pyodide.toPy(message.argv);
|
|
187
|
+
try {
|
|
188
|
+
exitCode = runPython(message.mode, message.target, argv, message.cwd, message.stdin);
|
|
189
|
+
} finally {
|
|
190
|
+
argv.destroy();
|
|
191
|
+
sink = null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const after = new Map();
|
|
195
|
+
const afterDirs = new Set();
|
|
196
|
+
for (const root of ROOTS) if (lstat(root)) walk(root, after, afterDirs);
|
|
197
|
+
|
|
198
|
+
const written = [];
|
|
199
|
+
for (const [path, data] of after) {
|
|
200
|
+
const old = before.get(path);
|
|
201
|
+
if (!old || !sameBytes(old, data)) written.push({ path, data });
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
exitCode,
|
|
205
|
+
stdout: output.stdout.finish(),
|
|
206
|
+
stderr: output.stderr.finish(),
|
|
207
|
+
written,
|
|
208
|
+
removed: [...before.keys()].filter((path) => !after.has(path)),
|
|
209
|
+
createdDirs: [...afterDirs].filter((dir) => !beforeDirs.has(dir)),
|
|
210
|
+
removedDirs: [...beforeDirs].filter((dir) => !ROOTS.includes(dir) && !afterDirs.has(dir)),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
self.onmessage = (event) => {
|
|
215
|
+
const message = event.data;
|
|
216
|
+
if (message.type === 'init') {
|
|
217
|
+
init(message).then(
|
|
218
|
+
() => self.postMessage({ type: 'ready' }),
|
|
219
|
+
(error) => self.postMessage({ type: 'failed', message: describe(error) })
|
|
220
|
+
);
|
|
221
|
+
} else if (message.type === 'run') {
|
|
222
|
+
execute(message).then(
|
|
223
|
+
(result) => self.postMessage({ type: 'result', id: message.id, ...result }),
|
|
224
|
+
(error) =>
|
|
225
|
+
self.postMessage({
|
|
226
|
+
type: 'result',
|
|
227
|
+
id: message.id,
|
|
228
|
+
exitCode: 1,
|
|
229
|
+
stdout: '',
|
|
230
|
+
stderr: \`Python 运行环境出错:\${describe(error)}\\n\`,
|
|
231
|
+
written: [],
|
|
232
|
+
removed: [],
|
|
233
|
+
createdDirs: [],
|
|
234
|
+
removedDirs: [],
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
`;
|
|
240
|
+
export {
|
|
241
|
+
e as default
|
|
242
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var d = Object.defineProperty, l = Object.defineProperties;
|
|
2
|
+
var N = Object.getOwnPropertyDescriptors;
|
|
3
|
+
var s = Object.getOwnPropertySymbols;
|
|
4
|
+
var a = Object.prototype.hasOwnProperty, f = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var A = (e, n, t) => n in e ? d(e, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[n] = t, T = (e, n) => {
|
|
6
|
+
for (var t in n || (n = {}))
|
|
7
|
+
a.call(n, t) && A(e, t, n[t]);
|
|
8
|
+
if (s)
|
|
9
|
+
for (var t of s(n))
|
|
10
|
+
f.call(n, t) && A(e, t, n[t]);
|
|
11
|
+
return e;
|
|
12
|
+
}, _ = (e, n) => l(e, N(n));
|
|
13
|
+
var O = (e, n, t) => new Promise((u, o) => {
|
|
14
|
+
var U = (r) => {
|
|
15
|
+
try {
|
|
16
|
+
c(t.next(r));
|
|
17
|
+
} catch (i) {
|
|
18
|
+
o(i);
|
|
19
|
+
}
|
|
20
|
+
}, C = (r) => {
|
|
21
|
+
try {
|
|
22
|
+
c(t.throw(r));
|
|
23
|
+
} catch (i) {
|
|
24
|
+
o(i);
|
|
25
|
+
}
|
|
26
|
+
}, c = (r) => r.done ? u(r.value) : Promise.resolve(r.value).then(U, C);
|
|
27
|
+
c((t = t.apply(e, n)).next());
|
|
28
|
+
});
|
|
29
|
+
const R = 16e3, D = `
|
|
30
|
+
…输出已截断`;
|
|
31
|
+
function M(e) {
|
|
32
|
+
if (e.length <= 16e3)
|
|
33
|
+
return e;
|
|
34
|
+
let n = 16e3;
|
|
35
|
+
const t = e.charCodeAt(n - 1);
|
|
36
|
+
return t >= 55296 && t <= 56319 && (n -= 1), e.slice(0, n) + D;
|
|
37
|
+
}
|
|
38
|
+
function h(e) {
|
|
39
|
+
return {
|
|
40
|
+
exec(t) {
|
|
41
|
+
return O(this, null, function* () {
|
|
42
|
+
const u = yield e.exec(t);
|
|
43
|
+
return _(T({}, u), {
|
|
44
|
+
stdout: M(u.stdout),
|
|
45
|
+
stderr: M(u.stderr)
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
R as MAX_COMMAND_OUTPUT_CHARS,
|
|
53
|
+
D as OUTPUT_TRUNCATED_NOTE,
|
|
54
|
+
M as limitOutput,
|
|
55
|
+
h as withOutputLimit
|
|
56
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const _ = ["shell", "read_file", "write_file", "append_file", "run_file", "edit_file", "grep", "find", "load_skill", "read_skill_resource", "run_skill_script"], e = 81920, s = 81920, l = 2e4, i = ".", n = "/workspace", o = [".py", ".sh", ".js"];
|
|
2
|
+
export {
|
|
3
|
+
_ as BUILTIN_FUNCTION_CODES,
|
|
4
|
+
l as MAX_COMMAND_CHARS,
|
|
5
|
+
e as MAX_READ_BYTES,
|
|
6
|
+
s as MAX_WRITE_BYTES,
|
|
7
|
+
o as RUNNABLE_EXTENSIONS,
|
|
8
|
+
i as SHELL_CWD,
|
|
9
|
+
n as WORKSPACE_MOUNT
|
|
10
|
+
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
var G = Object.defineProperty, K = Object.defineProperties;
|
|
2
|
+
var W = Object.getOwnPropertyDescriptors;
|
|
3
|
+
var D = Object.getOwnPropertySymbols;
|
|
4
|
+
var X = Object.prototype.hasOwnProperty, Q = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var P = (e, t, o) => t in e ? G(e, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : e[t] = o, s = (e, t) => {
|
|
6
|
+
for (var o in t || (t = {}))
|
|
7
|
+
X.call(t, o) && P(e, o, t[o]);
|
|
8
|
+
if (D)
|
|
9
|
+
for (var o of D(t))
|
|
10
|
+
Q.call(t, o) && P(e, o, t[o]);
|
|
11
|
+
return e;
|
|
12
|
+
}, h = (e, t) => K(e, W(t));
|
|
13
|
+
var U = (e, t, o) => new Promise((l, u) => {
|
|
14
|
+
var m = (n) => {
|
|
15
|
+
try {
|
|
16
|
+
d(o.next(n));
|
|
17
|
+
} catch (r) {
|
|
18
|
+
u(r);
|
|
19
|
+
}
|
|
20
|
+
}, c = (n) => {
|
|
21
|
+
try {
|
|
22
|
+
d(o.throw(n));
|
|
23
|
+
} catch (r) {
|
|
24
|
+
u(r);
|
|
25
|
+
}
|
|
26
|
+
}, d = (n) => n.done ? l(n.value) : Promise.resolve(n.value).then(m, c);
|
|
27
|
+
d((o = o.apply(e, t)).next());
|
|
28
|
+
});
|
|
29
|
+
import { v4 as Y } from "uuid";
|
|
30
|
+
import Z from "../Logger.mjs";
|
|
31
|
+
import { HostBridgeAdapter as k } from "../localFiles/adapters/HostBridgeAdapter.mjs";
|
|
32
|
+
import { SANDBOX_PROTOCOL as ee } from "../localFiles/host/protocol.mjs";
|
|
33
|
+
import { cancelledError as w, workspaceNotGranted as te, ToolError as f, ToolCode as a, toToolError as oe } from "../localFiles/errors.mjs";
|
|
34
|
+
import { validateToolInput as ne } from "../localFiles/validate.mjs";
|
|
35
|
+
import { BrowserCommandRunner as re } from "./browserRuntime/BrowserCommandRunner.mjs";
|
|
36
|
+
import { withOutputLimit as E } from "./command.mjs";
|
|
37
|
+
import { BUILTIN_FUNCTION_CODES as ie, SHELL_CWD as se } from "./constants.mjs";
|
|
38
|
+
import { BUILTIN_TOOL_SCHEMAS as le } from "./schemas.mjs";
|
|
39
|
+
import { shell as ae, readFile as de, writeFile as ce, appendFile as ue, runFile as me, editFile as fe, grep as ge, find as he, loadSkill as _e, readSkillResource as be, runSkillScript as ye } from "./tools.mjs";
|
|
40
|
+
const Te = {
|
|
41
|
+
shell: ae,
|
|
42
|
+
read_file: de,
|
|
43
|
+
write_file: ce,
|
|
44
|
+
append_file: ue,
|
|
45
|
+
run_file: me,
|
|
46
|
+
edit_file: fe,
|
|
47
|
+
grep: ge,
|
|
48
|
+
find: he,
|
|
49
|
+
load_skill: _e,
|
|
50
|
+
read_skill_resource: be,
|
|
51
|
+
run_skill_script: ye
|
|
52
|
+
}, T = new Z("[BuiltinTools] "), H = /* @__PURE__ */ new Set(["shell", "run_file", "run_skill_script"]);
|
|
53
|
+
function we(e, t, o) {
|
|
54
|
+
var l, u;
|
|
55
|
+
if (e.commandRunner)
|
|
56
|
+
return E(e.commandRunner);
|
|
57
|
+
if (t instanceof k && t.capabilities.has("sandbox-exec")) {
|
|
58
|
+
if (t.canExec)
|
|
59
|
+
return E({
|
|
60
|
+
exec: (c) => t.exec(c)
|
|
61
|
+
});
|
|
62
|
+
const m = `${(l = t.sandboxVersion) != null ? l : ""}@${(u = t.sandboxProtocol) != null ? u : ""}`;
|
|
63
|
+
o.rejectedSandbox !== m && (o.rejectedSandbox = m, T.error("sandbox-protocol", {
|
|
64
|
+
sandboxVersion: t.sandboxVersion,
|
|
65
|
+
sandboxProtocol: t.sandboxProtocol,
|
|
66
|
+
supported: ee
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
if (e.browserRuntime.enabled)
|
|
70
|
+
return (o.adapter !== t || !o.runner) && (o.adapter = t, o.runner = E(new re({
|
|
71
|
+
adapter: t,
|
|
72
|
+
sensitive: e.sensitive,
|
|
73
|
+
moduleURL: e.browserRuntime.bashModuleURL,
|
|
74
|
+
pyodideIndexURL: e.browserRuntime.pyodideIndexURL
|
|
75
|
+
}))), o.runner;
|
|
76
|
+
}
|
|
77
|
+
function pe(e) {
|
|
78
|
+
if (typeof e != "string")
|
|
79
|
+
return e;
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(e);
|
|
82
|
+
} catch (t) {
|
|
83
|
+
throw new f(a.BadRequest, "参数不是合法的 JSON 对象。");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function xe(e) {
|
|
87
|
+
const t = e instanceof DOMException ? e.name : "", o = e instanceof Error ? e.message : "";
|
|
88
|
+
if (t === "NotFoundError")
|
|
89
|
+
return new f(a.NotFound, "脚本或目录不存在。");
|
|
90
|
+
if (t === "SecurityError")
|
|
91
|
+
return new f(a.Forbidden, "命令路径不在工作区内。");
|
|
92
|
+
if (t === "AbortError")
|
|
93
|
+
return o.includes("超时") ? new f(a.Timeout, "命令运行超时,已中止。") : o.includes("已有") ? new f(a.TooManyRequests, "已有一个命令在运行。") : w();
|
|
94
|
+
if (t === "NotAllowedError")
|
|
95
|
+
return new f(a.NotImplemented, "当前环境不能执行命令或脚本,需要端侧宿主。");
|
|
96
|
+
}
|
|
97
|
+
function Ie(e) {
|
|
98
|
+
return new Promise((t, o) => {
|
|
99
|
+
e.aborted && o(w()), e.addEventListener("abort", () => o(w()), {
|
|
100
|
+
once: !0
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function V(e, t = 160) {
|
|
105
|
+
return e.length > t ? `${e.slice(0, t)}…` : e;
|
|
106
|
+
}
|
|
107
|
+
function Oe(e) {
|
|
108
|
+
const t = {};
|
|
109
|
+
for (const o of ["path", "skill_name", "resource_name", "script_name", "pattern", "name"])
|
|
110
|
+
typeof e[o] == "string" && (t[o] = e[o]);
|
|
111
|
+
return typeof e.command == "string" && (t.command = V(e.command)), typeof e.start_line == "number" && (t.start_line = e.start_line), typeof e.end_line == "number" && (t.end_line = e.end_line), typeof e.content == "string" && (t.contentLength = e.content.length), typeof e.old_text == "string" && (t.oldTextLength = e.old_text.length), typeof e.new_text == "string" && (t.newTextLength = e.new_text.length), Array.isArray(e.args) && (t.argCount = e.args.length), t;
|
|
112
|
+
}
|
|
113
|
+
function Le(e) {
|
|
114
|
+
return s({
|
|
115
|
+
code: e.code,
|
|
116
|
+
message: e.message
|
|
117
|
+
}, e.data ? {
|
|
118
|
+
data: e.data
|
|
119
|
+
} : {});
|
|
120
|
+
}
|
|
121
|
+
function Ue({
|
|
122
|
+
pluginCode: e,
|
|
123
|
+
workspace: t
|
|
124
|
+
}) {
|
|
125
|
+
const o = /* @__PURE__ */ new Map(), l = {}, u = {};
|
|
126
|
+
return ie.forEach((m) => {
|
|
127
|
+
u[m] = (c, d, n) => {
|
|
128
|
+
let r = !1;
|
|
129
|
+
Se(t, o, l, m, c, (S) => {
|
|
130
|
+
if (!r) {
|
|
131
|
+
r = !0;
|
|
132
|
+
try {
|
|
133
|
+
d(S);
|
|
134
|
+
} catch (x) {
|
|
135
|
+
console.error("[BuiltinTools] callback failed", x);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}, h(s({}, n), {
|
|
139
|
+
pluginCode: e
|
|
140
|
+
}));
|
|
141
|
+
};
|
|
142
|
+
}), {
|
|
143
|
+
[e]: u
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function Se(e, t, o, l, u, m, c) {
|
|
147
|
+
return U(this, null, function* () {
|
|
148
|
+
var N, F, M, A, q;
|
|
149
|
+
const d = {
|
|
150
|
+
requestId: c.requestId || Y(),
|
|
151
|
+
applicationId: c.applicationId || e.applicationId,
|
|
152
|
+
sessionId: c.sessionId || "",
|
|
153
|
+
pluginCode: c.pluginCode,
|
|
154
|
+
functionCode: l,
|
|
155
|
+
signal: c.signal
|
|
156
|
+
}, n = {
|
|
157
|
+
requestId: d.requestId,
|
|
158
|
+
sessionId: d.sessionId,
|
|
159
|
+
functionCode: l
|
|
160
|
+
}, r = new AbortController();
|
|
161
|
+
let p = !1;
|
|
162
|
+
const S = setTimeout(() => {
|
|
163
|
+
p = !0, r.abort();
|
|
164
|
+
}, e.limits.toolTimeoutMs), x = () => r.abort();
|
|
165
|
+
(N = d.signal) == null || N.addEventListener("abort", x, {
|
|
166
|
+
once: !0
|
|
167
|
+
}), (F = d.signal) != null && F.aborted && r.abort();
|
|
168
|
+
let b = null, y = null, I;
|
|
169
|
+
const R = Date.now();
|
|
170
|
+
try {
|
|
171
|
+
const O = pe(u), i = ne(O, le[l].parameters);
|
|
172
|
+
if (typeof i.path == "string" && (n.path = i.path), T.log("start", s(s({}, n), Oe(i))), yield e.ready, r.signal.aborted)
|
|
173
|
+
throw w();
|
|
174
|
+
const _ = e.adapter;
|
|
175
|
+
if (!_)
|
|
176
|
+
throw te();
|
|
177
|
+
if (b = e.acquireSlot(), !b)
|
|
178
|
+
throw new f(a.TooManyRequests, "同时进行的文件操作过多,请稍后重试。");
|
|
179
|
+
if (H.has(l) && (y = e.acquireCommand(), !y))
|
|
180
|
+
throw new f(a.TooManyRequests, "已有一个命令在运行,请等它结束后再试。");
|
|
181
|
+
I = e.track(r), e.emit("tool:start", s({}, n));
|
|
182
|
+
const v = d.sessionId || "default";
|
|
183
|
+
let g = t.get(v);
|
|
184
|
+
g || (g = {
|
|
185
|
+
cwd: se
|
|
186
|
+
}, t.set(v, g));
|
|
187
|
+
const $ = we(e, _, o), j = g.cwd, J = {
|
|
188
|
+
adapter: _,
|
|
189
|
+
runner: $,
|
|
190
|
+
signal: r.signal,
|
|
191
|
+
timeoutMs: e.limits.toolTimeoutMs,
|
|
192
|
+
shellCwd: g
|
|
193
|
+
}, L = yield Promise.race([Te[l](i, J), Ie(r.signal)]), B = {
|
|
194
|
+
code: a.Ok,
|
|
195
|
+
message: "ok",
|
|
196
|
+
data: L.data
|
|
197
|
+
};
|
|
198
|
+
L.truncated && (B.truncated = !0);
|
|
199
|
+
const z = Date.now() - R, C = L.data.exitCode;
|
|
200
|
+
T.log("finish", s(s(s(h(s({}, n), {
|
|
201
|
+
elapsedMs: z,
|
|
202
|
+
code: a.Ok
|
|
203
|
+
}), L.truncated ? {
|
|
204
|
+
truncated: !0
|
|
205
|
+
} : {}), typeof C == "number" ? {
|
|
206
|
+
exitCode: C
|
|
207
|
+
} : {}), l === "shell" ? {
|
|
208
|
+
cwd: g.cwd,
|
|
209
|
+
cwdChanged: g.cwd !== j
|
|
210
|
+
} : {})), e.emit("tool:finish", h(s({}, n), {
|
|
211
|
+
code: a.Ok
|
|
212
|
+
})), H.has(l) && e.notifyFilesChanged(), m(B);
|
|
213
|
+
} catch (O) {
|
|
214
|
+
let i = (M = xe(O)) != null ? M : oe(O);
|
|
215
|
+
p ? i = new f(a.Timeout, "操作超时,已中止。") : r.signal.aborted && i.code !== a.Cancelled && (i = w());
|
|
216
|
+
const _ = Date.now() - R;
|
|
217
|
+
i.code === a.Cancelled ? (T.log("cancelled", h(s({}, n), {
|
|
218
|
+
elapsedMs: _,
|
|
219
|
+
timedOut: p
|
|
220
|
+
})), e.emit("tool:cancelled", s({}, n))) : (T.error("error", h(s({}, n), {
|
|
221
|
+
elapsedMs: _,
|
|
222
|
+
code: i.code,
|
|
223
|
+
message: V(i.message, 300)
|
|
224
|
+
})), e.emit("tool:error", h(s({}, n), {
|
|
225
|
+
code: i.code,
|
|
226
|
+
message: i.message,
|
|
227
|
+
reason: (A = i.data) == null ? void 0 : A.reason
|
|
228
|
+
}))), m(Le(i));
|
|
229
|
+
} finally {
|
|
230
|
+
clearTimeout(S), (q = d.signal) == null || q.removeEventListener("abort", x), b == null || b(), y == null || y(), I == null || I();
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
export {
|
|
235
|
+
Ue as createBuiltinToolsPlugin
|
|
236
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function c(r) {
|
|
2
|
+
return `预览:
|
|
3
|
+
${r.length > 500 ? r.slice(0, 500) : r}`;
|
|
4
|
+
}
|
|
5
|
+
function O(r) {
|
|
6
|
+
let n;
|
|
7
|
+
try {
|
|
8
|
+
n = JSON.parse(r);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
return `JSON 无法完整解析。
|
|
11
|
+
${c(r)}`;
|
|
12
|
+
}
|
|
13
|
+
if (Array.isArray(n)) {
|
|
14
|
+
const e = n[0], t = e && typeof e == "object" && !Array.isArray(e) ? `元素字段:${Object.keys(e).slice(0, 20).join(", ") || "(无)"}。` : `元素类型:${e === null ? "null" : typeof e}。`;
|
|
15
|
+
return `JSON 数组,长度 ${n.length}。${t}
|
|
16
|
+
${c(r)}`;
|
|
17
|
+
}
|
|
18
|
+
if (n && typeof n == "object") {
|
|
19
|
+
const e = n, t = Object.keys(e), s = t.filter((i) => Array.isArray(e[i])).slice(0, 10).map((i) => `${i} (${e[i].length})`), o = s.length ? `数组字段:${s.join("、")}。` : "";
|
|
20
|
+
return `JSON 对象。字段:${t.slice(0, 40).join(", ") || "(无)"}。${o}
|
|
21
|
+
${c(r)}`;
|
|
22
|
+
}
|
|
23
|
+
return `JSON ${n === null ? "null" : typeof n}。
|
|
24
|
+
${c(r)}`;
|
|
25
|
+
}
|
|
26
|
+
function h(r, n) {
|
|
27
|
+
var a, p;
|
|
28
|
+
const e = r.match(/<([A-Za-z_][\w:.-]*)\b/), t = (a = e == null ? void 0 : e[1]) != null ? a : "未知", s = /* @__PURE__ */ new Map(), o = new RegExp("<([A-Za-z_][\\w:.-]*)\\b", "g");
|
|
29
|
+
let i, u = !1;
|
|
30
|
+
for (; i = o.exec(r); ) {
|
|
31
|
+
const l = i[1];
|
|
32
|
+
if (!u && l === t) {
|
|
33
|
+
u = !0;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (s.set(l, ((p = s.get(l)) != null ? p : 0) + 1), s.size > 30)
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
const f = Array.from(s.entries()).slice(0, 20).map(([l, v]) => `${l} (${v})`).join("、");
|
|
40
|
+
return `${n} 根元素 ${t}。直接或嵌套子元素:${f || "(无)"}。
|
|
41
|
+
${c(r)}`;
|
|
42
|
+
}
|
|
43
|
+
function g(r, n, e) {
|
|
44
|
+
var f;
|
|
45
|
+
const t = r.split(/\r?\n/).filter((a) => a.length > 0), s = (f = t[0]) != null ? f : "", o = s ? s.split(n).length : 0, i = Math.max(t.length - 1, 0), u = t.slice(0, 4).join(`
|
|
46
|
+
`);
|
|
47
|
+
return `${e},${o} 列,数据行 ${i}。表头:${s}
|
|
48
|
+
预览:
|
|
49
|
+
${u}`;
|
|
50
|
+
}
|
|
51
|
+
function j(r) {
|
|
52
|
+
const n = $(r);
|
|
53
|
+
return n === ".json" || n === ".xml" || n === ".svg" || n === ".csv" || n === ".tsv";
|
|
54
|
+
}
|
|
55
|
+
function m(r, n) {
|
|
56
|
+
const e = $(r);
|
|
57
|
+
return e === ".json" ? O(n) : e === ".svg" ? h(n, "SVG") : e === ".xml" ? h(n, "XML") : e === ".tsv" ? g(n, " ", "TSV") : e === ".csv" ? g(n, ",", "CSV") : c(n);
|
|
58
|
+
}
|
|
59
|
+
function $(r) {
|
|
60
|
+
var t;
|
|
61
|
+
const n = (t = r.split("/").pop()) != null ? t : "", e = n.lastIndexOf(".");
|
|
62
|
+
return e >= 0 ? n.slice(e).toLowerCase() : "";
|
|
63
|
+
}
|
|
64
|
+
const S = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".ico", ".tif", ".tiff"]);
|
|
65
|
+
function w(r) {
|
|
66
|
+
return S.has($(r));
|
|
67
|
+
}
|
|
68
|
+
function A(r, n) {
|
|
69
|
+
return $(r) === ".pdf" ? !0 : !n || n.byteLength < 4 ? !1 : n[0] === 37 && n[1] === 80 && n[2] === 68 && n[3] === 70;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
$ as extensionOf,
|
|
73
|
+
w as isImagePath,
|
|
74
|
+
A as isPdf,
|
|
75
|
+
j as isStructuredPath,
|
|
76
|
+
m as structureOverview
|
|
77
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ToolError as o, ToolCode as i } from "../localFiles/errors.mjs";
|
|
2
|
+
const l = ["input", "output", "uploads", "tmp"], h = "不要使用 input、output、uploads、tmp,也不要新建这些目录。请把文件直接放在工作区已有位置或根目录。", c = /(?:^|[\s'"=;|&<>`:])\/?(?:input|output|uploads|tmp)(?=\/|[\s'"=;|&<>`:]|$)/;
|
|
3
|
+
function d(t) {
|
|
4
|
+
return c.test(t);
|
|
5
|
+
}
|
|
6
|
+
function u(t) {
|
|
7
|
+
const n = t.split("/")[0];
|
|
8
|
+
return l.includes(n);
|
|
9
|
+
}
|
|
10
|
+
function r(t) {
|
|
11
|
+
throw new o(i.Forbidden, t, {
|
|
12
|
+
reason: "path_outside_workspace"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function f(t) {
|
|
16
|
+
if (typeof t != "string" || t.length === 0)
|
|
17
|
+
throw new o(i.BadRequest, "path 必须是工作区内绝对路径。");
|
|
18
|
+
(t.includes("\0") || t.includes("\\")) && r("路径不能包含反斜杠。");
|
|
19
|
+
const n = t.normalize("NFC").trim();
|
|
20
|
+
if (!n.startsWith("/"))
|
|
21
|
+
throw new o(i.BadRequest, "path 必须是工作区内绝对路径,例如 /说明.md。");
|
|
22
|
+
const e = n.split("/").filter((s) => s.length > 0);
|
|
23
|
+
if (e.some((s) => s === "." || s === "..") && r("路径不能包含 . 或 .. 。"), e.length > 0 && u(e[0]))
|
|
24
|
+
throw new o(i.BadRequest, h);
|
|
25
|
+
return e.join("/");
|
|
26
|
+
}
|
|
27
|
+
function a(t) {
|
|
28
|
+
return f(t);
|
|
29
|
+
}
|
|
30
|
+
function w(t) {
|
|
31
|
+
return f(t);
|
|
32
|
+
}
|
|
33
|
+
function R(t) {
|
|
34
|
+
return t ? `/${t}` : "/";
|
|
35
|
+
}
|
|
36
|
+
function S(t) {
|
|
37
|
+
if (t === ".")
|
|
38
|
+
return !0;
|
|
39
|
+
if (!t || t.startsWith("/") || t.includes("\\") || t.includes("\0"))
|
|
40
|
+
return !1;
|
|
41
|
+
const n = t.split("/").filter((e) => e.length > 0);
|
|
42
|
+
return n.length > 0 && n.every((e) => e !== "." && e !== "..") && !u(n[0]);
|
|
43
|
+
}
|
|
44
|
+
function g(t, n) {
|
|
45
|
+
if (!t || /[\\/\0]/.test(t) || t === "." || t === "..")
|
|
46
|
+
throw new o(i.BadRequest, "skill_name 必须是单个技能目录名。");
|
|
47
|
+
if (!n || n.startsWith("/") || n.includes("\\") || n.includes("\0"))
|
|
48
|
+
throw new o(i.BadRequest, "资源路径必须是技能目录内的相对路径。");
|
|
49
|
+
const e = n.split("/").filter((s) => s.length > 0);
|
|
50
|
+
return (e.length === 0 || e.some((s) => s === "." || s === "..")) && r("资源路径不能跳出技能目录。"), `skills/${t}/${e.join("/")}`;
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
l as SYNTHETIC_DIRS,
|
|
54
|
+
h as SYNTHETIC_DIR_MESSAGE,
|
|
55
|
+
S as isSafeCwd,
|
|
56
|
+
u as isSyntheticCwd,
|
|
57
|
+
d as mentionsSyntheticDir,
|
|
58
|
+
a as resolveFilePath,
|
|
59
|
+
w as resolveRunPath,
|
|
60
|
+
f as resolveWorkspacePath,
|
|
61
|
+
g as skillRelative,
|
|
62
|
+
R as toVirtualPath
|
|
63
|
+
};
|