feat: Modell der Coder/Judge-Schleife per PI_CODER_MODEL wählbar
PI_CODER_MODEL=<provider>/<id> setzt das Modell für beide Rollen; ohne Variable bleibt es bei llama-cpp-single/coding_model. Die Bereitschafts- prüfung nutzt baseUrl des Modells statt fest Port 8001. Neuer Provider strata (lokaler Strata-Server, 127.0.0.1:9090) in models.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0cb637783c
commit
a608f1dda8
6 changed files with 120 additions and 42 deletions
|
|
@ -144,6 +144,21 @@ Falls die GGUF-Datei an einem anderen Ort liegt:
|
||||||
HF_HOME=/mnt/daten/huggingface ./start-coding-server.sh
|
HF_HOME=/mnt/daten/huggingface ./start-coding-server.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Anderes Modell für die Schleife
|
||||||
|
|
||||||
|
Ohne weitere Angabe arbeiten Coder und Judge mit `llama-cpp-single/coding_model` (Port 8001). Ein anderes Modell aus
|
||||||
|
`models.json` setzt die Umgebungsvariable `PI_CODER_MODEL` beim Start von pi, als `<provider>/<id>`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PI_CODER_MODEL=strata/qwen3.8-flash-next-iq3_s \
|
||||||
|
pi --provider strata --model qwen3.8-flash-next-iq3_s
|
||||||
|
```
|
||||||
|
|
||||||
|
`--provider`/`--model` machen das Modell auch für freie Eingaben zum Standard dieses Laufs; die globalen
|
||||||
|
Einstellungen bleiben unverändert. Die Bereitschaftsprüfung fragt den Endpunkt aus `baseUrl` des Modells ab. Der
|
||||||
|
Provider `strata` (lokaler Strata-Server auf `127.0.0.1:9090`) steht in `models.json`; den Server startet man außerhalb
|
||||||
|
dieses Repos.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Neues Projekt anlegen
|
## 4. Neues Projekt anlegen
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ nur die Persona im System-Prompt ändert sich.
|
||||||
Coder- und Judge-Rollen werden durch verschiedene System-Prompts realisiert —
|
Coder- und Judge-Rollen werden durch verschiedene System-Prompts realisiert —
|
||||||
dasselbe Modell, derselbe Container, unterschiedliche Persona.
|
dasselbe Modell, derselbe Container, unterschiedliche Persona.
|
||||||
|
|
||||||
|
Ein anderes Modell für beide Rollen (z. B. den lokalen Strata-Server) setzt `PI_CODER_MODEL=<provider>/<id>`,
|
||||||
|
siehe [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md#anderes-modell-für-die-schleife).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Voraussetzungen
|
## Voraussetzungen
|
||||||
|
|
|
||||||
22
models.json
22
models.json
|
|
@ -39,6 +39,28 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"strata": {
|
||||||
|
"baseUrl": "http://127.0.0.1:9090/v1",
|
||||||
|
"api": "openai-completions",
|
||||||
|
"apiKey": "none",
|
||||||
|
"compat": {
|
||||||
|
"supportsDeveloperRole": false,
|
||||||
|
"supportsReasoningEffort": true,
|
||||||
|
"maxTokensField": "max_tokens"
|
||||||
|
},
|
||||||
|
"models": [
|
||||||
|
{
|
||||||
|
"id": "qwen3.8-flash-next-iq3_s",
|
||||||
|
"name": "Strata Qwen3.8-Flash-Next IQ3_S (lokal :9090)",
|
||||||
|
"reasoning": true,
|
||||||
|
"input": ["text"],
|
||||||
|
"contextWindow": 262144,
|
||||||
|
"maxTokens": 16384,
|
||||||
|
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
"openrouter": {
|
"openrouter": {
|
||||||
"models": [
|
"models": [
|
||||||
{ "id": "qwen/qwen3-235b-a22b:free", "name": "Qwen3 235B (Free)" },
|
{ "id": "qwen/qwen3-235b-a22b:free", "name": "Qwen3 235B (Free)" },
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// pi-coding-extension.ts
|
// pi-coding-extension.ts
|
||||||
// Automatisierter Coder-Judge-Fix-Workflow für AI-Coding-Assistenten
|
// Automatisierter Coder-Judge-Fix-Workflow für AI-Coding-Assistenten
|
||||||
// Ein Modell (coding_model) auf Single-Server (Port 8001); Rollen Coder/Judge via System-Prompt
|
// Ein Modell (Standard: coding_model auf Single-Server :8001, sonst PI_CODER_MODEL); Rollen Coder/Judge via System-Prompt
|
||||||
|
|
||||||
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
||||||
import { Type } from "typebox";
|
import { Type } from "typebox";
|
||||||
|
|
@ -432,13 +432,30 @@ async function tickTaskMdStatus(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single-Server: genau ein Modell (coding_model auf :8001) für beide Rollen.
|
// Single-Modell: genau ein Modell (Standard coding_model auf :8001, oder PI_CODER_MODEL) für beide Rollen.
|
||||||
// Der Rollenwechsel Coder/Judge erfolgt NICHT mehr über den Modellwechsel, sondern
|
// Der Rollenwechsel Coder/Judge erfolgt NICHT mehr über den Modellwechsel, sondern
|
||||||
// über den System-Prompt (siehe before_agent_start-Hook + currentRole). Diese Funktion
|
// über den System-Prompt (siehe before_agent_start-Hook + currentRole). Diese Funktion
|
||||||
// stellt nur sicher, dass das eine Single-Modell aktiv ist; nach dem ersten Aufruf
|
// stellt nur sicher, dass das eine Single-Modell aktiv ist; nach dem ersten Aufruf
|
||||||
// ist der Wechsel via currentModelKey gecacht und damit ein No-op.
|
// ist der Wechsel via currentModelKey gecacht und damit ein No-op.
|
||||||
const SINGLE_PROVIDER = "llama-cpp-single";
|
// PI_CODER_MODEL="<provider>/<id>" setzt ein anderes Modell für beide Rollen (z. B. strata/qwen3.8-flash-next-iq3_s);
|
||||||
const SINGLE_MODEL_ID = "coding_model";
|
// ohne die Variable bleibt es beim Single-Server auf :8001.
|
||||||
|
const DEFAULT_SINGLE_MODEL = "llama-cpp-single/coding_model";
|
||||||
|
const SINGLE_MODEL_SPEC = (process.env.PI_CODER_MODEL || DEFAULT_SINGLE_MODEL).trim();
|
||||||
|
const SINGLE_PROVIDER = SINGLE_MODEL_SPEC.slice(0, SINGLE_MODEL_SPEC.indexOf("/"));
|
||||||
|
const SINGLE_MODEL_ID = SINGLE_MODEL_SPEC.slice(SINGLE_MODEL_SPEC.indexOf("/") + 1);
|
||||||
|
const SINGLE_LABEL = `${SINGLE_PROVIDER}/${SINGLE_MODEL_ID}`;
|
||||||
|
|
||||||
|
// Endpunkt des Single-Modells laut models.json, für Bereitschaftsprüfung und Meldungen.
|
||||||
|
function singleEndpoint(ctx: ExtensionCommandContext): string {
|
||||||
|
const model = ctx.modelRegistry.find(SINGLE_PROVIDER, SINGLE_MODEL_ID);
|
||||||
|
return model?.baseUrl ? model.baseUrl.replace(/\/+$/, "") : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function notReadyMessage(ctx: ExtensionCommandContext): string {
|
||||||
|
const where = singleEndpoint(ctx) || SINGLE_LABEL;
|
||||||
|
const hint = SINGLE_MODEL_SPEC === DEFAULT_SINGLE_MODEL ? "start-coding-server.sh ausführen" : "Server starten";
|
||||||
|
return `Server nicht bereit (${where}) — ${hint}`;
|
||||||
|
}
|
||||||
|
|
||||||
async function ensureSingleModel(
|
async function ensureSingleModel(
|
||||||
pi: ExtensionAPI,
|
pi: ExtensionAPI,
|
||||||
|
|
@ -518,17 +535,20 @@ async function sendAndWait(
|
||||||
async function waitUntilModelReady(
|
async function waitUntilModelReady(
|
||||||
pi: ExtensionAPI,
|
pi: ExtensionAPI,
|
||||||
ctx: ExtensionCommandContext,
|
ctx: ExtensionCommandContext,
|
||||||
port: number,
|
|
||||||
modelAlias: string,
|
|
||||||
maxWaitMs = 180_000
|
maxWaitMs = 180_000
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
|
const endpoint = singleEndpoint(ctx);
|
||||||
|
if (!endpoint) {
|
||||||
|
ctx.ui.notify(`Modell ${SINGLE_LABEL} nicht in models.json gefunden`, "error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const deadline = Date.now() + maxWaitMs;
|
const deadline = Date.now() + maxWaitMs;
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
model: modelAlias,
|
model: SINGLE_MODEL_ID,
|
||||||
messages: [{ role: "user", content: "ping" }],
|
messages: [{ role: "user", content: "ping" }],
|
||||||
max_tokens: 1, temperature: 0.0, stream: false,
|
max_tokens: 1, temperature: 0.0, stream: false,
|
||||||
});
|
});
|
||||||
// Body als Datei — verhindert Shell-Injection wenn modelAlias Sonderzeichen enthält
|
// Body als Datei — verhindert Shell-Injection wenn die Modell-ID Sonderzeichen enthält
|
||||||
const tmpBody = `/tmp/pi_ready_${Date.now()}_${Math.random().toString(36).slice(2)}.json`;
|
const tmpBody = `/tmp/pi_ready_${Date.now()}_${Math.random().toString(36).slice(2)}.json`;
|
||||||
await pi.exec("bash", ["-c", `printf "%s" "$1" > "${tmpBody}"`, "_", body], { cwd: ctx.cwd });
|
await pi.exec("bash", ["-c", `printf "%s" "$1" > "${tmpBody}"`, "_", body], { cwd: ctx.cwd });
|
||||||
let notified = false;
|
let notified = false;
|
||||||
|
|
@ -536,13 +556,13 @@ async function waitUntilModelReady(
|
||||||
while (Date.now() < deadline) {
|
while (Date.now() < deadline) {
|
||||||
const r = await pi.exec("bash", ["-c",
|
const r = await pi.exec("bash", ["-c",
|
||||||
`curl -s -o /dev/null -w "%{http_code}" --max-time 5 ` +
|
`curl -s -o /dev/null -w "%{http_code}" --max-time 5 ` +
|
||||||
`-X POST http://localhost:${port}/v1/chat/completions ` +
|
`-X POST "$1/chat/completions" ` +
|
||||||
`-H "Content-Type: application/json" ` +
|
`-H "Content-Type: application/json" ` +
|
||||||
`-d "@${tmpBody}"`
|
`-d "@${tmpBody}"`, "_", endpoint
|
||||||
], { cwd: ctx.cwd });
|
], { cwd: ctx.cwd });
|
||||||
if (r.stdout?.trim() === "200") return true;
|
if (r.stdout?.trim() === "200") return true;
|
||||||
if (!notified) {
|
if (!notified) {
|
||||||
ctx.ui.notify(`Modell-Server (Port ${port}) lädt noch — warte bis zu 3 min…`, "info");
|
ctx.ui.notify(`Modell-Server (${endpoint}) lädt noch — warte bis zu 3 min…`, "info");
|
||||||
notified = true;
|
notified = true;
|
||||||
}
|
}
|
||||||
await new Promise(res => setTimeout(res, 3000));
|
await new Promise(res => setTimeout(res, 3000));
|
||||||
|
|
@ -1128,15 +1148,15 @@ export default function (pi: ExtensionAPI) {
|
||||||
// ── Manuelle Kommandos ───────────────────────────────────────────────────
|
// ── Manuelle Kommandos ───────────────────────────────────────────────────
|
||||||
|
|
||||||
pi.registerCommand("coder", {
|
pi.registerCommand("coder", {
|
||||||
description: "Implementiert <auftrag> ohne Review-Loop → Coder-Rolle (:8001).",
|
description: "Implementiert <auftrag> ohne Review-Loop → Coder-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
const task = (args || "").trim();
|
const task = (args || "").trim();
|
||||||
if (!task) {
|
if (!task) {
|
||||||
ctx.ui.notify("Benutzung: /coder <auftrag>", "error");
|
ctx.ui.notify("Benutzung: /coder <auftrag>", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ensureLocalGitRepo(pi, ctx);
|
await ensureLocalGitRepo(pi, ctx);
|
||||||
|
|
@ -1149,10 +1169,10 @@ export default function (pi: ExtensionAPI) {
|
||||||
});
|
});
|
||||||
|
|
||||||
pi.registerCommand("judge", {
|
pi.registerCommand("judge", {
|
||||||
description: "Review gegen TASK.md + git show HEAD → Judge-Rolle (:8001).",
|
description: "Review gegen TASK.md + git show HEAD → Judge-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await selectRole(pi, ctx, "judge");
|
await selectRole(pi, ctx, "judge");
|
||||||
|
|
@ -1163,10 +1183,10 @@ export default function (pi: ExtensionAPI) {
|
||||||
});
|
});
|
||||||
|
|
||||||
pi.registerCommand("fix", {
|
pi.registerCommand("fix", {
|
||||||
description: "Fixt Judge-Kritik, committet Ergebnis → Coder-Rolle (:8001).",
|
description: "Fixt Judge-Kritik, committet Ergebnis → Coder-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ensureLocalGitRepo(pi, ctx);
|
await ensureLocalGitRepo(pi, ctx);
|
||||||
|
|
@ -1178,10 +1198,10 @@ export default function (pi: ExtensionAPI) {
|
||||||
});
|
});
|
||||||
|
|
||||||
pi.registerCommand("shipit", {
|
pi.registerCommand("shipit", {
|
||||||
description: "Finale Freigabe gegen TASK.md + git log → Judge-Rolle (:8001).",
|
description: "Finale Freigabe gegen TASK.md + git log → Judge-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await selectRole(pi, ctx, "judge");
|
await selectRole(pi, ctx, "judge");
|
||||||
|
|
@ -1246,11 +1266,11 @@ export default function (pi: ExtensionAPI) {
|
||||||
: `--continue: Überspringe Implementierung, starte direkt mit Judge-Prüfung.`;
|
: `--continue: Überspringe Implementierung, starte direkt mit Judge-Prüfung.`;
|
||||||
ctx.ui.notify(continueMsg, "info");
|
ctx.ui.notify(continueMsg, "info");
|
||||||
|
|
||||||
// Im --continue-Modus: Single-Server prüfen (Port 8001 — Coder + Judge in einem).
|
// Im --continue-Modus: Single-Modell prüfen (Coder + Judge in einem).
|
||||||
ctx.ui.setStatus("optimize", "Single-Server wird geprüft (Port 8001)…");
|
ctx.ui.setStatus("optimize", `Single-Modell wird geprüft (${SINGLE_LABEL})…`);
|
||||||
const serverReady = await waitUntilModelReady(pi, ctx, 8001, "coding_model");
|
const serverReady = await waitUntilModelReady(pi, ctx);
|
||||||
if (!serverReady) {
|
if (!serverReady) {
|
||||||
finalNotify(ctx, "⛔ Server nicht erreichbar", "Port 8001 — kein HTTP 200 nach 3 min. start-coding-server.sh ausführen");
|
finalNotify(ctx, "⛔ Server nicht erreichbar", `${notReadyMessage(ctx)} (kein HTTP 200 nach 3 min)`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1260,7 +1280,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
const taskPreview = task.length > 55 ? task.slice(0, 52) + "…" : task;
|
const taskPreview = task.length > 55 ? task.slice(0, 52) + "…" : task;
|
||||||
ctx.ui.setStatus("optimize", `◉ Coder liest Anforderungen + implementiert: ${taskPreview}`);
|
ctx.ui.setStatus("optimize", `◉ Coder liest Anforderungen + implementiert: ${taskPreview}`);
|
||||||
if (!await selectRole(pi, ctx, "coder")) {
|
if (!await selectRole(pi, ctx, "coder")) {
|
||||||
finalNotify(ctx, "⛔ Modell-Fehler", "Modell (llama-cpp-single) nicht verfügbar");
|
finalNotify(ctx, "⛔ Modell-Fehler", `Modell (${SINGLE_LABEL}) nicht verfügbar`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentActivity = "Coder implementiert…";
|
currentActivity = "Coder implementiert…";
|
||||||
|
|
@ -1274,8 +1294,8 @@ export default function (pi: ExtensionAPI) {
|
||||||
// GPU-Ladevorgangs und ist kein verlässliches Signal. Nur HTTP 200 auf einen
|
// GPU-Ladevorgangs und ist kein verlässliches Signal. Nur HTTP 200 auf einen
|
||||||
// echten Completion-Request bedeutet: Modell ist im VRAM und bereit.
|
// echten Completion-Request bedeutet: Modell ist im VRAM und bereit.
|
||||||
ctx.ui.setStatus("optimize", "Single-Server wird geprüft…");
|
ctx.ui.setStatus("optimize", "Single-Server wird geprüft…");
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
finalNotify(ctx, "⛔ Server nicht erreichbar", "Port 8001 — kein HTTP 200 nach 3 min. start-coding-server.sh ausführen");
|
finalNotify(ctx, "⛔ Server nicht erreichbar", `${notReadyMessage(ctx)} (kein HTTP 200 nach 3 min)`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1313,7 +1333,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
for (let round = 1; round <= maxRounds; round++) {
|
for (let round = 1; round <= maxRounds; round++) {
|
||||||
const prog = "●".repeat(round - 1) + "◉" + "○".repeat(maxRounds - round);
|
const prog = "●".repeat(round - 1) + "◉" + "○".repeat(maxRounds - round);
|
||||||
if (!await selectRole(pi, ctx, "judge")) {
|
if (!await selectRole(pi, ctx, "judge")) {
|
||||||
finalNotify(ctx, "⛔ Modell-Fehler", "Modell (llama-cpp-single) nicht verfügbar");
|
finalNotify(ctx, "⛔ Modell-Fehler", `Modell (${SINGLE_LABEL}) nicht verfügbar`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1378,7 +1398,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
? (currentBlockers.length > 50 ? currentBlockers.slice(0, 47) + "…" : currentBlockers)
|
? (currentBlockers.length > 50 ? currentBlockers.slice(0, 47) + "…" : currentBlockers)
|
||||||
: "Kritikpunkte aus Judge-Bericht";
|
: "Kritikpunkte aus Judge-Bericht";
|
||||||
if (!await selectRole(pi, ctx, "coder")) {
|
if (!await selectRole(pi, ctx, "coder")) {
|
||||||
finalNotify(ctx, "⛔ Modell-Fehler", "Modell (llama-cpp-single) nicht verfügbar");
|
finalNotify(ctx, "⛔ Modell-Fehler", `Modell (${SINGLE_LABEL}) nicht verfügbar`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentActivity = `Coder fixt: ${blockerHint}`;
|
currentActivity = `Coder fixt: ${blockerHint}`;
|
||||||
|
|
@ -1471,15 +1491,15 @@ export default function (pi: ExtensionAPI) {
|
||||||
// ── Schlanke Kommandos für kleine Änderungen ─────────────────────────────
|
// ── Schlanke Kommandos für kleine Änderungen ─────────────────────────────
|
||||||
|
|
||||||
pi.registerCommand("patch", {
|
pi.registerCommand("patch", {
|
||||||
description: "Gezielte Minimaländerung ohne Refactoring, committet → Coder-Rolle (:8001).",
|
description: "Gezielte Minimaländerung ohne Refactoring, committet → Coder-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
const change = (args || "").trim();
|
const change = (args || "").trim();
|
||||||
if (!change) {
|
if (!change) {
|
||||||
ctx.ui.notify("Benutzung: /patch <beschreibung der änderung>", "error");
|
ctx.ui.notify("Benutzung: /patch <beschreibung der änderung>", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ensureLocalGitRepo(pi, ctx);
|
await ensureLocalGitRepo(pi, ctx);
|
||||||
|
|
@ -1491,10 +1511,10 @@ export default function (pi: ExtensionAPI) {
|
||||||
});
|
});
|
||||||
|
|
||||||
pi.registerCommand("quick_check", {
|
pi.registerCommand("quick_check", {
|
||||||
description: "Schnelle OK/PROBLEM-Prüfung einer kleinen Codeänderung → Judge-Rolle (:8001).",
|
description: "Schnelle OK/PROBLEM-Prüfung einer kleinen Codeänderung → Judge-Rolle (Single-Modell).",
|
||||||
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
handler: async function (args: string, ctx: ExtensionCommandContext) {
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await selectRole(pi, ctx, "judge");
|
await selectRole(pi, ctx, "judge");
|
||||||
|
|
@ -1562,8 +1582,8 @@ export default function (pi: ExtensionAPI) {
|
||||||
ctx.ui.notify("Benutzung: /plan <auftrag>", "error");
|
ctx.ui.notify("Benutzung: /plan <auftrag>", "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await writeTaskMd(pi, ctx, task);
|
await writeTaskMd(pi, ctx, task);
|
||||||
|
|
@ -1645,8 +1665,8 @@ export default function (pi: ExtensionAPI) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standard-Verhalten: unterbrochenen Prozess wieder aufnehmen
|
// Standard-Verhalten: unterbrochenen Prozess wieder aufnehmen
|
||||||
if (!await waitUntilModelReady(pi, ctx, 8001, "coding_model")) {
|
if (!await waitUntilModelReady(pi, ctx)) {
|
||||||
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
|
ctx.ui.notify(notReadyMessage(ctx), "error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await selectRole(pi, ctx, "coder");
|
await selectRole(pi, ctx, "coder");
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,13 @@ test("models.json: Provider llama-cpp-single hat genau ein Modell coding_model a
|
||||||
assert.deepEqual(p.models.map((m) => m.id), ["coding_model"]);
|
assert.deepEqual(p.models.map((m) => m.id), ["coding_model"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("models.json: Provider strata zeigt auf den lokalen Strata-Server (:9090)", () => {
|
||||||
|
const p = models.providers["strata"];
|
||||||
|
assert.ok(p, "Provider strata fehlt");
|
||||||
|
assert.match(p.baseUrl, /^http:\/\/127\.0\.0\.1:9090\/v1$/);
|
||||||
|
assert.deepEqual(p.models.map((m) => m.id), ["qwen3.8-flash-next-iq3_s"]);
|
||||||
|
});
|
||||||
|
|
||||||
test("models.json: tote Dual-/Alt-Provider sind entfernt", () => {
|
test("models.json: tote Dual-/Alt-Provider sind entfernt", () => {
|
||||||
for (const dead of ["llama-cpp", "llama-cpp-coder", "llama-cpp-judge"]) {
|
for (const dead of ["llama-cpp", "llama-cpp-coder", "llama-cpp-judge"]) {
|
||||||
assert.ok(!(dead in models.providers), `Toter Provider '${dead}' noch vorhanden`);
|
assert.ok(!(dead in models.providers), `Toter Provider '${dead}' noch vorhanden`);
|
||||||
|
|
|
||||||
|
|
@ -61,3 +61,14 @@ test("LICENCE.md: deterministisch in der Doku-Phase, nur wenn nicht vorhanden, p
|
||||||
assert.match(extSource, /git config user\.name/);
|
assert.match(extSource, /git config user\.name/);
|
||||||
assert.match(extSource, /new Date\(\)\.getFullYear\(\)/);
|
assert.match(extSource, /new Date\(\)\.getFullYear\(\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Single-Modell: Standard bleibt llama-cpp-single/coding_model, PI_CODER_MODEL überschreibt", () => {
|
||||||
|
assert.match(extSource, /DEFAULT_SINGLE_MODEL = "llama-cpp-single\/coding_model"/);
|
||||||
|
assert.match(extSource, /process\.env\.PI_CODER_MODEL \|\| DEFAULT_SINGLE_MODEL/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Bereitschaftsprüfung: Endpunkt aus models.json statt fest Port 8001", () => {
|
||||||
|
assert.doesNotMatch(extSource, /waitUntilModelReady\(pi, ctx, 8001/);
|
||||||
|
assert.doesNotMatch(extSource, /localhost:\$\{port\}/);
|
||||||
|
assert.match(extSource, /function singleEndpoint\b/);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue