Instructions to use devshub-ai/knack with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use devshub-ai/knack with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf devshub-ai/knack:Q4_K_M # Run inference directly in the terminal: llama cli -hf devshub-ai/knack:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf devshub-ai/knack:Q4_K_M # Run inference directly in the terminal: llama cli -hf devshub-ai/knack:Q4_K_M
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf devshub-ai/knack:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama cli -hf devshub-ai/knack:Q4_K_M
Use Docker
docker model run hf.co/devshub-ai/knack:Q4_K_M
- Llama new
- LM Studio
- Jan
- Ollama
How to use devshub-ai/knack with Ollama:
ollama run hf.co/devshub-ai/knack:Q4_K_M
- Unsloth Desktop
- Pi
How to use devshub-ai/knack with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf devshub-ai/knack:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "devshub-ai/knack:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use devshub-ai/knack with Docker Model Runner:
docker model run hf.co/devshub-ai/knack:Q4_K_M
- Lemonade
How to use devshub-ai/knack with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull devshub-ai/knack:Q4_K_M
Run and chat with the model
lemonade run user.knack-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use devshub-ai/knack with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf devshub-ai/knack:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default devshub-ai/knack:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use devshub-ai/knack with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf devshub-ai/knack:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "devshub-ai/knack:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Knack v3 as an Ollama decision model (--ask, /v1/systemone)
Browse files- README.md +78 -33
- knack-v3-Q4_K_M.gguf +2 -2
- knack-v3-Q8_0.gguf +2 -2
- knack.py +34 -25
README.md
CHANGED
|
@@ -73,43 +73,90 @@ ollama pull devshub/knack:q4_k_m # 516 MB, near-identical accuracy
|
|
| 73 |
ollama pull hf.co/devshub-ai/knack:Q8_0 # same model, straight from this repo
|
| 74 |
```
|
| 75 |
|
| 76 |
-
|
| 77 |
-
per field) followed by one **question id**. The answer is the next token: a letter `A`, `B`,
|
| 78 |
-
`C`... that picks the question's option in the order listed below.
|
| 79 |
|
| 80 |
-
```
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
}'
|
| 86 |
```
|
| 87 |
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
## What it decides
|
| 94 |
|
| 95 |
**Every shell command** (state fields: `command`, `description`):
|
| 96 |
|
| 97 |
-
| id | options
|
| 98 |
-
|---|---|
|
| 99 |
-
| `risk` | 0 safe, 1 needs care, 2 destructive |
|
| 100 |
-
| `long_running` | yes, no |
|
| 101 |
-
| `activity` | testing, building, installing, git, inspecting, running |
|
| 102 |
-
| `verifies` | yes, no |
|
| 103 |
-
| `mutates_repo` | yes, no |
|
| 104 |
-
| `deploys` | yes, no |
|
| 105 |
-
| `runtime_check` | yes, no |
|
| 106 |
-
| `serves` | yes, no |
|
| 107 |
|
| 108 |
**Every user turn** (state fields, in this order: `prompt`, `current_mode`,
|
| 109 |
`recent_activity`, `conversation_size`, `open_task`, `turns_on_open_task`,
|
| 110 |
`interrupted_work`, `browser_context`; see `turn_state()` in `knack.py` for defaults):
|
| 111 |
|
| 112 |
-
| id | options
|
| 113 |
|---|---|
|
| 114 |
| `turn.chat_or_task` | chat, task |
|
| 115 |
| `turn.actionable` / `turn.question_shaped` / `turn.new_task` / `turn.resume` / `turn.mission` / `turn.plan_authoring` / `turn.demo` / `turn.skip_orientation` | yes, no |
|
|
@@ -123,8 +170,8 @@ its own can be an unused letter. `knack.py` does this for you.
|
|
| 123 |
| `route.risk` | low, medium, high |
|
| 124 |
| `browser` / `messaging` / `delivery.feature_task` / `delivery.slash_task` | yes, no |
|
| 125 |
|
| 126 |
-
Knack only knows these 29 questions
|
| 127 |
-
|
| 128 |
|
| 129 |
## Results
|
| 130 |
|
|
@@ -135,10 +182,9 @@ Measured on CodeSync's own judgments (version v3, November 2026):
|
|
| 135 |
| Hand-labelled set | **97.9%** | 97.9% | 97.4% | 233 decisions labelled by hand |
|
| 136 |
| Held-out set | **95.5%** | 95.7% | 95.7% | 3,267 decisions from real sessions, never trained on |
|
| 137 |
| Rare-case set | **93.7%** | 93.6% | 93.6% | 4,120 decisions on the hardest, rarest cases |
|
| 138 |
-
| Latency | **13 ms** |
|
| 139 |
|
| 140 |
-
|
| 141 |
-
questions of a turn in a single forward pass, which is why it is faster.
|
| 142 |
|
| 143 |
## Use it inside CodeSync
|
| 144 |
|
|
@@ -156,13 +202,12 @@ picked up automatically. To turn it off: `CODESYNC_KNACK_DISABLED=1`.
|
|
| 156 |
|
| 157 |
| File | Purpose |
|
| 158 |
|---|---|
|
| 159 |
-
| `knack-v3-Q8_0.gguf`, `knack-v3-Q4_K_M.gguf` | Ollama / llama.cpp
|
| 160 |
| `knack.py` | standalone runner (CLI and local server), standard library only |
|
| 161 |
-
| `template`, `params` | Ollama prompt template and parameters (raw prompt, 1 token, temperature 0) |
|
| 162 |
| `manifest.json`, `knack-<version>.tar.gz` | the PyTorch model folder CodeSync installs |
|
| 163 |
|
| 164 |
-
The GGUF edition is the same weights
|
| 165 |
-
|
| 166 |
-
|
| 167 |
|
| 168 |
Built by [DevsHub](https://app.devshub.ai) for [CodeSync](https://app.devshub.ai).
|
|
|
|
| 73 |
ollama pull hf.co/devshub-ai/knack:Q8_0 # same model, straight from this repo
|
| 74 |
```
|
| 75 |
|
| 76 |
+
Then use it like any Ollama decision model:
|
|
|
|
|
|
|
| 77 |
|
| 78 |
+
```
|
| 79 |
+
echo "npm run dev" | ollama run devshub/knack --ask "Will it keep running?"
|
| 80 |
+
```
|
| 81 |
+
|
| 82 |
+
```
|
| 83 |
+
yes 97%
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
Ask by question id or by its plain phrasing (both listed below). Knack reads the text as a
|
| 87 |
+
shell command for the command questions and as a user message for the turn questions:
|
| 88 |
+
|
| 89 |
+
```
|
| 90 |
+
echo "git push --force" | ollama run devshub/knack --ask risk --level safe --level "needs care" --level destructive
|
| 91 |
+
echo "fix the failing login test" | ollama run devshub/knack --ask "Is this a new task?"
|
| 92 |
+
echo "fix the failing login test" | ollama run devshub/knack --ask task.intent \
|
| 93 |
+
--choice bug_fix --choice feature --choice refactor --choice api_schema --choice config_deploy \
|
| 94 |
+
--choice test --choice documentation --choice investigation --choice unknown
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
Knack only knows its 29 questions. Anything else ("Is a refund being requested?") is
|
| 98 |
+
rejected with the list of what it can answer, rather than guessed. A question asked with
|
| 99 |
+
the wrong options gets back the exact flags to use.
|
| 100 |
+
|
| 101 |
+
### cURL
|
| 102 |
+
|
| 103 |
+
```
|
| 104 |
+
curl http://localhost:11434/v1/systemone \
|
| 105 |
+
-H "Content-Type: application/json" \
|
| 106 |
+
-d '{
|
| 107 |
+
"model": "devshub/knack",
|
| 108 |
+
"state": "npm run dev",
|
| 109 |
+
"questions": {
|
| 110 |
+
"long_running": {"type": "noul", "instructions": "Will it keep running?"},
|
| 111 |
+
"serves": {"type": "noul", "instructions": "Does it start a server?"}
|
| 112 |
+
}
|
| 113 |
}'
|
| 114 |
```
|
| 115 |
|
| 116 |
+
```
|
| 117 |
+
{"model":"devshub/knack","answers":{"long_running":{"type":"noul","noul":0.9708},"serves":{"type":"noul","noul":0.9701}}}
|
| 118 |
+
```
|
| 119 |
+
|
| 120 |
+
The state can also be an object with Knack's own fields, for example
|
| 121 |
+
`{"command": "npm run dev", "description": "start the app"}`.
|
| 122 |
+
|
| 123 |
+
### Python
|
| 124 |
+
|
| 125 |
+
```
|
| 126 |
+
pip install ollama
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
```python
|
| 130 |
+
import ollama
|
| 131 |
+
|
| 132 |
+
response = ollama.systemone(
|
| 133 |
+
model="devshub/knack",
|
| 134 |
+
state="npm run dev",
|
| 135 |
+
questions={"long_running": {"type": "noul", "instructions": "Will it keep running?"}},
|
| 136 |
+
)
|
| 137 |
+
print(response.answers["long_running"].noul) # 0.9708
|
| 138 |
+
```
|
| 139 |
|
| 140 |
## What it decides
|
| 141 |
|
| 142 |
**Every shell command** (state fields: `command`, `description`):
|
| 143 |
|
| 144 |
+
| id | options | plain question |
|
| 145 |
+
|---|---|---|
|
| 146 |
+
| `risk` | 0 safe, 1 needs care, 2 destructive | How risky is this command? |
|
| 147 |
+
| `long_running` | yes, no | Will it keep running? |
|
| 148 |
+
| `activity` | testing, building, installing, git, inspecting, running | What kind of command is this? |
|
| 149 |
+
| `verifies` | yes, no | Does it verify the work? |
|
| 150 |
+
| `mutates_repo` | yes, no | Does it change the repo? |
|
| 151 |
+
| `deploys` | yes, no | Does it deploy? |
|
| 152 |
+
| `runtime_check` | yes, no | Does it need a running app? |
|
| 153 |
+
| `serves` | yes, no | Does it start a server? |
|
| 154 |
|
| 155 |
**Every user turn** (state fields, in this order: `prompt`, `current_mode`,
|
| 156 |
`recent_activity`, `conversation_size`, `open_task`, `turns_on_open_task`,
|
| 157 |
`interrupted_work`, `browser_context`; see `turn_state()` in `knack.py` for defaults):
|
| 158 |
|
| 159 |
+
| id | options |
|
| 160 |
|---|---|
|
| 161 |
| `turn.chat_or_task` | chat, task |
|
| 162 |
| `turn.actionable` / `turn.question_shaped` / `turn.new_task` / `turn.resume` / `turn.mission` / `turn.plan_authoring` / `turn.demo` / `turn.skip_orientation` | yes, no |
|
|
|
|
| 170 |
| `route.risk` | low, medium, high |
|
| 171 |
| `browser` / `messaging` / `delivery.feature_task` / `delivery.slash_task` | yes, no |
|
| 172 |
|
| 173 |
+
Knack only knows these 29 questions; Ollama rejects any other one instead of guessing.
|
| 174 |
+
Inside CodeSync, anything else goes to CodeSync's cloud judgment service.
|
| 175 |
|
| 176 |
## Results
|
| 177 |
|
|
|
|
| 182 |
| Hand-labelled set | **97.9%** | 97.9% | 97.4% | 233 decisions labelled by hand |
|
| 183 |
| Held-out set | **95.5%** | 95.7% | 95.7% | 3,267 decisions from real sessions, never trained on |
|
| 184 |
| Rare-case set | **93.7%** | 93.6% | 93.6% | 4,120 decisions on the hardest, rarest cases |
|
| 185 |
+
| Latency | **13 ms** | 17 ms | ~17 ms | median per command (8 questions) on a laptop GPU |
|
| 186 |
|
| 187 |
+
Latency is the median for all 8 command questions in one `/v1/systemone` request.
|
|
|
|
| 188 |
|
| 189 |
## Use it inside CodeSync
|
| 190 |
|
|
|
|
| 202 |
|
| 203 |
| File | Purpose |
|
| 204 |
|---|---|
|
| 205 |
+
| `knack-v3-Q8_0.gguf`, `knack-v3-Q4_K_M.gguf` | Ollama / llama.cpp decision model (`--ask`, `/v1/systemone`) |
|
| 206 |
| `knack.py` | standalone runner (CLI and local server), standard library only |
|
|
|
|
| 207 |
| `manifest.json`, `knack-<version>.tar.gz` | the PyTorch model folder CodeSync installs |
|
| 208 |
|
| 209 |
+
The GGUF edition is the same weights packaged as an Ollama decision model: a `systemone`
|
| 210 |
+
prompt template rebuilds Knack's training prompt from the request, and the answer is read
|
| 211 |
+
from the option letters exactly as CodeSync's own runtime reads it.
|
| 212 |
|
| 213 |
Built by [DevsHub](https://app.devshub.ai) for [CodeSync](https://app.devshub.ai).
|
knack-v3-Q4_K_M.gguf
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:efa47599cece417c1e66daa86b876e7665fa6d2e28a3e5c79a2425ae64dd5e23
|
| 3 |
+
size 515970400
|
knack-v3-Q8_0.gguf
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:18aaebf8083a4b123495e373131bf3fe858599c95421b412bdcc1db38d16f753
|
| 3 |
+
size 816661856
|
knack.py
CHANGED
|
@@ -15,11 +15,9 @@ Usage:
|
|
| 15 |
python knack.py --turn "add dark mode" --mode plan --json
|
| 16 |
python knack.py serve --port 33727 # CodeSync-compatible POST /v1/systemone
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
answer is the most likely of THOSE letters, renormalised (this script does that from
|
| 22 |
-
Ollama's logprobs). Do not read the raw generated letter on its own.
|
| 23 |
|
| 24 |
Env: KNACK_OLLAMA_HOST (default http://127.0.0.1:11434),
|
| 25 |
KNACK_MODEL (default devshub/knack; devshub/knack:q4_k_m is smaller, 516 MB;
|
|
@@ -30,20 +28,15 @@ from __future__ import annotations
|
|
| 30 |
|
| 31 |
import argparse
|
| 32 |
import json
|
| 33 |
-
import math
|
| 34 |
import os
|
| 35 |
import sys
|
| 36 |
import urllib.error
|
| 37 |
import urllib.request
|
| 38 |
-
from concurrent.futures import ThreadPoolExecutor
|
| 39 |
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
| 40 |
from typing import Any
|
| 41 |
|
| 42 |
HOST = os.environ.get("KNACK_OLLAMA_HOST", "http://127.0.0.1:11434").rstrip("/")
|
| 43 |
MODEL = os.environ.get("KNACK_MODEL", "devshub/knack")
|
| 44 |
-
PREFIX = "<|im_start|>user\n"
|
| 45 |
-
SUFFIX = "<|im_end|>\n<|im_start|>assistant\n"
|
| 46 |
-
LETTERS = [chr(65 + i) for i in range(26)]
|
| 47 |
_READY: set[str] = set()
|
| 48 |
|
| 49 |
# question id -> (type, option keys in letter order, what it decides)
|
|
@@ -110,19 +103,25 @@ def _post(path: str, body: dict[str, Any], timeout: float = 60.0) -> dict[str, A
|
|
| 110 |
return json.loads(r.read())
|
| 111 |
|
| 112 |
|
| 113 |
-
def
|
| 114 |
-
"""
|
| 115 |
kind, keys, _ = QUESTIONS[qid]
|
| 116 |
-
|
| 117 |
-
"
|
| 118 |
-
|
| 119 |
-
"
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
best = max(probs, key=probs.__getitem__)
|
| 127 |
return {"answer": best, "confidence": probs[best], "probabilities": probs, "type": kind}
|
| 128 |
|
|
@@ -147,8 +146,15 @@ def ask(state: dict[str, Any], qids: list[str], model: str = MODEL) -> dict[str,
|
|
| 147 |
if unknown:
|
| 148 |
raise KeyError(f"Knack was not trained on: {unknown}")
|
| 149 |
ensure_model(model)
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
|
| 154 |
def to_systemone(qid: str, a: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -213,8 +219,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 213 |
qids = a.question or (TURN if a.turn else BASH)
|
| 214 |
try:
|
| 215 |
res = ask(state, qids, a.model)
|
|
|
|
|
|
|
|
|
|
| 216 |
except OSError as exc:
|
| 217 |
-
print(f"cannot reach Ollama at {HOST} ({exc}).
|
| 218 |
return 1
|
| 219 |
if a.json:
|
| 220 |
print(json.dumps(res, indent=1))
|
|
|
|
| 15 |
python knack.py --turn "add dark mode" --mode plan --json
|
| 16 |
python knack.py serve --port 33727 # CodeSync-compatible POST /v1/systemone
|
| 17 |
|
| 18 |
+
Knack is an Ollama decision model: this script sends all questions of a command or turn in
|
| 19 |
+
one ``POST /v1/systemone`` request (needs an Ollama with decision-model support). Without the
|
| 20 |
+
script: ``echo "npm run dev" | ollama run devshub/knack --ask long_running``.
|
|
|
|
|
|
|
| 21 |
|
| 22 |
Env: KNACK_OLLAMA_HOST (default http://127.0.0.1:11434),
|
| 23 |
KNACK_MODEL (default devshub/knack; devshub/knack:q4_k_m is smaller, 516 MB;
|
|
|
|
| 28 |
|
| 29 |
import argparse
|
| 30 |
import json
|
|
|
|
| 31 |
import os
|
| 32 |
import sys
|
| 33 |
import urllib.error
|
| 34 |
import urllib.request
|
|
|
|
| 35 |
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
| 36 |
from typing import Any
|
| 37 |
|
| 38 |
HOST = os.environ.get("KNACK_OLLAMA_HOST", "http://127.0.0.1:11434").rstrip("/")
|
| 39 |
MODEL = os.environ.get("KNACK_MODEL", "devshub/knack")
|
|
|
|
|
|
|
|
|
|
| 40 |
_READY: set[str] = set()
|
| 41 |
|
| 42 |
# question id -> (type, option keys in letter order, what it decides)
|
|
|
|
| 103 |
return json.loads(r.read())
|
| 104 |
|
| 105 |
|
| 106 |
+
def _spec(qid: str) -> dict[str, Any]:
|
| 107 |
+
"""System One question for /v1/systemone (the id is what Knack matches on)."""
|
| 108 |
kind, keys, _ = QUESTIONS[qid]
|
| 109 |
+
if kind == "noul":
|
| 110 |
+
return {"type": "noul", "instructions": qid}
|
| 111 |
+
if kind == "score":
|
| 112 |
+
return {"type": "score", "instructions": qid, "criteria": keys}
|
| 113 |
+
return {"type": "choice", "instructions": qid, "criteria": {k: None for k in keys}}
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def _answer(qid: str, a: dict[str, Any]) -> dict[str, Any]:
|
| 117 |
+
"""{answer, confidence, probabilities, type} from one /v1/systemone answer."""
|
| 118 |
+
kind, keys, _ = QUESTIONS[qid]
|
| 119 |
+
if kind == "noul":
|
| 120 |
+
yes = float(a["noul"])
|
| 121 |
+
probs = {"yes": yes, "no": 1.0 - yes}
|
| 122 |
+
else:
|
| 123 |
+
raw = a.get("probabilities") or {}
|
| 124 |
+
probs = {k: float(raw.get(k, raw.get(str(i), 0.0))) for i, k in enumerate(keys)}
|
| 125 |
best = max(probs, key=probs.__getitem__)
|
| 126 |
return {"answer": best, "confidence": probs[best], "probabilities": probs, "type": kind}
|
| 127 |
|
|
|
|
| 146 |
if unknown:
|
| 147 |
raise KeyError(f"Knack was not trained on: {unknown}")
|
| 148 |
ensure_model(model)
|
| 149 |
+
try:
|
| 150 |
+
out = _post("/v1/systemone", {"model": model, "state": state,
|
| 151 |
+
"questions": {q: _spec(q) for q in qids}})
|
| 152 |
+
except urllib.error.HTTPError as exc:
|
| 153 |
+
detail = exc.read().decode(errors="replace")[:300]
|
| 154 |
+
raise RuntimeError(f"Ollama /v1/systemone: HTTP {exc.code} {detail} "
|
| 155 |
+
"(update Ollama and re-pull the model if this is an old build)") from None
|
| 156 |
+
answers = out.get("answers") or {}
|
| 157 |
+
return {q: _answer(q, answers[q]) for q in qids if q in answers}
|
| 158 |
|
| 159 |
|
| 160 |
def to_systemone(qid: str, a: dict[str, Any]) -> dict[str, Any]:
|
|
|
|
| 219 |
qids = a.question or (TURN if a.turn else BASH)
|
| 220 |
try:
|
| 221 |
res = ask(state, qids, a.model)
|
| 222 |
+
except RuntimeError as exc:
|
| 223 |
+
print(exc, file=sys.stderr)
|
| 224 |
+
return 1
|
| 225 |
except OSError as exc:
|
| 226 |
+
print(f"cannot reach Ollama at {HOST} ({exc}). Is Ollama running?", file=sys.stderr)
|
| 227 |
return 1
|
| 228 |
if a.json:
|
| 229 |
print(json.dumps(res, indent=1))
|