@huggingface/tasks 0.20.4 → 0.20.5
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/dist/commonjs/local-apps.d.ts.map +1 -1
- package/dist/commonjs/local-apps.js +35 -10
- package/dist/commonjs/local-apps.spec.js +21 -0
- package/dist/esm/local-apps.d.ts.map +1 -1
- package/dist/esm/local-apps.js +35 -10
- package/dist/esm/local-apps.spec.js +21 -0
- package/package.json +1 -1
- package/src/local-apps.spec.ts +23 -0
- package/src/local-apps.ts +39 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-apps.d.ts","sourceRoot":"","sources":["../../src/local-apps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,kBAAkB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,GAAG,CACD;IACA;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;CACtD,GACD;IACA;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,eAAe,GAAG,eAAe,EAAE,CAAC;CACzG,CACH,CAAC;AAsBF,iBAAS,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE7C;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,SAAS,WAE5C;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAU9C;AAED,iBAAS,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE3D;
|
|
1
|
+
{"version":3,"file":"local-apps.d.ts","sourceRoot":"","sources":["../../src/local-apps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,kBAAkB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,GAAG,CACD;IACA;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;CACtD,GACD;IACA;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,eAAe,GAAG,eAAe,EAAE,CAAC;CACzG,CACH,CAAC;AAsBF,iBAAS,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE7C;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,SAAS,WAE5C;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAU9C;AAED,iBAAS,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE3D;AA0BD,iBAAS,cAAc,CAAC,KAAK,EAAE,SAAS,WAEvC;AA6ZD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU;;;;;;yBA3ZS,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBAiDzC,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBAmF3D,SAAS,KAAG,eAAe,EAAE;;;;;;oCAiT3B,SAAS;yBA3PT,SAAS,KAAG,eAAe,EAAE;;;;;;;yBAoF9B,SAAS,KAAG,eAAe,EAAE;;;;;;;yBA7B/B,SAAS,KAAG,eAAe,EAAE;;;;;;;;;;;;;;yBApIzB,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA9CjD,SAAS,aAAa,MAAM,KAAG,MAAM;;;;;;;yBAIpC,SAAS,KAAG,eAAe,EAAE;;;;;;;yBA6RnB,SAAS,aAAa,MAAM,KAAG,MAAM;;;;;;;yBAM9C,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBArDtD,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;CAuStC,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,UAAU,CAAC"}
|
|
@@ -43,6 +43,20 @@ function isAmdRyzenModel(model) {
|
|
|
43
43
|
function isMlxModel(model) {
|
|
44
44
|
return model.tags.includes("mlx");
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Returns the model's chat template string, coalescing across sources:
|
|
48
|
+
* GGUF metadata > chat_template_jinja file > tokenizer_config.json
|
|
49
|
+
*/
|
|
50
|
+
function getChatTemplate(model) {
|
|
51
|
+
const ct = model.gguf?.chat_template ?? model.config?.chat_template_jinja ?? model.config?.tokenizer_config?.chat_template;
|
|
52
|
+
if (typeof ct === "string") {
|
|
53
|
+
return ct;
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(ct)) {
|
|
56
|
+
return ct[0]?.template;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
46
60
|
function isUnslothModel(model) {
|
|
47
61
|
return model.tags.includes("unsloth") || isLlamaCppGgufModel(model);
|
|
48
62
|
}
|
|
@@ -338,12 +352,25 @@ const snippetMlxLm = (model) => {
|
|
|
338
352
|
];
|
|
339
353
|
};
|
|
340
354
|
const snippetPi = (model, filepath) => {
|
|
341
|
-
const quantTag = getQuantTag(filepath);
|
|
342
355
|
const modelName = model.id.split("/").pop() ?? model.id;
|
|
356
|
+
const isMLX = isMlxModel(model);
|
|
357
|
+
// Step 1: Server — differs by backend
|
|
358
|
+
const serverStep = isMLX
|
|
359
|
+
? {
|
|
360
|
+
title: "Start the MLX server",
|
|
361
|
+
setup: "# Install MLX LM:\nuv tool install mlx-lm",
|
|
362
|
+
content: `# Start a local OpenAI-compatible server:\nmlx_lm.server --model "${model.id}"`,
|
|
363
|
+
}
|
|
364
|
+
: {
|
|
365
|
+
title: "Start the llama.cpp server",
|
|
366
|
+
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
367
|
+
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${getQuantTag(filepath)} --jinja`,
|
|
368
|
+
};
|
|
369
|
+
// Step 2: Pi config — port and provider name differ
|
|
343
370
|
const modelsJson = JSON.stringify({
|
|
344
371
|
providers: {
|
|
345
|
-
"llama-cpp": {
|
|
346
|
-
baseUrl: "http://localhost:8080/v1",
|
|
372
|
+
[isMLX ? "mlx-lm" : "llama-cpp"]: {
|
|
373
|
+
baseUrl: isMLX ? "http://localhost:8000/v1" : "http://localhost:8080/v1",
|
|
347
374
|
api: "openai-completions",
|
|
348
375
|
apiKey: "none",
|
|
349
376
|
models: [{ id: modelName }],
|
|
@@ -351,11 +378,7 @@ const snippetPi = (model, filepath) => {
|
|
|
351
378
|
},
|
|
352
379
|
}, null, 2);
|
|
353
380
|
return [
|
|
354
|
-
|
|
355
|
-
title: "Start the llama.cpp server",
|
|
356
|
-
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
357
|
-
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${quantTag} --jinja`,
|
|
358
|
-
},
|
|
381
|
+
serverStep,
|
|
359
382
|
{
|
|
360
383
|
title: "Configure the model in Pi",
|
|
361
384
|
setup: "# Install Pi:\nnpm install -g @mariozechner/pi-coding-agent",
|
|
@@ -363,7 +386,7 @@ const snippetPi = (model, filepath) => {
|
|
|
363
386
|
},
|
|
364
387
|
{
|
|
365
388
|
title: "Run Pi",
|
|
366
|
-
content:
|
|
389
|
+
content: "# Start Pi in your project directory:\npi",
|
|
367
390
|
},
|
|
368
391
|
];
|
|
369
392
|
};
|
|
@@ -604,7 +627,9 @@ exports.LOCAL_APPS = {
|
|
|
604
627
|
prettyLabel: "Pi",
|
|
605
628
|
docsUrl: "https://github.com/badlogic/pi-mono",
|
|
606
629
|
mainTask: "text-generation",
|
|
607
|
-
displayOnModelPage: (model) => isLlamaCppGgufModel(model)
|
|
630
|
+
displayOnModelPage: (model) => (isLlamaCppGgufModel(model) || isMlxModel(model)) &&
|
|
631
|
+
model.pipeline_tag === "text-generation" &&
|
|
632
|
+
!!getChatTemplate(model)?.includes("tools"),
|
|
608
633
|
snippet: snippetPi,
|
|
609
634
|
},
|
|
610
635
|
};
|
|
@@ -126,6 +126,27 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \\
|
|
|
126
126
|
(0, vitest_1.expect)(snippet[1].content).toContain(`"id": "Llama-3.2-3B-Instruct-GGUF"`);
|
|
127
127
|
(0, vitest_1.expect)(snippet[2].content).toContain("pi");
|
|
128
128
|
});
|
|
129
|
+
(0, vitest_1.it)("pi - mlx", async () => {
|
|
130
|
+
const { snippet: snippetFunc } = local_apps_js_1.LOCAL_APPS["pi"];
|
|
131
|
+
const model = {
|
|
132
|
+
id: "mlx-community/Llama-3.2-3B-Instruct-mlx",
|
|
133
|
+
tags: ["mlx", "conversational"],
|
|
134
|
+
pipeline_tag: "text-generation",
|
|
135
|
+
config: {
|
|
136
|
+
tokenizer_config: {
|
|
137
|
+
chat_template: "{% if tools %}...{% endif %}",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
inference: "",
|
|
141
|
+
};
|
|
142
|
+
const snippet = snippetFunc(model);
|
|
143
|
+
(0, vitest_1.expect)(snippet[0].setup).toContain("uv tool install mlx-lm");
|
|
144
|
+
(0, vitest_1.expect)(snippet[0].content).toContain('mlx_lm.server --model "mlx-community/Llama-3.2-3B-Instruct-mlx"');
|
|
145
|
+
(0, vitest_1.expect)(snippet[1].setup).toContain("npm install -g @mariozechner/pi-coding-agent");
|
|
146
|
+
(0, vitest_1.expect)(snippet[1].content).toContain('"baseUrl": "http://localhost:8000/v1"');
|
|
147
|
+
(0, vitest_1.expect)(snippet[1].content).toContain('"id": "Llama-3.2-3B-Instruct-mlx"');
|
|
148
|
+
(0, vitest_1.expect)(snippet[2].content).toContain("pi");
|
|
149
|
+
});
|
|
129
150
|
(0, vitest_1.it)("docker model runner", async () => {
|
|
130
151
|
const { snippet: snippetFunc } = local_apps_js_1.LOCAL_APPS["docker-model-runner"];
|
|
131
152
|
const model = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-apps.d.ts","sourceRoot":"","sources":["../../src/local-apps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,kBAAkB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,GAAG,CACD;IACA;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;CACtD,GACD;IACA;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,eAAe,GAAG,eAAe,EAAE,CAAC;CACzG,CACH,CAAC;AAsBF,iBAAS,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE7C;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,SAAS,WAE5C;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAU9C;AAED,iBAAS,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE3D;
|
|
1
|
+
{"version":3,"file":"local-apps.d.ts","sourceRoot":"","sources":["../../src/local-apps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,kBAAkB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;CAClD,GAAG,CACD;IACA;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC;CACtD,GACD;IACA;;;;OAIG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,EAAE,GAAG,eAAe,GAAG,eAAe,EAAE,CAAC;CACzG,CACH,CAAC;AAsBF,iBAAS,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE7C;AAED,iBAAS,mBAAmB,CAAC,KAAK,EAAE,SAAS,WAE5C;AAED,iBAAS,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAU9C;AAED,iBAAS,wBAAwB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAE3D;AA0BD,iBAAS,cAAc,CAAC,KAAK,EAAE,SAAS,WAEvC;AA6ZD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU;;;;;;yBA3ZS,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBAiDzC,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBAmF3D,SAAS,KAAG,eAAe,EAAE;;;;;;oCAiT3B,SAAS;yBA3PT,SAAS,KAAG,eAAe,EAAE;;;;;;;yBAoF9B,SAAS,KAAG,eAAe,EAAE;;;;;;;yBA7B/B,SAAS,KAAG,eAAe,EAAE;;;;;;;;;;;;;;yBApIzB,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBA9CjD,SAAS,aAAa,MAAM,KAAG,MAAM;;;;;;;yBAIpC,SAAS,KAAG,eAAe,EAAE;;;;;;;yBA6RnB,SAAS,aAAa,MAAM,KAAG,MAAM;;;;;;;yBAM9C,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;;;;;;yBArDtD,SAAS,aAAa,MAAM,KAAG,eAAe,EAAE;;CAuStC,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/esm/local-apps.js
CHANGED
|
@@ -40,6 +40,20 @@ function isAmdRyzenModel(model) {
|
|
|
40
40
|
function isMlxModel(model) {
|
|
41
41
|
return model.tags.includes("mlx");
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Returns the model's chat template string, coalescing across sources:
|
|
45
|
+
* GGUF metadata > chat_template_jinja file > tokenizer_config.json
|
|
46
|
+
*/
|
|
47
|
+
function getChatTemplate(model) {
|
|
48
|
+
const ct = model.gguf?.chat_template ?? model.config?.chat_template_jinja ?? model.config?.tokenizer_config?.chat_template;
|
|
49
|
+
if (typeof ct === "string") {
|
|
50
|
+
return ct;
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(ct)) {
|
|
53
|
+
return ct[0]?.template;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
43
57
|
function isUnslothModel(model) {
|
|
44
58
|
return model.tags.includes("unsloth") || isLlamaCppGgufModel(model);
|
|
45
59
|
}
|
|
@@ -335,12 +349,25 @@ const snippetMlxLm = (model) => {
|
|
|
335
349
|
];
|
|
336
350
|
};
|
|
337
351
|
const snippetPi = (model, filepath) => {
|
|
338
|
-
const quantTag = getQuantTag(filepath);
|
|
339
352
|
const modelName = model.id.split("/").pop() ?? model.id;
|
|
353
|
+
const isMLX = isMlxModel(model);
|
|
354
|
+
// Step 1: Server — differs by backend
|
|
355
|
+
const serverStep = isMLX
|
|
356
|
+
? {
|
|
357
|
+
title: "Start the MLX server",
|
|
358
|
+
setup: "# Install MLX LM:\nuv tool install mlx-lm",
|
|
359
|
+
content: `# Start a local OpenAI-compatible server:\nmlx_lm.server --model "${model.id}"`,
|
|
360
|
+
}
|
|
361
|
+
: {
|
|
362
|
+
title: "Start the llama.cpp server",
|
|
363
|
+
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
364
|
+
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${getQuantTag(filepath)} --jinja`,
|
|
365
|
+
};
|
|
366
|
+
// Step 2: Pi config — port and provider name differ
|
|
340
367
|
const modelsJson = JSON.stringify({
|
|
341
368
|
providers: {
|
|
342
|
-
"llama-cpp": {
|
|
343
|
-
baseUrl: "http://localhost:8080/v1",
|
|
369
|
+
[isMLX ? "mlx-lm" : "llama-cpp"]: {
|
|
370
|
+
baseUrl: isMLX ? "http://localhost:8000/v1" : "http://localhost:8080/v1",
|
|
344
371
|
api: "openai-completions",
|
|
345
372
|
apiKey: "none",
|
|
346
373
|
models: [{ id: modelName }],
|
|
@@ -348,11 +375,7 @@ const snippetPi = (model, filepath) => {
|
|
|
348
375
|
},
|
|
349
376
|
}, null, 2);
|
|
350
377
|
return [
|
|
351
|
-
|
|
352
|
-
title: "Start the llama.cpp server",
|
|
353
|
-
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
354
|
-
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${quantTag} --jinja`,
|
|
355
|
-
},
|
|
378
|
+
serverStep,
|
|
356
379
|
{
|
|
357
380
|
title: "Configure the model in Pi",
|
|
358
381
|
setup: "# Install Pi:\nnpm install -g @mariozechner/pi-coding-agent",
|
|
@@ -360,7 +383,7 @@ const snippetPi = (model, filepath) => {
|
|
|
360
383
|
},
|
|
361
384
|
{
|
|
362
385
|
title: "Run Pi",
|
|
363
|
-
content:
|
|
386
|
+
content: "# Start Pi in your project directory:\npi",
|
|
364
387
|
},
|
|
365
388
|
];
|
|
366
389
|
};
|
|
@@ -601,7 +624,9 @@ export const LOCAL_APPS = {
|
|
|
601
624
|
prettyLabel: "Pi",
|
|
602
625
|
docsUrl: "https://github.com/badlogic/pi-mono",
|
|
603
626
|
mainTask: "text-generation",
|
|
604
|
-
displayOnModelPage: (model) => isLlamaCppGgufModel(model)
|
|
627
|
+
displayOnModelPage: (model) => (isLlamaCppGgufModel(model) || isMlxModel(model)) &&
|
|
628
|
+
model.pipeline_tag === "text-generation" &&
|
|
629
|
+
!!getChatTemplate(model)?.includes("tools"),
|
|
605
630
|
snippet: snippetPi,
|
|
606
631
|
},
|
|
607
632
|
};
|
|
@@ -124,6 +124,27 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \\
|
|
|
124
124
|
expect(snippet[1].content).toContain(`"id": "Llama-3.2-3B-Instruct-GGUF"`);
|
|
125
125
|
expect(snippet[2].content).toContain("pi");
|
|
126
126
|
});
|
|
127
|
+
it("pi - mlx", async () => {
|
|
128
|
+
const { snippet: snippetFunc } = LOCAL_APPS["pi"];
|
|
129
|
+
const model = {
|
|
130
|
+
id: "mlx-community/Llama-3.2-3B-Instruct-mlx",
|
|
131
|
+
tags: ["mlx", "conversational"],
|
|
132
|
+
pipeline_tag: "text-generation",
|
|
133
|
+
config: {
|
|
134
|
+
tokenizer_config: {
|
|
135
|
+
chat_template: "{% if tools %}...{% endif %}",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
inference: "",
|
|
139
|
+
};
|
|
140
|
+
const snippet = snippetFunc(model);
|
|
141
|
+
expect(snippet[0].setup).toContain("uv tool install mlx-lm");
|
|
142
|
+
expect(snippet[0].content).toContain('mlx_lm.server --model "mlx-community/Llama-3.2-3B-Instruct-mlx"');
|
|
143
|
+
expect(snippet[1].setup).toContain("npm install -g @mariozechner/pi-coding-agent");
|
|
144
|
+
expect(snippet[1].content).toContain('"baseUrl": "http://localhost:8000/v1"');
|
|
145
|
+
expect(snippet[1].content).toContain('"id": "Llama-3.2-3B-Instruct-mlx"');
|
|
146
|
+
expect(snippet[2].content).toContain("pi");
|
|
147
|
+
});
|
|
127
148
|
it("docker model runner", async () => {
|
|
128
149
|
const { snippet: snippetFunc } = LOCAL_APPS["docker-model-runner"];
|
|
129
150
|
const model = {
|
package/package.json
CHANGED
package/src/local-apps.spec.ts
CHANGED
|
@@ -138,6 +138,29 @@ curl -X POST "http://localhost:8000/v1/chat/completions" \\
|
|
|
138
138
|
expect(snippet[2].content).toContain("pi");
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
+
it("pi - mlx", async () => {
|
|
142
|
+
const { snippet: snippetFunc } = LOCAL_APPS["pi"];
|
|
143
|
+
const model: ModelData = {
|
|
144
|
+
id: "mlx-community/Llama-3.2-3B-Instruct-mlx",
|
|
145
|
+
tags: ["mlx", "conversational"],
|
|
146
|
+
pipeline_tag: "text-generation",
|
|
147
|
+
config: {
|
|
148
|
+
tokenizer_config: {
|
|
149
|
+
chat_template: "{% if tools %}...{% endif %}",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
inference: "",
|
|
153
|
+
};
|
|
154
|
+
const snippet = snippetFunc(model);
|
|
155
|
+
|
|
156
|
+
expect(snippet[0].setup).toContain("uv tool install mlx-lm");
|
|
157
|
+
expect(snippet[0].content).toContain('mlx_lm.server --model "mlx-community/Llama-3.2-3B-Instruct-mlx"');
|
|
158
|
+
expect(snippet[1].setup).toContain("npm install -g @mariozechner/pi-coding-agent");
|
|
159
|
+
expect(snippet[1].content).toContain('"baseUrl": "http://localhost:8000/v1"');
|
|
160
|
+
expect(snippet[1].content).toContain('"id": "Llama-3.2-3B-Instruct-mlx"');
|
|
161
|
+
expect(snippet[2].content).toContain("pi");
|
|
162
|
+
});
|
|
163
|
+
|
|
141
164
|
it("docker model runner", async () => {
|
|
142
165
|
const { snippet: snippetFunc } = LOCAL_APPS["docker-model-runner"];
|
|
143
166
|
const model: ModelData = {
|
package/src/local-apps.ts
CHANGED
|
@@ -115,6 +115,22 @@ function isMlxModel(model: ModelData) {
|
|
|
115
115
|
return model.tags.includes("mlx");
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Returns the model's chat template string, coalescing across sources:
|
|
120
|
+
* GGUF metadata > chat_template_jinja file > tokenizer_config.json
|
|
121
|
+
*/
|
|
122
|
+
function getChatTemplate(model: ModelData): string | undefined {
|
|
123
|
+
const ct =
|
|
124
|
+
model.gguf?.chat_template ?? model.config?.chat_template_jinja ?? model.config?.tokenizer_config?.chat_template;
|
|
125
|
+
if (typeof ct === "string") {
|
|
126
|
+
return ct;
|
|
127
|
+
}
|
|
128
|
+
if (Array.isArray(ct)) {
|
|
129
|
+
return ct[0]?.template;
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
118
134
|
function isUnslothModel(model: ModelData) {
|
|
119
135
|
return model.tags.includes("unsloth") || isLlamaCppGgufModel(model);
|
|
120
136
|
}
|
|
@@ -436,14 +452,28 @@ const snippetMlxLm = (model: ModelData): LocalAppSnippet[] => {
|
|
|
436
452
|
};
|
|
437
453
|
|
|
438
454
|
const snippetPi = (model: ModelData, filepath?: string): LocalAppSnippet[] => {
|
|
439
|
-
const quantTag = getQuantTag(filepath);
|
|
440
455
|
const modelName = model.id.split("/").pop() ?? model.id;
|
|
456
|
+
const isMLX = isMlxModel(model);
|
|
457
|
+
|
|
458
|
+
// Step 1: Server — differs by backend
|
|
459
|
+
const serverStep: LocalAppSnippet = isMLX
|
|
460
|
+
? {
|
|
461
|
+
title: "Start the MLX server",
|
|
462
|
+
setup: "# Install MLX LM:\nuv tool install mlx-lm",
|
|
463
|
+
content: `# Start a local OpenAI-compatible server:\nmlx_lm.server --model "${model.id}"`,
|
|
464
|
+
}
|
|
465
|
+
: {
|
|
466
|
+
title: "Start the llama.cpp server",
|
|
467
|
+
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
468
|
+
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${getQuantTag(filepath)} --jinja`,
|
|
469
|
+
};
|
|
441
470
|
|
|
471
|
+
// Step 2: Pi config — port and provider name differ
|
|
442
472
|
const modelsJson = JSON.stringify(
|
|
443
473
|
{
|
|
444
474
|
providers: {
|
|
445
|
-
"llama-cpp": {
|
|
446
|
-
baseUrl: "http://localhost:8080/v1",
|
|
475
|
+
[isMLX ? "mlx-lm" : "llama-cpp"]: {
|
|
476
|
+
baseUrl: isMLX ? "http://localhost:8000/v1" : "http://localhost:8080/v1",
|
|
447
477
|
api: "openai-completions",
|
|
448
478
|
apiKey: "none",
|
|
449
479
|
models: [{ id: modelName }],
|
|
@@ -455,11 +485,7 @@ const snippetPi = (model: ModelData, filepath?: string): LocalAppSnippet[] => {
|
|
|
455
485
|
);
|
|
456
486
|
|
|
457
487
|
return [
|
|
458
|
-
|
|
459
|
-
title: "Start the llama.cpp server",
|
|
460
|
-
setup: "# Install llama.cpp:\nbrew install llama.cpp",
|
|
461
|
-
content: `# Start a local OpenAI-compatible server:\nllama-server -hf ${model.id}${quantTag} --jinja`,
|
|
462
|
-
},
|
|
488
|
+
serverStep,
|
|
463
489
|
{
|
|
464
490
|
title: "Configure the model in Pi",
|
|
465
491
|
setup: "# Install Pi:\nnpm install -g @mariozechner/pi-coding-agent",
|
|
@@ -467,7 +493,7 @@ const snippetPi = (model: ModelData, filepath?: string): LocalAppSnippet[] => {
|
|
|
467
493
|
},
|
|
468
494
|
{
|
|
469
495
|
title: "Run Pi",
|
|
470
|
-
content:
|
|
496
|
+
content: "# Start Pi in your project directory:\npi",
|
|
471
497
|
},
|
|
472
498
|
];
|
|
473
499
|
};
|
|
@@ -714,7 +740,10 @@ export const LOCAL_APPS = {
|
|
|
714
740
|
prettyLabel: "Pi",
|
|
715
741
|
docsUrl: "https://github.com/badlogic/pi-mono",
|
|
716
742
|
mainTask: "text-generation",
|
|
717
|
-
displayOnModelPage: (model) =>
|
|
743
|
+
displayOnModelPage: (model) =>
|
|
744
|
+
(isLlamaCppGgufModel(model) || isMlxModel(model)) &&
|
|
745
|
+
model.pipeline_tag === "text-generation" &&
|
|
746
|
+
!!getChatTemplate(model)?.includes("tools"),
|
|
718
747
|
snippet: snippetPi,
|
|
719
748
|
},
|
|
720
749
|
} satisfies Record<string, LocalApp>;
|