open-classify 0.9.1 → 0.9.3
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/README.md +30 -61
- package/bin/open-classify.mjs +79 -60
- package/docs/adding-a-classifier.md +1 -8
- package/docs/manifests.md +4 -5
- package/open-classify.config.example.json +3 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,23 +43,21 @@ Every classifier uses the same manifest shape and emits the same output envelope
|
|
|
43
43
|
|
|
44
44
|
## Getting started
|
|
45
45
|
|
|
46
|
-
Node 18
|
|
47
|
-
|
|
48
|
-
**1. Install**
|
|
46
|
+
Prerequisites: Node 18+, [Ollama](https://ollama.com), and the default classifier model:
|
|
49
47
|
|
|
50
48
|
```sh
|
|
51
|
-
|
|
49
|
+
ollama pull gemma4:e4b-it-q4_K_M
|
|
52
50
|
```
|
|
53
51
|
|
|
54
|
-
**
|
|
52
|
+
**1. Scaffold (from your project root)**
|
|
55
53
|
|
|
56
54
|
```sh
|
|
57
55
|
npx open-classify init
|
|
58
56
|
```
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
If the package isn't installed yet, `init` offers to add it. It writes `open-classify.config.json`, `downstream-models.json`, and a `classifiers/` directory. Re-run safe: existing files are skipped. Verify the install at any time with `npx open-classify doctor`.
|
|
61
59
|
|
|
62
|
-
**
|
|
60
|
+
**2. Use it**
|
|
63
61
|
|
|
64
62
|
```ts
|
|
65
63
|
import { createClassifier } from "open-classify";
|
|
@@ -75,31 +73,29 @@ else if (result.action === "block") handleBlock(result.block_reason); // inj
|
|
|
75
73
|
else callDownstream(result.model_id, result.tools, result.reply?.text); // route the real request
|
|
76
74
|
```
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
`createClassifier()` looks for `open-classify.config.json` in the working directory, so the scaffolded layout works with no further wiring.
|
|
77
|
+
|
|
78
|
+
**3. Enable or customize optional classifiers**
|
|
79
|
+
|
|
80
|
+
Four mandatory base classifiers (`preflight`, `model_tier`, `model_specialization`, `prompt_injection`) always run from the package. Four more (`tools`, `memory_retrieval_queries`, `conversation_digest`, `context_shift`) are optional and default to off.
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
You have two ways to use the optional ones:
|
|
81
83
|
|
|
82
84
|
```json
|
|
83
|
-
{
|
|
84
|
-
"classifiers": {
|
|
85
|
-
"stock": {
|
|
86
|
-
"tools": false
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
85
|
+
{ "classifiers": { "stock": { "tools": true } } }
|
|
90
86
|
```
|
|
91
87
|
|
|
92
|
-
Set `
|
|
88
|
+
Set the toggle to `true` to run the package-owned version. `npm update open-classify` keeps the prompt current.
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
Or customize a local copy. `init` scaffolds editable templates in `classifiers/_<name>/` (inactive because of the underscore prefix). To take one over, keep the stock toggle off and rename the folder:
|
|
95
91
|
|
|
96
92
|
```sh
|
|
97
93
|
mv classifiers/_tools classifiers/tools
|
|
98
94
|
```
|
|
99
95
|
|
|
100
|
-
|
|
96
|
+
The same convention works in reverse: rename any active classifier `<name>/` → `_<name>/` to deactivate without deleting.
|
|
101
97
|
|
|
102
|
-
To write a new classifier
|
|
98
|
+
To write a new classifier, drop a `<name>/manifest.json` + `<name>/prompt.md` in `classifiers/`. See [docs/adding-a-classifier.md](docs/adding-a-classifier.md).
|
|
103
99
|
|
|
104
100
|
### Classifying assistant output
|
|
105
101
|
|
|
@@ -310,45 +306,20 @@ The resolver picks the cheapest model matching `model_specialization` and `model
|
|
|
310
306
|
- Open Classify keeps whole messages only, drops oldest first to fit a 5,000-char budget, and caps history at 20 messages.
|
|
311
307
|
- Unknown fields are rejected, not passed through.
|
|
312
308
|
|
|
313
|
-
##
|
|
309
|
+
## Configuration
|
|
314
310
|
|
|
315
|
-
|
|
316
|
-
npm run setup
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
Checks prerequisites (Node, npm, Ollama), confirms the base model is pulled, installs dependencies, and builds. Idempotent — safe to re-run.
|
|
320
|
-
|
|
321
|
-
Optional Ollama runtime config:
|
|
311
|
+
`npx open-classify init` writes a working `open-classify.config.json` for you. To customize, edit it directly — the full set of supported fields (with realistic example values) lives in [open-classify.config.example.json](open-classify.config.example.json).
|
|
322
312
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
"model_tier": "qwen2.5:7b-instruct-q4_K_M",
|
|
334
|
-
"prompt_injection": "llama-guard3:8b",
|
|
335
|
-
"memory_retrieval_queries": "qwen2.5:7b-instruct-q4_K_M"
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
"catalog": "downstream-models.json",
|
|
339
|
-
"classifiers": {
|
|
340
|
-
"dirs": ["classifiers"],
|
|
341
|
-
"stock": {
|
|
342
|
-
"tools": false,
|
|
343
|
-
"memory_retrieval_queries": false,
|
|
344
|
-
"conversation_digest": false,
|
|
345
|
-
"context_shift": false
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
`runner.provider` currently supports `"ollama"` only. `runner.defaultModel` applies to any classifier without an explicit `runner.models` entry. `runner.models` is a flat map keyed by classifier name. `classifiers.dirs` is for user-owned copied/custom classifiers; `classifiers.stock` toggles package-owned optional classifiers.
|
|
313
|
+
| Field | What it controls |
|
|
314
|
+
|---|---|
|
|
315
|
+
| `runner.provider` | Backend. Currently `"ollama"` only. |
|
|
316
|
+
| `runner.host` | Ollama host URL. Defaults to `http://127.0.0.1:11434`. |
|
|
317
|
+
| `runner.defaultModel` | Classifier model used when there is no per-classifier override. |
|
|
318
|
+
| `runner.options` | Ollama generation options: `temperature`, `top_p`, `seed`, `num_ctx`. |
|
|
319
|
+
| `runner.models` | Per-classifier model overrides. Flat map keyed by classifier name. |
|
|
320
|
+
| `catalog` | Path to the downstream model catalog (relative to the config file). |
|
|
321
|
+
| `classifiers.dirs` | Directories of user-owned classifiers to load. |
|
|
322
|
+
| `classifiers.stock` | Toggles for package-owned optional stock classifiers. |
|
|
352
323
|
|
|
353
324
|
## Bring your own backend
|
|
354
325
|
|
|
@@ -383,8 +354,6 @@ For the lowest-level entry points, `classifyOpenClassifyInput(input, { runClassi
|
|
|
383
354
|
- [docs/resolver.md](docs/resolver.md) — aggregation and model resolution
|
|
384
355
|
- [docs/adding-a-classifier.md](docs/adding-a-classifier.md) — author guide
|
|
385
356
|
|
|
386
|
-
##
|
|
357
|
+
## Contributing
|
|
387
358
|
|
|
388
|
-
|
|
389
|
-
npm test # build + run the Node test runner suite
|
|
390
|
-
```
|
|
359
|
+
Clone the repo, then `npm run setup` (checks Node/Ollama, pulls the base model, installs and builds) and `npm test` (build + Node test runner). PRs welcome.
|
package/bin/open-classify.mjs
CHANGED
|
@@ -35,55 +35,29 @@ const TEMPLATE_DESCRIPTIONS = {
|
|
|
35
35
|
|
|
36
36
|
const CLASSIFIERS_README = `# classifiers/
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
Each classifier is a folder with two files:
|
|
39
39
|
|
|
40
|
-
- \`manifest.json\` —
|
|
41
|
-
- \`prompt.md\` — the
|
|
40
|
+
- \`manifest.json\` — declares the output shape and fallback
|
|
41
|
+
- \`prompt.md\` — the classification instructions
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
The loader skips any folder whose name starts with \`_\`. That's how the
|
|
44
|
+
four \`_<name>/\` templates here stay inactive until you opt in: drop the
|
|
45
|
+
underscore (\`mv _tools tools\`) and the classifier runs on the next start.
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
Each template mirrors a package-owned stock classifier. You have two ways
|
|
48
|
+
to use them:
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
1. **Enable in place** — set \`classifiers.stock.<name>: true\` in
|
|
51
|
+
\`open-classify.config.json\`. The package-owned version runs and is
|
|
52
|
+
updated by \`npm update open-classify\`.
|
|
53
|
+
2. **Customize a local copy** — keep the stock toggle off, drop the
|
|
54
|
+
underscore on the template here, and edit \`prompt.md\` /
|
|
55
|
+
\`manifest.json\` to taste.
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
\`
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
\`tools\`, \`memory_retrieval_queries\`, \`conversation_digest\`, and \`context_shift\`
|
|
57
|
-
ship with the package but are disabled by default in \`open-classify.config.json\`.
|
|
58
|
-
Enable a package-owned stock classifier by setting it to \`true\`:
|
|
59
|
-
|
|
60
|
-
\`\`\`json
|
|
61
|
-
{
|
|
62
|
-
"classifiers": {
|
|
63
|
-
"stock": {
|
|
64
|
-
"tools": true
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
\`\`\`
|
|
69
|
-
|
|
70
|
-
Package-owned stock classifiers are updated by \`npm update open-classify\`.
|
|
71
|
-
|
|
72
|
-
## Customizing a stock classifier
|
|
73
|
-
|
|
74
|
-
The four \`_<name>/\` directories below are editable copies of the stock classifiers.
|
|
75
|
-
They are inactive because the loader skips any folder starting with \`_\`. To customize one,
|
|
76
|
-
keep the matching \`classifiers.stock.<name>\` value \`false\`, edit the files, then drop the underscore:
|
|
77
|
-
|
|
78
|
-
\`\`\`sh
|
|
79
|
-
mv _tools tools
|
|
80
|
-
\`\`\`
|
|
81
|
-
|
|
82
|
-
You probably also want to edit its \`manifest.json\` first to fit your app (e.g. trim the \`allowed_tools\` list).
|
|
83
|
-
|
|
84
|
-
## Deactivating without deleting
|
|
85
|
-
|
|
86
|
-
Same trick in reverse — rename \`my_classifier\` → \`_my_classifier\` to take it out of the active set without losing your work.
|
|
57
|
+
To write your own classifier, drop a new \`<name>/\` folder here with its
|
|
58
|
+
own \`manifest.json\` and \`prompt.md\`. The folder name must match the
|
|
59
|
+
manifest's \`name\` field. See the
|
|
60
|
+
[author guide](https://github.com/taylorbayouth/open-classify/blob/main/docs/adding-a-classifier.md).
|
|
87
61
|
`;
|
|
88
62
|
|
|
89
63
|
const DEFAULT_CONFIG = {
|
|
@@ -186,6 +160,8 @@ function parseUninstallFlags(args) {
|
|
|
186
160
|
yes: false,
|
|
187
161
|
dryRun: false,
|
|
188
162
|
force: false,
|
|
163
|
+
keepPackage: false,
|
|
164
|
+
packageManager: null,
|
|
189
165
|
classifierDir: "classifiers",
|
|
190
166
|
};
|
|
191
167
|
|
|
@@ -194,6 +170,9 @@ function parseUninstallFlags(args) {
|
|
|
194
170
|
if (arg === "--yes" || arg === "-y") flags.yes = true;
|
|
195
171
|
else if (arg === "--dry-run") flags.dryRun = true;
|
|
196
172
|
else if (arg === "--force") flags.force = true;
|
|
173
|
+
else if (arg === "--keep-package") flags.keepPackage = true;
|
|
174
|
+
else if (arg === "--package-manager" && args[i + 1]) flags.packageManager = args[++i];
|
|
175
|
+
else if (arg.startsWith("--package-manager=")) flags.packageManager = arg.split("=")[1];
|
|
197
176
|
else if (arg === "--classifier-dir" && args[i + 1]) flags.classifierDir = args[++i];
|
|
198
177
|
else if (arg.startsWith("--classifier-dir=")) flags.classifierDir = arg.split("=")[1];
|
|
199
178
|
}
|
|
@@ -208,9 +187,10 @@ Commands:
|
|
|
208
187
|
init [options] Scaffold open-classify.config.json and classifiers/ in the
|
|
209
188
|
current directory. Re-run safe: existing files are skipped.
|
|
210
189
|
|
|
211
|
-
uninstall Remove open-classify scaffold
|
|
212
|
-
|
|
213
|
-
|
|
190
|
+
uninstall Remove the open-classify scaffold and uninstall the
|
|
191
|
+
package. Use --force to also delete active/custom
|
|
192
|
+
classifiers, --keep-package to leave the npm dependency
|
|
193
|
+
in place.
|
|
214
194
|
|
|
215
195
|
doctor Check that the install, config, Ollama, and classifiers are
|
|
216
196
|
all working. Exits non-zero on failure.
|
|
@@ -231,6 +211,8 @@ Options for init:
|
|
|
231
211
|
Options for uninstall:
|
|
232
212
|
--dry-run Preview what would be removed; don't delete anything
|
|
233
213
|
--force Remove the whole classifiers/ directory
|
|
214
|
+
--keep-package Don't run the package manager uninstall step
|
|
215
|
+
--package-manager <m> npm | pnpm | yarn | bun (default: auto-detect)
|
|
234
216
|
--classifier-dir <p> Directory for classifiers (default: ./classifiers)
|
|
235
217
|
--yes, -y Accept all prompts (CI mode)
|
|
236
218
|
|
|
@@ -389,21 +371,31 @@ async function runInit({ cwd, yes, minimal, dryRun, force, noInstall, packageMan
|
|
|
389
371
|
}
|
|
390
372
|
}
|
|
391
373
|
|
|
392
|
-
const classifierDirRel = relative(cwd, resolvedClassifierDir);
|
|
393
374
|
process.stdout.write(`
|
|
394
375
|
Next steps:
|
|
395
376
|
|
|
396
|
-
1. Pull the default model:
|
|
377
|
+
1. Pull the default classifier model:
|
|
378
|
+
|
|
397
379
|
ollama pull ${config.runner.defaultModel}
|
|
398
380
|
|
|
399
|
-
2.
|
|
400
|
-
see ./${classifierDirRel}/README.md → "Quickstart"
|
|
381
|
+
2. Verify everything is wired up:
|
|
401
382
|
|
|
402
|
-
3. Verify the install:
|
|
403
383
|
npx open-classify doctor
|
|
404
384
|
|
|
405
|
-
|
|
406
|
-
|
|
385
|
+
3. Try it without writing any code:
|
|
386
|
+
|
|
387
|
+
npx open-classify try "hello"
|
|
388
|
+
|
|
389
|
+
4. Use it from your code:
|
|
390
|
+
|
|
391
|
+
import { createClassifier } from "open-classify";
|
|
392
|
+
const { classify } = createClassifier();
|
|
393
|
+
const result = await classify({
|
|
394
|
+
messages: [{ role: "user", text: "hello" }],
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
The factory finds open-classify.config.json in your working
|
|
398
|
+
directory and wires in the classifiers/ folder automatically.
|
|
407
399
|
|
|
408
400
|
Docs: https://github.com/taylorbayouth/open-classify#readme
|
|
409
401
|
`);
|
|
@@ -562,12 +554,21 @@ function showDiffs(conflicts, cwd, classifierDir, config = DEFAULT_CONFIG) {
|
|
|
562
554
|
// uninstall
|
|
563
555
|
// ---------------------------------------------------------------------------
|
|
564
556
|
|
|
565
|
-
async function runUninstall({ cwd, yes, dryRun, force, classifierDir }) {
|
|
557
|
+
async function runUninstall({ cwd, yes, dryRun, force, keepPackage, packageManager, classifierDir }) {
|
|
566
558
|
const resolvedClassifierDir = resolve(cwd, classifierDir);
|
|
567
559
|
const plan = planUninstall(cwd, { classifierDir: resolvedClassifierDir, force });
|
|
568
560
|
|
|
569
|
-
|
|
570
|
-
|
|
561
|
+
const pkgPath = join(cwd, "package.json");
|
|
562
|
+
let pkg = null;
|
|
563
|
+
if (existsSync(pkgPath)) {
|
|
564
|
+
try { pkg = JSON.parse(readFileSync(pkgPath, "utf8")); } catch { pkg = null; }
|
|
565
|
+
}
|
|
566
|
+
const packageInstalled = pkg !== null && isOpenClassifyDep(pkg);
|
|
567
|
+
const willRemovePackage = !keepPackage && packageInstalled;
|
|
568
|
+
const pm = packageManager || detectPackageManager(cwd);
|
|
569
|
+
|
|
570
|
+
if (plan.toRemove.length === 0 && !willRemovePackage) {
|
|
571
|
+
process.stdout.write("Nothing to remove — no open-classify scaffold or dependency found.\n");
|
|
571
572
|
if (plan.toSkip.length > 0) {
|
|
572
573
|
process.stdout.write("\nSkipped active/custom classifier dirs:\n");
|
|
573
574
|
for (const p of plan.toSkip) process.stdout.write(` ${p}\n`);
|
|
@@ -576,8 +577,11 @@ async function runUninstall({ cwd, yes, dryRun, force, classifierDir }) {
|
|
|
576
577
|
return;
|
|
577
578
|
}
|
|
578
579
|
|
|
579
|
-
process.stdout.write(`\nThe following
|
|
580
|
+
process.stdout.write(`\nThe following will be removed from ${cwd}:\n\n`);
|
|
580
581
|
for (const p of plan.toRemove) process.stdout.write(` ${p}\n`);
|
|
582
|
+
if (willRemovePackage) {
|
|
583
|
+
process.stdout.write(` open-classify (via ${pm} uninstall)\n`);
|
|
584
|
+
}
|
|
581
585
|
|
|
582
586
|
if (plan.toSkip.length > 0) {
|
|
583
587
|
process.stdout.write("\nSkipped active/custom classifier dirs:\n");
|
|
@@ -585,6 +589,10 @@ async function runUninstall({ cwd, yes, dryRun, force, classifierDir }) {
|
|
|
585
589
|
process.stdout.write("\nUse --force to remove the whole classifiers/ directory.\n");
|
|
586
590
|
}
|
|
587
591
|
|
|
592
|
+
if (keepPackage && packageInstalled) {
|
|
593
|
+
process.stdout.write("\nKeeping the open-classify package (--keep-package).\n");
|
|
594
|
+
}
|
|
595
|
+
|
|
588
596
|
if (dryRun) {
|
|
589
597
|
process.stdout.write("\n(dry run — nothing removed)\n");
|
|
590
598
|
return;
|
|
@@ -600,8 +608,19 @@ async function runUninstall({ cwd, yes, dryRun, force, classifierDir }) {
|
|
|
600
608
|
|
|
601
609
|
process.stdout.write("\n");
|
|
602
610
|
for (const action of plan.actions) action();
|
|
603
|
-
|
|
604
|
-
|
|
611
|
+
if (plan.toRemove.length > 0) {
|
|
612
|
+
process.stdout.write("\n✓ removed open-classify scaffold\n");
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (willRemovePackage) {
|
|
616
|
+
process.stdout.write(`\n Running: ${pm} uninstall open-classify\n\n`);
|
|
617
|
+
const result = spawnSync(pm, ["uninstall", "open-classify"], { cwd, stdio: "inherit" });
|
|
618
|
+
if (result.status !== 0) {
|
|
619
|
+
process.stderr.write(`\n✖ Package uninstall failed. Run manually: ${pm} uninstall open-classify\n`);
|
|
620
|
+
process.exit(1);
|
|
621
|
+
}
|
|
622
|
+
process.stdout.write("\n✓ removed open-classify package\n");
|
|
623
|
+
}
|
|
605
624
|
}
|
|
606
625
|
|
|
607
626
|
function planUninstall(cwd, { classifierDir, force }) {
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
# Adding a classifier
|
|
2
2
|
|
|
3
|
-
Every classifier
|
|
4
|
-
|
|
5
|
-
There are two places a classifier can live:
|
|
6
|
-
|
|
7
|
-
- **In your own app**, in a directory listed in `open-classify.config.json` under `classifiers.dirs` (almost always `./classifiers/` after `npx open-classify init`). This is the right path when you've installed Open Classify as a dependency.
|
|
8
|
-
- **In this repo**, under `src/classifiers/<name>/`. Only do this when you're contributing a new mandatory built-in back to Open Classify.
|
|
9
|
-
|
|
10
|
-
Either way, the layout and contract are identical.
|
|
3
|
+
Every classifier uses the same two-file layout. Drop a folder into a directory listed under `classifiers.dirs` in `open-classify.config.json` (defaults to `./classifiers/` after `npx open-classify init`) and the runtime picks it up on the next start.
|
|
11
4
|
|
|
12
5
|
## 1. Create the directory
|
|
13
6
|
|
package/docs/manifests.md
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# Manifest reference
|
|
2
2
|
|
|
3
|
-
Every classifier
|
|
3
|
+
Every classifier is a directory with exactly two files:
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
|
|
7
|
-
_prompts/ # shared base markdown (base.md, reason.md, confidence.md)
|
|
6
|
+
classifiers/
|
|
8
7
|
<classifier_name>/
|
|
9
8
|
manifest.json
|
|
10
9
|
prompt.md
|
|
11
10
|
```
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
Folders whose names start with `_` are skipped by the loader — that's how the scaffolded `_<name>/` templates stay inactive until you drop the underscore.
|
|
14
13
|
|
|
15
14
|
## Fields
|
|
16
15
|
|
|
@@ -145,7 +144,7 @@ A manifest may declare both reserved fields and custom properties; they sit alon
|
|
|
145
144
|
|
|
146
145
|
`prompt.md` is the classifier-specific instruction text. The runtime composes the system prompt at load time from:
|
|
147
146
|
|
|
148
|
-
1. Shared base sections (JSON-only contract, `reason` + `certainty` rules)
|
|
147
|
+
1. Shared base sections (JSON-only contract, `reason` + `certainty` rules)
|
|
149
148
|
2. The classifier header (name and purpose, with the purpose stated as a hard scope boundary)
|
|
150
149
|
3. Auto-injected fragments for each declared reserved field (canonical enum values included, so you can't drift)
|
|
151
150
|
4. Your `prompt.md`
|
|
@@ -4,16 +4,13 @@
|
|
|
4
4
|
"host": "http://127.0.0.1:11434",
|
|
5
5
|
"defaultModel": "gemma4:e4b-it-q4_K_M",
|
|
6
6
|
"options": {
|
|
7
|
-
"num_ctx": 4096,
|
|
8
7
|
"temperature": 0,
|
|
9
8
|
"top_p": 1,
|
|
10
|
-
"seed": 0
|
|
9
|
+
"seed": 0,
|
|
10
|
+
"num_ctx": 4096
|
|
11
11
|
},
|
|
12
12
|
"models": {
|
|
13
|
-
"
|
|
14
|
-
"model_tier": "gemma4:e4b-it-q4_K_M",
|
|
15
|
-
"model_specialization": "gemma4:e4b-it-q4_K_M",
|
|
16
|
-
"prompt_injection": "gemma4:e4b-it-q4_K_M"
|
|
13
|
+
"prompt_injection": "llama-guard3:8b"
|
|
17
14
|
}
|
|
18
15
|
},
|
|
19
16
|
"catalog": "downstream-models.json",
|