asa-api / README.md
cjerzak's picture
add files
f23dbdb
---
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.