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:
80 files changed
+587
-2575
No files matched your search
+2
-19
@@ -14,7 +14,7 @@ import { fillPrompt } from "../prompt/fill.ts"
|
||||
import { splitPurpose, toSpec, ToolError, type Tool, type ToolContext, type ToolResult } from "../tool/tool.ts"
|
||||
import { fill, promptText } from "../prompt/assemble.ts"
|
||||
import { resolveCall } from "../tool/names.ts"
|
||||
import { contextWindow } from "../provider/discover.ts"
|
||||
import { contextWindow } from "../provider/index.ts"
|
||||
import { summaryTurns, type Store } from "./store.ts"
|
||||
import { estimateTokens, estimateValue } from "../provider/tokens.ts"
|
||||
import { duration } from "../duration.ts"
|
||||
@@ -43,9 +43,6 @@ export interface EngineOptions {
|
||||
compaction?: { autoAt?: number }
|
||||
/** Starts a subagent for the task tool; absent in a subagent. */
|
||||
spawn?: ToolContext["spawn"]
|
||||
/** The model to switch to when this one's server cannot be reached (its `fallback` list), or
|
||||
* undefined when there is none left to try. */
|
||||
fallback?: (current: ResolvedModel, tried: Set<string>) => { model: ResolvedModel; client: Client; effort: Effort | null } | undefined
|
||||
/** What a message sent mid-turn starts with: the user's words for a session, the main agent's for
|
||||
* a subagent (loop.json jobs.marks to_subagent). */
|
||||
steerMark?: string
|
||||
@@ -264,7 +261,7 @@ export class Engine {
|
||||
}
|
||||
|
||||
private droppedThinking(): number {
|
||||
if (!this.usage || this.model.connection.dialect !== "openai-chat") return 0
|
||||
if (!this.usage) return 0
|
||||
const reply = this.messages[this.usageAt - 1]
|
||||
if (reply?.role !== "assistant") return 0
|
||||
const estimate = reply.parts.reduce((n, p) => n + (p.type === "reasoning" ? estimateTokens(p.text) : 0), 0)
|
||||
@@ -468,7 +465,6 @@ export class Engine {
|
||||
let ranOut: { limit: string; said: string } | undefined
|
||||
let nudges = 0
|
||||
let midRetries = 0
|
||||
const tried = new Set<string>()
|
||||
|
||||
for (let step = 1; ; step++) {
|
||||
// Checked between steps, never mid-reply: a reply cut off mid-sentence is worth nothing.
|
||||
@@ -519,19 +515,6 @@ export class Engine {
|
||||
bus.emit({ type: "done", reason: "cancelled" })
|
||||
return "cancelled"
|
||||
}
|
||||
// The server is not there at all: the model's fallback, if it has one, for the rest of the
|
||||
// session — said, and shown in the status bar.
|
||||
if (e instanceof ProviderError && e.unreachable && this.o.fallback) {
|
||||
tried.add(this.model.ref)
|
||||
const next = this.o.fallback(this.model, tried)
|
||||
if (next) {
|
||||
bus.emit({ type: "notice", message: `${e.message.split("\n")[0]!.slice(0, 160)} — switching to ${next.model.ref}, its fallback` })
|
||||
this.setModel(next.model, next.client, next.effort)
|
||||
bus.emit({ type: "setting", key: "model", value: next.model.ref })
|
||||
step--
|
||||
continue
|
||||
}
|
||||
}
|
||||
// A server failure part-way through a reply (llama.cpp failing to parse gpt-oss's own
|
||||
// output is the one seen) is worth two more goes. What was already shown is discarded.
|
||||
if (e instanceof ProviderError && !e.beforeOutput && (e.status ?? 0) >= 500 && midRetries < 2) {
|
||||
|
||||
Reference in new issue
Block a user