chore(pi): scope AritmoLab provider to project, drop Gemma model

Move the AritmoLab provider (Qwen) into harness/.pi/extensions/ so it is
auto-discovered only when Pi runs with cwd=harness, keeping it project-local.
GLM (~/.pi/agent/models.json) and DeepSeek (built-in) stay user-wide. File is
.js (not .mjs) because Pi extension auto-discovery matches only /\.(ts|js)$/.

Removes the gemma4-26b-a4b model (404 at the endpoint) from both the provider
and the model-matrix default list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 11:49:11 +02:00
co-authored by Claude Fable 5
parent cdaca9b87d
commit 4479683cf4
2 changed files with 97 additions and 1 deletions
@@ -0,0 +1,96 @@
import { createAssistantMessageEventStream, streamSimpleOpenAICompletions } from "@mariozechner/pi-ai";
function convertThinkingBlocks(message) {
return {
...message,
content: (message.content ?? []).map((block) => {
if (block?.type !== "thinking") return block;
return { type: "text", text: block.thinking ?? "" };
}),
};
}
function convertEvent(event) {
if (event.type === "thinking_start") {
return { type: "text_start", contentIndex: event.contentIndex, partial: convertThinkingBlocks(event.partial) };
}
if (event.type === "thinking_delta") {
return { type: "text_delta", contentIndex: event.contentIndex, delta: event.delta, partial: convertThinkingBlocks(event.partial) };
}
if (event.type === "thinking_end") {
return { type: "text_end", contentIndex: event.contentIndex, content: event.content, partial: convertThinkingBlocks(event.partial) };
}
if (event.type === "done") {
return { ...event, message: convertThinkingBlocks(event.message) };
}
if (event.type === "error") {
return { ...event, error: convertThinkingBlocks(event.error) };
}
if (event.partial) {
return { ...event, partial: convertThinkingBlocks(event.partial) };
}
return event;
}
function streamAritmolab(model, context, options) {
const source = streamSimpleOpenAICompletions(model, context, options);
const stream = createAssistantMessageEventStream();
(async () => {
try {
for await (const event of source) {
stream.push(convertEvent(event));
}
} catch (error) {
const message = {
role: "assistant",
content: [],
api: model.api,
provider: model.provider,
model: model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
stopReason: options?.signal?.aborted ? "aborted" : "error",
errorMessage: error instanceof Error ? error.message : String(error),
timestamp: Date.now(),
};
stream.push({ type: "error", reason: message.stopReason, error: message });
stream.end();
}
})();
return stream;
}
export default function (pi) {
pi.registerProvider("aritmolab", {
name: "AritmoLab",
baseUrl: "https://ml-aritmolab.policlinicosandonato.it/v1",
apiKey: "aritmolab",
api: "openai-completions",
streamSimple: streamAritmolab,
models: [
{
id: "qwen3.6-35b-a3b",
name: "AritmoLab Qwen3.6 35B A3B",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 131072,
maxTokens: 16384,
compat: {
supportsDeveloperRole: false,
supportsReasoningEffort: false,
supportsStore: false,
maxTokensField: "max_tokens",
},
},
],
});
}
+1 -1
View File
@@ -32,7 +32,7 @@ if (!sessionId) {
process.exit(2);
}
const models = (process.argv[3] ??
"zai/glm-5.2,deepseek/deepseek-v4-pro,aritmolab/qwen3.6-35b-a3b,aritmolab/gemma4-26b-a4b")
"zai/glm-5.2,deepseek/deepseek-v4-pro,aritmolab/qwen3.6-35b-a3b")
.split(",").map((s) => s.trim()).filter(Boolean);
const thinking = process.argv[4] ?? "medium";
const outDir = process.argv[5] ?? "/tmp/model-matrix";