Commit Graph
41 Commits
Author SHA1 Message Date
Adrià Arrufat a6df7b04d0 agent: drop the OrcaRouter provider
zenai no longer ships the OrcaRouter preset. It still works as an
OpenAI-compatible endpoint via OPENAI_BASE_URL + OPENAI_API_KEY.
2026-09-26 23:58:30 +02:00
Adrià Arrufat 92a6b698fc agent: --search-engine, and say when the engine has no key
The search engine could only be set from the REPL's `/searchEngine`, so a
one-shot run had no way to pin one -- and a benchmark that wants its
results to mean something has to record which API answered.

`/searchEngine` also carried the only warning about key state, which is
the half that matters more. A keyless engine is not an error and starts
fine, so a run that silently falls back to a rate-limited public endpoint
looks exactly like a working one until every search begins failing, and
then it looks like a bad agent. Both messages now fire wherever the
engine is resolved, not just from the command.

`resolveSearchEngine`'s doc comment said there was no CLI flag. There is
one now.
2026-09-22 15:50:15 +02:00
Adrià Arrufat 290e4f81d9 agent: simplify REPL command dispatch and provider bookkeeping
- `available_providers` holds the static enum tag names; drop the dupe
  loop, its errdefer and the per-string frees.
- `reconcileModel` returns `error.ModelNotAvailable` directly instead of
  a `use`/`abort` union the caller only mapped to that same error.
- `runCommand`/`printCommandResult` take `Command.ToolCall`; the caller
  already has it, so the unreachable "no tool mapping" branches go.
- `handleSave` reuses `rememberSavePath`, which now propagates its
  allocation failure so a first save under OOM warns instead of
  unwrapping a null `save_path`.
- `SlashCommand.all_names` is a comptime `++` of the three name lists.
- `buildUserMessageParts` reads the attachment once for both text and
  image, and prepends the text part instead of copying the list.
- `printSeverity`/`formatBulletLine` use `allocPrint` and the shared
  `emitStderr`; drop an unreachable `ends_ws` check in `renderMetaHint`.
2026-09-18 00:45:55 +02:00
Adrià Arrufat fc13928672 agent: document the OpenRouter and OrcaRouter providers
zenai now ships openrouter and orcarouter presets (OPENROUTER_API_KEY /
ORCAROUTER_API_KEY, provider-prefixed model ids). The provider enum is
derived from zenai, so only the help text, key hint, and README need
to name them.
2026-09-16 12:21:34 +02:00
Karl Seguin 2e6999f20b chore: make declarations private if they don't need to be public
This change is 99%  s/pub//   + a handful of dead code removal.
2026-09-10 14:42:09 +08:00
Adrià Arrufat 42c3cbf20b search: default to Keenable's keyless endpoint, drop the DuckDuckGo scrape
The DuckDuckGo HTML endpoint the search tool fell back to is disallowed by
its robots.txt, so it is removed: the `duckduckgo` engine, the scrape via
`performGoto`, and the tool's browser-side dependency (`execSearch` no
longer needs a session). In its place `.auto` is a single walk over the
API engines in table order — each when its key is set — with Keenable
last, keyed if `KEENABLE_API_KEY` is set and its public endpoint
otherwise. Search therefore always has a rung with zero configuration,
and a set key is never shadowed by a keyless retry.

Every search now goes through zenai's `std.http.Client`, which had no
timeout at all; a stalled response would have blocked the MCP server's
shared browser thread for every session. zenai now bounds each attempt
(lightpanda-io/zenai#10, pinned here), and the tool's `timeout` argument
drives it, defaulting to 10 s. Retries are a property of the call path:
off in the cascade, where the next rung is the retry, and the engine
default for an explicit engine.

Cleanups from the #3252 review: `keyless` is derived from the client's
`api_key` type instead of a hand-set table flag; `engineIndex` no longer
depends on enum declaration order; one `searchKeyStatus` query replaces
three pub helpers for the REPL; the engine order and env-var list in the
tool description and `/searchEngine` help are generated from the table;
an empty result title renders as its URL instead of `****`.
2026-08-25 09:35:26 +02:00
Adrià Arrufat 8b6f7fe064 agent: simplify credential and key ownership handling 2026-07-28 13:05:46 +02:00
Adrià Arrufat a53fbcc6eb agent: introduce KeyOwnership union for credentials
Consolidates owned_key, session, and unowned env key management into a
tagged union KeyOwnership to simplify resource lifetime handling.
2026-07-28 12:44:37 +02:00
Adrià Arrufat 00cdc3ba8d agent: update zenai and switch auth to interruptible HTTP 2026-07-28 11:17:08 +02:00
Adrià Arrufat d7cc090ca1 Merge branch 'main' into codex 2026-07-28 10:11:31 +02:00
Adrià Arrufat e99a5ab99b agent: pivot subscription auth from Claude Code to Codex
Replace the Anthropic Claude-Code-import flow with OpenAI Codex (ChatGPT
subscription) OAuth: device-code login, a real token store (auth.json,
0600) with refresh-grant, and JWT ChatGPT-Account-Id extraction. Codex is
now a distinct zenai provider, so the bearer-mode credential collapses to
provider==.codex; account_id threads to the client via InitOptions.

Unit-tested (build green): JWT account-id extraction, token store
round-trip, OAuth request-body encoding, token-response parsing. The
device-login / refresh network path is unverified pending a subscription.

Pins zenai to the codex branch (6967324).
2026-07-27 11:24:01 +02:00
Adrià Arrufat 41cd1cd734 agent: support subscription auth via Claude Code 2026-07-23 14:56:41 +02:00
Adrià Arrufat bae9388f1c Merge branch 'main' into brave-search 2026-07-22 16:27:35 +02:00
Adrià Arrufat 99262190da feat(tools): add Brave search + /searchEngine metacommand
Add Brave as a second API-backed web search engine: the search tool's
auto mode tries Brave then Tavily (keyed on BRAVE_API_KEY/TAVILY_API_KEY)
before the DuckDuckGo scrape. A new /searchEngine REPL metacommand pins
the engine explicitly (auto|tavily|brave|duckduckgo) — an explicit
engine surfaces its failures instead of silently degrading — and is
persisted to .lp-agent.zon like the other REPL settings.

Bumps zenai to pick up the zenai.search.brave client.
2026-07-22 13:44:51 +02:00
Karl Seguin 802862120f update zenai dep (zig 0.16) 2026-07-22 13:26:06 +08:00
Karl Seguin 8e42d63c1c zig: Zig 0.16
Built against https://github.com/lightpanda-io/zig-v8-fork/tree/zig-0.16 but
it doesn't require a new v8 build.

Built against https://github.com/lightpanda-io/boringssl-zig/tree/zig-0.16
since the current fork we point to isn't updated.

A global std.Io instance, lp.io. Way easier this way and requires 0 changes to
our libcurl integration / event loop.

Network code uses a new layer that does what Zig 0.15's posix package used to
do. Again, quicker migration that way. But, as long as we have the global IO,
and given the half-baked nature of networking in std.Io 0.16, this just makes
sense. Things can be migrated as needed.

The std.time.* -> std.Io.Timestamp/Clock/Duration resulted in _a lot_ of
changes. ArrayList = .{} -> ArrayList -> .empty also resulted in a lot of
changes, but that's obviously superficial. As is the trimLeft/trimRight ->
trimStart/trimEnd rename.

Locking adopt the `Uncancelable` variants, e.g. mutex.lockUncancelable() to
preserve the error-free signature (and, because cancellation would be something
we'd have to put more thought into).

std.json.ObjectMap is now unmanaged, so the allocator had to be passed along.
However, there's still a deprecated managed variant of MemoryPool, so I switched
to it (we can do a small follow up PR to move to the unmanaged after).

I tried use_llvm = false, but it locks my computer, consuming RAM until MacOS
gives me a popup I've never seen before, begging me to start killing processes.

Agent and the networking stuff saw the most significant changes.
2026-07-22 13:26:03 +08:00
Adrià Arrufat f48498073d agent: extract the choice picker into picker.zig
The numbered/interactive picker (ChoiceState, RawTerminal, render loop)
was ~215 self-contained lines inside Terminal.zig. It runs before - or
without - the isocline REPL (provider selection during setup), so
settings.zig no longer imports the isocline-configured Terminal at all.
Pure code motion; the ChoiceState tests move with it and stay in the
suite via Agent.zig's test hook.
2026-07-15 11:40:55 +02:00
Adrià Arrufat 46be87f2ca test(agent): cover resolveStream precedence and stream round-trip
Verify the stream default is on, that a remembered value wins, and that
the field parses from (and is absent-safe in) .lp-agent.zon.
2026-07-12 22:13:49 +02:00
Adrià Arrufat 049c5f08f2 feat(agent): add assistant text streaming 2026-07-11 00:50:01 +02:00
Adrià Arrufat ff7545a8c3 agent: add Google Vertex AI support
Supports both express mode (via VERTEX_API_KEY) and project mode
(via GOOGLE_CLOUD_PROJECT and gcloud auth). Handles automatic
OAuth token retrieval and refresh.
2026-07-03 20:23:51 +02:00
Adrià Arrufat 59dc69f1fe agent: support provider-specific default effort
Updates the zenai dependency and resolves the agent's effort based on
the configured provider's default. Also dynamically updates the active
effort when switching providers.
2026-06-18 13:22:29 +02:00
Adrià Arrufat 34f6afb019 agent: simplify local provider detection
Remove redundant `detectOllama` and `detectLlamaCpp` wrappers in
settings, calling `detectLocalProvider` directly instead. Also clean
up some logic in Agent.zig.
2026-06-17 20:03:11 +02:00
Adrià Arrufat f244478dbe Merge pull request #2768 from lightpanda-io/terminal-single-positional-arg
terminal: support positional args for single-field schemas
2026-06-17 16:52:22 +02:00
Adrià Arrufat 144b3a58a0 terminal: support positional args for single-field schemas
Allows tools like `/getEnv` with a single optional field to accept
positional arguments. Also adds autocompletion and ghost hints for
live `LP_*` environment variables.

Additionally, fixes a memory leak in `settings.zig` when parsing
invalid ZON configurations.
2026-06-17 16:26:43 +02:00
Adrià Arrufat 88bfec4c7e agent: add support for Vercel AI Gateway and Mistral 2026-06-17 15:38:48 +02:00
Adrià Arrufat 45dd56258b agent: simplify and shorten comments 2026-06-17 12:45:18 +02:00
Adrià Arrufat 285c5eb523 agent: support llama.cpp as local provider
Generalizes Ollama detection, completion, and model reconciliation
to support llama.cpp. Also improves API error reporting by formatting
and surfacing HTTP status and messages on failures.
2026-06-17 12:24:45 +02:00
Adrià Arrufat 78dfc03007 agent: probe Ollama reachability for completions
Lazily probes and caches Ollama server reachability for `/provider`
autocomplete. Validates Ollama availability when manually setting
the provider. Updates zenai dependency.
2026-06-15 23:13:56 +02:00
Adrià Arrufat e7cfc2f72a agent: avoid double Ollama probe at startup
Renames `wouldResolve` to `hasDetectableKey` and removes the Ollama
probe from it. Defers printing the welcome banner for Ollama-only
paths to prevent probing the local server twice. Also bumps zenai.
2026-06-15 22:56:20 +02:00
Adrià Arrufat 3e5294318c Agent: add support for Huggingface inference
Updates the zenai dependency to the latest commit and adds HF_TOKEN to
the API keys hint.
2026-06-15 19:12:05 +02:00
Adrià Arrufat aeba63427e script: enforce positional arguments come first
Returns a specific `PositionalMustComeFirst` error when a positional
argument is placed after key-value pairs.
2026-06-11 18:24:44 +02:00
Adrià Arrufat 3baa2726e9 agent: streamline and shorten comments 2026-06-09 09:34:26 +02:00
Adrià Arrufat f2b5f05479 agent: extract conversation, welcome, and settings
Extracts chat history and arena management into `Conversation.zig`,
the startup banner into `welcome.zig`, and model/config resolution
helpers into `settings.zig` to simplify `Agent.zig`.
2026-06-09 07:54:32 +02:00
Adrià Arrufat 5ad664a63a agent: allow disabling LLM via /provider null
Adds support for `/provider null` to disable the LLM and persist this
preference in `.lp-agent.zon`. Subsequent REPL launches will start
in basic mode without prompting for API keys. Transient `--no-llm`
runs do not clobber the saved provider.
2026-06-05 15:12:04 +02:00
Adrià Arrufat ce34ea6625 agent: persist and restore verbosity setting
Saves the agent's verbosity setting to `.lp-agent.zon` and
restores it on initialization, similar to the effort setting.
2026-06-05 14:40:55 +02:00
Adrià Arrufat 5f2330bb2f agent: add reasoning effort configuration
Adds the `--effort` CLI flag and `/effort` REPL command to control
the reasoning budget, persisting the setting in `.lp-agent.zon`.
2026-06-05 12:40:34 +02:00
Adrià Arrufat ab540e9bdf agent: auto-detect Ollama and fallback models
Probes local Ollama as a fallback provider when no API keys are set.
Swaps to an installed Ollama model if the default model is missing.
2026-06-04 18:29:29 +02:00
Adrià Arrufat 560897ea89 agent: clean up save mode and terminal prompts
- Use `std.meta.fieldNames` for the save mode prompt.
- Update terminal prompt functions to accept null-terminated strings.
- Respect the resolved save mode in `synthesizeSave`.
2026-06-03 17:13:52 +02:00
Adrià Arrufat e208b4b638 repl: add dynamic status bar
Integrates isocline's top and bottom bar APIs to display the active
provider, model, and shortcut hints. Updates the status bar on
terminal resize and mode switches.
2026-06-03 15:09:09 +02:00
Francis Bouvier f54359aef6 agent: improve banner 2026-06-02 10:45:19 +02:00
Adrià Arrufat 03e96d9e8f agent: extract settings and use shared utf8 truncation
Extracts provider and model settings logic from `Agent.zig` into a new
`settings.zig` module. Replaces custom UTF-8 truncation logic with
`truncateUtf8` from `string.zig`. Also updates the `zenai` dependency.
2026-06-01 15:03:42 +02:00