@shog-lab/pi-toolkit 0.1.0
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/LICENSE +21 -0
- package/README.md +75 -0
- package/bin/init.js +100 -0
- package/dist/extensions/jimeng/index.d.ts +11 -0
- package/dist/extensions/jimeng/index.d.ts.map +1 -0
- package/dist/extensions/jimeng/index.js +130 -0
- package/dist/extensions/jimeng/index.js.map +1 -0
- package/dist/extensions/jimeng/package.json +12 -0
- package/dist/extensions/mcp-bridge/index.d.ts +29 -0
- package/dist/extensions/mcp-bridge/index.d.ts.map +1 -0
- package/dist/extensions/mcp-bridge/index.js +142 -0
- package/dist/extensions/mcp-bridge/index.js.map +1 -0
- package/dist/extensions/mcp-bridge/mcp-client.d.ts +49 -0
- package/dist/extensions/mcp-bridge/mcp-client.d.ts.map +1 -0
- package/dist/extensions/mcp-bridge/mcp-client.js +145 -0
- package/dist/extensions/mcp-bridge/mcp-client.js.map +1 -0
- package/dist/extensions/mcp-bridge/package.json +8 -0
- package/dist/extensions/subagent/index.d.ts +20 -0
- package/dist/extensions/subagent/index.d.ts.map +1 -0
- package/dist/extensions/subagent/index.js +118 -0
- package/dist/extensions/subagent/index.js.map +1 -0
- package/dist/extensions/subagent/package.json +8 -0
- package/dist/extensions/understand_image/index.d.ts +10 -0
- package/dist/extensions/understand_image/index.d.ts.map +1 -0
- package/dist/extensions/understand_image/index.js +159 -0
- package/dist/extensions/understand_image/index.js.map +1 -0
- package/dist/extensions/understand_image/package.json +9 -0
- package/dist/extensions/web_search/index.d.ts +8 -0
- package/dist/extensions/web_search/index.d.ts.map +1 -0
- package/dist/extensions/web_search/index.js +100 -0
- package/dist/extensions/web_search/index.js.map +1 -0
- package/dist/extensions/web_search/package.json +9 -0
- package/package.json +40 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal MCP (Model Context Protocol) stdio JSON-RPC client.
|
|
3
|
+
*
|
|
4
|
+
* Spawns an MCP server as a child process, performs the initialize handshake,
|
|
5
|
+
* and exposes tools/list + tools/call.
|
|
6
|
+
*
|
|
7
|
+
* MCP spec: https://spec.modelcontextprotocol.io/
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
const PROTOCOL_VERSION = "2024-11-05";
|
|
11
|
+
const HANDSHAKE_TIMEOUT_MS = 10000;
|
|
12
|
+
const TOOL_CALL_TIMEOUT_MS = 60000;
|
|
13
|
+
export class McpClient {
|
|
14
|
+
proc;
|
|
15
|
+
nextId = 1;
|
|
16
|
+
pending = new Map();
|
|
17
|
+
stdoutBuffer = "";
|
|
18
|
+
initialized = false;
|
|
19
|
+
closed = false;
|
|
20
|
+
initializePromise = null;
|
|
21
|
+
serverName;
|
|
22
|
+
constructor(serverName, config) {
|
|
23
|
+
this.serverName = serverName;
|
|
24
|
+
this.proc = spawn(config.command, config.args ?? [], {
|
|
25
|
+
env: { ...process.env, ...config.env },
|
|
26
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
27
|
+
});
|
|
28
|
+
this.proc.stdout?.on("data", (chunk) => this.onStdout(chunk));
|
|
29
|
+
this.proc.stderr?.on("data", (chunk) => {
|
|
30
|
+
// MCP servers commonly use stderr for logs — surface as warnings, don't fail
|
|
31
|
+
const line = chunk.toString().trim();
|
|
32
|
+
if (line)
|
|
33
|
+
console.warn(`[mcp:${this.serverName}] ${line}`);
|
|
34
|
+
});
|
|
35
|
+
this.proc.on("error", (err) => this.failAll(err));
|
|
36
|
+
this.proc.on("exit", (code, signal) => {
|
|
37
|
+
this.closed = true;
|
|
38
|
+
this.failAll(new Error(`MCP server "${this.serverName}" exited (code=${code}, signal=${signal})`));
|
|
39
|
+
});
|
|
40
|
+
this.proc.unref(); // don't keep event loop alive on our own
|
|
41
|
+
}
|
|
42
|
+
/** Run the MCP initialize handshake. Idempotent — multiple callers share one in-flight promise. */
|
|
43
|
+
initialize() {
|
|
44
|
+
if (this.initialized)
|
|
45
|
+
return Promise.resolve();
|
|
46
|
+
if (this.initializePromise)
|
|
47
|
+
return this.initializePromise;
|
|
48
|
+
this.initializePromise = (async () => {
|
|
49
|
+
await this.send("initialize", {
|
|
50
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
51
|
+
capabilities: {},
|
|
52
|
+
clientInfo: { name: "pi-toolkit-mcp-bridge", version: "0.1.0" },
|
|
53
|
+
}, HANDSHAKE_TIMEOUT_MS);
|
|
54
|
+
this.notify("notifications/initialized");
|
|
55
|
+
this.initialized = true;
|
|
56
|
+
})();
|
|
57
|
+
return this.initializePromise;
|
|
58
|
+
}
|
|
59
|
+
async listTools() {
|
|
60
|
+
await this.initialize();
|
|
61
|
+
const result = await this.send("tools/list", undefined, HANDSHAKE_TIMEOUT_MS);
|
|
62
|
+
return result.tools ?? [];
|
|
63
|
+
}
|
|
64
|
+
async callTool(name, args) {
|
|
65
|
+
await this.initialize();
|
|
66
|
+
const result = await this.send("tools/call", { name, arguments: args }, TOOL_CALL_TIMEOUT_MS);
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
close() {
|
|
70
|
+
if (this.closed)
|
|
71
|
+
return;
|
|
72
|
+
this.closed = true;
|
|
73
|
+
if (!this.proc.killed) {
|
|
74
|
+
try {
|
|
75
|
+
this.proc.kill("SIGTERM");
|
|
76
|
+
}
|
|
77
|
+
catch { /* ignore */ }
|
|
78
|
+
}
|
|
79
|
+
this.failAll(new Error(`MCP client "${this.serverName}" closed`));
|
|
80
|
+
}
|
|
81
|
+
// --- internals ---
|
|
82
|
+
send(method, params, timeoutMs) {
|
|
83
|
+
if (this.closed)
|
|
84
|
+
return Promise.reject(new Error(`MCP client "${this.serverName}" closed`));
|
|
85
|
+
const id = this.nextId++;
|
|
86
|
+
const req = { jsonrpc: "2.0", id, method, params };
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
const timer = setTimeout(() => {
|
|
89
|
+
this.pending.delete(id);
|
|
90
|
+
reject(new Error(`MCP "${this.serverName}" ${method} timed out after ${timeoutMs}ms`));
|
|
91
|
+
}, timeoutMs);
|
|
92
|
+
timer.unref();
|
|
93
|
+
this.pending.set(id, {
|
|
94
|
+
resolve: resolve,
|
|
95
|
+
reject,
|
|
96
|
+
timer,
|
|
97
|
+
});
|
|
98
|
+
this.proc.stdin?.write(JSON.stringify(req) + "\n");
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
notify(method, params) {
|
|
102
|
+
if (this.closed)
|
|
103
|
+
return;
|
|
104
|
+
const req = { jsonrpc: "2.0", method, params };
|
|
105
|
+
this.proc.stdin?.write(JSON.stringify(req) + "\n");
|
|
106
|
+
}
|
|
107
|
+
onStdout(chunk) {
|
|
108
|
+
this.stdoutBuffer += chunk.toString();
|
|
109
|
+
const lines = this.stdoutBuffer.split("\n");
|
|
110
|
+
this.stdoutBuffer = lines.pop() ?? "";
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
if (!line.trim())
|
|
113
|
+
continue;
|
|
114
|
+
let msg;
|
|
115
|
+
try {
|
|
116
|
+
msg = JSON.parse(line);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
console.warn(`[mcp:${this.serverName}] non-JSON output: ${line.slice(0, 200)}`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (msg.id === undefined)
|
|
123
|
+
continue; // notification from server, ignore for now
|
|
124
|
+
const pending = this.pending.get(msg.id);
|
|
125
|
+
if (!pending)
|
|
126
|
+
continue;
|
|
127
|
+
this.pending.delete(msg.id);
|
|
128
|
+
clearTimeout(pending.timer);
|
|
129
|
+
if (msg.error) {
|
|
130
|
+
pending.reject(new Error(`MCP "${this.serverName}" error ${msg.error.code}: ${msg.error.message}`));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
pending.resolve(msg.result);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
failAll(err) {
|
|
138
|
+
for (const { reject, timer } of this.pending.values()) {
|
|
139
|
+
clearTimeout(timer);
|
|
140
|
+
reject(err);
|
|
141
|
+
}
|
|
142
|
+
this.pending.clear();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=mcp-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../../../extensions/mcp-bridge/mcp-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shog-lab/pi-toolkit-mcp-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Bridge MCP (Model Context Protocol) servers as pi-coding-agent tools. Reads mcp-servers.json, spawns servers, registers tools.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "index.js"
|
|
8
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-toolkit Sub-Agent Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides spawn_subagent tool for an agent to spawn a focused sub-agent in a
|
|
5
|
+
* target directory. Sub-agents have minimal context: no memory access, no parent
|
|
6
|
+
* skills, no system prompt — just the task plus web_search (when installed
|
|
7
|
+
* alongside in toolkit).
|
|
8
|
+
*
|
|
9
|
+
* Lives in pi-toolkit (not pi-mind) because it's an agent-facing tool with no
|
|
10
|
+
* memory dependency — it just wraps spawnPi from pi-utils. Pi-mind has its own
|
|
11
|
+
* internal L2 spawn helper for memory-specific use cases.
|
|
12
|
+
*
|
|
13
|
+
* Use cases:
|
|
14
|
+
* - Run tests / read code in an isolated context
|
|
15
|
+
* - Generate a SKILL.md from raw observations
|
|
16
|
+
* - Classify content without bias from the parent agent's loaded context
|
|
17
|
+
*/
|
|
18
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
19
|
+
export default function subagentExtension(pi: ExtensionAPI): void;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../extensions/subagent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAgCpE,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,YAAY,QA0EzD"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-toolkit Sub-Agent Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides spawn_subagent tool for an agent to spawn a focused sub-agent in a
|
|
5
|
+
* target directory. Sub-agents have minimal context: no memory access, no parent
|
|
6
|
+
* skills, no system prompt — just the task plus web_search (when installed
|
|
7
|
+
* alongside in toolkit).
|
|
8
|
+
*
|
|
9
|
+
* Lives in pi-toolkit (not pi-mind) because it's an agent-facing tool with no
|
|
10
|
+
* memory dependency — it just wraps spawnPi from pi-utils. Pi-mind has its own
|
|
11
|
+
* internal L2 spawn helper for memory-specific use cases.
|
|
12
|
+
*
|
|
13
|
+
* Use cases:
|
|
14
|
+
* - Run tests / read code in an isolated context
|
|
15
|
+
* - Generate a SKILL.md from raw observations
|
|
16
|
+
* - Classify content without bias from the parent agent's loaded context
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
19
|
+
import { dirname, join, normalize, resolve } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { Type } from "@sinclair/typebox";
|
|
22
|
+
import { spawnPi } from "@shog-lab/pi-utils";
|
|
23
|
+
const SubAgentParams = Type.Object({
|
|
24
|
+
cwd: Type.String({ description: "Absolute path to the working directory for the sub-agent (typically a repo or a subdirectory)." }),
|
|
25
|
+
prompt: Type.String({ description: "Task instruction for the sub-agent. Be specific about what to do and what to return." }),
|
|
26
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 300, max: 600)" })),
|
|
27
|
+
});
|
|
28
|
+
/** Resolve the toolkit package extensions directory regardless of symlink chain. */
|
|
29
|
+
function getExtensionsDir() {
|
|
30
|
+
const here = realpathSync(fileURLToPath(import.meta.url));
|
|
31
|
+
// index.ts is at <pkg-root>/extensions/subagent/index.ts → up two levels = extensions/
|
|
32
|
+
return join(dirname(here), "..");
|
|
33
|
+
}
|
|
34
|
+
function ok(text, details = {}) {
|
|
35
|
+
return { content: [{ type: "text", text }], details };
|
|
36
|
+
}
|
|
37
|
+
function err(text) {
|
|
38
|
+
return { content: [{ type: "text", text }], details: {}, isError: true };
|
|
39
|
+
}
|
|
40
|
+
function resolveExtensionPath(name) {
|
|
41
|
+
const p = join(getExtensionsDir(), name);
|
|
42
|
+
for (const entry of ["dist/index.js", "index.ts", "index.js"]) {
|
|
43
|
+
if (existsSync(join(p, entry)))
|
|
44
|
+
return join(p, entry);
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
export default function subagentExtension(pi) {
|
|
49
|
+
pi.registerTool({
|
|
50
|
+
name: "spawn_subagent",
|
|
51
|
+
label: "Spawn Sub-Agent",
|
|
52
|
+
description: "Spawn a focused sub-agent in a target directory to execute a specific task. " +
|
|
53
|
+
"The sub-agent has minimal context: no memory access, no parent skills, no system prompt. " +
|
|
54
|
+
"Use this for isolated tasks like running tests, reading code, classifying content.",
|
|
55
|
+
parameters: SubAgentParams,
|
|
56
|
+
async execute(_toolCallId, params) {
|
|
57
|
+
const normalized = resolve(normalize(params.cwd));
|
|
58
|
+
if (!existsSync(normalized)) {
|
|
59
|
+
return err(`Working directory does not exist: ${params.cwd}`);
|
|
60
|
+
}
|
|
61
|
+
const timeoutSec = Math.min(params.timeout ?? 300, 600);
|
|
62
|
+
const timeoutMs = timeoutSec * 1000;
|
|
63
|
+
const args = [
|
|
64
|
+
"-p",
|
|
65
|
+
"--no-extensions",
|
|
66
|
+
];
|
|
67
|
+
if (process.env.MODEL) {
|
|
68
|
+
args.push("--model", process.env.MODEL);
|
|
69
|
+
}
|
|
70
|
+
// Load basic work tools — explicitly excludes memory (sub-agents must not touch parent memory).
|
|
71
|
+
// Browser automation belongs in pi-chrome, not pi-mind, so it isn't loaded here;
|
|
72
|
+
// a sub-agent that needs the browser should be spawned from a pi-chrome-aware caller.
|
|
73
|
+
const basicExts = ["web_search"];
|
|
74
|
+
for (const ext of basicExts) {
|
|
75
|
+
const extPath = resolveExtensionPath(ext);
|
|
76
|
+
if (extPath)
|
|
77
|
+
args.push("-e", extPath);
|
|
78
|
+
}
|
|
79
|
+
const systemPrompt = [
|
|
80
|
+
"You are a sub-agent executing a focused task.",
|
|
81
|
+
"Rules:",
|
|
82
|
+
"- Read code, run tests, verify behavior — report findings as plain text",
|
|
83
|
+
"- Do not write code unless the task explicitly requires it",
|
|
84
|
+
"- Do not access memory, parent skills, or persistent state",
|
|
85
|
+
"- Do not modify files unless the task explicitly requires it",
|
|
86
|
+
"- Return findings, results, or errors as plain text",
|
|
87
|
+
"",
|
|
88
|
+
`Task: ${params.prompt}`,
|
|
89
|
+
].join("\n");
|
|
90
|
+
args.push("--append-system-prompt", systemPrompt);
|
|
91
|
+
args.push(params.prompt);
|
|
92
|
+
let stdout = "";
|
|
93
|
+
let stderr = "";
|
|
94
|
+
const result = await spawnPi({
|
|
95
|
+
cwd: normalized,
|
|
96
|
+
args,
|
|
97
|
+
onStdout: (d) => { stdout += d; },
|
|
98
|
+
onStderr: (d) => { stderr += d; },
|
|
99
|
+
timeoutMs,
|
|
100
|
+
});
|
|
101
|
+
if (result.killed) {
|
|
102
|
+
return err(`Sub-agent timed out after ${timeoutSec}s`);
|
|
103
|
+
}
|
|
104
|
+
else if (result.code === 0) {
|
|
105
|
+
const text = stdout
|
|
106
|
+
.replace(/^\*\*Output:\*\*\n?/s, "")
|
|
107
|
+
.replace(/^.*?---\n/s, "")
|
|
108
|
+
.replace(/^\*\*\(.+\)\*\*\n?/s, "")
|
|
109
|
+
.trim() || "Done.";
|
|
110
|
+
return ok(text, result.tokens ? { tokens: result.tokens } : {});
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return err(stderr || stdout || `Sub-agent exited with code ${result.code}`);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../extensions/subagent/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-mind Image Understanding Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides image understanding via mmx vision CLI.
|
|
5
|
+
* Also intercepts base64 images in prompts and saves them to temp files,
|
|
6
|
+
* so the agent can reference them when MiniMax doesn't receive images directly.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
export default function imageUnderstandingExtension(pi: ExtensionAPI): void;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../extensions/understand_image/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA4EpE,MAAM,CAAC,OAAO,UAAU,2BAA2B,CAAC,EAAE,EAAE,YAAY,QAoEnE"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-mind Image Understanding Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides image understanding via mmx vision CLI.
|
|
5
|
+
* Also intercepts base64 images in prompts and saves them to temp files,
|
|
6
|
+
* so the agent can reference them when MiniMax doesn't receive images directly.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import * as os from "os";
|
|
11
|
+
import { Type } from "@sinclair/typebox";
|
|
12
|
+
import { spawn } from "child_process";
|
|
13
|
+
const MMX = "mmx";
|
|
14
|
+
/** Tracks temp image files created by this extension (path -> true) */
|
|
15
|
+
const tempFiles = new Map();
|
|
16
|
+
/** Reads MINIMAX_API_KEY: env var preferred, fallback to disk */
|
|
17
|
+
function getMinimaxKey() {
|
|
18
|
+
if (process.env.MINIMAX_API_KEY)
|
|
19
|
+
return process.env.MINIMAX_API_KEY;
|
|
20
|
+
if (process.env.MINIMAX_CN_API_KEY)
|
|
21
|
+
return process.env.MINIMAX_CN_API_KEY;
|
|
22
|
+
const mmxConfig = path.join(process.env.HOME || "", ".mmx", "config.json");
|
|
23
|
+
if (fs.existsSync(mmxConfig)) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(fs.readFileSync(mmxConfig, "utf-8")).api_key;
|
|
26
|
+
}
|
|
27
|
+
catch { }
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
function ok(text) {
|
|
32
|
+
return { content: [{ type: "text", text }], details: {} };
|
|
33
|
+
}
|
|
34
|
+
function err(text) {
|
|
35
|
+
return { content: [{ type: "text", text }], details: {}, isError: true };
|
|
36
|
+
}
|
|
37
|
+
function execMmx(args, timeoutMs = 30000) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const key = getMinimaxKey();
|
|
40
|
+
const env = {};
|
|
41
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
42
|
+
if (v !== undefined)
|
|
43
|
+
env[k] = v;
|
|
44
|
+
}
|
|
45
|
+
if (key)
|
|
46
|
+
env.MINIMAX_API_KEY = key;
|
|
47
|
+
const proc = spawn(MMX, args, { timeout: timeoutMs, env });
|
|
48
|
+
let stdout = "";
|
|
49
|
+
let stderr = "";
|
|
50
|
+
proc.stdout?.on("data", (d) => { stdout += d.toString(); });
|
|
51
|
+
proc.stderr?.on("data", (d) => { stderr += d.toString(); });
|
|
52
|
+
proc.on("close", (code) => {
|
|
53
|
+
if (code === 0)
|
|
54
|
+
resolve(stdout);
|
|
55
|
+
else
|
|
56
|
+
reject(new Error(stderr || stdout || `mmx exited with code ${code}`));
|
|
57
|
+
});
|
|
58
|
+
proc.on("error", reject);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function resolveImageToPath(imageInput) {
|
|
62
|
+
// URL or absolute path — use as-is
|
|
63
|
+
if (imageInput.startsWith("http://") || imageInput.startsWith("https://") || imageInput.startsWith("/")) {
|
|
64
|
+
return imageInput;
|
|
65
|
+
}
|
|
66
|
+
// Base64 data URL: data:image/png;base64,xxxx
|
|
67
|
+
if (imageInput.startsWith("data:")) {
|
|
68
|
+
const match = imageInput.match(/^data:([^;]+);base64,(.+)$/);
|
|
69
|
+
if (!match)
|
|
70
|
+
throw new Error(`Invalid base64 data URL`);
|
|
71
|
+
const mimeType = match[1];
|
|
72
|
+
const data = match[2];
|
|
73
|
+
const ext = mimeType.split("/")[1] || "png";
|
|
74
|
+
const tmpFile = path.join(os.tmpdir(), `img-${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`);
|
|
75
|
+
fs.writeFileSync(tmpFile, Buffer.from(data, "base64"));
|
|
76
|
+
tempFiles.set(tmpFile, true);
|
|
77
|
+
return tmpFile;
|
|
78
|
+
}
|
|
79
|
+
// Plain base64 (no prefix) — treat as PNG
|
|
80
|
+
const tmpFile = path.join(os.tmpdir(), `img-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
|
|
81
|
+
fs.writeFileSync(tmpFile, Buffer.from(imageInput, "base64"));
|
|
82
|
+
tempFiles.set(tmpFile, true);
|
|
83
|
+
return tmpFile;
|
|
84
|
+
}
|
|
85
|
+
const UnderstandImageParams = Type.Object({
|
|
86
|
+
image: Type.String({ description: "Image file path, URL, or base64 data URL (data:image/png;base64,...)" }),
|
|
87
|
+
prompt: Type.Optional(Type.String({ description: "Question about the image (default: 'Describe the image.')" })),
|
|
88
|
+
});
|
|
89
|
+
export default function imageUnderstandingExtension(pi) {
|
|
90
|
+
// Intercept base64 images before LLM call — save to temp files
|
|
91
|
+
// so the agent can use understand_image with file paths
|
|
92
|
+
pi.on("before_agent_start", async (event) => {
|
|
93
|
+
if (!event.images || event.images.length === 0)
|
|
94
|
+
return;
|
|
95
|
+
const imageDescs = [];
|
|
96
|
+
for (const img of event.images) {
|
|
97
|
+
if (img.type === "image" && img.data) {
|
|
98
|
+
try {
|
|
99
|
+
const filePath = resolveImageToPath(img.data);
|
|
100
|
+
imageDescs.push(`[图片已保存: ${filePath}]`);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// ignore resolve errors
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (imageDescs.length > 0) {
|
|
108
|
+
const note = `\n\n${imageDescs.join("\n")}`;
|
|
109
|
+
return {
|
|
110
|
+
message: {
|
|
111
|
+
customType: "image_attachments",
|
|
112
|
+
content: `你收到了 ${imageDescs.length} 张图片,已保存为临时文件。你可以使用 understand_image 工具分析这些图片。${note}`,
|
|
113
|
+
display: false,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
pi.registerTool({
|
|
119
|
+
name: "understand_image",
|
|
120
|
+
label: "Understand Image",
|
|
121
|
+
description: "Understand and analyze images. Supports local file paths, URLs, and base64 data URLs.",
|
|
122
|
+
parameters: UnderstandImageParams,
|
|
123
|
+
async execute(_toolCallId, params) {
|
|
124
|
+
let tmpFile;
|
|
125
|
+
try {
|
|
126
|
+
const imagePath = resolveImageToPath(params.image);
|
|
127
|
+
tmpFile = imagePath.startsWith(os.tmpdir()) ? imagePath : undefined;
|
|
128
|
+
const args = [
|
|
129
|
+
"vision", "describe",
|
|
130
|
+
"--image", imagePath,
|
|
131
|
+
"--output", "json",
|
|
132
|
+
];
|
|
133
|
+
if (params.prompt) {
|
|
134
|
+
args.push("--prompt", params.prompt);
|
|
135
|
+
}
|
|
136
|
+
const output = await execMmx(args);
|
|
137
|
+
let text = output.trim();
|
|
138
|
+
try {
|
|
139
|
+
const json = JSON.parse(text);
|
|
140
|
+
text = typeof json === "string" ? json : JSON.stringify(json, null, 2);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// output is plain text
|
|
144
|
+
}
|
|
145
|
+
return ok(text);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
return err(`understand_image failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
if (tmpFile && fs.existsSync(tmpFile) && tempFiles.has(tmpFile)) {
|
|
152
|
+
fs.unlinkSync(tmpFile);
|
|
153
|
+
tempFiles.delete(tmpFile);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../extensions/understand_image/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-mind Web Search Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides web search via mmx search CLI.
|
|
5
|
+
*/
|
|
6
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
export default function webSearchExtension(pi: ExtensionAPI): void;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../extensions/web_search/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAiDpE,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,EAAE,YAAY,QAuC1D"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-mind Web Search Extension
|
|
3
|
+
*
|
|
4
|
+
* Provides web search via mmx search CLI.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import { spawn } from "child_process";
|
|
10
|
+
const MMX = "mmx";
|
|
11
|
+
function ok(text) {
|
|
12
|
+
return { content: [{ type: "text", text }], details: {} };
|
|
13
|
+
}
|
|
14
|
+
function err(text) {
|
|
15
|
+
return { content: [{ type: "text", text }], details: {}, isError: true };
|
|
16
|
+
}
|
|
17
|
+
/** Reads MINIMAX_API_KEY: env var preferred, fallback to disk */
|
|
18
|
+
function getMinimaxKey() {
|
|
19
|
+
if (process.env.MINIMAX_API_KEY)
|
|
20
|
+
return process.env.MINIMAX_API_KEY;
|
|
21
|
+
if (process.env.MINIMAX_CN_API_KEY)
|
|
22
|
+
return process.env.MINIMAX_CN_API_KEY;
|
|
23
|
+
const mmxConfig = path.join(process.env.HOME || "", ".mmx", "config.json");
|
|
24
|
+
if (fs.existsSync(mmxConfig)) {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(fs.readFileSync(mmxConfig, "utf-8")).api_key;
|
|
27
|
+
}
|
|
28
|
+
catch { }
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function execMmx(args, timeoutMs = 30000) {
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const key = getMinimaxKey();
|
|
35
|
+
const env = {};
|
|
36
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
37
|
+
if (v !== undefined)
|
|
38
|
+
env[k] = v;
|
|
39
|
+
}
|
|
40
|
+
if (key)
|
|
41
|
+
env.MINIMAX_API_KEY = key;
|
|
42
|
+
const proc = spawn(MMX, args, { timeout: timeoutMs, env });
|
|
43
|
+
let stdout = "";
|
|
44
|
+
let stderr = "";
|
|
45
|
+
proc.stdout?.on("data", (d) => { stdout += d.toString(); });
|
|
46
|
+
proc.stderr?.on("data", (d) => { stderr += d.toString(); });
|
|
47
|
+
proc.on("close", (code) => {
|
|
48
|
+
if (code === 0)
|
|
49
|
+
resolve(stdout);
|
|
50
|
+
else
|
|
51
|
+
reject(new Error(stderr || stdout || `mmx exited with code ${code}`));
|
|
52
|
+
});
|
|
53
|
+
proc.on("error", reject);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const SearchParams = Type.Object({
|
|
57
|
+
query: Type.String({ description: "Search query" }),
|
|
58
|
+
max_results: Type.Optional(Type.Number({ description: "Maximum number of results (default: 5)" })),
|
|
59
|
+
});
|
|
60
|
+
export default function webSearchExtension(pi) {
|
|
61
|
+
pi.registerTool({
|
|
62
|
+
name: "web_search",
|
|
63
|
+
label: "Web Search",
|
|
64
|
+
description: "Search the web. Returns titles, URLs, and snippets.",
|
|
65
|
+
parameters: SearchParams,
|
|
66
|
+
async execute(_toolCallId, params) {
|
|
67
|
+
try {
|
|
68
|
+
const args = [
|
|
69
|
+
"search", "query",
|
|
70
|
+
"--q", params.query,
|
|
71
|
+
"--output", "json",
|
|
72
|
+
];
|
|
73
|
+
const output = await execMmx(args);
|
|
74
|
+
let text = output.trim();
|
|
75
|
+
try {
|
|
76
|
+
const json = JSON.parse(text);
|
|
77
|
+
// mmx returns {organic: [...]} — also handle plain arrays and results wrappers
|
|
78
|
+
const results = Array.isArray(json) ? json : (json.organic || json.results || json.data || []);
|
|
79
|
+
if (results.length > 0) {
|
|
80
|
+
text = results
|
|
81
|
+
.slice(0, params.max_results ?? 5)
|
|
82
|
+
.map((r, i) => `${i + 1}. ${r.title || ""}\n ${r.url || r.link || ""}\n ${r.snippet || r.description || ""}`)
|
|
83
|
+
.join("\n\n");
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
text = typeof json === "string" ? json : JSON.stringify(json, null, 2);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// output is plain text
|
|
91
|
+
}
|
|
92
|
+
return ok(text);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
return err(`web_search failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../extensions/web_search/index.ts"],"names":[],"mappings":"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"}
|