Commit Graph
237 Commits
Author SHA1 Message Date
Karl Seguin 6a83881634 chore: add lp.IS_DEBUG and lp.IS_TEST
Change all users to builtin.mode and built.is_test
2026-08-01 09:15:18 +08:00
Karl Seguin 0871b6a8da disable Zig 0.16 signal_stack_size
Make sure jemallocator is disabled in Release builds (we only use it in Debug
builds to collect metrics. Supposedly something changed in our 0.16 build that
causes it to be initialized even though it isn't used. Not sure, for this, I'm
just doing what Claude tell me, but disabling something in Release that I know
we aren't using sounds ok).
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 d06731d8fb cli: page help output through $PAGER when stdout is a tty
Explicitly requested help (help, help <cmd>, --help) now goes to stdout
instead of stderr, and is piped through $PAGER (fallback: less -FIRX)
when stdout is an interactive terminal, so long help like 'help agent'
(~225 lines) no longer clobbers the screen. Piped or redirected output
stays plain, and error-path usage remains unpaged on stderr.
2026-07-16 11:27:32 +02:00
Karl Seguin 4d81e48e44 ops: Add prometheus metrics
Adds a /metrics endpoint in serve mode. Can be disabled via --disable-metrics.

In fetch, dumps the metrics if --metrics is specified (defaults to false).

None of the metrics being collected are on a hot path, so they're just always
collected using atomic operations (i.e. no `if (!enabled) return;`). Because
the operations are cheap and infrequent enough not to matter.

The one place I want to add more metrics is in HttpClient (bytes, status,
counts, ...) but after the pending HttpClient-related PR is merged.

./lightpanda fetch --log-level fatal --metrics "https://lightpanda.io/"

```
build_info{version="1.0.0-dev.7837+70493ce35"} 1
cdp_connections_total 0
cdp_connection_limit_total 0
cdp_active_connections 0
cdp_commands_total 0
cdp_unknown_commands_total 0
js_heap_limits_total 0
script_errors_total 0
arena_hit_total{size="tiny"} 908
arena_hit_total{size="small"} 35
arena_hit_total{size="medium"} 0
arena_hit_total{size="large"} 27
arena_miss_total{size="tiny"} 193
arena_miss_total{size="small"} 31
arena_miss_total{size="medium"} 5
arena_miss_total{size="large"} 23
navigate_total{type="page"} 1
navigate_total{type="iframe"} 0
navigate_total{type="popup"} 0
js_heap_size_bytes_bucket{le="4194304"} 0
js_heap_size_bytes_bucket{le="8388608"} 0
js_heap_size_bytes_bucket{le="16777216"} 1
js_heap_size_bytes_bucket{le="33554432"} 1
js_heap_size_bytes_bucket{le="67108864"} 1
js_heap_size_bytes_bucket{le="134217728"} 1
js_heap_size_bytes_bucket{le="268435456"} 1
js_heap_size_bytes_bucket{le="536870912"} 1
js_heap_size_bytes_bucket{le="+Inf"} 1
js_heap_size_bytes_sum 11223040
js_heap_size_bytes_count 1
```
2026-07-14 09:17:14 +08:00
Adrià Arrufat f66f0c191d mcp: add HTTP transport and multi-session support
Introduces an HTTP transport option to serve multipleagents from a
single process. Each connection is routed to its own isolated
browsing session using the `Mcp-Session-Id` header.

Also adds new session management tools (`session_new`, `session_list`,
`session_close`) and refactors the MCP server to support multiple V8
isolates with parking.
2026-07-12 15:27:20 +02:00
Halil Durak 8673fbb489 lp.update -> lp.checkVersion + honor --check in version 2026-07-08 13:00:30 +03:00
Halil Durak d8184dc462 move update command to version --check 2026-07-08 13:00:30 +03:00
Halil Durak 32fefeaa7a update: remove nightly channel check 2026-07-08 13:00:29 +03:00
Halil Durak 6919400c42 add update command and make it runnable in main 2026-07-08 13:00:28 +03:00
Pierre Tachoire 5fcfb4e344 Merge pull request #2859 from lightpanda-io/crypto-random-leak
use getrandom syscall for std.crypto.random
2026-07-02 12:03:30 +02:00
Pierre Tachoire e56a4f6259 use getrandom syscall for std.crypto.random
std.crypto.random's default backend mmaps a thread-local 528-byte state
page on first use and never unmaps it — there is no thread-exit hook.
With one detached thread per CDP connection (Server.handleConnection),
that leaks one resident page per connection (uuidv4 in
Page.getOrCreateOrigin touches it), ~4KB/conn of unbounded RSS growth.
Route every std.crypto.random call to the getrandom syscall instead.
.crypto_always_getrandom = true,
2026-07-02 11:19:53 +02:00
Scott Taylor f7f149c9c0 feat: add LIGHTPANDA_DISABLE_CORE_DUMP to suppress crash core dumps
Lightpanda installs no SIGSEGV handler, so a segfault (or the abort() in
the panic path) falls through to the kernel and writes a core dump. When
many instances run under a shared core_pattern crash reporter -- e.g. a
containerized crawl fleet -- those cores become pure storage/alert noise,
and a browser core can capture the contents of arbitrary pages.

Crashes are already reported via telemetry, so this adds an opt-in
LIGHTPANDA_DISABLE_CORE_DUMP env var (mirroring LIGHTPANDA_DISABLE_TELEMETRY)
that zeroes the soft RLIMIT_CORE at startup. Default behavior is unchanged.
2026-06-30 21:58:05 -04:00
Karl Seguin 13eb35720a telemetry: Move telemetry worker to its own thread
This reverts recent(ish) changes to telemetry which moved it from its own thread
onto the main thread.

The downside is: we have an extra thread.

The upside is largely that Network.zig becomes drastically simpler and more
efficient. There's a bunch of machinery in Network.zig to support arbitrary
workers, of which Telemetry is the only one. There's also a lot of code to
support an optional multi and requests made to is. This is all removed.

Also, fetch, agent and mcp without a cdp server no longer even need to start
the network loop. And, it IS started (e.g. serve/cdp), there's no longer an
arbitrary 250ms wakeup on poll to progress workers. Nor can telemtry block CDP.

Telemetry's implementation itself was changed. The ring buffer was removed in
favor of a double-buffer arraylist. When telemetry is disabled, this saves
64Kb of memory. When it's enabled, it creates more allocator churn, but should
still use less memory in most cases (and never more). Finally, Telemetry is
given its own easy connection rather than using one out of the pool (which
workers would maybe like to use).
2026-06-26 08:38:49 +08:00
Karl Seguin 630826160e cli: fetch multiple urls
Modified the fetch command to support multiple URLs. Only allowed when --json
is specified (we can revisit this limitation if anyone asks for it, but for now
it's the only non-ambiguous way to get multiple results).

Probably not a big surprise, but the performance gain comes from being able to
concurrently fetch resources. On fast network, or with caching enabled, the
difference wouldn't be so significant:

```
time begin;
./lightpanda fetch "https://github.com/lightpanda-io/browser/" --json;
./lightpanda fetch "https://www.reddit.com/r/Zig/comments/1p0ur0d/i_started_learning_zig" --json;
end
10.28 secs
```

vs

```
time ./lightpanda fetch --json \
  "https://github.com/lightpanda-io/browser/" \
  "https://www.reddit.com/r/Zig/comments/1p0ur0d/i_started_learning_zig"
5.12 secs
```
2026-06-24 18:16:02 +08:00
Pierre Tachoire 828444675f feat(log): support +/-/all syntax in --log-filter-scopes
`--log-filter-scopes` previously took a comma-separated list of scopes to
suppress. Extend it with explicit include/exclude directives applied
left-to-right:

  -X     filter out scope X
  X      alias for -X (backward compatible)
  +X     filter in scope X
  all    target every scope

This makes "filter everything except one scope" expressible, e.g.
`-all,+cdp` suppresses all logs except `cdp`. Bare scope names keep their
old meaning, so existing invocations like `http,unknown_prop` are
unaffected.

Internally, the suppressed-scope list is replaced by a resolved per-scope
`scope_enabled` boolean array built via `log.resolveFilterScopes()`, so the
hot-path `enabled()` check is a single array index. Filtering remains
Debug-only, as before. `testing.LogFilter` is adapted to the new
representation; all existing call sites are unchanged.

Adds a unit test for resolveFilterScopes (default, backward-compat,
-all,+cdp, ordering) and updates the help text.
2026-06-18 14:42:07 +02:00
Pierre Tachoire 20be50db7f Merge pull request #2644 from lightpanda-io/agent-telemetry
telemetry: send agent_replay mode on non-interactive usage
2026-06-16 14:03:10 +02:00
Adrià Arrufat 30c8bcbdd9 mcp: pump browser session during idle periods
Pumps the browser session while waiting for MCP requests to prevent
curl timeouts. Adds an idle polling loop to the request router.
2026-06-11 17:48:24 +02:00
Pierre Tachoire d44bdaa0c9 telemetry: remove allocation for llm event
The model length is limited to 23 char in DB.
2026-06-05 11:09:08 +02:00
Pierre Tachoire 3f5d19d7dc telemetry: send a new llm event 2026-06-04 17:35:26 +02:00
Adrià Arrufat 651504efb5 agent: consolidate LLM provider and key resolution
Introduce an `Llm` struct to bundle the provider and API key together.
Add `UserError` to identify errors that have already printed human-
readable messages, preventing duplicate logging on exit.
2026-05-21 15:01:44 +02:00
Adrià Arrufat 989932b40a Merge branch 'main' into agent 2026-05-20 14:57:32 +02:00
Marc Helbling a89a28a4a2 feat: add --json to fetch command
The `fetch` command is very practical to render pages without needing to
have a long running browser instance.
It is however masking all details on the fetch, most importantly the HTTP status code.
This is a big caveat when leveraging `lightpanda fetch` in a pipeline.

This introduces a `--json` option to provide a structured output that
contains:
* url
* HTTP status code
* response headers
* rendered content as controlled by the `--dump` option

The proposal is to always output the same JSON format even when not
using `--dump` with an option.
2026-05-19 12:08:23 +02:00
Adrià Arrufat 8d102b8511 Merge branch 'main' into agent 2026-05-19 11:33:46 +02:00
Adrià Arrufat 28d35f96ec fix: detach sig_bridge before agent deinit
Reorder defer statements in agentThread to ensure the signal bridge is
detached before the agent instance is deinitialized.
2026-05-19 10:09:57 +02:00
Adrià Arrufat d0a8da453b agent: implement graceful Ctrl-C interruption 2026-05-15 18:45:56 +02:00
Halil Durak 3489129f68 main.zig: changes for new help 2026-05-15 18:31:10 +03:00
Adrià Arrufat b23eb8a51a agent: handle user cancellation in interactive prompts 2026-05-13 11:51:36 +02:00
Adrià Arrufat 75b7a8ec6d Merge branch 'main' into agent 2026-05-11 17:52:35 +02:00
Halil Durak c566d0c41c introduce --inject-script and --inject-script-file
* Prefer `--inject-*` prefix.
* Support injecting multiple scripts (also allows using both variants together).
* Instead of executing scripts in JS context, actually insert them to `<head>` for correct dump output.
2026-05-11 15:15:35 +03:00
Halil Durak 39f12a5669 fetch: add support for --script option
Allows passing a JS file as an arg to be executed alongside other scripts.
2026-05-11 15:15:35 +03:00
Adrià Arrufat 1de98efbc4 agent: simplify model string ownership 2026-05-09 20:27:16 +02:00
Adrià Arrufat 5284abc3e7 agent: consolidate listModels logic into Agent.zig 2026-05-09 20:18:27 +02:00
Adrià Arrufat 16b83f5093 agent: add provider auto-detection and --no-llm flag 2026-05-09 19:52:42 +02:00
Adrià Arrufat 357033eb0c agent: add --list-models flag 2026-05-09 19:16:48 +02:00
Adrià Arrufat 7bf69a9a34 agent: remove integrated mcp server
Removes the `--mcp` flag and the internal `task` tool from the agent.
Users should use `lightpanda mcp` for external agent integrations.
2026-05-07 17:12:46 +02:00
Adrià Arrufat a00161f54c Merge branch 'main' into agent 2026-05-05 08:05:57 +02:00
Nikolay Govorov 9a312a4177 Refactor server/client/cdp structure 2026-05-04 16:41:22 +01:00
Adrià Arrufat 300fdfb34c agent: add MCP server mode with task tool 2026-04-30 17:11:48 +02:00
Adrià Arrufat 1d7e92beeb Merge branch 'main' into agent 2026-04-27 06:40:15 +02:00
Karl Seguin 12c2efb811 Adds --terminate-ms command line argument + ctrl-c improvements in fetch
The main.zig path for `fetch` now captures the *Browser so that
browser.env.terminate() can be called. This is a bit more complex than the serve
path because the Browser owns the Isolate and can't be moved from one thread to
another.

With main having access to the browser, two things are now possible:
1 - We can support a --terminate-ms flag (https://github.com/lightpanda-io/browser/issues/2206)
2 - ctrl-c can correctly stop blocked JavaScript processes

1 is implemented via setitimer to set a timer for SIGALRM, avoiding the need to
add another "watcher" thread, or putting a timer in Network.run.
2026-04-25 12:34:06 +08:00
Adrià Arrufat ec3ff945cd Merge branch 'main' into agent 2026-04-23 12:31:24 +02:00
Halil Durak 1da11d8da8 Config: revert to --strip-mode 2026-04-22 16:08:13 +03:00
Halil Durak 10914d6288 cli: fix --log-filter-scopes regression 2026-04-22 16:07:02 +03:00
Halil Durak 0e4ed2639f main: changes to build, introduced couple regressions
`help` command, `--dump` and `--log-filter-scopes` regressed, will come up with a solution for these.
2026-04-22 16:07:01 +03:00
Adrià Arrufat 570c901239 agent: improve recorder robustness and cleanup
- Add heap fallback for `Recorder` when fixed buffers overflow.
- Replace global atomic `agent_failed` with a local variable in `main.zig`.
- Fix `UnkownOption` typo in `Config.zig`.
- Add `Verifier` tests and debug logging for navigations.
- Add memory usage TODO and pointer arithmetic comments in `Agent.zig`.
2026-04-13 18:02:18 +02:00
Adrià Arrufat c61423ff94 Merge branch 'main' into agent 2026-04-11 11:28:57 +02:00
Karl Seguin 63104a7f82 Re-enable debug allocator in debug
Disabled this when looking at memory profiles, and must have accidentally
committed it.
2026-04-11 12:24:19 +08:00
Adrià Arrufat 81413d9291 agent: add scroll command and improve script reliability
Adds the SCROLL command and ensures WAIT actions are recorded.
Refactors TYPE to use the fill tool, adds self-heal retries, and
propagates agent failures to the process exit code.
2026-04-10 11:45:14 +02:00
Adrià Arrufat 7fe580214e Merge branch 'main' into agent 2026-04-10 09:32:43 +02:00