@roll-agent/octopus-agent 0.0.4 → 0.0.6
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 +7 -4
- package/SKILL.md +4 -4
- package/bin/check-python.js +117 -0
- package/bin/start-roll-server.js +109 -0
- package/package.json +8 -5
- package/pyproject.toml +2 -2
- package/src/octopus_sponge_skill/__init__.py +1 -1
- package/src/octopus_sponge_skill/_version.py +1 -1
- package/src/octopus_sponge_skill/agent.py +236 -31
- package/src/octopus_sponge_skill/config.py +8 -1
- package/src/octopus_sponge_skill/prompt_builder.py +10 -1
- package/src/octopus_sponge_skill/roll_server.py +3 -3
- package/src/octopus_sponge_skill/schema_context_retriever.py +62 -2
- package/src/octopus_sponge_skill/sql_generator.py +359 -29
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Octopus
|
|
1
|
+
# 丸子Agent(Octopus Agent)
|
|
2
2
|
|
|
3
3
|
本仓库实现 Octopus 对接 Sponge MCP Server 的第一版 MVP。
|
|
4
4
|
|
|
@@ -32,7 +32,8 @@ roll run octopus-agent diagnostic_status --json
|
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
该 npm package(npm 包)直接包含 Python 源码;`roll agent install` 不会再从 PyPI 下载 `octopus-sponge-skill`。
|
|
35
|
-
|
|
35
|
+
安装机器需要 Python 3.11+。Windows 默认检查 `python --version`,macOS/Linux 默认检查 `python3 --version`。
|
|
36
|
+
安装阶段会执行 Python 环境检查;没有 Python 3.11+ 时,Windows 会尝试通过 winget 自动安装,macOS 会尝试通过 Homebrew 自动安装,Linux 会提示手动安装。
|
|
36
37
|
|
|
37
38
|
### 本地源码注册
|
|
38
39
|
|
|
@@ -83,13 +84,15 @@ roll run octopus-agent query_sponge --json \
|
|
|
83
84
|
"rollAgent": {
|
|
84
85
|
"runtime": {"ownership": "on-demand", "transport": "stdio"},
|
|
85
86
|
"start": {
|
|
86
|
-
"command": "
|
|
87
|
-
"args": ["-
|
|
87
|
+
"command": "node",
|
|
88
|
+
"args": ["bin/start-roll-server.js"]
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
```
|
|
92
93
|
|
|
94
|
+
`start-roll-server.js` 会按系统选择 Python 命令:Windows 优先 `python`,macOS/Linux 优先 `python3`;都不可用或版本低于 3.11 时会报错提示安装。
|
|
95
|
+
|
|
93
96
|
环境变量可放到 `roll.config.yaml`:
|
|
94
97
|
|
|
95
98
|
```yaml
|
package/SKILL.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: octopus-agent
|
|
3
|
-
description: Octopus
|
|
3
|
+
description: 丸子Agent(Octopus Agent),把自然语言问题转换为只读 SQL,并通过 Sponge MCP Server 校验和执行。
|
|
4
4
|
metadata:
|
|
5
5
|
roll-env-file: references/env.yaml
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# Octopus
|
|
8
|
+
# 丸子Agent(Octopus Agent)
|
|
9
9
|
|
|
10
10
|
## 职责
|
|
11
11
|
|
|
12
|
-
本 Agent
|
|
12
|
+
本 Agent 只负责海绵数据查询:
|
|
13
13
|
|
|
14
14
|
- 读取和刷新 Schema Cache(表结构缓存)。
|
|
15
15
|
- 基于用户问题和 schema context,通过 MCP Sampling(采样)请求 roll-core 代调 LLM 生成只读 SQL。
|
|
@@ -22,7 +22,7 @@ metadata:
|
|
|
22
22
|
|-|-|-|
|
|
23
23
|
| `diagnostic_status` | 诊断状态 | 检查配置、缓存和日志路径 |
|
|
24
24
|
| `refresh_schema` | 刷新表结构 | 人工刷新本地 schema 缓存 |
|
|
25
|
-
| `query_sponge` |
|
|
25
|
+
| `query_sponge` | 查询海绵数据 | 自然语言查询入口 |
|
|
26
26
|
|
|
27
27
|
`refresh_schema` 必填 `traceId`;Agent 会自动读取本地缓存里的 `schemaVersion` 并传给 Sponge。
|
|
28
28
|
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
const MIN_VERSION = [3, 11, 0];
|
|
6
|
+
|
|
7
|
+
function pythonCandidates() {
|
|
8
|
+
if (process.platform === "win32") {
|
|
9
|
+
return [["python"], ["python3"]];
|
|
10
|
+
}
|
|
11
|
+
return [["python3"], ["python"]];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseVersion(output) {
|
|
15
|
+
const match = String(output).match(/Python\s+(\d+)\.(\d+)\.(\d+)/);
|
|
16
|
+
if (!match) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return match.slice(1).map((part) => Number(part));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function versionLabel(version) {
|
|
23
|
+
return version.join(".");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isSupported(version) {
|
|
27
|
+
for (let index = 0; index < MIN_VERSION.length; index += 1) {
|
|
28
|
+
if (version[index] > MIN_VERSION[index]) return true;
|
|
29
|
+
if (version[index] < MIN_VERSION[index]) return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function commandLabel(command) {
|
|
35
|
+
return command.join(" ");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function run(command, args, options = {}) {
|
|
39
|
+
return spawnSync(command[0], [...command.slice(1), ...args], {
|
|
40
|
+
encoding: "utf8",
|
|
41
|
+
stdio: options.stdio || ["ignore", "pipe", "pipe"],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function findPython() {
|
|
46
|
+
const checked = [];
|
|
47
|
+
for (const command of pythonCandidates()) {
|
|
48
|
+
const result = run(command, ["--version"]);
|
|
49
|
+
const output = `${result.stdout || ""}${result.stderr || ""}`;
|
|
50
|
+
const version = parseVersion(output);
|
|
51
|
+
if (result.status === 0 && version && isSupported(version)) {
|
|
52
|
+
return { command, version, checked };
|
|
53
|
+
}
|
|
54
|
+
checked.push({
|
|
55
|
+
command,
|
|
56
|
+
reason: version
|
|
57
|
+
? `当前版本 ${versionLabel(version)},需要 ${versionLabel(MIN_VERSION)}+`
|
|
58
|
+
: "未找到或无法读取版本",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return { command: null, version: null, checked };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function installPython() {
|
|
65
|
+
if (process.platform === "win32") {
|
|
66
|
+
return run(["winget"], ["install", "--id", "Python.Python.3.11", "-e"], {
|
|
67
|
+
stdio: "inherit",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (process.platform === "darwin") {
|
|
71
|
+
return run(["brew"], ["install", "python@3.11"], { stdio: "inherit" });
|
|
72
|
+
}
|
|
73
|
+
return { status: 1 };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function printInstallHelp() {
|
|
77
|
+
console.error("未找到 Python 3.11+,且自动安装失败。请手动安装后重试。");
|
|
78
|
+
console.error("Windows: 安装后确认 `python --version` 可用。");
|
|
79
|
+
console.error("macOS: 安装 Homebrew 后可执行 `brew install python@3.11`。");
|
|
80
|
+
console.error("Linux: 请使用当前发行版的包管理器安装 Python 3.11+。");
|
|
81
|
+
console.error("macOS/Linux: 安装后确认 `python3 --version` 可用。");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function main() {
|
|
85
|
+
let result = findPython();
|
|
86
|
+
if (result.command) {
|
|
87
|
+
console.log(
|
|
88
|
+
`Found Python ${versionLabel(result.version)}: ${commandLabel(
|
|
89
|
+
result.command
|
|
90
|
+
)}`
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const item of result.checked) {
|
|
96
|
+
console.error(`${commandLabel(item.command)}: ${item.reason}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.error("正在尝试自动安装 Python 3.11...");
|
|
100
|
+
const installResult = installPython();
|
|
101
|
+
if (installResult.status === 0) {
|
|
102
|
+
result = findPython();
|
|
103
|
+
if (result.command) {
|
|
104
|
+
console.log(
|
|
105
|
+
`Found Python ${versionLabel(result.version)}: ${commandLabel(
|
|
106
|
+
result.command
|
|
107
|
+
)}`
|
|
108
|
+
);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
printInstallHelp();
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main();
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn, spawnSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
const MIN_VERSION = [3, 11, 0];
|
|
6
|
+
|
|
7
|
+
function pythonCandidates() {
|
|
8
|
+
if (process.platform === "win32") {
|
|
9
|
+
return [["python"], ["python3"]];
|
|
10
|
+
}
|
|
11
|
+
return [["python3"], ["python"]];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseVersion(output) {
|
|
15
|
+
const match = String(output).match(/Python\s+(\d+)\.(\d+)\.(\d+)/);
|
|
16
|
+
if (!match) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return match.slice(1).map((part) => Number(part));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function versionLabel(version) {
|
|
23
|
+
return version.join(".");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isSupported(version) {
|
|
27
|
+
for (let index = 0; index < MIN_VERSION.length; index += 1) {
|
|
28
|
+
if (version[index] > MIN_VERSION[index]) return true;
|
|
29
|
+
if (version[index] < MIN_VERSION[index]) return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function commandLabel(command) {
|
|
35
|
+
return command.join(" ");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findPython() {
|
|
39
|
+
const checked = [];
|
|
40
|
+
for (const command of pythonCandidates()) {
|
|
41
|
+
const result = spawnSync(command[0], [...command.slice(1), "--version"], {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
44
|
+
});
|
|
45
|
+
const output = `${result.stdout || ""}${result.stderr || ""}`;
|
|
46
|
+
const version = parseVersion(output);
|
|
47
|
+
if (result.status === 0 && version && isSupported(version)) {
|
|
48
|
+
return { command, version, checked };
|
|
49
|
+
}
|
|
50
|
+
checked.push({
|
|
51
|
+
command,
|
|
52
|
+
reason: version
|
|
53
|
+
? `当前版本 ${versionLabel(version)},需要 ${versionLabel(MIN_VERSION)}+`
|
|
54
|
+
: "未找到或无法读取版本",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { command: null, version: null, checked };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function printPythonError(checked) {
|
|
61
|
+
for (const item of checked) {
|
|
62
|
+
console.error(`${commandLabel(item.command)}: ${item.reason}`);
|
|
63
|
+
}
|
|
64
|
+
console.error("未找到 Python 3.11+,无法启动 octopus-agent。");
|
|
65
|
+
console.error("Windows: 请安装 Python 3.11+,并确认 `python --version` 可用。");
|
|
66
|
+
console.error(
|
|
67
|
+
"macOS/Linux: 请安装 Python 3.11+,并确认 `python3 --version` 可用。"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function main() {
|
|
72
|
+
const passthroughArgs = process.argv.slice(2);
|
|
73
|
+
const checkOnly = passthroughArgs[0] === "--check";
|
|
74
|
+
const serverArgs = checkOnly ? [] : passthroughArgs;
|
|
75
|
+
const result = findPython();
|
|
76
|
+
|
|
77
|
+
if (!result.command) {
|
|
78
|
+
printPythonError(result.checked);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (checkOnly) {
|
|
83
|
+
console.log(
|
|
84
|
+
`${commandLabel(result.command)} ${versionLabel(result.version)}`
|
|
85
|
+
);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const child = spawn(
|
|
90
|
+
result.command[0],
|
|
91
|
+
[...result.command.slice(1), "-m", "octopus_sponge_skill.roll_server", ...serverArgs],
|
|
92
|
+
{ stdio: "inherit" }
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
child.on("exit", (code, signal) => {
|
|
96
|
+
if (signal) {
|
|
97
|
+
process.kill(process.pid, signal);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
process.exit(code || 0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
child.on("error", (error) => {
|
|
104
|
+
console.error(`启动 Python 失败: ${error.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roll-agent/octopus-agent",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Octopus
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "丸子Agent(Octopus Agent)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"roll-agent",
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node bin/check-python.js"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
18
|
+
"bin",
|
|
15
19
|
"octopus_sponge_skill",
|
|
16
20
|
"src",
|
|
17
21
|
"references",
|
|
@@ -27,10 +31,9 @@
|
|
|
27
31
|
"transport": "stdio"
|
|
28
32
|
},
|
|
29
33
|
"start": {
|
|
30
|
-
"command": "
|
|
34
|
+
"command": "node",
|
|
31
35
|
"args": [
|
|
32
|
-
"-
|
|
33
|
-
"octopus_sponge_skill.roll_server"
|
|
36
|
+
"bin/start-roll-server.js"
|
|
34
37
|
]
|
|
35
38
|
}
|
|
36
39
|
}
|
package/pyproject.toml
CHANGED