New agents (11): - chat-search, code-analysis, code-ingest, database - document-writer, home-automation, image-maker - iot-coder, iot-hardware, video-analyze, vscode-setup Fixes: - Remove broken :deepseek suffix from coder-basic, coder-pro, devops-basic, devops-pro (caused silent fallback to parent model) - Add models.json with openRouterRouting for DeepSeek, Qwen, MiniMax, Moonshot AI provider cache targeting Additions: - headroom-bridge extension (compress_for_agent tool) - models.json with provider routing config Cleanup: - Remove old pi-subagents extension (replaced by @tintinweb/pi-subagents)
119 lines
3.8 KiB
TypeScript
119 lines
3.8 KiB
TypeScript
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
import { compress } from "headroom-ai";
|
|
|
|
const HEADROOM_URL = "http://192.168.20.13:8787";
|
|
const COMPRESS_MIN_CHARS = 20_000;
|
|
|
|
export default function (pi: ExtensionAPI) {
|
|
|
|
pi.registerTool({
|
|
name: "compress_for_agent",
|
|
description:
|
|
"Compress large logs, code files, or context before sending to a subagent. Saves tokens on expensive models. Call this when you have more than ~20K chars of text to delegate.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {
|
|
content: {
|
|
type: "string",
|
|
description: "The text content to compress (logs, code, configs, error output, etc.)"
|
|
}
|
|
},
|
|
required: ["content"]
|
|
},
|
|
execute: async (_toolCallId: string, params: { content: string }) => {
|
|
const content = params?.content || "";
|
|
if (!content || content.length < COMPRESS_MIN_CHARS) {
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
compressed: content,
|
|
originalLength: content.length,
|
|
compressedLength: content.length,
|
|
savingsPercent: "0%",
|
|
note: "Content too small to compress (min 20K chars)"
|
|
}, null, 2) }]
|
|
};
|
|
}
|
|
|
|
try {
|
|
const messages = [{ role: "user" as const, content }];
|
|
const result = await compress(messages, {
|
|
baseUrl: HEADROOM_URL,
|
|
fallback: true,
|
|
timeout: 15_000,
|
|
});
|
|
|
|
if (result.messages && result.messages.length > 0) {
|
|
const compressed = result.messages.map((m: any) => m.content).join("\n");
|
|
const saved = result.tokensBefore > 0
|
|
? ((result.tokensBefore - result.tokensAfter) / result.tokensBefore * 100).toFixed(0)
|
|
: "0";
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
compressed,
|
|
originalLength: content.length,
|
|
compressedLength: compressed.length,
|
|
tokensBefore: result.tokensBefore,
|
|
tokensAfter: result.tokensAfter,
|
|
savingsPercent: `${saved}%`
|
|
}, null, 2) }]
|
|
};
|
|
}
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
compressed: content,
|
|
originalLength: content.length,
|
|
compressedLength: content.length,
|
|
savingsPercent: "0%",
|
|
note: "No compression applied"
|
|
}, null, 2) }]
|
|
};
|
|
} catch (err: any) {
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
compressed: content,
|
|
originalLength: content.length,
|
|
compressedLength: content.length,
|
|
savingsPercent: "0%",
|
|
error: err?.message || "Headroom compression failed"
|
|
}, null, 2) }],
|
|
isError: true
|
|
};
|
|
}
|
|
}
|
|
});
|
|
|
|
pi.registerTool({
|
|
name: "check_headroom",
|
|
description: "Check if the Headroom compression service at 192.168.20.13:8787 is reachable.",
|
|
parameters: {
|
|
type: "object",
|
|
properties: {}
|
|
},
|
|
execute: async () => {
|
|
try {
|
|
const res = await fetch(`${HEADROOM_URL}/health`, {
|
|
method: "GET",
|
|
signal: AbortSignal.timeout(5000)
|
|
});
|
|
const data = await res.json();
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
status: res.ok ? "healthy" : "unhealthy",
|
|
statusCode: res.status,
|
|
version: data.version,
|
|
uptime_seconds: data.uptime_seconds
|
|
}, null, 2) }]
|
|
};
|
|
} catch (err: any) {
|
|
return {
|
|
content: [{ type: "text", text: JSON.stringify({
|
|
status: "unreachable",
|
|
error: err?.message || "Cannot reach Headroom at 192.168.20.13:8787"
|
|
}, null, 2) }],
|
|
isError: true
|
|
};
|
|
}
|
|
}
|
|
});
|
|
}
|