Custom connections are gone: the CLI talks to the LLeMbas server it is logged in to

LLeMbas CLI 2.0 is LLeMbas-server-specific (CLI rule 2). Removed: the
anthropic, gemini, ollama and responses clients, context discovery and
llama-swap unloading (discover.ts), the Connection schema with its dialect,
auth, key_cmd, discover, unload_url and one_model_at_a_time, the model
`fallback` (it only ever moved to another server), effort_map and cache, and
the multi-connection refs. Kept: openai-chat, http, sse, think, effort,
tokens and all of src/lembas.

- connections.yaml holds the login (`type: webui`, as lembas login writes
  it). A custom entry from 1.x is read past with a warning that says how to
  log in, so an old file still starts; with several logins left, the latest
  is used and the others named.
- A model's ref is the id the server serves it under; the older forms
  (`<login>/<id>`, `<login>/<model>`) still resolve and config.yaml is
  rewritten once. Without a login there is no model, and the error (and the
  first-run screen, now the sign-in alone) says `lembas login <address>`.
- A login to another server signs this machine out of the previous one.
- The window is the server's word (no discovery); a capacity group comes
  from the server's `capacity.group` alone; embeddings use the server's
  /v1/embeddings.
- `lembas models` lists the server's models; install.sh's starter files, the
  README and the JSON schemas say the same.

Tests: every fixture is a login now (the fake server lists models, answers
other GETs with 404, and can hand one model to another script, as a server
with several backends); the dialect suites and the cross-connection tests are
gone with their code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-10-27 21:00:05 +00:00
1 parent f20e8c4307
commit 28ff205ed0
80 files changed
+587 -2575

No files matched your search

+8 -32
View File
@@ -1,18 +1,9 @@
import { TextAttributes } from "@opentui/core"
import { useKeyboard } from "@opentui/solid"
import { join } from "node:path"
import { createSignal, Show } from "solid-js"
import { paths } from "../../config/paths.ts"
import { ModelError } from "../../provider/index.ts"
import { ModelError, NOT_LOGGED_IN } from "../../provider/index.ts"
import { useTui } from "../context.ts"
const EXAMPLE = `connections:
local: # any name; llama.cpp, LM Studio, vLLM, Ollama's /v1…
dialect: openai-chat
base_url: http://127.0.0.1:8080/v1
models:
qwen3: { context: 131072 }`
/** Before there is a session: no model to talk to (a fresh install), or a config file that cannot
* be read. Says what to do and where; r tries again once the files are fixed, q or ctrl+c leaves.
* Not an exception: thrown with the terminal still the TUI's, mouse reporting would stay on, and
@@ -38,7 +29,7 @@ export function Setup(p: { error: Error; onRetry: () => void; onQuit: () => void
try {
const { codeInstructions, login } = await import("../../lembas/login.ts")
const r = await login(target, { onCode: (start, d) => setStatus(codeInstructions(start, d)) })
setStatus(`Signed in: ${r.models.length} model${r.models.length === 1 ? "" : "s"} as ${r.connection}/…${r.instanceDefault ? `, starting on ${r.connection}/${r.instanceDefault}` : ""}.`)
setStatus(`Signed in: ${r.models.length} model${r.models.length === 1 ? "" : "s"}${r.instanceDefault ? `, starting on ${r.instanceDefault}` : ""}.`)
p.onRetry()
} catch (e) {
setStatus((e as Error).message)
@@ -65,11 +56,11 @@ export function Setup(p: { error: Error; onRetry: () => void; onQuit: () => void
return (
<box flexDirection="column" width="100%" height="100%" paddingLeft={2} paddingTop={1} paddingRight={2} gap={1}>
<text fg={c().title} attributes={TextAttributes.BOLD}>
{theme().branding.agentName} — {noModel() ? "no model to talk to yet" : "the configuration has a mistake"}
{theme().branding.agentName} — {p.error.message === NOT_LOGGED_IN ? "not logged in to a LLeMbas server" : noModel() ? "no model to talk to" : "the configuration has a mistake"}
</text>
{/* "No model configured" is what the rest of the screen explains; anything else (a model
that does not exist, a file that does not parse) is shown as it is. */}
<Show when={!p.error.message.startsWith("No model configured")}>
{/* Not being logged in is what the rest of the screen explains; anything else (a model the
server does not serve, a file that does not parse) is shown as it is. */}
<Show when={p.error.message !== NOT_LOGGED_IN}>
<text fg={noModel() ? c().text : c().error} wrapMode="word">
{p.error.message}
</text>
@@ -80,7 +71,7 @@ export function Setup(p: { error: Error; onRetry: () => void; onQuit: () => void
when={typing()}
fallback={
<text fg={c().muted} wrapMode="word">
{"Sign in to a LLeMbas instance and use its models: press l (or, from a shell, lembas login <address>)."}
{"LLeMbas CLI uses the models of the LLeMbas server it is logged in to. Log in: press l (or, from a shell, lembas login <address>)."}
</text>
}
>
@@ -96,24 +87,9 @@ export function Setup(p: { error: Error; onRetry: () => void; onQuit: () => void
{status()}
</text>
</Show>
<text fg={c().muted} wrapMode="word">
{`Or, without an instance — nothing is predefined: add the server you use to ${join(paths.config, "connections.yaml")}, for example`}
</text>
<box paddingLeft={2}>
<text fg={c().text}>{EXAMPLE}</text>
</box>
<text fg={c().muted} wrapMode="word">
{`and pick the model in ${join(paths.config, "config.yaml")}:`}
</text>
<box paddingLeft={2}>
<text fg={c().text}>model: local/qwen3</text>
</box>
<text fg={c().muted} wrapMode="word">
A key is never pasted in: api_key: "{"{env:NAME}"}" or "{"{file:~/path}"}". https://llembas.eu/docs/ has the other dialects (Anthropic, OpenAI, Gemini, Ollama).
</text>
</Show>
<text fg={c().muted} wrapMode="word">
From a shell, lembas config check reads the files and says what is wrong, and lembas models lists the models it found.
From a shell, lembas config check reads the files and says what is wrong, and lembas models lists the server's models.
</text>
<text fg={c().label}>{typing() ? "enter sign in · esc back · ctrl+r try again · ctrl+c quit" : `${noModel() ? "l log in · " : ""}r try again · q quit`}</text>
</box>