File size: 8,740 Bytes
b16eb64
baa72b1
 
a7d7c12
 
baa72b1
 
a7d7c12
 
b16eb64
a59174a
142e11e
a59174a
142e11e
 
 
 
 
a59174a
142e11e
a59174a
142e11e
 
 
 
 
 
 
 
 
f23dbdb
1dd1e45
142e11e
1dd1e45
 
bc43d06
 
 
142e11e
a59174a
142e11e
a59174a
142e11e
1dd1e45
def264a
142e11e
 
 
 
def264a
 
142e11e
1dd1e45
a59174a
142e11e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a59174a
142e11e
 
 
 
 
a59174a
142e11e
1dd1e45
142e11e
 
 
def264a
 
142e11e
 
 
 
 
 
 
 
 
 
 
a59174a
1dd1e45
142e11e
 
 
 
 
 
 
 
 
 
 
 
a59174a
1dd1e45
142e11e
 
 
 
 
 
 
 
 
 
 
 
 
a3f50a3
 
142e11e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a3f50a3
142e11e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a3f50a3
142e11e
 
 
 
 
 
 
dd0cabe
 
142e11e
 
dd0cabe
 
 
 
142e11e
 
 
 
f67f117
dcfb803
f67f117
 
7f40cff
dcfb803
1dd1e45
f67f117
142e11e
 
 
 
7f40cff
 
142e11e
 
 
 
 
 
 
 
 
 
 
1dd1e45
def264a
1dd1e45
142e11e
 
 
 
 
 
 
1dd1e45
a59174a
1dd1e45
 
 
 
 
 
 
 
 
 
 
 
 
 
a59174a
 
 
 
 
 
 
 
 
 
 
1dd1e45
a59174a
 
 
 
1dd1e45
 
a59174a
 
 
 
 
 
 
 
 
 
 
1dd1e45
a59174a
 
 
 
 
 
142e11e
 
a59174a
142e11e
a59174a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
---
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 $ASA_API_BEARER_TOKEN`
- GUI auth is password-based:
  - `/gui/query` verifies the submitted password against an in-memory hash derived from `GUI_PASSWORD`
- The service fails closed if either auth secret env var is missing or blank.
- Auth errors are diagnostic but safe:
  - missing auth env vars return `503` with `error_code: "auth_config_missing"` and `details.missing_env_vars`
  - wrong GUI/API credentials return `401` with `error_code: "credential_mismatch"` and `details.auth_target`

## Required Environment Variables

Set these when running the container:

- `ASA_API_BEARER_TOKEN`
- `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_ENABLE_TOR` (default: `false`; set to `true` to route ASA search/web traffic through the bundled local Tor proxy)
- `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 ${ASA_API_BEARER_TOKEN}" \
  -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 ${ASA_API_BEARER_TOKEN}" \
  -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 ${ASA_API_BEARER_TOKEN}" \
  -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 remains available for opt-in startup through `ASA_ENABLE_TOR=true`.

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 ASA_API_BEARER_TOKEN=your-api-bearer-token \
  -e GOOGLE_API_KEY=... \
  -e GUI_PASSWORD=your-gui-password \
  asa-api
```

Then open:
- `http://localhost:7860/healthz`
- `http://localhost:7860/`

Tor stays off in that default run. To opt in later:

```bash
docker run --rm -p 7860:7860 \
  -e ASA_API_BEARER_TOKEN=your-api-bearer-token \
  -e GOOGLE_API_KEY=... \
  -e GUI_PASSWORD=your-gui-password \
  -e ASA_ENABLE_TOR=true \
  asa-api
```

## Tor Integration

The image still includes Tor and the Tor entrypoint integration, but `asa-api` does not activate it unless `ASA_ENABLE_TOR=true`.

When Tor is enabled, 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 when `ASA_ENABLE_TOR=true` 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.

When `ASA_ENABLE_TOR=false`, the startup script skips Tor bootstrap and clears Tor proxy env vars before launching the API, so the agent pipeline runs direct.

`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_ENABLE_TOR`
- `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.