@maheidem/model-discovery 0.7.1 → 0.8.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 +49 -12
- package/application.ts +104 -0
- package/commands.ts +70 -0
- package/index.ts +475 -452
- package/package.json +28 -5
- package/storage.ts +265 -0
- package/ui/wizard-shell.ts +442 -0
- package/ui-model.ts +127 -0
- package/scripts/bisect-grammar.ts +0 -65
- package/scripts/live-schema-repair-check.ts +0 -86
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LIVE verification: push the local Pi MCP catalogue through the repair and against
|
|
3
|
-
* a llama.cpp-compatible endpoint. Not part of `npm test` (needs the network).
|
|
4
|
-
*
|
|
5
|
-
* node --experimental-strip-types scripts/live-schema-repair-check.ts BASE_URL [MODEL]
|
|
6
|
-
*
|
|
7
|
-
* This sends tool definitions but never executes a tool call.
|
|
8
|
-
*/
|
|
9
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
10
|
-
import { homedir } from "node:os";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import { repairRequestToolSchemas, describeToolSchemaRepair } from "../schema-repair.ts";
|
|
13
|
-
|
|
14
|
-
const BASE = process.argv[2];
|
|
15
|
-
const MODEL = process.argv[3] ?? "qwen3.8-27b";
|
|
16
|
-
const CACHE = process.env.PI_MCP_CACHE ?? join(homedir(), ".pi", "agent", "mcp-cache.json");
|
|
17
|
-
|
|
18
|
-
if (!BASE) {
|
|
19
|
-
console.error("usage: node --experimental-strip-types scripts/live-schema-repair-check.ts BASE_URL [MODEL]");
|
|
20
|
-
process.exit(2);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function collectRefs(node: unknown, out: string[] = []): string[] {
|
|
24
|
-
if (Array.isArray(node)) for (const item of node) collectRefs(item, out);
|
|
25
|
-
else if (node && typeof node === "object") {
|
|
26
|
-
for (const [key, value] of Object.entries(node)) {
|
|
27
|
-
if (key === "$ref" && typeof value === "string") out.push(value);
|
|
28
|
-
else if (key === "$defs" || key === "definitions") out.push(`<${key}:${Object.keys(value as object).length} entries>`);
|
|
29
|
-
else collectRefs(value, out);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return out;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async function post(tools: unknown[], model = MODEL): Promise<{ status: number; body: string }> {
|
|
36
|
-
const res = await fetch(`${BASE}/v1/chat/completions`, {
|
|
37
|
-
method: "POST",
|
|
38
|
-
headers: { "Content-Type": "application/json" },
|
|
39
|
-
body: JSON.stringify({ model, messages: [{ role: "user", content: "reply with OK" }], max_tokens: 16, tools }),
|
|
40
|
-
});
|
|
41
|
-
return { status: res.status, body: await res.text() };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!existsSync(CACHE)) {
|
|
45
|
-
console.error(`no mcp cache at ${CACHE}`);
|
|
46
|
-
process.exit(2);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const cache = JSON.parse(readFileSync(CACHE, "utf8")) as { servers: Record<string, { tools?: Record<string, unknown>[] }> };
|
|
50
|
-
const servers = Object.entries(cache.servers);
|
|
51
|
-
const tools: Record<string, unknown>[] = [];
|
|
52
|
-
for (const [name, server] of servers) {
|
|
53
|
-
for (const tool of (server.tools ?? []) as Record<string, unknown>[]) {
|
|
54
|
-
// MCP catalogue entries carry `inputSchema`; OpenAI-shaped ones carry `function.parameters`.
|
|
55
|
-
const fn = (tool.function ?? tool) as Record<string, unknown>;
|
|
56
|
-
const parameters = fn.parameters ?? fn.inputSchema;
|
|
57
|
-
if (!fn.name || !parameters) continue;
|
|
58
|
-
tools.push({
|
|
59
|
-
type: "function",
|
|
60
|
-
function: { name: `${name}__${String(fn.name).replace(/[^A-Za-z0-9_-]/g, "_")}`, description: String(fn.description ?? ""), parameters },
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const broken = tools.filter((t) => collectRefs((t as { function: { parameters: unknown } }).function.parameters).length > 0);
|
|
66
|
-
console.log(`endpoint : ${BASE}`);
|
|
67
|
-
console.log(`tools collected : ${tools.length} from ${servers.length} MCP servers`);
|
|
68
|
-
console.log(`tools w/ refs : ${broken.length}`);
|
|
69
|
-
for (const t of broken) console.log(` - ${String((t as { function: { name: string } }).function.name)}`);
|
|
70
|
-
|
|
71
|
-
const before = await post(tools);
|
|
72
|
-
console.log(`\nBEFORE repair -> HTTP ${before.status}`);
|
|
73
|
-
if (before.status !== 200) console.log(` ${before.body.slice(0, 260)}`);
|
|
74
|
-
|
|
75
|
-
const { payload, report } = repairRequestToolSchemas({ model: MODEL, messages: [{ role: "user", content: "reply with OK" }], max_tokens: 16, tools });
|
|
76
|
-
console.log(`\nrepair summary : ${describeToolSchemaRepair(report) || "(nothing to repair)"}`);
|
|
77
|
-
if (report.droppedRefs.length) console.log(` loosened refs : ${report.droppedRefs.join(", ")}`);
|
|
78
|
-
|
|
79
|
-
const after = await post((payload as { tools: unknown[] }).tools);
|
|
80
|
-
console.log(`\nAFTER repair -> HTTP ${after.status}`);
|
|
81
|
-
if (after.status === 200) console.log(" ✅ llama-swap/llama.cpp accepted the repaired tool set");
|
|
82
|
-
else console.log(` ❌ ${after.body.slice(0, 260)}`);
|
|
83
|
-
|
|
84
|
-
const leftovers = collectRefs((payload as { tools: unknown[] }).tools).filter((r) => r.startsWith("#") || r.includes("entries"));
|
|
85
|
-
console.log(`\nresidual refs/defs on the wire: ${leftovers.length === 0 ? "none ✅" : leftovers.join(", ")}`);
|
|
86
|
-
process.exit(after.status === 200 && leftovers.length === 0 ? 0 : 1);
|