add 11 new sub-agent types, fix model routing, add models.json

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)
This commit is contained in:
2026-06-13 12:14:17 +10:00
parent b62d25bd8d
commit aaa21a4f2f
50 changed files with 436 additions and 12426 deletions

View File

@@ -0,0 +1,118 @@
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
};
}
}
});
}