mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
fix/dev-python/python-upper-bound
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
786899700f |
feat(litellm): serve OpenAI, Anthropic and OpenRouter from declared keys
The gateway could reach exactly one remote provider, through a bare
OPENROUTER_API_KEY group_var with an empty-string default and an `{% if %}`
around a single hardcoded model entry. OpenAI and Anthropic had no path at all.
All three are now declared in roles/svc-ai-litellm/meta/secrets.yml, which
mapping.py already calls the application config schema, so a key lands at
applications.svc-ai-litellm.secrets.credentials.<provider>_api_key like every
other credential. Each carries the `type` and `regex` its value must satisfy and
defaults to the central API.<provider>.api_key block, which keeps one
operator-facing place to fill a provider in while the role owns the shape.
type and regex had to become real to be worth declaring. 192 `validation:`
blocks sit in the role schemas today and not one line of Python enforces them,
so a `regex` would have joined a pile of decoration. validate_supplied_value
now runs on every path a value arrives from outside — the --set override, a
value already in the inventory, and the value standing next to a `default:`.
A generated value stays exempt because the algorithm that produced it is named
by the same schema and generate_value takes no schema argument. min_length is
deliberately left unenforced: the generators ignore it, so holding them to it
would fail where nothing is wrong.
The pattern is written for the paste, not for the vendor. OpenAI moved issuance
from sk- to sk-proj- without notice and Anthropic issues sk-ant-api03-; a schema
pinning a prefix would reject a valid key and abort inventory creation. `\S{20,}`
accepts every form those three issue today and one nobody has announced, and
rejects a trailing newline, an embedded space, a truncated copy and a
<placeholder>. A key pasted into the wrong provider's slot is caught at deploy
instead, where the route it publishes answers nothing.
The gateway iterates one LITELLM_REMOTE_BACKENDS list instead of three `{% if %}`
blocks; config.yaml.j2 and env.j2 read the same list and selectattr('key')
decides. LITELLM_CHAT_MODEL falls back to the first configured remote alias
rather than to a hardcoded openrouter/auto.
For CI the keys travel as INFINITO_API_{OPENAI,ANTHROPIC,OPENROUTER}_KEY through
default.env, the passthrough allowlist, the infinito service in compose.yml, the
workflow env block and the development inventory. The compose leg is not
optional: the env lint rejected the change without it, because a key the
inventory reads but compose does not forward resolves to empty inside the
container with no error. The workflow reads `secrets.X || vars.X` so a variable
works as asked while a secret wins, which matters because a variable is not
masked and the development inventory sets MASK_CREDENTIALS_IN_LOGS: false.
An unset key is not an error anywhere: the provider's routes stay unpublished
and the CLI test asserts their absence rather than skipping.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
c2120395e7 |
fix(litellm): let the database follow the inventory and keep the network a dedicated one is reached on
Run 34421944328 web-app-litellm#1 (README host-mode replay) answered
every health probe on llm.ai.infinito.test with 502: litellm
crash-looped on "P1000: Authentication failed against database server
at postgres" while postgres logged 'Role "litellm" does not exist'. The
README inventory has no svc-db-postgres group, so sys-svc-rdbms skipped
the central provisioning, yet svc-ai-litellm pinned postgres.shared to
true and kept consuming a shared database nobody had created its role in.
postgres.shared now reads "{{ 'svc-db-postgres' in group_names }}":
an inventory with the central group keeps the shared database, the
README inventory gets a dedicated one.
That dedicated instance, rendered by sys-svc-rdbms postgres.yml.j2,
joins only the compose default network, and the networks renderer
dropped default from every svc-db-*/svc-ai-* role. A local variant-1
deploy measured litellm-database on litellm_default alone and litellm on
the shared litellm network alone. _suppress_default now keeps default
when the role's database is local. The variants pin shared to true (0)
and false (1) so the matrix exercises both paths, and the generated
READMEs show the postgres relation as 0..1.
The three attachment helpers move from render.py to attachments.py,
which render.py re-exports, and test_render.py splits along the same
seams into five files plus _render_helpers.py with every test id kept.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
4986e80dd4 |
feat(readme): ask the reader for a domain the deployment can resolve
The Production block never set one. inventory provision writes only
ansible_connection for a local host, so DOMAIN_PRIMARY stayed at the
group_vars default of infinito.localhost and the deployment served a zone its
own resolver knows nothing about. CoreDNS templates answers for
INFINITO_DOMAIN_RE and nothing else, so every lookup of the deployment's own
name came back NXDOMAIN.
Mastodon is where that surfaced. tootctl accounts create validates the address
through EmailMxValidator, which resolves MX and then, for the domain itself,
A and AAAA. All six queries returned NXDOMAIN in run 33574056480, the
validator recorded email :unreachable, and the admin account was never created.
Only the guide rows were affected: the matrix rows write
DOMAIN_PRIMARY: "{{ lookup('env', 'INFINITO_DOMAIN') }}" into their host_vars
and resolve fine.
The template now carries DOMAIN=<your-domain> in both the host and the
container form and threads it into --vars, with the container form passing it
through the docker run boundary as well. The two guide runners substitute it
the way they already substitute the SSH key, so the replay deploys under
INFINITO_DOMAIN like every other CI deploy. compose_deploy.sh moves its env
load ahead of the substitutions to have the value; host_deploy.sh had no env
load at all.
A production reader is asked for a domain now instead of silently inheriting
infinito.localhost, which no real deployment wants either. The shipped default
keeps its value: sys-svc-nss documents that *.localhost resolves through the
myhostname NSS module without any zone, and host-side tasks lean on it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
7162b7bf4c |
Merge fork/feature/svc-net-tor into feature/ai-agent-employees
834 commits from the Tor onion-service branch against 299 of ours, from merge base |
||
|
|
507e3f4337 |
docs(036): record the gateway integration in the requirement and the matrix
The requirement corrects two rows against what the pinned releases actually expose: Moodle 4.5 configures aiprovider_openai per action rather than through a single base URL, and n8n 1.95.3 reads its endpoint from a stored credential, after N8N_INSTANCE_AI_MODEL_URL turned out not to exist in that release. espocrm and peertube move into the exclusion table with measured evidence rather than vendor claims, and the variant-coverage section records which round exercises the gateway. Criteria 2, 5, 8 and 9 are ticked. Criteria 3, 4, 6 and 7 stay open on purpose: the wiring is complete across all nine confirmed roles, but only zammad's spec has been observed answering a prompt through the gateway, and the last deploy ended before Playwright ran. Criterion 1 is still open because homeassistant, xwiki and baserow have not been probed. The 027 generator gains litellm as a framework key and litellm and n8n on the web-app axis, so every consumer's gateway edge appears in the matrix. Its regenerated output is committed alongside it; the generator writes the file in place rather than to stdout, and a fresh run reproduces the committed matrix byte-for-byte. Touching the generator also brought its comment history into the lint's scope, so about thirty section banners and narration lines go with it. The espocrm README carries the exclusion evidence -- at tag 10.0.4 only Crm ships under application/Espo/Modules, the config metadata declares no AI key, and the release ZIP leaves custom/Espo/Modules empty -- plus four steps for enabling the commercial Intelligence extension once licensed. A version bump does not help: upstream documents that extension as requiring 10.0.3 or greater, so newer cores host it rather than absorb it. The provider field names are only discoverable by unpacking the purchased artifact, and the note says so rather than guessing. The root README and the litellm README are generated; both now show the gateway among the dependencies of its eight consumers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
92c45e2471 |
refactor(openwebui): serve models through the gateway, not the model server
Open WebUI talked to Ollama directly. It now speaks the OpenAI-compatible surface of svc-ai-litellm with a per-consumer virtual key, so a second backend or an external provider becomes a gateway config change instead of a role change. A lint keeps future roles off the model servers. The gateway advertised a hardcoded model list (ollama/llama3, ollama/nomic-embed-text) while the matrix variant preloads smollm2:135m, so it offered only models the backend did not have and hid the one it did. The list is derived from the ollama preload SPOT now. The chat spec followed the rename: it gates on litellm instead of the removed ollama service flag, and picks the first non-embedding model from /api/models rather than pinning a variant-specific name, so it exercises the chain rather than a fixture. Routing openwebui through the gateway pulls both model backends into the closure of every role that consumes it, which pushed nextcloud variant 2 over the memory budget. The budget stays at 32/64 GB; instead the matrix variants of svc-ai-ollama and svc-ai-lmstudio now declare the size their test model needs (1g/2g) while the base keeps the 6g/8g that llama3 and mistral require. The budget guard only saw half of that: it replaced the evaluated role with its variant but counted every dependency from meta/services.yml, a combination no matrix round deploys. It now evaluates every variant-carrying role at the same round index, falling back to variant 0, the way the deploy planner does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
8b5312445b |
docs(roles): write the AI and runtime role documentation
The eight new roles shipped with the README template unfilled: every one of them described itself as "[Name](https://example.com/) is an application" with a single "Describe a capability" feature. They were implemented, deployed and tested; their documentation was placeholder text. Each role now carries a Description, Overview and Features written against its own services, tasks and templates, with TODO.md as the binding list of what is not wired. That caught a false claim: OpenClaw advertised routing through the shared gateway, but it reads model providers from openclaw.json rather than the environment, so the gateway only shapes its deploy topology. The claim is gone. The overview table derives its Name column from each README H1, and all eight had kept the humanised fallback. Worst of these, both LiteLLM roles rendered as "Litellm" on adjacent rows, so a reference in the Integrated with column could not say which one it meant; they are now the Gateway and the Admin UI. The rest take their official spelling. The galaxy descriptions all repeated the product name the Name column already carries, one named a role id in prose and one used a hyphen as a dash. svc-virt-kata also claimed to install Kata, which it does not: it installs gVisor and registers an already-present Kata shim. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
ad743bf447 |
feat(svc-ai): add the LiteLLM gateway and the LM Studio backend
Consumers of the model plane speak one OpenAI-compatible endpoint and carry one virtual key; which backend answers is the gateway's business. svc-ai-litellm renders its model_list from the round's actual topology, so an alias only exists when its backend role is in group_names, and it emits an explicit empty list when no backend is present at all because LiteLLM rejects a bare model_list: key. Keys reach the gateway through the per-consumer credential rather than being minted there: 01_keys.yml probes /key/info and only POSTs /key/generate on 404, so reruns stay idempotent. The consumer list is built in 00_core.yml, not inside the included file, because 01_keys.yml delegates to the hosting node and delegate_to is templated before when. The gateway declares ollama and lmstudio as consumer flags so the network renderer attaches it to its own backends; without them it cannot reach them. svc-ai-lmstudio runs the headless llmster daemon behind expose only, so it is reachable from the gateway but never bound on the host, matching svc-ai-ollama. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |