Commit Graph
337 Commits
Author SHA1 Message Date
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 f462223277 agent: tighten the seams the terminal split left behind
- attachCompleter now takes the CompletionSource: Agent no longer
  reaches through terminal.assist to configure what it just attached,
  and attach/configure can't be sequenced wrong.
- history_paths flows through one channel: attach() loads the initial
  history from the same State field modeCallback swaps from, instead of
  setupRepl receiving a second copy that had to agree.
- all_names + closestCommand move to SlashCommand.zig, the command
  registry - prompt_assist consumes it like everyone else and
  Terminal's closestCommand re-export disappears.
- picker treats a tty that refuses raw mode as NotInteractive and
  degrades to the line prompt instead of leaking termios errnos to
  callers that can only blanket-catch.
- kitty keyboard flags become named ansi.zig constants shared by
  Terminal.readLine and picker's RawTerminal.
- skipWhitespace was std.mem.indexOfNonePos; single-use style consts
  inline into the style table; drop the dead CompletionSource default
  and doc-comment splice in Spinner.
2026-07-15 12:16:53 +02:00
Adrià Arrufat 673b16528f agent: extract prompt assistance into prompt_assist.zig
Completion, ghost hints, and prompt highlighting (~640 lines) were
cohabiting with Terminal's readline lifecycle and output printing. They
now live in prompt_assist.zig, which owns the isocline callbacks, the
ps-* style palette, and the slash-command name table. The C callbacks
read a small prompt_assist.State (js_mode, completion_source,
history_paths) embedded in Terminal, replacing the three loose fields.
Pure code motion otherwise; the valueAt/renderSchemaHint tests move
with their code and stay in the suite via Terminal's test hook.
2026-07-15 11:50:44 +02: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 4307509094 agent: improve REPL syntax highlighting and terminal colors
- Add highlighting for JS functions, methods, types, and template
  interpolations.
- Introduce teal color and adjust cyan to bright cyan.
- Import `ansi.zig` directly instead of through `Terminal`.
- Add PandaScript semantics note to the agent's system prompt.
- Refactor markdown table rendering and streaming.
2026-07-15 11:02:46 +02:00
Adrià Arrufat d0ce9a02a8 terminal: stream and render markdown incrementally
Introduces an incremental markdown renderer (`md_term.Stream`) to
format streamed assistant responses in real time. Buffers lines,
maintains code fence state across chunks, and temporarily withholds
tables to render them with proper column alignment once complete.
2026-07-14 22:51:43 +02:00
Adrià Arrufat 8c0ec3d73a Merge branch 'main' into pandascript-skill 2026-07-14 12:06:05 +02:00
Adrià Arrufat 3e801fb83b script: generate the PandaScript skill from the tool schemas
The /save script documentation lived as a hand-maintained string in
Agent.zig whose primitives table drifted whenever a tool changed. Move
it to src/script/skill.zig and render the reference (signatures, option
lists, enums, defaults, per-parameter descriptions) from Schema.all()
at first use, keeping the curated per-tool notes behind an exhaustive
switch on Tool so a new or renamed tool is a compile error until its
doc entry exists.

The rendered skill is shared by three consumers:
- the /save and revision system prompts (built lazily in Agent.zig)
- a new mcp://skill/pandascript resource
- `zig build skills`, which writes zig-out/skills/<name>/SKILL.md with
  Claude Code frontmatter via a registry-based generator exe, so
  future Lightpanda skills are one registry entry each

Schema.FieldEntry now retains per-parameter schema descriptions, which
previously existed only in the raw JSON.
2026-07-13 10:54:13 +02:00
Adrià Arrufat bdb122cdce Merge branch 'main' into agent-streaming 2026-07-12 22:56:54 +02:00
Adrià Arrufat fa2dc02721 fix(agent): reset stream_active at turn start
`stream_active` relied on every runTools exit path balancing pause with
`endStreamedText`. If one is ever missed, a stale-true flag skips the
spinner pause on the next turn, interleaving frames with streamed text.
Reset it alongside `streamed_text` so the invariant is local.
2026-07-12 22:10:29 +02:00
Adrià Arrufat 2e8e0d1a6f docs(agent): note why the streamed_text guard is turn-wide safe
Document the invariant that lets a single per-turn flag suppress the
buffered reprint without risking a dropped final answer.
2026-07-12 22:10:11 +02:00
Adrià Arrufat a64ced0ccc fix(agent): stream assistant text only in the REPL
Streaming defaulted on for every mode, so one-shot `--task` and script
runs interleaved intermediate assistant commentary into stdout, which
wrappers treat as the answer. Gate the stream hook on `Terminal.isRepl`
so non-interactive modes keep the buffered final answer.
2026-07-12 22:09:48 +02:00
Adrià Arrufat 5abae593d8 fix(agent): keep streaming off for suppressed turns
Streaming wrote assistant deltas straight to stdout regardless of
`suppress_answer`, so `--save`/capture turns (which set it to hide the
answer) leaked model text past the `runTurn` guard. Pass a null stream
hook when the turn's answer is suppressed.
2026-07-12 22:09:25 +02:00
Karl Seguin d43d11a641 Merge pull request #2912 from lightpanda-io/agent-repl-fixes
agent: multi-line slash commands and --save .js extension
2026-07-11 07:26:29 +08:00
Adrià Arrufat 049c5f08f2 feat(agent): add assistant text streaming 2026-07-11 00:50:01 +02:00
Adrià Arrufat 7547d3ac72 agent: emit intent comments in saved scripts
Instruct the /save synthesis model to annotate the generated script with
short `//` intent comments — one per logical block (navigate, extract,
fan out, aggregate, return) describing what the block accomplishes, so a
later reader (human or agent) grasps the script at a glance.

The save synthesis prompt previously ended with "no commentary", which
discouraged code comments; reword it to forbid only prose/markdown fences
outside the code while explicitly asking for the `//` intent comments. The
same prompt backs the MCP `save` tool, so both surfaces benefit. Also add a
matching best-practice bullet + example to the agent's script-writing skill.
2026-07-10 16:12:16 +02:00
Adrià Arrufat 03f6577efa agent: continue slash commands across lines inside '''...''' blocks
The docs promise triple-quoted values that span multiple lines, but the
REPL dispatched every physical line immediately, so the multi-line
/extract form died with 'unterminated quote' on its first line. A slash
command that leaves a '''...''' block open now keeps reading lines at a
continuation prompt until the block closes; Ctrl-D abandons it.
2026-07-10 11:55:50 +02:00
Adrià Arrufat 0f686381dd agent: append .js to --save destinations like /save does
The one-shot --save flag bypassed save.parseCommand, so '--save test'
wrote a file literally named 'test' while the REPL's /save appended the
extension. Share one ensureJsExtension helper so the paths can't drift.
2026-07-10 11:34:53 +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
Karl Seguin f1e49aae6e perf: Increase default max connections
max http connections 10 -> 40
max http connetions per host 4 -> 6

These are just the defaults and can still be adjusted by the command line
arguments. 6 appears to be both Chrome and FireFox's default per host (which
is probably the more important of the two settings).

The limits are really use-case specific. A use case that it multi-threading
different domains can benefit from a conservative max-host with a very large
max conn. A use case that is multi-threading the same host will need to decide
if it's safe to raise max-host.
2026-07-03 09:43:13 +08:00
Adrià Arrufat 1dd5f6548d agent: update script instructions for parallel pages
Updates the `script_skill` prompt to recommend and demonstrate parallel
page navigation using `Promise.all` and multiple `Page` instances,
rather than serial navigation on a single page.
2026-06-30 13:27:54 +02:00
Adrià Arrufat 98a5458205 agent: allow paths in --save option 2026-06-19 07:46:42 +02:00
Adrià Arrufat 69d302fabe agent: add --save flag to synthesize scripts from tasks 2026-06-18 17:45:26 +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 275ed43b1e agent: respect configured reasoning effort
Respect the user's configured reasoning effort during save synthesis
and user message processing. This prevents API errors on models that
do not support reasoning effort (like Mistral) when `.none` is set.
2026-06-18 10:53:59 +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 f52bbc0f48 agent: scrub remaining global-goto/extract refs from messages and docs 2026-06-16 08:10:43 +02:00
Adrià Arrufat 39924dcd8e Agent: record navigating read tools as goto commands 2026-06-16 00:03:12 +02:00
Adrià Arrufat 7e5777b3e7 Merge branch 'agent' into agent-page-syntax 2026-06-15 23:16:36 +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 21477b39c9 script: introduce Page API with async goto
Replaces global blocking functions with a `Page` class. `page.goto` is
now asynchronous and must be awaited, while other methods remain
synchronous. Scripts are wrapped in an async IIFE to support top-level
await, and output is returned via `return <value>`.
2026-06-15 22:48:12 +02:00
Adrià Arrufat 7a9924ab22 Agent: support HF_BILL_TO for Hugging Face
Passes the `HF_BILL_TO` environment variable to the ZenAI client
to route Hugging Face billing to an organization. Also updates
the `zenai` dependency.
2026-06-15 19:27:58 +02:00
Adrià Arrufat e35c66c2a6 agent: reset save destination on /clear and /reset
clearConversation reset the recorded action buffer but left save_path
set, so after /clear or /reset a /save <newfile> was rejected with
"already saving to <oldfile>". Free and clear save_path alongside the
buffer so a cleared session can save to a fresh file.
2026-06-15 14:54:26 +02:00
Adrià Arrufat a1bd1a4834 Merge pull request #2702 from lightpanda-io/save_system_prompt
agent: improve save system prompt
2026-06-12 16:01:37 +02:00
Adrià Arrufat 5eb8e3f8c3 Merge pull request #2705 from lightpanda-io/agent-feedback-fixes
Agent feedback fixes
2026-06-12 15:16:26 +02:00
Adrià Arrufat c98c762366 agent: add explicit update mode for script saving
Introduces an `update` save mode that allows the LLM to revise an
existing script. Distinguishes this from `append`, which now performs
a blind append. Updates the save prompts and system instructions
accordingly.
2026-06-12 13:39:22 +02:00
Adrià Arrufat 454594137b agent: revise the saved script on repeat /save
A second /save with nothing recorded and no prompt sent an empty user
message, which Anthropic rejects (HTTP 400: text content blocks must be
non-empty). Bail out early instead, telling the user to run commands or
give a prompt.

When a /save targets an existing script (a remembered save path, or
choosing append for an existing file), feed the file contents back to
the model and ask for the complete updated script, then overwrite. This
makes '/save fix X' actually fix the saved script — previously the
blind regeneration was appended after the buggy one. The --no-llm dump
path keeps its verbatim append semantics.
2026-06-12 11:57:40 +02:00
Adrià Arrufat d292f2b342 agent: pump session during terminal idle
Updates isocline to support idle callbacks and registers a hook to
pump the session's curl multi while waiting for user input. This
prevents connection timeouts. Also refactors the idle pumping logic
into `Session.idleSlice` to share it with the MCP server.
2026-06-11 18:19:51 +02:00
Adrià Arrufat de7ad43bb9 agent: treat first arg of /save as filename and append .js
Updates `/save` to always treat the first token as the filename,
appending `.js` if missing. Remaining tokens are used as the prompt.
2026-06-11 17:35:15 +02:00
Francis Bouvier ac34d2f9b7 agent: better instructions not to use evaluate on /save 2026-06-11 14:28:45 +02:00
Francis Bouvier 9ca117a235 agent: improve /save system prompt
Remove redudancy between general instructions and skill-like doc.
+ some others improvements
2026-06-11 14:26:57 +02:00