Packages

Typed Elixir client for Kagi Search, Summarizer, and Maps, built on Req.

Current section

Files

Jump to
kagi_ex CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project follows Semantic Versioning.
## [0.3.0] - 28.08.2026
### Changed
- `req` must now be 0.7 (`~> 0.7`, was `~> 0.5 or ~> 0.6`). `cloaked_req` must
now be 0.6 (`~> 0.6`, was `~> 0.5.1`). `cloaked_req` 0.6.0 needs `req` 0.7,
and it dropped `req` 0.5 and `req` 0.6. Move your application to `req` 0.7
first. This is a breaking change.
- An impersonated request now sends the profile `user-agent`. Before, it sent
`user-agent: req/<version>` next to the profile `sec-ch-ua`. A detector can
find this pair. It also now sends the profile `accept-encoding`. The fix
comes from `cloaked_req` 0.6.0.
- The impersonation headers changed for each profile. The header set and the
header order are different. Test again each profile that you tuned against a
detector.
- The `cloaked_req` cookie jar changed. A host-only cookie no longer goes to a
subdomain. `Max-Age` now expires a cookie. The `cookie` header now has a
stable order. An `http://` origin can no longer set a `Secure` cookie. This
applies only if you pass `:cookie_jar` through `:req_options`. `kagi_ex`
sends the session cookie as a header, thus its own requests do not change.
- Update `ex_slop` to 0.4.4 and `styler` to 1.12.2 (dev and test only).
- CI now uses Elixir 1.20.3 (was 1.20.2) and OTP 29.0.5 (was 29.0.3).
## [0.2.0] - 11.06.2026
### Added
- `:timeout` option for `Kagi.summarize/1..3`, the total request timeout in
milliseconds. Precedence: per-call `:timeout`, then the client's
`req_options[:receive_timeout]`, then the summarizer default of 60 seconds.
- `req` 0.6 support: the requirement is now `~> 0.5 or ~> 0.6`, and
`cloaked_req` 0.4.2 carries the matching adapter support.
- `:invalid_session_token` error reason: tokens with characters that cannot
appear in a cookie value (a pasted `Cookie` header, for example) are rejected
before any request instead of being sent raw.
### Fixed
- `inspect(%Kagi.Client{})` no longer prints the session token; the field is
redacted from the derived `Inspect` implementation.
- Search results keep Kagi's ranking: grouped and standard rows are parsed in
one document-order pass, so `:limit` no longer drops grouped results that
Kagi ranks near the top.
- Search queries that are not strings or lists of strings (charlists, keyword
lists) return `:invalid_option` instead of being mangled or raising.
- `CloakedReq` adapter options (`:impersonate`, `:cookie_jar`, ...) passed via
`:req_options` no longer raise `ArgumentError`; the adapter is attached
before the configured options are merged.
- Maps results with drifting scalar types (numeric `price`, string `rating`,
...) normalize to `nil` instead of crashing `sort: :price` with a
`FunctionClauseError`; integer ratings and distances convert to floats.
- Maps `:limit` is validated before the HTTP request, matching search, so an
invalid value no longer burns an authenticated request.
- A `pois` value that is not an array of objects returns a descriptive
`:parse_error` instead of raising.
- Maps and search parse errors no longer embed whole response payloads in the
error message; inspected values are bounded.
- Maps queries that are not strings or lists of strings (charlists, keyword
lists) return `:invalid_option` instead of being mangled or raising.
### Changed
- Challenge detection runs only when a page has no recognizable results and no
longer downcases the whole HTML body on the happy path.
- Requests no longer follow redirects, so the session cookie cannot travel to
another host. Re-enable with `redirect: true` in `:req_options`. The
endpoint URL and method are pinned after configuration merging, so
`:req_options` can never point a request at another host.
- Requests no longer retry transient HTTP errors behind the caller's back; a
429 returns `:rate_limited` after a single attempt. Re-enable with
`retry: :safe_transient` in `:req_options`.
- Transport failures now include the adapter's failure reason (timeout, DNS,
TLS, ...) in the `:request_failed` error message.
- Summarizer requests default to a 60-second timeout instead of inheriting the
adapter's 15-second total request timeout, which failed long summaries.
- Summarizer-reported failures (`"state": "error"` payloads and empty
summaries) return the new `:summarizer_error` reason instead of
`:parse_error`, so callers can tell an unfetchable URL from a client parsing
bug. Code matching on `:parse_error` for these cases must be updated.
## [0.1.1] - 23.05.2026
### Changed
- Update `cloaked_req` to `~> 0.4.0`, which runs native HTTP requests on the shared Tokio runtime, aborts in-flight requests when the caller exits, and honours Req `connect_options` for proxy configuration.
## [0.1.0] - 17.05.2026
### Added
- Typed `Kagi.search/2`, `Kagi.search/3`, `Kagi.summarize/2`, and `Kagi.summarize/3` APIs.
- Typed `Kagi.maps/2` and `Kagi.maps/3` API with `%Kagi.Maps{}`, `%Kagi.MapsResult{}`, and `%Kagi.MapsResult.Coordinates{}` structs.
- Client-side maps sorting by `:relevance`, `:rating`, `:distance`, or `:price` with sensible default orders.
- Reusable `%Kagi.Client{}` with configurable session token resolution.
- `Req` transport by default and explicit `CloakedReq` transport support.
- Search, summarizer, and maps parsers ported from the Rust `kagi` CLI.
- Release, CI, and package documentation matching the companion Elixir libraries.