Updates
This commit is contained in:
1 parent
6b9b1697f2
commit
631987c62d
11 files changed
+116
-442
No files matched your search
@@ -7,7 +7,7 @@
|
||||
- [Reasoning effort per model](litellm-extra-body-reasoning.md) — GLM-5.3 defaults to reasoning_effort=max and cannot disable thinking; gpt-oss needs chat_template_kwargs via extra_body
|
||||
- [Reasoning vs completion tokens](reasoning-tokens-vs-completion-tokens.md) — reasoning comes out of max_tokens, and providers disagree about counting it
|
||||
- [Open WebUI image generation](owui-image-generation.md) — works via LiteLLM; the default 512x512 size is rejected by every image model
|
||||
- [Local code autocomplete](local-code-autocomplete.md) — FIM via /v1/completions; check rbw first; never tune for decode; ncmoe 22 + 8 s timeout since Viseron took VRAM
|
||||
- [Local code autocomplete](local-code-autocomplete.md) — retired 2026-10-29; FIM via /v1/completions, never tune for decode, if it comes back
|
||||
- [NPU setting clamps memory](npu-setting-clamps-memory.md) — MSI NPU/AI BIOS options cost 17% DRAM bandwidth and the NPU is unusable by llama.cpp anyway.
|
||||
- [mainframe bad core](mainframe-bad-core.md) — APIC 20 (cpu10, an E-core) throws fatal MCEs; offlined by a unit, RMA candidate.
|
||||
- [crowdsec bans own devices](crowdsec-bans-own-devices.md) — "no external access" is usually crowdsec banning his own phone; http_path includes the query string
|
||||
@@ -20,3 +20,5 @@
|
||||
- [Podman NFS binds go blind](podman-nfs-bind-rprivate-blind.md) — a mount landing after container start leaves containers permanently empty; podman ps looks fine
|
||||
- [dotbot force deletes live dirs](dotbot-force-deletes-live-dirs.md) — install replaces a real dir at a link target; the Claude memory dir is now one of them
|
||||
- [Discuss before adding content](discuss-before-adding-content.md) — in his notes, record what he said; suggest extras in chat, add only on agreement
|
||||
- [Container storage on /home](container-storage-on-home.md) — bind mounts since 2026-10-29; overlay origin xattrs and conmon KillMode traps
|
||||
- [Caddy 2.11.6 cuts HTTP/1.1 streams at 60 s](caddy-2116-http1-stream-cut.md) — OpenCode ECONNRESET; upgraded to 2.11.7; test --http1.1 vs --http2 first
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: caddy-2116-http1-stream-cut
|
||||
description: Caddy 2.11.6 cut HTTP/1.1 streamed responses to POSTs at exactly 60 s (OpenCode ECONNRESET); fixed by upgrading to 2.11.7 on 2026-10-29
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
|
||||
Caddy 2.11.6 added a default 1-minute idle read timeout that cancels an
|
||||
HTTP/1.1 response still streaming 60 s after the request body was read
|
||||
(caddyserver/caddy#8103). Through llm.rcjohnstone.com this ended every LLM
|
||||
stream longer than a minute: OpenCode (HTTP/1.1) reported `ECONNRESET` and
|
||||
retried, Caddy logged `aborting with incomplete response ... reading: context
|
||||
canceled`, and Strata logged `disconnect, cancel=True` at 60 s. HTTP/2 clients
|
||||
were unaffected. Fixed by recreating connor_caddy_1 on 2.11.7.
|
||||
|
||||
Ruled out first, all measured: Caddy `write` and `read_header` timeouts (no
|
||||
change), LiteLLM (177 s stream fine over HTTP/1.1 direct), Strata, the network
|
||||
(the cut reproduced from mainframe itself with `curl --http1.1`).
|
||||
|
||||
**How to apply:** a stream that dies at exactly 60 s through Caddy is this,
|
||||
not the model. Test with `curl --http1.1` and `--http2` before anything else.
|
||||
Caddy floats on `caddy:latest` and podman-stack-update refreshes it weekly, so
|
||||
a regression can arrive the same way.
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
name: container-storage-on-home
|
||||
description: Rootful podman and docker storage live on the SATA LVM via fstab bind mounts since 2026-10-29; how the move was done and the two traps it hit
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
|
||||
Since 2026-10-29, `/var/lib/containers` and `/var/lib/docker` are bind mounts
|
||||
of `/home/var-lib/containers` and `/home/var-lib/docker` (fstab,
|
||||
`x-systemd.requires-mounts-for=/home`). The NVMe is kept for models. Paths and
|
||||
configs are unchanged, so podman, docker and restic see the same paths.
|
||||
|
||||
Scripts and logs from the move: `~/podman-move-2026-10-29/` (cutover2.sh,
|
||||
fixcopy.sh, mounttest.py).
|
||||
|
||||
**Why:** Connor wants the only fast SSD free for LLM weights.
|
||||
|
||||
**How to apply — two traps, both hit on the first attempt:**
|
||||
|
||||
1. Copied overlay layers do not mount on a different filesystem. Overlay
|
||||
`index` is on by default in this kernel (`/sys/module/overlay/parameters/index`
|
||||
= Y). Each container's upper `diff` root carries `trusted.overlay.origin`,
|
||||
and each layer's `work/index` carries `trusted.overlay.upper`; both are file
|
||||
handles from the old filesystem. Every `podman start` failed with
|
||||
`overlayfs: failed to verify upper root origin`. Fix: remove that xattr and
|
||||
delete `work/index` after the final rsync (fixcopy.sh).
|
||||
2. `podman start` run from a transient systemd unit with default KillMode puts
|
||||
conmon in that unit's cgroup, and systemd kills every conmon when the unit
|
||||
ends. This produced the stale-`running` state from CLAUDE.md item 3a for all
|
||||
51 containers. Always use `systemd-run -p KillMode=process`.
|
||||
|
||||
Also: `mount(8)` from util-linux 2.42 fails any overlay with more than 8
|
||||
lowerdirs, with no kernel message, even on healthy storage. Test overlay mounts
|
||||
with mount(2) directly (mounttest.py), and run a control against known-good
|
||||
layers before trusting a failure. And any podman call between the final rsync
|
||||
and an rsync verify touches `storage.lock` and `db.sql` and fails the verify.
|
||||
|
||||
Jellyfin must start before Home Assistant; both bind udp/1900 and whichever
|
||||
starts second fails.
|
||||
@@ -13,7 +13,7 @@ The LiteLLM stack serves two profiles with different permitted providers:
|
||||
formally banned by his office but should be treated as prohibited until the
|
||||
security office gives written approval. That restriction is about HOSTED
|
||||
PRC-origin models (Moonshot/Kimi etc.). A PRC-origin model running locally
|
||||
(qwen3-coder-30b on llama-swap) is fine for work, since nothing leaves the
|
||||
(a Qwen model on llama-swap) is fine for work, since nothing leaves the
|
||||
machine. Connor's ruling, 2026-10-22.
|
||||
- **Personal** — `anthropic/*`, `openai/*`, and local.
|
||||
- `zen/*` is blocked for both, see [[zen-tos-hold]].
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
---
|
||||
name: local-code-autocomplete
|
||||
description: "Local code autocomplete (FIM) works on mainframe; qwen3-coder-30b is the best model for it despite being written off for capacity"
|
||||
description: "RETIRED 2026-10-29. Local FIM autocomplete on mainframe (minuet + qwen3-coder-30b): what was measured, kept in case it comes back"
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
|
||||
Retired 2026-10-29: Connor found the completions not worth having. minuet was
|
||||
removed from nvim and qwen3-coder-30b from llama-swap, LiteLLM and disk. The
|
||||
full config is archived in `~/guides/llm/archive/local-tier-2026-10.md`. What
|
||||
follows is the state before removal.
|
||||
|
||||
Measured 2026-09-18 (llmbench suite 6b, `fim`).
|
||||
|
||||
**Local code autocomplete is viable on this box.** Route: a raw
|
||||
|
||||
@@ -64,8 +64,6 @@ vim.pack.add({
|
||||
{ src = "https://github.com/nvim-treesitter/nvim-treesitter" },
|
||||
-- copilot deliberately off on every machine
|
||||
-- { src = "https://github.com/github/copilot.vim" },
|
||||
-- ...and this is what replaced it: FIM completion off the local box.
|
||||
{ src = "https://github.com/milanglacier/minuet-ai.nvim" },
|
||||
})
|
||||
|
||||
require("mason").setup()
|
||||
@@ -93,225 +91,6 @@ vim.lsp.config("rust_analyzer", {
|
||||
}
|
||||
})
|
||||
|
||||
-- ------------------------------------------------------------------------------
|
||||
-- Local FIM autocomplete (minuet-ai -> LiteLLM -> llama-swap -> qwen3-coder-30b)
|
||||
-- ------------------------------------------------------------------------------
|
||||
--
|
||||
-- Replaces copilot, which is off on every machine deliberately. Nothing leaves
|
||||
-- the LAN: the model runs on mainframe's 3060 and `llm.rcjohnstone.com` has no
|
||||
-- public A record -- internal CA, and Caddy source-IP gates it to 10.0.0.0/24,
|
||||
-- 10.0.1.0/24 and the podman subnets.
|
||||
--
|
||||
-- ⚠ ROUTE: `/v1/completions`, NOT `/infill`. Measured 2026-09-18 through the
|
||||
-- proxy: `/v1/completions` 200 with FIM tokens in a raw prompt, `/infill` 404
|
||||
-- because LiteLLM does not expose it. `llama.vim` wants `/infill`, which would
|
||||
-- mean talking to llama-server directly and bypassing the virtual key -- and on
|
||||
-- the work laptop that key IS the policy boundary that makes Anthropic and PRC
|
||||
-- models 403. Not worth routing around for an editor plugin.
|
||||
--
|
||||
-- ⚠ WHY qwen3-coder-30b: it is the best local FIM model by measurement (0.511
|
||||
-- exact / 0.826 similarity against qwen3-next-80b's 0.302), and FIM is a
|
||||
-- VOCABULARY feature -- gpt-oss-20b and gemma3-12b have no FIM tokens and
|
||||
-- cannot do this at all. Its "skipped for capacity" verdict was about the 128k
|
||||
-- agentic floor and does not bind here; autocomplete needs a few thousand
|
||||
-- tokens of context, not 128k.
|
||||
--
|
||||
-- ⚠ EXPECT AN OCCASIONAL MULTI-SECOND PAUSE. llama-swap runs `-np 1` with a
|
||||
-- ttl, so if another model was used in between, the next completion pays a
|
||||
-- full reload. Measured: ~10 s cold, 0.7-1.3 s warm. Accepted deliberately --
|
||||
-- concurrent agentic work is not viable on this hardware anyway.
|
||||
-- ⚠ ALWAYS call setup(). The first version of this guarded the whole require()
|
||||
-- behind "is the key present", which meant that with no key the module never
|
||||
-- loaded, `:Minuet` was never registered, and nvim gave NO indication why --
|
||||
-- the exact failure it hit in practice. `:Minuet` is created at module load,
|
||||
-- not inside setup(), and the plugin already notifies clearly when the key is
|
||||
-- missing. Let it do that job instead of silently doing nothing.
|
||||
--
|
||||
-- The key resolves lazily and is cached: env var first, then rbw, matching the
|
||||
-- opencode convention of reading keys at launch rather than writing them to
|
||||
-- disk. `false` is cached for "looked and found nothing" so a locked rbw costs
|
||||
-- one probe per session rather than one per keystroke.
|
||||
local _minuet_key
|
||||
local function minuet_key()
|
||||
if _minuet_key ~= nil then
|
||||
return _minuet_key or nil
|
||||
end
|
||||
local k = vim.env.LITELLM_KEY_NVIM
|
||||
if k and k ~= "" then
|
||||
_minuet_key = k
|
||||
return k
|
||||
end
|
||||
if vim.fn.executable("rbw") == 1 then
|
||||
vim.fn.system({ "rbw", "unlocked" })
|
||||
if vim.v.shell_error == 0 then
|
||||
-- ⚠ The work laptop MUST use the work key: it is enforced
|
||||
-- server-side to 403 Anthropic and hosted PRC-origin models, and a
|
||||
-- personal key here would silently remove that guarantee for
|
||||
-- everything nvim sends.
|
||||
local host = vim.uv.os_gethostname() or ""
|
||||
local entry = host:lower():match("sctfw004") and "litellm-key-work"
|
||||
or "litellm-key-personal"
|
||||
local out = vim.fn.system({ "rbw", "get", entry })
|
||||
if vim.v.shell_error == 0 and vim.trim(out) ~= "" then
|
||||
_minuet_key = vim.trim(out)
|
||||
return _minuet_key
|
||||
end
|
||||
end
|
||||
end
|
||||
_minuet_key = false
|
||||
return nil
|
||||
end
|
||||
|
||||
local minuet_base = vim.env.LITELLM_BASE
|
||||
if not minuet_base or minuet_base == "" then
|
||||
minuet_base = "https://llm.rcjohnstone.com"
|
||||
end
|
||||
|
||||
-- ⚠ pcall, because a hard require here takes the WHOLE config down with it.
|
||||
-- `vim.pack.add` installs on first launch, and that needs to reach github --
|
||||
-- which is not a given on a work-issued machine behind a proxy. Without this,
|
||||
-- a failed install means no MinuetStatus, no colorscheme, no anything below
|
||||
-- this line, and an error that points at minuet rather than at the network.
|
||||
local minuet_ok, minuet = pcall(require, "minuet")
|
||||
if minuet_ok then
|
||||
minuet.setup({
|
||||
provider = "openai_fim_compatible",
|
||||
-- Default is 'warn', which hides request failures. If completions stop
|
||||
-- appearing, set this to 'debug' and the reason shows up in `:messages`.
|
||||
notify = "warn",
|
||||
-- Default 3. Measured 2026-10-22 at -ncmoe 22: a fresh ~3k-token context
|
||||
-- takes 4.8 s to prefill, the same context again 0.8 s. At 3 s the first
|
||||
-- completion in a file times out, and it may not leave a cache behind.
|
||||
request_timeout = 8,
|
||||
-- Ghost text: there is no completion engine here (no nvim-cmp, no blink)
|
||||
-- and virtual text is the copilot-shaped one.
|
||||
virtualtext = {
|
||||
-- Every filetype. The ignore list is UI buffers, where typing would
|
||||
-- send a request per keystroke into a picker.
|
||||
auto_trigger_ft = { "*" },
|
||||
auto_trigger_ignore_ft = { "TelescopePrompt", "oil" },
|
||||
keymap = {
|
||||
-- Accept and dismiss are <C-l> and <C-h>, mapped below.
|
||||
accept = false,
|
||||
accept_line = false,
|
||||
prev = "<A-[>",
|
||||
next = "<A-]>",
|
||||
dismiss = false,
|
||||
},
|
||||
},
|
||||
provider_options = {
|
||||
openai_fim_compatible = {
|
||||
-- A FUNCTION, not an env var name: this is what lets the key come
|
||||
-- from rbw when the shell did not export one.
|
||||
api_key = minuet_key,
|
||||
name = "litellm",
|
||||
end_point = minuet_base .. "/v1/completions",
|
||||
model = "qwen3-coder-30b",
|
||||
-- ⚠ KEEP THIS SMALL. Measured on the real path at 48: `def add`
|
||||
-- came back with `sub` and `mul` attached, so most of the latency
|
||||
-- was spent generating text that would be discarded. Raise it only
|
||||
-- if completions are being truncated mid-expression.
|
||||
optional = {
|
||||
max_tokens = 32,
|
||||
top_p = 0.9,
|
||||
stop = { "<|fim_pad|>", "<|endoftext|>", "\n\n" },
|
||||
},
|
||||
-- ⚠ THREE POSITIONAL ARGS, not a context table. minuet calls
|
||||
-- this as `template.prompt(before, after, opts)` -- the first
|
||||
-- version took `(ctx)` and died with "attempt to concatenate
|
||||
-- field 'lines_after' (a nil value)" on the first real
|
||||
-- completion, while loading perfectly cleanly. A config that
|
||||
-- loads is not a config that works.
|
||||
--
|
||||
-- `suffix = false` because the whole FIM prompt is built here;
|
||||
-- letting minuet also send a `suffix` field would give the server
|
||||
-- two competing descriptions of the same gap.
|
||||
template = {
|
||||
prompt = function(before, after, _opts)
|
||||
return "<|fim_prefix|>" .. (before or "")
|
||||
.. "<|fim_suffix|>" .. (after or "")
|
||||
.. "<|fim_middle|>"
|
||||
end,
|
||||
suffix = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- <C-l> accepts one line; a second <C-l> within 300 ms accepts the rest, so a
|
||||
-- double tap takes the whole suggestion. <C-h> dismisses. With no suggestion
|
||||
-- showing, <C-h> deletes a character as usual and <C-l> does nothing (its
|
||||
-- default inserts a literal ^L).
|
||||
local minuet_vt = require("minuet.virtualtext").action
|
||||
local minuet_last_accept = 0
|
||||
vim.keymap.set("i", "<C-l>", function()
|
||||
if not minuet_vt.is_visible() then
|
||||
return ""
|
||||
end
|
||||
-- hrtime, not uv.now(): now() is cached per loop iteration and can miss
|
||||
-- the gap between two key presses.
|
||||
local now = vim.uv.hrtime() / 1e6
|
||||
local n_lines = 1
|
||||
if now - minuet_last_accept < 300 then
|
||||
n_lines = nil
|
||||
end
|
||||
minuet_last_accept = now
|
||||
vim.schedule(function() minuet_vt.accept(n_lines) end)
|
||||
return ""
|
||||
end, { expr = true, silent = true, desc = "Accept minuet line; double tap accepts all" })
|
||||
vim.keymap.set("i", "<C-h>", function()
|
||||
if minuet_vt.is_visible() then
|
||||
vim.schedule(minuet_vt.dismiss)
|
||||
return ""
|
||||
end
|
||||
return "<C-h>"
|
||||
end, { expr = true, silent = true, desc = "Dismiss minuet suggestion, else delete" })
|
||||
end
|
||||
|
||||
-- Ghost text, dimmer than a comment.
|
||||
--
|
||||
-- minuet links MinuetVirtualText -> Comment, which in `vague` is #606079 --
|
||||
-- the same colour as real comments, so a suggestion reads as if it were
|
||||
-- already part of the file. This drops it toward the background.
|
||||
--
|
||||
-- Reference points in this colourscheme, for tuning:
|
||||
-- Normal #cdcdcd (actual code)
|
||||
-- Comment #606079 (minuet's default -- too prominent)
|
||||
-- MINUET #4a4a5c <- here
|
||||
-- Whitespace #333738 (about as dim as stays legible)
|
||||
--
|
||||
-- ⚠ MUST be re-applied on ColorScheme. Loading a colourscheme runs
|
||||
-- `highlight clear`, which drops custom groups -- so setting this once at
|
||||
-- startup works until the first `:colorscheme` and then silently stops.
|
||||
local MINUET_FG = "#4a4a5c"
|
||||
local function minuet_highlight()
|
||||
vim.api.nvim_set_hl(0, "MinuetVirtualText", { fg = MINUET_FG, italic = true })
|
||||
end
|
||||
vim.api.nvim_create_autocmd("ColorScheme", {
|
||||
group = vim.api.nvim_create_augroup("MinuetHighlight", { clear = true }),
|
||||
callback = minuet_highlight,
|
||||
})
|
||||
minuet_highlight()
|
||||
|
||||
-- Registered UNCONDITIONALLY, so it can report the case where the plugin
|
||||
-- itself is missing. A status command that only exists when everything
|
||||
-- already works is not a status command.
|
||||
vim.api.nvim_create_user_command("MinuetStatus", function()
|
||||
local k = minuet_key()
|
||||
local lines = {
|
||||
"plugin: " .. (minuet_ok and "loaded" or "NOT INSTALLED -- run :lua vim.pack.update()"),
|
||||
"endpoint: " .. minuet_base .. "/v1/completions",
|
||||
"model: qwen3-coder-30b",
|
||||
"key: " .. (k and ("found (" .. #k .. " chars)") or "NOT FOUND"),
|
||||
}
|
||||
if not k then
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, "Set LITELLM_KEY_NVIM in ~/.secrets.zsh, or unlock rbw")
|
||||
table.insert(lines, "(`rbw unlock`) so it can be read from there.")
|
||||
end
|
||||
vim.notify(table.concat(lines, "\n"), k and vim.log.levels.INFO or vim.log.levels.WARN)
|
||||
end, { desc = "Show minuet FIM autocomplete status" })
|
||||
|
||||
vim.cmd("colorscheme vague")
|
||||
|
||||
-- KEYMAPS
|
||||
|
||||
+14
-67
@@ -9,11 +9,11 @@
|
||||
"apiKey": "{env:LITELLM_KEY}"
|
||||
},
|
||||
"models": {
|
||||
"gpt-oss-20b": {
|
||||
"name": "gpt-oss-20b (local, resident)",
|
||||
"qwen3.8-flash-next-iq3s-med": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -22,11 +22,11 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3-coder-30b": {
|
||||
"name": "qwen3-coder-30b (local, on demand)",
|
||||
"qwen3.8-flash-next-iq3s": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, default reasoning - slow)",
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -48,32 +48,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/librarian": {
|
||||
"name": "Librarian - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/explore": {
|
||||
"name": "Explore - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"muse-glimmer-30b-low": {
|
||||
"name": "Muse Glimmer 30B (local, low reasoning)",
|
||||
"limit": {
|
||||
@@ -87,32 +61,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3.8-27b-gsq-s-low": {
|
||||
"name": "Qwen3.8-27B GSQ IQ3_S (local, low reasoning)",
|
||||
"limit": {
|
||||
"context": 131072,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3.8-27b-gsq-s-med": {
|
||||
"name": "Qwen3.8-27B GSQ IQ3_S (local, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 131072,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"muse-glimmer-30b": {
|
||||
"name": "Muse Glimmer 30B (local, full reasoning - slow)",
|
||||
"limit": {
|
||||
@@ -132,23 +80,22 @@
|
||||
"enabled_providers": [
|
||||
"litellm"
|
||||
],
|
||||
"model": "litellm/local/librarian",
|
||||
"small_model": "litellm/local/librarian",
|
||||
"model": "litellm/muse-glimmer-30b",
|
||||
"agent": {
|
||||
"dev": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"architect": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"review": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"duck": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"brainstorm": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@
|
||||
"apiKey": "{env:LITELLM_KEY}"
|
||||
},
|
||||
"models": {
|
||||
"gpt-oss-20b": {
|
||||
"name": "gpt-oss-20b (local, resident)",
|
||||
"qwen3.8-flash-next-iq3s-med": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -22,11 +22,11 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3-coder-30b": {
|
||||
"name": "qwen3-coder-30b (local, on demand)",
|
||||
"qwen3.8-flash-next-iq3s": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, default reasoning - slow)",
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -48,32 +48,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/librarian": {
|
||||
"name": "Librarian - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/explore": {
|
||||
"name": "Explore - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"anthropic/claude-opus-5": {
|
||||
"name": "claude-opus-5 (Anthropic direct)",
|
||||
"limit": {
|
||||
@@ -243,32 +217,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3.8-27b-gsq-s-low": {
|
||||
"name": "Qwen3.8-27B GSQ IQ3_S (local, low reasoning)",
|
||||
"limit": {
|
||||
"context": 131072,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3.8-27b-gsq-s-med": {
|
||||
"name": "Qwen3.8-27B GSQ IQ3_S (local, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 131072,
|
||||
"output": 8192
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"muse-glimmer-30b": {
|
||||
"name": "Muse Glimmer 30B (local, full reasoning - slow)",
|
||||
"limit": {
|
||||
@@ -288,23 +236,22 @@
|
||||
"enabled_providers": [
|
||||
"litellm"
|
||||
],
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med",
|
||||
"small_model": "litellm/local/librarian",
|
||||
"model": "litellm/muse-glimmer-30b",
|
||||
"agent": {
|
||||
"dev": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"architect": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"review": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"duck": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
},
|
||||
"brainstorm": {
|
||||
"model": "litellm/qwen3.8-27b-gsq-s-med"
|
||||
"model": "litellm/muse-glimmer-30b"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@
|
||||
"apiKey": "{env:LITELLM_KEY}"
|
||||
},
|
||||
"models": {
|
||||
"gpt-oss-20b": {
|
||||
"name": "gpt-oss-20b (local, resident)",
|
||||
"qwen3.8-flash-next-iq3s-med": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -22,11 +22,11 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3-coder-30b": {
|
||||
"name": "qwen3-coder-30b (local, on demand)",
|
||||
"qwen3.8-flash-next-iq3s": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, default reasoning - slow)",
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -48,32 +48,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/librarian": {
|
||||
"name": "Librarian - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/explore": {
|
||||
"name": "Explore - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"chatgpt/gpt-5.6-sol": {
|
||||
"name": "gpt-5.6-sol (ChatGPT Plus, flat fee)",
|
||||
"limit": {
|
||||
@@ -211,7 +185,6 @@
|
||||
"litellm"
|
||||
],
|
||||
"model": "litellm/chatgpt/gpt-5.6-terra-low",
|
||||
"small_model": "litellm/local/librarian",
|
||||
"permission": {
|
||||
"read": {
|
||||
"*": "ask",
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"apiKey": "{env:LITELLM_KEY}"
|
||||
},
|
||||
"models": {
|
||||
"gpt-oss-20b": {
|
||||
"name": "gpt-oss-20b (local, resident)",
|
||||
"qwen3.8-flash-next-iq3s-med": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, medium reasoning)",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -22,11 +22,11 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"qwen3-coder-30b": {
|
||||
"name": "qwen3-coder-30b (local, on demand)",
|
||||
"qwen3.8-flash-next-iq3s": {
|
||||
"name": "qwen3.8-flash-next IQ3_S (local Strata, default reasoning - slow)",
|
||||
"limit": {
|
||||
"context": 32768,
|
||||
"output": 8192
|
||||
"context": 196608,
|
||||
"output": 32768
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
@@ -61,32 +61,6 @@
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/librarian": {
|
||||
"name": "Librarian - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"local/explore": {
|
||||
"name": "Explore - local gpt-oss",
|
||||
"limit": {
|
||||
"context": 65536,
|
||||
"output": 4096
|
||||
},
|
||||
"cost": {
|
||||
"input": 0.0,
|
||||
"output": 0.0,
|
||||
"cache_read": 0.0,
|
||||
"cache_write": 0.0
|
||||
}
|
||||
},
|
||||
"chatgpt/gpt-5.6-sol": {
|
||||
"name": "gpt-5.6-sol (ChatGPT Plus, flat fee)",
|
||||
"limit": {
|
||||
@@ -224,7 +198,6 @@
|
||||
"litellm"
|
||||
],
|
||||
"model": "litellm/chatgpt/gpt-5.6-terra-low",
|
||||
"small_model": "litellm/local/librarian",
|
||||
"permission": {
|
||||
"read": {
|
||||
"*": "ask",
|
||||
|
||||
@@ -11,20 +11,6 @@ export LASTFM_API_SECRET=""
|
||||
# syntax, so an unset value becomes an empty string and every request 401s.
|
||||
export LITELLM_KEY=""
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# nvim FIM autocomplete (minuet-ai -> LiteLLM -> qwen3-coder-30b)
|
||||
# ------------------------------------------------------------------------------
|
||||
# ⚠ WHICH KEY DEPENDS ON THE MACHINE, and on the work laptop it is the policy
|
||||
# boundary, not a preference. `litellm-key-work` is enforced server-side to 403
|
||||
# Anthropic and PRC-origin models; a personal key here would silently remove
|
||||
# that guarantee for anything nvim sends.
|
||||
#
|
||||
# sctfw004 (work) rbw get litellm-key-work
|
||||
# mainframe / system76 rbw get litellm-key-personal
|
||||
#
|
||||
# The NAS does not need it -- nvim disables the plugin silently when unset.
|
||||
export LITELLM_KEY_NVIM="$(rbw get litellm-key-work 2>/dev/null)"
|
||||
|
||||
# Where the proxy lives. Mainframe talks to itself; every other machine uses
|
||||
# the internal name, which has no public A record and is source-IP gated.
|
||||
# export LITELLM_BASE="https://llm.rcjohnstone.com"
|
||||
Reference in new issue
Block a user