From 215d87766e919b58149f2edc7631b6b556bf4033 Mon Sep 17 00:00:00 2001 From: Microck Date: Wed, 18 Mar 2026 18:19:50 +0000 Subject: [PATCH 1/7] feat(translate): add text-mode Kagi Translate support Add a new kagi translate command that bootstraps translate.kagi.com from the existing session token, then calls detect, translate, alternatives, alignments, suggestions, and word insights over direct HTTP. Document the new command, update auth and coverage references, and note the current runtime dependency on python3 plus curl_cffi for bootstrap. --- Cargo.lock | 21 + Cargo.toml | 2 +- README.md | 23 +- docs/api-coverage.md | 10 +- docs/commands/translate.mdx | 259 +++++++++ docs/docs.json | 1 + docs/index.mdx | 10 +- docs/reference/auth-matrix.mdx | 5 + docs/reference/coverage.mdx | 21 +- docs/reference/error-reference.mdx | 15 + docs/reference/output-contract.mdx | 34 ++ src/api.rs | 867 ++++++++++++++++++++++++++++- src/auth.rs | 64 ++- src/cli.rs | 97 ++++ src/main.rs | 90 ++- src/types.rs | 177 ++++++ 16 files changed, 1632 insertions(+), 64 deletions(-) create mode 100644 docs/commands/translate.mdx diff --git a/Cargo.lock b/Cargo.lock index 62edc34..4eceeb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,6 +241,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1187,6 +1197,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "siphasher" version = "1.0.2" @@ -1354,6 +1374,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.61.2", diff --git a/Cargo.toml b/Cargo.toml index 677d5a9..26ef15f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,5 +30,5 @@ scraper = "0.25.0" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" thiserror = "2.0.12" -tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.44.2", features = ["macros", "process", "rt-multi-thread"] } toml = "1.0.6" diff --git a/README.md b/README.md index 712e700..243e1ac 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ --- -`kagi` is a terminal CLI for Kagi that gives you command-line access to search, lenses, assistant, summarization, feeds, and paid API commands. it is built for people who want one command surface for interactive use, shell workflows, and structured JSON output. +`kagi` is a terminal CLI for Kagi that gives you command-line access to search, lenses, assistant, translate, summarization, feeds, and paid API commands. it is built for people who want one command surface for interactive use, shell workflows, and structured JSON output. the main setup path is your existing Kagi session-link URL. paste it into `kagi auth set --session-token` and the CLI extracts the token for you. if you also use Kagi's paid API, add `KAGI_API_TOKEN` and the public API commands are available too. @@ -29,7 +29,7 @@ if you already use Kagi and want to access it from scripts, shell workflows, or - use your existing session-link URL for subscriber features - get structured JSON for scripts, agents, and other tooling -- use one CLI for search, assistant, summarization, and feeds +- use one CLI for search, assistant, translate, summarization, and feeds - add `KAGI_API_TOKEN` only when you want the paid public API commands ## quickstart @@ -101,7 +101,7 @@ export KAGI_API_TOKEN='...' | credential | what it unlocks | | --- | --- | -| `KAGI_SESSION_TOKEN` | base search, `search --lens`, `assistant`, `summarize --subscriber` | +| `KAGI_SESSION_TOKEN` | base search, `search --lens`, `assistant`, `translate`, `summarize --subscriber` | | `KAGI_API_TOKEN` | public `summarize`, `fastgpt`, `enrich web`, `enrich news` | | none | `news`, `smallweb`, `auth status`, `--help` | @@ -125,6 +125,7 @@ notes: - base `kagi search` defaults to the session-token path when both credentials are present - set `[auth] preferred_auth = "api"` if you want base search to prefer the API path instead - `search --lens` always requires `KAGI_SESSION_TOKEN` +- `translate` currently also requires `python3` with the `curl_cffi` package installed - `auth check` validates the selected primary credential without using search fallback logic for the full command-to-token matrix, use the [`auth-matrix`](https://kagi.micr.dev/reference/auth-matrix) docs page. @@ -139,6 +140,7 @@ for the full command-to-token matrix, use the [`auth-matrix`](https://kagi.micr. | `kagi summarize` | use the paid public summarizer API or the subscriber summarizer with `--subscriber` | | `kagi news` | read Kagi News from public JSON endpoints | | `kagi assistant` | prompt Kagi Assistant with a subscriber session token | +| `kagi translate` | translate text through Kagi Translate with a subscriber session token | | `kagi fastgpt` | query FastGPT through the paid API | | `kagi enrich` | query Kagi's web and news enrichment indexes | | `kagi smallweb` | fetch the Kagi Small Web feed | @@ -200,6 +202,18 @@ continue research with assistant: kagi assistant "plan a focused research session in the terminal" ``` +translate text and keep all text-mode extras: + +```bash +kagi translate "Bonjour tout le monde" +``` + +translate only the core text result: + +```bash +kagi translate "Bonjour tout le monde" --no-alternatives --no-word-insights --no-suggestions --no-alignments +``` + use the subscriber summarizer: ```bash @@ -258,6 +272,3 @@ for the fuller install matrix and platform-specific setup, use the [installation ## license [mit license](LICENSE) - -### todo -- add https://translate.kagi.com/ diff --git a/docs/api-coverage.md b/docs/api-coverage.md index 21287e0..f71bab8 100644 --- a/docs/api-coverage.md +++ b/docs/api-coverage.md @@ -12,6 +12,7 @@ - **Subscriber web Summarizer** - implemented on the session-token web-product path via `kagi summarize --subscriber ...` - **Kagi News public product endpoints** - implemented via `kagi news ...` - **Subscriber web Assistant prompt flow** - implemented on Kagi Assistant's authenticated tagged stream via `kagi assistant ...` +- **Kagi Translate text mode** - implemented via `kagi translate ...` with runtime bootstrap from `KAGI_SESSION_TOKEN` ## Source of truth @@ -27,10 +28,6 @@ This CLI also implements non-public or product-only seams: - subscriber web Assistant prompt flow via Kagi session-token auth - Kagi News product endpoints -## TODO / deferred - -- **Kagi Translate** - removed from the public CLI surface until there is a live-verified Session Link compatible implementation - ## Notes - Lens support is not documented on the official Search API. In this CLI it works through Kagi's live HTML/session flow using the `l=` query parameter. @@ -39,7 +36,8 @@ This CLI also implements non-public or product-only seams: - Base-search fallback to session-token search happens on the user-facing `search` command only. `auth check` validates the selected primary credential without fallback. - The paid public Summarizer, FastGPT, and Enrichment APIs require `KAGI_API_TOKEN` and sufficient API credit. - The subscriber web Summarizer requires `KAGI_SESSION_TOKEN` and uses the authenticated `GET /mother/summary_labs?...` stream path instead of the public `/api/v0/summarize` endpoint. -- Live verification on March 16, 2026 showed that `https://translate.kagi.com/api/auth` returns `null` even when the same `KAGI_SESSION_TOKEN` works on `kagi.com`. -- Because the repo is marketed around Session Link auth, `translate` was removed from the CLI surface until that mismatch is solved. +- Live verification on March 18, 2026 showed that direct raw-cookie HTTP bootstrap still fails, but a browserless `python3 + curl_cffi` bootstrap can mint `translate_session` from the same `KAGI_SESSION_TOKEN`. +- After bootstrap, the CLI uses normal Rust HTTP requests for `/api/detect`, `/api/translate`, `/api/alternative-translations`, `/api/text-alignments`, `/api/translation-suggestions`, and `/api/word-insights`. +- `translate` requires `python3` with the `curl_cffi` package installed at runtime. - Assistant requires `KAGI_SESSION_TOKEN` and currently targets `/assistant/prompt` with the same tagged stream protocol used by the web app. - News uses `https://news.kagi.com/api/...` JSON endpoints and does not require auth. diff --git a/docs/commands/translate.mdx b/docs/commands/translate.mdx new file mode 100644 index 0000000..85ec45d --- /dev/null +++ b/docs/commands/translate.mdx @@ -0,0 +1,259 @@ +--- +title: "translate" +description: "Complete reference for *kagi* translate command - translate text through Kagi Translate with session-token auth." +--- + +# `kagi translate` + +Translate text through Kagi Translate and return one JSON envelope with the core translation plus the auxiliary text-mode sections. + +## Synopsis + +```bash +kagi translate [OPTIONS] +``` + +## Description + +`kagi translate` uses your existing `KAGI_SESSION_TOKEN`, bootstraps a `translate_session` at runtime, then calls the live `translate.kagi.com` endpoints over HTTP. + +By default the command fetches: + +- language detection +- translated text +- alternative translations +- text alignments +- translation suggestions +- word insights + +If an auxiliary section fails, the core translation still succeeds and the failure is recorded in `warnings`. + +## Authentication + +**Required:** `KAGI_SESSION_TOKEN` + +The command follows the same Session Link auth story as other subscriber features. Save the full Session Link URL with: + +```bash +kagi auth set --session-token 'https://kagi.com/search?token=...' +``` + +## Runtime Dependency + +Translate bootstrap currently requires: + +- `python3` +- the Python package `curl_cffi` + +The CLI shells out once to mint `translate_session`, then uses normal Rust HTTP requests for the rest of the flow. + +## Arguments + +### `` (Required) + +The text to translate. + +```bash +kagi translate "Bonjour tout le monde" +``` + +## Core Options + +### `--from ` + +Source language code. Default: `auto`. + +### `--to ` + +Target language code. Default: `en`. + +### `--quality ` + +Quality preference passed through to Kagi Translate. + +### `--model ` + +Model override passed through to Kagi Translate. + +## Context and Style Options + +### `--prediction ` + +Bias translation toward a predicted completion. + +### `--predicted-language ` + +Predicted source language code. + +### `--formality ` + +Formality hint. + +### `--speaker-gender ` + +Speaker gender hint. + +### `--addressee-gender ` + +Addressee gender hint. + +### `--language-complexity ` + +Language complexity hint. + +### `--translation-style