| | --- |
| | title: asa-api |
| | emoji: 🔎 |
| | colorFrom: yellow |
| | colorTo: indigo |
| | sdk: docker |
| | pinned: false |
| | license: mit |
| | --- |
| | |
| | # asa-api (Self-Hosted Docker + Tor) |
| |
|
| | `asa-api` is a self-hosted Docker API + GUI wrapper around [`asa::run_task()`](https://github.com/cjerzak/asa-software). |
| |
|
| | It uses: |
| | - `R` + `plumber` for HTTP endpoints |
| | - The `asa` package for orchestration (`run_task`, `run_task_batch`) |
| | - A lightweight password-protected browser GUI at `/` |
| | - A local Tor daemon for search/web egress inside the container |
| |
|
| | ## What This Service Exposes |
| |
|
| | 1. `GET /healthz` |
| | 2. `POST /v1/run` for a single prompt |
| | 3. `POST /v1/batch` for many prompts |
| | 4. `GET /` GUI page |
| | 5. `POST /gui/query` used by the GUI |
| |
|
| | ## Security Model |
| |
|
| | - API bearer auth is required for `/v1/*`: |
| | - Include `Authorization: Bearer 999` |
| | - GUI auth is password-based: |
| | - `/gui/query` checks `GUI_PASSWORD` |
| |
|
| | ## Required Environment Variables |
| |
|
| | Set these when running the container: |
| |
|
| | - `GOOGLE_API_KEY` (or the provider key you use) |
| | - `GUI_PASSWORD` |
| |
|
| | Optional secrets / vars: |
| |
|
| | - `ASA_DEFAULT_BACKEND` (defaults to `gemini` if unset; examples: `openai`, `groq`, `anthropic`, `gemini`, `openrouter`) |
| | - `ASA_DEFAULT_MODEL` (example: `gemini-2.5-flash`) |
| | - `ASA_CONDA_ENV` (default: `asa_env`) |
| | - `ASA_USE_BROWSER_DEFAULT` (default: `false`, recommended for container stability) |
| | - `CORS_ALLOW_ORIGIN` (default: `*`) |
| |
|
| | Provider-specific keys supported by `asa` include: |
| |
|
| | - `OPENAI_API_KEY` |
| | - `GROQ_API_KEY` |
| | - `ANTHROPIC_API_KEY` |
| | - `GOOGLE_API_KEY` (or `GEMINI_API_KEY`) |
| | - `OPENROUTER_API_KEY` |
| | - Bedrock credentials if using `bedrock` |
| |
|
| | ## API Usage |
| |
|
| | ### 1) Health check |
| |
|
| | ```bash |
| | curl -s http://localhost:7860/healthz |
| | ``` |
| |
|
| | ### 2) Single query |
| |
|
| | ```bash |
| | curl -s http://localhost:7860/v1/run \ |
| | -H "Content-Type: application/json" \ |
| | -H "Authorization: Bearer 999" \ |
| | -d '{ |
| | "prompt": "What is the population of Tokyo?", |
| | "config": { |
| | "backend": "gemini", |
| | "model": "gemini-2.5-flash" |
| | }, |
| | "run": { |
| | "output_format": "text", |
| | "recursion_limit": 20 |
| | } |
| | }' |
| | ``` |
| |
|
| | ### 3) Structured JSON output |
| |
|
| | ```bash |
| | curl -s http://localhost:7860/v1/run \ |
| | -H "Authorization: Bearer 999" \ |
| | -H "Content-Type: application/json" \ |
| | -d '{ |
| | "prompt": "Find Marie Curie birth year and nationality. Return JSON.", |
| | "run": { |
| | "output_format": "json" |
| | } |
| | }' |
| | ``` |
| |
|
| | ### 4) Batch query |
| |
|
| | ```bash |
| | curl -s http://localhost:7860/v1/batch \ |
| | -H "Authorization: Bearer 999" \ |
| | -H "Content-Type: application/json" \ |
| | -d '{ |
| | "prompts": [ |
| | "What is the capital of France?", |
| | "What is the capital of Japan?" |
| | ], |
| | "parallel": false, |
| | "run": { |
| | "output_format": "text" |
| | } |
| | }' |
| | ``` |
| |
|
| | `/v1/batch` accepts only a plain JSON array of strings for `prompts`. Structured row objects that mirror upstream `asa::run_task_batch()` data-frame inputs are rejected by this adapter. |
| |
|
| | ## Request Shape |
| |
|
| | ### `POST /v1/run` |
| |
|
| | ```json |
| | { |
| | "prompt": "string, required", |
| | "config": { |
| | "...": "any asa::asa_config argument" |
| | }, |
| | "run": { |
| | "...": "any asa::run_task argument except prompt/config/agent" |
| | }, |
| | "include_raw_output": false, |
| | "include_trace_json": false |
| | } |
| | ``` |
| |
|
| | ### `POST /v1/batch` |
| |
|
| | ```json |
| | { |
| | "prompts": ["required", "array", "of strings"], |
| | "config": { |
| | "...": "any asa::asa_config argument" |
| | }, |
| | "run": { |
| | "...": "batch-compatible shared options only; single-run-only keys are rejected" |
| | }, |
| | "batch": { |
| | "...": "any asa::run_task_batch argument except prompts/config/agent" |
| | }, |
| | "parallel": false, |
| | "include_raw_output": false, |
| | "include_trace_json": false |
| | } |
| | ``` |
| |
|
| | ## Future Compatibility Strategy |
| |
|
| | The adapter is intentionally resilient to `asa` changes: |
| |
|
| | - It dynamically inspects `formals(asa::asa_config)`, `formals(asa::run_task)`, and `formals(asa::run_task_batch)`. |
| | - It only forwards request keys that exist in current function signatures. |
| | - For `/v1/batch`, it rejects single-run-only passthrough keys instead of silently dropping them. |
| | - This avoids hard crashes when upstream adds/removes optional args. |
| |
|
| | ## GUI |
| |
|
| | - Open `/` in your browser. |
| | - Enter `GUI_PASSWORD`. |
| | - Enter prompt and choose output format. |
| | - Leave `Use direct provider call (skip ASA)` unchecked to run the normal ASA agent flow. |
| | - Check `Use direct provider call (skip ASA)` to send the prompt straight to the configured provider/model without ASA search/tool orchestration. |
| | - Submit (Ctrl/Cmd + Enter is supported). |
| |
|
| | Notes: |
| | - The checkbox is GUI-only; `/v1/run` and `/v1/batch` remain ASA endpoints. |
| | - The provider/model selection stays server-side and is not user-selectable in the GUI. |
| |
|
| | ## Docker Build and Runtime |
| |
|
| | The `Dockerfile` clones `asa-software` during build and installs `asa` from source. |
| |
|
| | R dependency strategy in this image: |
| | - Base image is `rocker/r2u:24.04`. |
| | - Core R runtime packages (`plumber`, `jsonlite`, `reticulate`, `remotes`) are installed as binary apt packages (`r-cran-*`), not compiled from CRAN source. |
| | - This avoids source-compile failures such as `sodium` -> `plumber` install breaks. |
| | - The Docker build pre-creates `asa_env` with pinned `python=3.12.3` and `openssl=3.0.13` before calling `asa::build_backend()`, reducing rebuild drift that can break `reticulate` SSL imports on Ubuntu 24.04 / Hugging Face rebuilds. |
| | - Runtime linker guardrails are set so `reticulate` prefers conda environment libraries (`/opt/conda/envs/asa_env/lib` and `/opt/conda/lib`) to avoid C++ ABI loader mismatches. |
| | - Tor is installed in the image and started before the API. If Tor does not become ready, the container exits instead of serving direct search traffic. |
| |
|
| | Build args: |
| |
|
| | - `ASA_SOFTWARE_REPO` (default: `https://github.com/cjerzak/asa-software`) |
| | - `ASA_SOFTWARE_REF` (default: `main`) |
| | - `ASA_CONDA_PYTHON_VERSION` (default: `3.12.3`) |
| | - `ASA_CONDA_OPENSSL_VERSION` (default: `3.0.13`) |
| |
|
| | Local build: |
| |
|
| | ```bash |
| | docker build -t asa-api . |
| | ``` |
| |
|
| | Local run: |
| |
|
| | ```bash |
| | docker run --rm -p 7860:7860 \ |
| | -e GOOGLE_API_KEY=... \ |
| | -e GUI_PASSWORD=XXX \ |
| | asa-api |
| | ``` |
| |
|
| | Then open: |
| | - `http://localhost:7860/healthz` |
| | - `http://localhost:7860/` |
| |
|
| | ## Tor Deployment Defaults |
| |
|
| | The container deploys Tor locally and exports these runtime defaults before starting `plumber`: |
| |
|
| | - `ASA_PROXY=socks5h://127.0.0.1:9050` |
| | - `TOR_CONTROL_PORT=9051` |
| | - `ASA_TOR_CONTROL_COOKIE=/tmp/tor/control.authcookie` |
| |
|
| | Tor scope is intentionally limited: |
| |
|
| | - Search and webpage retrieval traffic uses Tor. |
| | - LLM provider API traffic remains direct, matching upstream `asa` behavior. |
| | - Browser/Selenium search remains disabled by default. |
| |
|
| | Startup behavior is fail-closed: |
| |
|
| | - Tor must answer a probe to `https://check.torproject.org/api/ip` with `IsTor=true`. |
| | - If the SOCKS proxy, ControlPort, or cookie setup never becomes ready, the container exits non-zero. |
| |
|
| | `GET /healthz` now includes Tor readiness fields: |
| |
|
| | - `tor_enabled` |
| | - `tor_ready` |
| | - `tor_proxy` |
| | - `tor_control_port` |
| | - `tor_cookie_present` |
| | - `tor_cookie_readable` |
| |
|
| | You can override the local proxy defaults if needed: |
| |
|
| | - `ASA_PROXY` |
| | - `TOR_CONTROL_PORT` |
| | - `ASA_TOR_CONTROL_COOKIE` |
| | - `ASA_TOR_PROBE_URL` |
| | - `ASA_TOR_STARTUP_TIMEOUT_SEC` |
| |
|
| | ## Notes |
| |
|
| | - Browser/Selenium tier is disabled by default (`use_browser = FALSE`) for better reliability in minimal containers. |
| | - If you want browser tier, set `config.use_browser = true` explicitly per request and ensure supporting binaries are installed. |
| | - If startup fails with Python import/linker errors (for example `CXXABI_1.3.15 not found`), inspect container logs and verify `GET /healthz` for `boot_error` details once the service is up. |
| |
|