diff --git a/dankclaw/hermes/config.yaml.example b/dankclaw/hermes/config.yaml.example index afaa784..7b2154c 100644 --- a/dankclaw/hermes/config.yaml.example +++ b/dankclaw/hermes/config.yaml.example @@ -10,15 +10,15 @@ model: provider: dankclaw-large base_url: http://192.168.0.143:7770/v1 api_key: not-needed - default: frank-large + default: frank-dragoon providers: dankclaw-large: api: http://192.168.0.143:7770/v1 discover_models: false models: - frank-large: - context_length: 114688 + frank-dragoon: + context_length: 262144 dankserver-small: api: http://192.168.0.235:7770/v1 discover_models: false @@ -29,7 +29,7 @@ providers: # Auxiliary routing from the live configuration. Named providers route via # their `api:` URL; `custom` entries route by their explicit `base_url`. auxiliary: - vision: {provider: dankclaw-large, model: frank-large} + vision: {provider: dankclaw-large, model: frank-dragoon} web_extract: {provider: dankserver-small, model: frank-medium} compression: {provider: dankserver-small, model: frank-medium} skills_hub: {provider: dankserver-small, model: frank-medium} @@ -50,8 +50,8 @@ auxiliary: effort: none memory_query_rewrite: {provider: custom, model: frank-medium, base_url: http://192.168.0.235:7770/v1} tts_audio_tags: {provider: custom, model: frank-medium, base_url: http://192.168.0.235:7770/v1} - triage_specifier: {provider: dankclaw-large, model: frank-large} - kanban_decomposer: {provider: dankclaw-large, model: frank-large} + triage_specifier: {provider: dankclaw-large, model: frank-dragoon} + kanban_decomposer: {provider: dankclaw-large, model: frank-dragoon} profile_describer: {provider: dankserver-small, model: frank-medium} curator: {provider: dankserver-small, model: frank-medium} diff --git a/scripts/autoresearch-bench.py b/scripts/autoresearch-bench.py index 3c1fb15..8fd102a 100755 --- a/scripts/autoresearch-bench.py +++ b/scripts/autoresearch-bench.py @@ -104,7 +104,7 @@ def stream_completion(url: str, model: str, prompt: str): def main(): ap = argparse.ArgumentParser() ap.add_argument("--url", default="http://127.0.0.1:7770") - ap.add_argument("--model", default="frank-large") + ap.add_argument("--model", default="frank-dragoon") args = ap.parse_args() with urllib.request.urlopen(args.url.rstrip("/") + "/v1/models", diff --git a/scripts/autoresearch-frank-primary.sh b/scripts/autoresearch-frank-primary.sh index 9d9f857..5407bdb 100755 --- a/scripts/autoresearch-frank-primary.sh +++ b/scripts/autoresearch-frank-primary.sh @@ -146,7 +146,7 @@ while n < TGT: n += len(seg) + 1 prompt = " ".join(parts) json.dump( - {"model": "frank-primary", "prompt": prompt, + {"model": "frank-archon", "prompt": prompt, "max_tokens": 256, "temperature": 0.0, "stream": False, "stop": ["<|im_end|>"]}, open(sys.argv[1], "w"), diff --git a/scripts/autoresearch/frank-primary-measure.py b/scripts/autoresearch/frank-primary-measure.py index f3d3b09..6974118 100755 --- a/scripts/autoresearch/frank-primary-measure.py +++ b/scripts/autoresearch/frank-primary-measure.py @@ -45,7 +45,7 @@ import urllib.error import urllib.request BASE = os.environ.get("AR_BASE", "http://127.0.0.1:7770") -MODEL = os.environ.get("AR_MODEL", "frank-primary") +MODEL = os.environ.get("AR_MODEL", "frank-archon") PROMPT_CEILING = int(os.environ.get("AR_PROMPT_CEILING", "100000")) DEPTHS = (115, 1056, 4096) WARM_TOKENS = 64 diff --git a/scripts/bench-decode.sh b/scripts/bench-decode.sh index a130d0f..9431ca0 100755 --- a/scripts/bench-decode.sh +++ b/scripts/bench-decode.sh @@ -57,7 +57,7 @@ run_bench() { # Warmup (small request) curl -s -m 60 http://127.0.0.1:$PORT/v1/chat/completions \ -H "Content-Type: application/json" \ - -d '{"model":"frank-large","messages":[{"role":"user","content":"Hi"}],"max_tokens":16,"stream":false}' > /dev/null 2>&1 || true + -d '{"model":"frank-dragoon","messages":[{"role":"user","content":"Hi"}],"max_tokens":16,"stream":false}' > /dev/null 2>&1 || true # Build 8K prompt local prompt diff --git a/scripts/bench-probe.py b/scripts/bench-probe.py index 234ed59..6bc3e83 100755 --- a/scripts/bench-probe.py +++ b/scripts/bench-probe.py @@ -26,7 +26,7 @@ def build_prompt(): def probe(salt): prompt = f"[probe {salt}]\n" + build_prompt() body = json.dumps({ - "model": "frank-primary", + "model": "frank-archon", "prompt": prompt, "temperature": 0.0, "max_tokens": 512, }).encode() req = urllib.request.Request(URL, data=body, diff --git a/scripts/bench-threads-batch-http.py b/scripts/bench-threads-batch-http.py index c63a472..d6fe095 100755 --- a/scripts/bench-threads-batch-http.py +++ b/scripts/bench-threads-batch-http.py @@ -39,7 +39,7 @@ def send_prefill_request(): with open(PROMPT_FILE, "r") as f: prompt = f.read() body = json.dumps({ - "model": "frank-large", + "model": "frank-dragoon", "messages": [{"role": "user", "content": prompt}], "max_tokens": 1, "stream": False diff --git a/scripts/calib-push.py b/scripts/calib-push.py index ac0b069..562ffca 100755 --- a/scripts/calib-push.py +++ b/scripts/calib-push.py @@ -51,7 +51,7 @@ def tap_done(container): def push_one(url, prompt): body = json.dumps({ - "model": "frank-primary", + "model": "frank-archon", "prompt": prompt, "max_tokens": 1, "temperature": 0, diff --git a/scripts/deep-probe.py b/scripts/deep-probe.py index 2653e8a..8e2b9e0 100755 --- a/scripts/deep-probe.py +++ b/scripts/deep-probe.py @@ -18,7 +18,7 @@ def build(): def main(salt): body = json.dumps({ - "model": "frank-primary", + "model": "frank-archon", "messages": [{"role": "user", "content": f"[probe {salt}] Continue and summarize this material in English, 400 words.\n\n" + build()}], "temperature": 0.0, "max_tokens": 512, "stream": True, "stream_options": {"include_usage": True}, diff --git a/scripts/fleet-probes-swift15.sh b/scripts/fleet-probes-swift15.sh index 9d329cd..36ddd78 100755 --- a/scripts/fleet-probes-swift15.sh +++ b/scripts/fleet-probes-swift15.sh @@ -16,7 +16,7 @@ def png(color): + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b"")) b64 = base64.b64encode(png((255, 0, 0))).decode() -body = json.dumps({"model": "frank-primary", "max_tokens": 256, "temperature": 0, +body = json.dumps({"model": "frank-archon", "max_tokens": 256, "temperature": 0, "messages": [{"role": "user", "content": [ {"type": "image_url", "image_url": {"url": "data:image/png;base64," + b64}}, {"type": "text", "text": "What color is this image? Answer with one word."}]}]}).encode() @@ -30,7 +30,7 @@ PY echo "== tools (expect tool_calls)" curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' -d '{ - "model":"frank-primary","temperature":0,"max_tokens":128, + "model":"frank-archon","temperature":0,"max_tokens":128, "messages":[{"role":"user","content":"What is 23 times 47? Use the calculator tool."}], "tools":[{"type":"function","function":{"name":"calculator","description":"evaluate arithmetic", "parameters":{"type":"object","properties":{"expr":{"type":"string"}},"required":["expr"]}}}]}' \ @@ -40,17 +40,17 @@ echo "== reasoning_effort fold (xhigh/medium/low/high all 200 on froggeric v22.5 for lvl in xhigh medium low high; do code=$(curl -s -o /dev/null -w "%{http_code}" -m 120 $B/chat/completions \ -H 'Content-Type: application/json' \ - -d "{\"model\":\"frank-primary\",\"max_tokens\":8,\"reasoning_effort\":\"$lvl\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}") + -d "{\"model\":\"frank-archon\",\"max_tokens\":8,\"reasoning_effort\":\"$lvl\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}") echo " reasoning_effort=$lvl -> HTTP $code" done echo "== reasoning_content channel" curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' \ - -d '{"model":"frank-primary","max_tokens":64,"messages":[{"role":"user","content":"Is 97 prime? Think briefly."}]}' \ + -d '{"model":"frank-archon","max_tokens":64,"messages":[{"role":"user","content":"Is 97 prime? Think briefly."}]}' \ | python3 -c 'import json,sys; m=json.load(sys.stdin)["choices"][0]["message"]; print("has reasoning_content:", bool(m.get("reasoning_content")), "| content:", (m.get("content") or "")[:60].replace(chr(10)," "))' echo "== response_format json_object" curl -s -m 120 $B/chat/completions -H 'Content-Type: application/json' \ - -d '{"model":"frank-primary","max_tokens":64,"response_format":{"type":"json_object"},"messages":[{"role":"user","content":"Return JSON {\"ok\": true}"}]}' \ + -d '{"model":"frank-archon","max_tokens":64,"response_format":{"type":"json_object"},"messages":[{"role":"user","content":"Return JSON {\"ok\": true}"}]}' \ | python3 -c 'import json,sys; d=json.load(sys.stdin); print("JSON MODE:", (d["choices"][0]["message"].get("content") or "")[:60])' echo "PROBES_DONE" diff --git a/scripts/frank-large.env b/scripts/frank-large.env index da3caaa..1008c56 100644 --- a/scripts/frank-large.env +++ b/scripts/frank-large.env @@ -130,7 +130,10 @@ FRANK_LARGE_TOKENIZER_FILES="tokenizer.json chat_template.jinja tokenizer_config # --- engine flags (docs/FLAGS.md of the flash-server repo; anything unset # stays at the image default, which is what was qualified) ------------------ -HALOGEN_MODEL_ID=frank-large +# Served model id — Protoss name (wire rename 2026-10-09); the service, unit, +# scripts and this file keep the frank-large name. OpenWebUI api_configs +# model_ids for the :7770 backend MUST name this value. +HALOGEN_MODEL_ID=frank-dragoon HALOGEN_CTX=262144 HALOGEN_KV_POOL_POSITIONS=524288 HALOGEN_KV_SLOTS=2 diff --git a/scripts/frank-primary.env b/scripts/frank-primary.env index 8088eef..f59ea7a 100644 --- a/scripts/frank-primary.env +++ b/scripts/frank-primary.env @@ -86,7 +86,11 @@ FRANK_PRIMARY_STATE_DIR=/home/dank/radiance-state # the GPUs or the port. FRANK_PRIMARY_CONTAINER=frank-primary FRANK_PRIMARY_LEGACY_CONTAINERS="frank-primary-qwen frank-primary-r9v qwen-fp8 glm-probe" -FRANK_PRIMARY_SERVED_NAME=frank-primary +# Served model id — Protoss name (wire rename 2026-10-09). The container, +# unit, scripts and this file keep the frank-primary name above; only the +# alias on the wire moved. Radiance validates the requested model name, so +# every client (harness, bench scripts, probes) MUST send this value. +FRANK_PRIMARY_SERVED_NAME=frank-archon FRANK_PRIMARY_PORT=7770 # Frank's chat-template call: froggeric's fixed Qwen3.8 template (the # repo's root chat_template.jinja, vendored here; the checkpoint's own diff --git a/scripts/frank-secondary.env b/scripts/frank-secondary.env index bc0da57..9f63aa8 100644 --- a/scripts/frank-secondary.env +++ b/scripts/frank-secondary.env @@ -35,7 +35,13 @@ LLAMA_BIN=/home/dank/GitPackages/llama-master/build-cuda/bin/llama-server MODEL_FILE=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q6_K.gguf MMPROJ_FILE=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/mmproj-Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-BF16.gguf -ALIAS=frank-secondary +# Served model id — the harness/family name (Protoss rename completed to the +# wire 2026-10-09: harness ids + homepage cards 2026-10-08, /v1/models aliases +# this day). The SERVICE, unit, scripts and this env file keep the +# frank-secondary name; only the alias on the wire changed. Consumers that +# key on the served id: OpenWebUI (model row, access_grant, api_configs +# model_ids) and the harness models.yml. +ALIAS=frank-zealot BIND_ADDR=0.0.0.0 LISTEN_PORT=7771 # CTX_SIZE is the POOL llama.cpp divides across slots: 401,408 / 2 = 200,704 diff --git a/scripts/serve-frank-large.sh b/scripts/serve-frank-large.sh index e92323e..c67cd94 100755 --- a/scripts/serve-frank-large.sh +++ b/scripts/serve-frank-large.sh @@ -51,7 +51,7 @@ set +a : "${FRANK_LARGE_VISION_TOWER:?FRANK_LARGE_VISION_TOWER must name the tower}" : "${FRANK_LARGE_VISION_BYTES:?FRANK_LARGE_VISION_BYTES must pin the tower size}" : "${FRANK_LARGE_TOKENIZER_FILES:?FRANK_LARGE_TOKENIZER_FILES must list the tokenizer dir contents}" -: "${HALOGEN_MODEL_ID:?HALOGEN_MODEL_ID must be the served alias (frank-large)}" +: "${HALOGEN_MODEL_ID:?HALOGEN_MODEL_ID must be the served alias (frank-dragoon)}" : "${HALOGEN_CTX:?HALOGEN_CTX must be set (per-slot window)}" : "${HALOGEN_KV_POOL_POSITIONS:?HALOGEN_KV_POOL_POSITIONS must be set}" : "${HALOGEN_KV_SLOTS:?HALOGEN_KV_SLOTS must be set}" diff --git a/scripts/serve-frank-secondary.sh b/scripts/serve-frank-secondary.sh index 864d983..ba95d8a 100755 --- a/scripts/serve-frank-secondary.sh +++ b/scripts/serve-frank-secondary.sh @@ -39,7 +39,7 @@ fi # --- defaults (used when the env file does not set them) ------------------- : "${LLAMA_BIN:=/home/dank/GitPackages/llama-master/build-cuda/bin/llama-server}" : "${MODEL_FILE:=/home/dank/models/Qwen35-9B-HauhauCS-Q6K/Qwen3.5-9B-Uncensored-HauhauCS-Aggressive-Q6_K.gguf}" -: "${ALIAS:=frank-secondary}" +: "${ALIAS:=frank-zealot}" : "${BIND_ADDR:=0.0.0.0}" : "${LISTEN_PORT:=7771}" # ctx-size is the POOL llama.cpp divides across slots: 401,408 / 2 = 200,704 diff --git a/shared/homepage/docs.html b/shared/homepage/docs.html index 5b9f28f..450f5b0 100644 --- a/shared/homepage/docs.html +++ b/shared/homepage/docs.html @@ -70,8 +70,7 @@ conversations are saved to your account, so history follows you between devices.
Below the text box, the model box on the right chooses which model answers you.
- Family accounts get frank-zealot — the fleet's fast all-rounder
- (Open WebUI lists models by their API id; this one is frank-secondary),
+ Family accounts get frank-zealot — the fleet's fast all-rounder,
which also sees images: drag a photo or screenshot straight into the chat box.
Frank's account can additionally reach the bigger models.
@@ -85,11 +84,11 @@
The homepage "Model Information" panel shows whether each one is up right now —
and plays the unit's voice if you click its quoted line.
- Naming: the Open WebUI picker and the raw API show the - endpoint api ids in brackets below. The Protoss names are the family - names; a future switchover will rename the ids to match.
+Naming: the Open WebUI picker and the raw API show + exactly the Protoss names used on this page (renamed 2026-10-09). The name you + read here is the name you type into a config file.
-Which one to pick? Small utility work, autocomplete, RAG,
programming, and personal agents: frank-dragoon. Software
engineering, sysadmin, and instruction tasks: frank-archon (ask
- Frank first). The ids in brackets are what the Open WebUI picker and the
- raw API show today; the Protoss names are the family names, and the switchover
- will rename the ids to match.
https://ai.franksdank.cloud/api/v1frank-secondary — this is frank-zealot, the family utility model (the API uses the id, not the family name)frank-zealot — the family utility model (this is the id the API expects)sk-… from step 1 — sent as the header Authorization: Bearer sk-…Proof that it works, from any terminal (replace the key):
curl https://ai.franksdank.cloud/api/v1/chat/completions \
-H "Authorization: Bearer PASTE-YOUR-KEY" \
-H "Content-Type: application/json" \
- -d '{"model": "frank-secondary", "messages": [{"role": "user", "content": "Hello!"}]}'
+ -d '{"model": "frank-zealot", "messages": [{"role": "user", "content": "Hello!"}]}'
Install once (npm install -g opencode-ai), then create the file
@@ -177,13 +175,13 @@
"apiKey": "PASTE-YOUR-KEY"
},
"models": {
- "frank-secondary": { "name": "frank-secondary" }
+ "frank-zealot": { "name": "frank-zealot" }
}
}
}
}
Start opencode and pick the model with /model —
- it appears as frank/frank-secondary.
frank/frank-zealot.
Create the file ~/.pi/agent/models.json with:
Then start Pi with pi --model frank/frank-secondary.
Then start Pi with pi --model frank/frank-zealot.
The key works only for the family AI — it is not your Authentik password, and losing it costs nothing beyond asking Frank to rotate it. diff --git a/tests/frank_large_unit.bats b/tests/frank_large_unit.bats index 4add0f6..e0fa765 100755 --- a/tests/frank_large_unit.bats +++ b/tests/frank_large_unit.bats @@ -79,7 +79,7 @@ good_env() { "FRANK_LARGE_VISION_TOWER=vision.hgn" "FRANK_LARGE_VISION_BYTES=0" "FRANK_LARGE_TOKENIZER_FILES=tok.json" - "HALOGEN_MODEL_ID=frank-large" + "HALOGEN_MODEL_ID=frank-dragoon" "HALOGEN_CTX=262144" "HALOGEN_KV_POOL_POSITIONS=524288" "HALOGEN_KV_SLOTS=2" @@ -104,7 +104,7 @@ good_env() { grep -qE '^FRANK_LARGE_VISION_BYTES=[0-9]+$' "$ENV_FILE" grep -qE '^FRANK_LARGE_VISION_SHA256=[0-9a-f]{64}$' "$ENV_FILE" grep -qE '^FRANK_LARGE_TOKENIZER_FILES="tokenizer\.json( [a-z_.]+)+"$' "$ENV_FILE" - grep -qE '^HALOGEN_MODEL_ID=frank-large$' "$ENV_FILE" + grep -qE '^HALOGEN_MODEL_ID=frank-dragoon$' "$ENV_FILE" grep -qE '^HALOGEN_CTX=[0-9]+$' "$ENV_FILE" } @@ -262,7 +262,7 @@ good_env() { $(cat "$TEST_TMP/serve.log")" [[ "$output" == *"--name frank-large-halogen"* ]] [[ "$output" == *"--publish 7770:8731"* ]] - [[ "$output" == *"-e HALOGEN_MODEL_ID=frank-large"* ]] + [[ "$output" == *"-e HALOGEN_MODEL_ID=frank-dragoon"* ]] [[ "$output" == *"-e HALOGEN_CTX=262144"* ]] [[ "$output" == *"-e HALOGEN_KV_POOL_POSITIONS=524288"* ]] [[ "$output" == *"-e HALOGEN_KV_SLOTS=2"* ]] diff --git a/tests/frank_primary_unit.bats b/tests/frank_primary_unit.bats index d3d255e..0abc696 100755 --- a/tests/frank_primary_unit.bats +++ b/tests/frank_primary_unit.bats @@ -186,7 +186,7 @@ TEMPLATE="$REPO_ROOT/scripts/qwen38-froggeric-v22.5.jinja" ! grep -q -- '--publish' "$SERVE" ! grep -q -- '-p 7770' "$SERVE" grep -q '^FRANK_PRIMARY_PORT=7770$' "$ENV_FILE" - grep -q '^FRANK_PRIMARY_SERVED_NAME=frank-primary$' "$ENV_FILE" + grep -q '^FRANK_PRIMARY_SERVED_NAME=frank-archon$' "$ENV_FILE" grep -q -- '--init' "$SERVE" grep -q -- '--security-opt seccomp=unconfined' "$SERVE" grep -q -- '--ulimit memlock=-1' "$SERVE" diff --git a/tests/frank_secondary_unit.bats b/tests/frank_secondary_unit.bats index 521dc0d..870b94e 100755 --- a/tests/frank_secondary_unit.bats +++ b/tests/frank_secondary_unit.bats @@ -50,7 +50,7 @@ serve_argv() { LLAMA_BIN=$RUNTIME_DIR/bin/llama-server MODEL_FILE=$MODEL_DIR/$MODEL_STUB MMPROJ_FILE=$MODEL_DIR/$MM_STUB -ALIAS=frank-secondary +ALIAS=frank-zealot BIND_ADDR=0.0.0.0 LISTEN_PORT=7771 CTX_SIZE=$(sed -nE 's/^CTX_SIZE=([0-9]+)$/\1/p' "$ENV_FILE") @@ -118,7 +118,7 @@ run_stage() { @test "two conversations share the pool at a 200704 window each" { serve_argv [ "$status" -eq 0 ] - [ "$(argv_value --alias)" = "frank-secondary" ] + [ "$(argv_value --alias)" = "frank-zealot" ] [ "$(argv_value --port)" = "7771" ] [ "$(argv_value --host)" = "0.0.0.0" ] [ "$(argv_value --model)" = "$MODEL_DIR/$MODEL_STUB" ]