ada-agent 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +262 -263
- package/bench/README.md +88 -88
- package/bench/swebench.mjs +242 -242
- package/docs/architecture.md +163 -163
- package/docs/architecture.svg +73 -73
- package/docs/cloudflare.md +81 -81
- package/docs/connectors.md +49 -49
- package/docs/integrations.md +62 -62
- package/package.json +66 -65
- package/skills/aesthetic-direction/SKILL.md +24 -24
- package/skills/color-palette/SKILL.md +24 -24
- package/skills/component-library/SKILL.md +23 -23
- package/skills/dark-mode/SKILL.md +24 -24
- package/skills/dashboard-ui/SKILL.md +23 -23
- package/skills/design-system/SKILL.md +24 -24
- package/skills/design-tokens/SKILL.md +24 -24
- package/skills/empty-states/SKILL.md +23 -23
- package/skills/hero-section/SKILL.md +23 -23
- package/skills/micro-interactions/SKILL.md +23 -23
- package/skills/motion-design/SKILL.md +23 -23
- package/skills/page-transitions/SKILL.md +23 -23
- package/skills/pricing-page/SKILL.md +23 -23
- package/skills/scroll-animation/SKILL.md +23 -23
- package/skills/skeleton-loader/SKILL.md +23 -23
- package/skills/tailwind-theme/SKILL.md +24 -24
- package/skills/typography/SKILL.md +24 -24
- package/skills/ui-polish/SKILL.md +24 -24
- package/skills/ui-review/SKILL.md +24 -24
- package/skills/web-fonts/SKILL.md +24 -24
- package/src/client/autostart.ts +93 -0
- package/src/client/catalog.json +1 -1
- package/src/client/cli.ts +1275 -1262
- package/src/client/models-dev.ts +106 -106
- package/src/selfcheck.ts +404 -390
- package/src/server/config.ts +65 -65
- package/src/server/providers/openai-compat.ts +78 -78
- package/src/server/providers/registry.ts +32 -32
- package/src/server/router.ts +33 -33
- package/src/shared/types.ts +21 -21
package/docs/architecture.md
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# Architecture
|
|
2
|
-
|
|
3
|
-
ada is two programs in one repo: a thin **client** (the coding agent) and a **backend** (the
|
|
4
|
-
router that holds provider keys). They communicate in one wire format — OpenAI Chat Completions.
|
|
5
|
-
|
|
6
|
-

|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
ada (client) ada backend upstream providers
|
|
10
|
-
──────────── ─────────── ──────────────────
|
|
11
|
-
agentic loop ──── HTTP ───▶ auth (client key)
|
|
12
|
-
tools router: model id → provider
|
|
13
|
-
sessions adapter: provider → wire format ──▶ Anthropic / OpenAI / …
|
|
14
|
-
approval/TUI ◀── SSE ──── normalize back to OpenAI SSE
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Why split it: the backend is the **one control point**. Provider keys, auth, rate limits, and
|
|
18
|
-
billing all belong in one place; the client carries only an ada client key. Same shape as Cursor.
|
|
19
|
-
|
|
20
|
-
## Request flow
|
|
21
|
-
|
|
22
|
-
1. The client sends an OpenAI-format chat request (model, messages, tools) to `ADA_BACKEND_URL`
|
|
23
|
-
with its client key as the bearer.
|
|
24
|
-
2. The backend authenticates the key (`ADA_CLIENT_KEYS`, or open in dev mode), then `router.ts`
|
|
25
|
-
maps the model id → a provider.
|
|
26
|
-
3. The matching **adapter** calls the upstream with the server-held provider key — a pass-through
|
|
27
|
-
for OpenAI-compatible providers, a translation for Anthropic.
|
|
28
|
-
4. The backend streams normalized OpenAI SSE chunks back; the client renders text and runs tool
|
|
29
|
-
calls, appending one `{role:"tool", tool_call_id, content}` per call and looping.
|
|
30
|
-
|
|
31
|
-
## The agent loop
|
|
32
|
-
|
|
33
|
-

|
|
34
|
-
|
|
35
|
-
Each turn streams the model's reply; if it contains tool calls, gated ones go through the
|
|
36
|
-
**permission mode**, the tools run, and one `{role:"tool", tool_call_id, content}` per call is
|
|
37
|
-
appended before control returns to the model — looping until the model stops calling tools.
|
|
38
|
-
|
|
39
|
-
**Permission modes** (`/ask` · `/plan` · `/auto`, or `/mode` to cycle; shown in the prompt):
|
|
40
|
-
|
|
41
|
-
- **ask** (default) — each gated tool shows a plain-words prompt ("ada wants to run a shell command…")
|
|
42
|
-
and one key: `[y]es` · `[a]uto` · `[p]lan` · `[n]o`. Destructive `bash` always confirms.
|
|
43
|
-
- **plan** — read-only: ada plans but won't edit; `/run` approves and executes.
|
|
44
|
-
- **auto** — runs tools without asking (still confirms destructive `bash`). `--yolo` starts here.
|
|
45
|
-
|
|
46
|
-
**Skills.** ~285 bundled `SKILL.md` instructions load only on demand. A lexical router
|
|
47
|
-
(`client/skill-router.ts`) ranks every request; on a confident, name-exact match ada **auto-applies**
|
|
48
|
-
the skill (injects its procedure, announced `↳ skill: <name>`), otherwise it suggests them. The model
|
|
49
|
-
can also `list_skills` / `find_skill` / `use_skill`. See [orchestration.md](orchestration.md) for the
|
|
50
|
-
strategies (`react`/`plan`/`multi`/`toolsmith`) layered on the same loop.
|
|
51
|
-
|
|
52
|
-
**Programmatic surfaces.** Beyond the REPL/TUI, the same agent drives an HTTP API (`ada serve`), a
|
|
53
|
-
typed SDK, an ACP editor bridge (`ada acp`), and read-only session sharing (`ada share`) — see
|
|
54
|
-
[integrations.md](integrations.md). And it can run **SWE-bench Verified** via [bench/](../bench/).
|
|
55
|
-
|
|
56
|
-
## Sign in (device flow)
|
|
57
|
-
|
|
58
|
-

|
|
59
|
-
|
|
60
|
-
GitHub/Google login uses the OAuth 2.0 device authorization grant (RFC 8628) — no password ever
|
|
61
|
-
reaches ada. The token is stored locally and sent as the bearer; the backend verifies identity in
|
|
62
|
-
`server/identity.ts`. The GitHub `client_id` is baked in (public, like `gh`), so the client needs
|
|
63
|
-
zero config.
|
|
64
|
-
|
|
65
|
-
## One adapter per wire format
|
|
66
|
-
|
|
67
|
-
The key design decision: adapters are keyed by **wire format**, not by provider or model.
|
|
68
|
-
|
|
69
|
-
- Most providers speak the OpenAI format and share **`openai-compat.ts`** (a pass-through that just
|
|
70
|
-
swaps in the right base URL + key).
|
|
71
|
-
- Only a divergent format gets its own adapter — **`anthropic.ts`** translates OpenAI ⇄ Anthropic
|
|
72
|
-
Messages and re-emits Anthropic events as OpenAI SSE.
|
|
73
|
-
|
|
74
|
-
Consequences:
|
|
75
|
-
|
|
76
|
-
| Change | Cost |
|
|
77
|
-
|---|---|
|
|
78
|
-
| A new model | **0 code** (routing is by id) |
|
|
79
|
-
| A new OpenAI-compatible provider | **2 lines** in `config.ts` (base URL + key env) |
|
|
80
|
-
| A brand-new wire format | **1 adapter** + one line in `registry.ts` |
|
|
81
|
-
|
|
82
|
-
Vendor SDKs load **lazily** (pi-style): a `type`-only import plus a dynamic `import()`, so e.g.
|
|
83
|
-
`@anthropic-ai/sdk` never loads unless a Claude request actually arrives.
|
|
84
|
-
|
|
85
|
-
## Routing
|
|
86
|
-
|
|
87
|
-
`router.ts` maps a model id to a provider:
|
|
88
|
-
|
|
89
|
-
- a model id containing `:` (e.g. `qwen2.5-coder:latest`) → local **Ollama**;
|
|
90
|
-
- otherwise by prefix (`gpt*`/`o*` → openai, `claude*` → anthropic, `gemini*` → google,
|
|
91
|
-
`mistral*` → mistral, `grok*` → xai, …);
|
|
92
|
-
- an explicit `provider` field on the request always wins;
|
|
93
|
-
- anything unmatched falls through to **OpenRouter**.
|
|
94
|
-
|
|
95
|
-
## Context compaction
|
|
96
|
-
|
|
97
|
-
The client estimates context size (≈ chars / 4) and, when it crosses `ADA_COMPACT_AT` (default
|
|
98
|
-
100k) or a request overflows, summarizes older turns into one compact summary and keeps the recent
|
|
99
|
-
ones. `/compact` forces it; `/context` shows the current estimate.
|
|
100
|
-
|
|
101
|
-
## Tool-call recovery
|
|
102
|
-
|
|
103
|
-
Some providers (notably **Ollama over a streaming connection**) fail to parse a model's tool call
|
|
104
|
-
into the structured `tool_calls` field and leak it into the text as raw JSON. The client detects a
|
|
105
|
-
reply that *is* a JSON tool call (plain, ```` ```json ```` fenced, or `<tool_call>`-wrapped) for a
|
|
106
|
-
real tool and runs it instead of printing the JSON. Hallucinated tools (no such tool) are left as
|
|
107
|
-
text. See `parseTextToolCalls` in `client/agent.ts`.
|
|
108
|
-
|
|
109
|
-
## File layout
|
|
110
|
-
|
|
111
|
-
```
|
|
112
|
-
bin/
|
|
113
|
-
ada.mjs launcher: register tsx loader → run client/cli.ts
|
|
114
|
-
ada-server.mjs launcher: register tsx loader → run server/index.ts
|
|
115
|
-
|
|
116
|
-
src/
|
|
117
|
-
shared/
|
|
118
|
-
types.ts provider/model types shared by client and server
|
|
119
|
-
|
|
120
|
-
server/ the routing backend (ada-server | npm run server)
|
|
121
|
-
index.ts HTTP entry: auth → route → dispatch to an adapter (+ /v1/models, /v1/whoami)
|
|
122
|
-
config.ts providers, base URLs, key env vars, port, client-key auth
|
|
123
|
-
router.ts model id → provider
|
|
124
|
-
sse.ts Server-Sent Events helpers
|
|
125
|
-
identity.ts verify GitHub/Google tokens; allowlist
|
|
126
|
-
oauth.ts RFC 8628 device-flow login (built-in GitHub client id)
|
|
127
|
-
credentials.ts local credential store
|
|
128
|
-
providers/
|
|
129
|
-
adapter.ts the Adapter interface ← one adapter per WIRE FORMAT
|
|
130
|
-
registry.ts provider → adapter map
|
|
131
|
-
openai-compat.ts pass-through OpenAI-compatible adapter
|
|
132
|
-
anthropic.ts native Anthropic adapter (lazy @anthropic-ai/sdk)
|
|
133
|
-
|
|
134
|
-
client/ the terminal agent (ada | npm start)
|
|
135
|
-
cli.ts REPL: flags, model picker, slash commands, ask/plan/auto modes + approval
|
|
136
|
-
agent.ts the agentic loop (stream → tool calls → feed back → repeat) + orchestrators
|
|
137
|
-
tools.ts read_file/write_file/edit_file · apply_patch · bash (PTY) · ls/glob/grep (rg)
|
|
138
|
-
· web_fetch/web_search · lsp_diagnostics · ask_user; protected paths;
|
|
139
|
-
destructive detection; trust-gated auto-format
|
|
140
|
-
tui.ts inline TUI engine (composer, spinner, user bar)
|
|
141
|
-
tui-mode.ts the TUI loop
|
|
142
|
-
session.ts append-only JSONL session store (.ada/sessions/)
|
|
143
|
-
compaction.ts context summarization
|
|
144
|
-
checkpoint.ts · snapshot.ts undo (revert edits) · whole-tree git snapshot/restore
|
|
145
|
-
skills.ts · skill-router.ts skills + the relevance router (auto-apply)
|
|
146
|
-
mcp.ts · prompts.ts · background.ts · models-dev.ts · lsp.ts connectors, templates,
|
|
147
|
-
background jobs, models.dev catalog, LSP client
|
|
148
|
-
todos.ts · hooks.ts · extensions.ts tasks; extension hooks + tools + commands
|
|
149
|
-
settings.ts · platform.ts · render.ts · image.ts · telemetry.ts · pkg.ts
|
|
150
|
-
|
|
151
|
-
sdk/index.ts typed client for the HTTP API (`ada serve`)
|
|
152
|
-
selfcheck.ts offline checks (tools, sessions, routing, parsers, TUI, classifiers)
|
|
153
|
-
|
|
154
|
-
bench/
|
|
155
|
-
swebench.mjs SWE-bench Verified prediction generator (scored by the official harness)
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## No build step
|
|
159
|
-
|
|
160
|
-
Everything runs through `tsx` — TypeScript with no compile. The `bin/*.mjs` launchers register the
|
|
161
|
-
tsx ESM loader in-process, then import the relevant `.ts` entrypoint (which self-runs). `tsx` is a
|
|
162
|
-
runtime dependency so the global `ada` command works after `npx ada-agent`, `npm install -g ada-agent`,
|
|
163
|
-
or `npm link` from a clone. (`node-pty` is the one native dep, so a C toolchain is needed at install.)
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
ada is two programs in one repo: a thin **client** (the coding agent) and a **backend** (the
|
|
4
|
+
router that holds provider keys). They communicate in one wire format — OpenAI Chat Completions.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
ada (client) ada backend upstream providers
|
|
10
|
+
──────────── ─────────── ──────────────────
|
|
11
|
+
agentic loop ──── HTTP ───▶ auth (client key)
|
|
12
|
+
tools router: model id → provider
|
|
13
|
+
sessions adapter: provider → wire format ──▶ Anthropic / OpenAI / …
|
|
14
|
+
approval/TUI ◀── SSE ──── normalize back to OpenAI SSE
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Why split it: the backend is the **one control point**. Provider keys, auth, rate limits, and
|
|
18
|
+
billing all belong in one place; the client carries only an ada client key. Same shape as Cursor.
|
|
19
|
+
|
|
20
|
+
## Request flow
|
|
21
|
+
|
|
22
|
+
1. The client sends an OpenAI-format chat request (model, messages, tools) to `ADA_BACKEND_URL`
|
|
23
|
+
with its client key as the bearer.
|
|
24
|
+
2. The backend authenticates the key (`ADA_CLIENT_KEYS`, or open in dev mode), then `router.ts`
|
|
25
|
+
maps the model id → a provider.
|
|
26
|
+
3. The matching **adapter** calls the upstream with the server-held provider key — a pass-through
|
|
27
|
+
for OpenAI-compatible providers, a translation for Anthropic.
|
|
28
|
+
4. The backend streams normalized OpenAI SSE chunks back; the client renders text and runs tool
|
|
29
|
+
calls, appending one `{role:"tool", tool_call_id, content}` per call and looping.
|
|
30
|
+
|
|
31
|
+
## The agent loop
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
Each turn streams the model's reply; if it contains tool calls, gated ones go through the
|
|
36
|
+
**permission mode**, the tools run, and one `{role:"tool", tool_call_id, content}` per call is
|
|
37
|
+
appended before control returns to the model — looping until the model stops calling tools.
|
|
38
|
+
|
|
39
|
+
**Permission modes** (`/ask` · `/plan` · `/auto`, or `/mode` to cycle; shown in the prompt):
|
|
40
|
+
|
|
41
|
+
- **ask** (default) — each gated tool shows a plain-words prompt ("ada wants to run a shell command…")
|
|
42
|
+
and one key: `[y]es` · `[a]uto` · `[p]lan` · `[n]o`. Destructive `bash` always confirms.
|
|
43
|
+
- **plan** — read-only: ada plans but won't edit; `/run` approves and executes.
|
|
44
|
+
- **auto** — runs tools without asking (still confirms destructive `bash`). `--yolo` starts here.
|
|
45
|
+
|
|
46
|
+
**Skills.** ~285 bundled `SKILL.md` instructions load only on demand. A lexical router
|
|
47
|
+
(`client/skill-router.ts`) ranks every request; on a confident, name-exact match ada **auto-applies**
|
|
48
|
+
the skill (injects its procedure, announced `↳ skill: <name>`), otherwise it suggests them. The model
|
|
49
|
+
can also `list_skills` / `find_skill` / `use_skill`. See [orchestration.md](orchestration.md) for the
|
|
50
|
+
strategies (`react`/`plan`/`multi`/`toolsmith`) layered on the same loop.
|
|
51
|
+
|
|
52
|
+
**Programmatic surfaces.** Beyond the REPL/TUI, the same agent drives an HTTP API (`ada serve`), a
|
|
53
|
+
typed SDK, an ACP editor bridge (`ada acp`), and read-only session sharing (`ada share`) — see
|
|
54
|
+
[integrations.md](integrations.md). And it can run **SWE-bench Verified** via [bench/](../bench/).
|
|
55
|
+
|
|
56
|
+
## Sign in (device flow)
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
GitHub/Google login uses the OAuth 2.0 device authorization grant (RFC 8628) — no password ever
|
|
61
|
+
reaches ada. The token is stored locally and sent as the bearer; the backend verifies identity in
|
|
62
|
+
`server/identity.ts`. The GitHub `client_id` is baked in (public, like `gh`), so the client needs
|
|
63
|
+
zero config.
|
|
64
|
+
|
|
65
|
+
## One adapter per wire format
|
|
66
|
+
|
|
67
|
+
The key design decision: adapters are keyed by **wire format**, not by provider or model.
|
|
68
|
+
|
|
69
|
+
- Most providers speak the OpenAI format and share **`openai-compat.ts`** (a pass-through that just
|
|
70
|
+
swaps in the right base URL + key).
|
|
71
|
+
- Only a divergent format gets its own adapter — **`anthropic.ts`** translates OpenAI ⇄ Anthropic
|
|
72
|
+
Messages and re-emits Anthropic events as OpenAI SSE.
|
|
73
|
+
|
|
74
|
+
Consequences:
|
|
75
|
+
|
|
76
|
+
| Change | Cost |
|
|
77
|
+
|---|---|
|
|
78
|
+
| A new model | **0 code** (routing is by id) |
|
|
79
|
+
| A new OpenAI-compatible provider | **2 lines** in `config.ts` (base URL + key env) |
|
|
80
|
+
| A brand-new wire format | **1 adapter** + one line in `registry.ts` |
|
|
81
|
+
|
|
82
|
+
Vendor SDKs load **lazily** (pi-style): a `type`-only import plus a dynamic `import()`, so e.g.
|
|
83
|
+
`@anthropic-ai/sdk` never loads unless a Claude request actually arrives.
|
|
84
|
+
|
|
85
|
+
## Routing
|
|
86
|
+
|
|
87
|
+
`router.ts` maps a model id to a provider:
|
|
88
|
+
|
|
89
|
+
- a model id containing `:` (e.g. `qwen2.5-coder:latest`) → local **Ollama**;
|
|
90
|
+
- otherwise by prefix (`gpt*`/`o*` → openai, `claude*` → anthropic, `gemini*` → google,
|
|
91
|
+
`mistral*` → mistral, `grok*` → xai, …);
|
|
92
|
+
- an explicit `provider` field on the request always wins;
|
|
93
|
+
- anything unmatched falls through to **OpenRouter**.
|
|
94
|
+
|
|
95
|
+
## Context compaction
|
|
96
|
+
|
|
97
|
+
The client estimates context size (≈ chars / 4) and, when it crosses `ADA_COMPACT_AT` (default
|
|
98
|
+
100k) or a request overflows, summarizes older turns into one compact summary and keeps the recent
|
|
99
|
+
ones. `/compact` forces it; `/context` shows the current estimate.
|
|
100
|
+
|
|
101
|
+
## Tool-call recovery
|
|
102
|
+
|
|
103
|
+
Some providers (notably **Ollama over a streaming connection**) fail to parse a model's tool call
|
|
104
|
+
into the structured `tool_calls` field and leak it into the text as raw JSON. The client detects a
|
|
105
|
+
reply that *is* a JSON tool call (plain, ```` ```json ```` fenced, or `<tool_call>`-wrapped) for a
|
|
106
|
+
real tool and runs it instead of printing the JSON. Hallucinated tools (no such tool) are left as
|
|
107
|
+
text. See `parseTextToolCalls` in `client/agent.ts`.
|
|
108
|
+
|
|
109
|
+
## File layout
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
bin/
|
|
113
|
+
ada.mjs launcher: register tsx loader → run client/cli.ts
|
|
114
|
+
ada-server.mjs launcher: register tsx loader → run server/index.ts
|
|
115
|
+
|
|
116
|
+
src/
|
|
117
|
+
shared/
|
|
118
|
+
types.ts provider/model types shared by client and server
|
|
119
|
+
|
|
120
|
+
server/ the routing backend (ada-server | npm run server)
|
|
121
|
+
index.ts HTTP entry: auth → route → dispatch to an adapter (+ /v1/models, /v1/whoami)
|
|
122
|
+
config.ts providers, base URLs, key env vars, port, client-key auth
|
|
123
|
+
router.ts model id → provider
|
|
124
|
+
sse.ts Server-Sent Events helpers
|
|
125
|
+
identity.ts verify GitHub/Google tokens; allowlist
|
|
126
|
+
oauth.ts RFC 8628 device-flow login (built-in GitHub client id)
|
|
127
|
+
credentials.ts local credential store
|
|
128
|
+
providers/
|
|
129
|
+
adapter.ts the Adapter interface ← one adapter per WIRE FORMAT
|
|
130
|
+
registry.ts provider → adapter map
|
|
131
|
+
openai-compat.ts pass-through OpenAI-compatible adapter
|
|
132
|
+
anthropic.ts native Anthropic adapter (lazy @anthropic-ai/sdk)
|
|
133
|
+
|
|
134
|
+
client/ the terminal agent (ada | npm start)
|
|
135
|
+
cli.ts REPL: flags, model picker, slash commands, ask/plan/auto modes + approval
|
|
136
|
+
agent.ts the agentic loop (stream → tool calls → feed back → repeat) + orchestrators
|
|
137
|
+
tools.ts read_file/write_file/edit_file · apply_patch · bash (PTY) · ls/glob/grep (rg)
|
|
138
|
+
· web_fetch/web_search · lsp_diagnostics · ask_user; protected paths;
|
|
139
|
+
destructive detection; trust-gated auto-format
|
|
140
|
+
tui.ts inline TUI engine (composer, spinner, user bar)
|
|
141
|
+
tui-mode.ts the TUI loop
|
|
142
|
+
session.ts append-only JSONL session store (.ada/sessions/)
|
|
143
|
+
compaction.ts context summarization
|
|
144
|
+
checkpoint.ts · snapshot.ts undo (revert edits) · whole-tree git snapshot/restore
|
|
145
|
+
skills.ts · skill-router.ts skills + the relevance router (auto-apply)
|
|
146
|
+
mcp.ts · prompts.ts · background.ts · models-dev.ts · lsp.ts connectors, templates,
|
|
147
|
+
background jobs, models.dev catalog, LSP client
|
|
148
|
+
todos.ts · hooks.ts · extensions.ts tasks; extension hooks + tools + commands
|
|
149
|
+
settings.ts · platform.ts · render.ts · image.ts · telemetry.ts · pkg.ts
|
|
150
|
+
|
|
151
|
+
sdk/index.ts typed client for the HTTP API (`ada serve`)
|
|
152
|
+
selfcheck.ts offline checks (tools, sessions, routing, parsers, TUI, classifiers)
|
|
153
|
+
|
|
154
|
+
bench/
|
|
155
|
+
swebench.mjs SWE-bench Verified prediction generator (scored by the official harness)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## No build step
|
|
159
|
+
|
|
160
|
+
Everything runs through `tsx` — TypeScript with no compile. The `bin/*.mjs` launchers register the
|
|
161
|
+
tsx ESM loader in-process, then import the relevant `.ts` entrypoint (which self-runs). `tsx` is a
|
|
162
|
+
runtime dependency so the global `ada` command works after `npx ada-agent`, `npm install -g ada-agent`,
|
|
163
|
+
or `npm link` from a clone. (`node-pty` is the one native dep, so a C toolchain is needed at install.)
|
package/docs/architecture.svg
CHANGED
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
<svg viewBox="0 0 920 470" xmlns="http://www.w3.org/2000/svg" font-family="ui-sans-serif, system-ui, sans-serif" role="img" aria-labelledby="t d">
|
|
2
|
-
<title id="t">ada architecture</title>
|
|
3
|
-
<desc id="d">The ada terminal client sends OpenAI Chat Completions over HTTP to the ada backend, which authenticates the client key, routes by model id, adapts to each provider's wire format, and streams normalized SSE back. The backend holds every provider key and reaches Anthropic via a native adapter and all other providers via a shared OpenAI-compatible adapter.</desc>
|
|
4
|
-
|
|
5
|
-
<defs>
|
|
6
|
-
<marker id="fwd" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path d="M0,0 L9,4.5 L0,9 z" fill="#ffaf00"/></marker>
|
|
7
|
-
<marker id="back" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path d="M0,0 L9,4.5 L0,9 z" fill="#3fb950"/></marker>
|
|
8
|
-
</defs>
|
|
9
|
-
|
|
10
|
-
<!-- panel -->
|
|
11
|
-
<rect x="6" y="6" width="908" height="458" rx="16" fill="#0d0f12" stroke="#262b33"/>
|
|
12
|
-
<rect x="34" y="34" width="14" height="14" rx="4" transform="rotate(45 41 41)" fill="#ffaf00"/>
|
|
13
|
-
<text x="60" y="40" fill="#ffaf00" font-size="17" font-weight="700">ada · architecture</text>
|
|
14
|
-
<text x="60" y="60" fill="#9aa3af" font-size="12">terminal client → routing backend → providers · one wire format throughout</text>
|
|
15
|
-
|
|
16
|
-
<!-- request / response lanes -->
|
|
17
|
-
<g font-family="ui-monospace, monospace" font-size="10.5">
|
|
18
|
-
<!-- top: request (gold, →) -->
|
|
19
|
-
<line x1="226" y1="200" x2="340" y2="200" stroke="#ffaf00" stroke-width="1.6" marker-end="url(#fwd)"/>
|
|
20
|
-
<text x="283" y="190" fill="#c5cdd6" text-anchor="middle">OpenAI Chat</text>
|
|
21
|
-
<text x="283" y="178" fill="#9aa3af" text-anchor="middle" font-size="9">Completions · HTTP</text>
|
|
22
|
-
<line x1="652" y1="200" x2="710" y2="200" stroke="#ffaf00" stroke-width="1.6" marker-end="url(#fwd)"/>
|
|
23
|
-
<text x="683" y="190" fill="#c5cdd6" text-anchor="middle">+ key</text>
|
|
24
|
-
|
|
25
|
-
<!-- bottom: response (green, ←) -->
|
|
26
|
-
<line x1="710" y1="320" x2="652" y2="320" stroke="#3fb950" stroke-width="1.6" marker-end="url(#back)"/>
|
|
27
|
-
<text x="683" y="338" fill="#7ee08a" text-anchor="middle">SSE</text>
|
|
28
|
-
<line x1="340" y1="320" x2="226" y2="320" stroke="#3fb950" stroke-width="1.6" marker-end="url(#back)"/>
|
|
29
|
-
<text x="283" y="338" fill="#7ee08a" text-anchor="middle">normalized OpenAI SSE</text>
|
|
30
|
-
</g>
|
|
31
|
-
|
|
32
|
-
<!-- client card -->
|
|
33
|
-
<rect x="42" y="138" width="184" height="212" rx="12" fill="#14171c" stroke="#262b33"/>
|
|
34
|
-
<text x="134" y="166" fill="#ffaf00" font-size="16" font-weight="700" text-anchor="middle">ada client</text>
|
|
35
|
-
<text x="134" y="183" fill="#9aa3af" font-size="10.5" text-anchor="middle">the terminal</text>
|
|
36
|
-
<g font-family="ui-monospace, monospace" font-size="11" fill="#c5cdd6" text-anchor="middle">
|
|
37
|
-
<text x="134" y="207">agentic loop · tools</text>
|
|
38
|
-
<text x="134" y="226">285 skills · MCP</text>
|
|
39
|
-
<text x="134" y="245">ask · plan · auto</text>
|
|
40
|
-
<text x="134" y="264">REPL · TUI · sessions</text>
|
|
41
|
-
<text x="134" y="283" fill="#6b7480">serve · SDK · ACP</text>
|
|
42
|
-
</g>
|
|
43
|
-
<rect x="80" y="303" width="108" height="22" rx="11" fill="#0d0f12" stroke="#262b33"/>
|
|
44
|
-
<text x="134" y="318" fill="#6b7480" font-size="10" text-anchor="middle" font-family="ui-monospace, monospace">holds no keys</text>
|
|
45
|
-
|
|
46
|
-
<!-- backend card -->
|
|
47
|
-
<rect x="346" y="118" width="306" height="244" rx="12" fill="#101318" stroke="#262b33"/>
|
|
48
|
-
<text x="499" y="146" fill="#ffaf00" font-size="15" font-weight="700" text-anchor="middle">ada backend</text>
|
|
49
|
-
<text x="499" y="163" fill="#9aa3af" font-size="10" text-anchor="middle">the one control point — holds every key</text>
|
|
50
|
-
<g font-family="ui-monospace, monospace" font-size="11.5">
|
|
51
|
-
<g><rect x="366" y="176" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="195" fill="#e6e9ee"><tspan fill="#ffaf00">1</tspan> auth · client key</text></g>
|
|
52
|
-
<g><rect x="366" y="214" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="233" fill="#e6e9ee"><tspan fill="#ffaf00">2</tspan> route · model id → provider</text></g>
|
|
53
|
-
<g><rect x="366" y="252" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="271" fill="#e6e9ee"><tspan fill="#ffaf00">3</tspan> adapt · one per wire format</text></g>
|
|
54
|
-
<g><rect x="366" y="290" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="309" fill="#e6e9ee"><tspan fill="#ffaf00">4</tspan> normalize → OpenAI SSE</text></g>
|
|
55
|
-
</g>
|
|
56
|
-
|
|
57
|
-
<!-- providers card -->
|
|
58
|
-
<rect x="716" y="150" width="162" height="180" rx="12" fill="#14171c" stroke="#262b33"/>
|
|
59
|
-
<text x="797" y="180" fill="#e6e9ee" font-size="13" font-weight="700" text-anchor="middle">providers</text>
|
|
60
|
-
<text x="797" y="202" fill="#ff7a59" font-size="12" font-weight="700" text-anchor="middle" font-family="ui-monospace, monospace">Anthropic <tspan fill="#6b7480" font-weight="400" font-size="9">native</tspan></text>
|
|
61
|
-
<line x1="732" y1="214" x2="862" y2="214" stroke="#262b33"/>
|
|
62
|
-
<g font-family="ui-monospace, monospace" font-size="10.5" fill="#c5cdd6" text-anchor="middle">
|
|
63
|
-
<text x="797" y="234">OpenAI · Gemini · Groq</text>
|
|
64
|
-
<text x="797" y="252">Mistral · DeepSeek · xAI</text>
|
|
65
|
-
<text x="797" y="270">Together · DashScope</text>
|
|
66
|
-
<text x="797" y="288">Ollama · OpenRouter</text>
|
|
67
|
-
</g>
|
|
68
|
-
<text x="797" y="312" fill="#ffaf00" font-size="9.5" text-anchor="middle" font-family="ui-monospace, monospace">all but Anthropic: openai-compat</text>
|
|
69
|
-
|
|
70
|
-
<!-- footer note -->
|
|
71
|
-
<text x="460" y="406" fill="#9aa3af" font-size="11" text-anchor="middle" font-family="ui-monospace, monospace">a new model = 0 code · a new OpenAI-compatible provider = 2 lines · a new wire format = 1 adapter</text>
|
|
72
|
-
<text x="460" y="430" fill="#6b7480" font-size="10" text-anchor="middle">vendor SDKs load lazily — the Anthropic SDK never loads unless a Claude request arrives</text>
|
|
73
|
-
</svg>
|
|
1
|
+
<svg viewBox="0 0 920 470" xmlns="http://www.w3.org/2000/svg" font-family="ui-sans-serif, system-ui, sans-serif" role="img" aria-labelledby="t d">
|
|
2
|
+
<title id="t">ada architecture</title>
|
|
3
|
+
<desc id="d">The ada terminal client sends OpenAI Chat Completions over HTTP to the ada backend, which authenticates the client key, routes by model id, adapts to each provider's wire format, and streams normalized SSE back. The backend holds every provider key and reaches Anthropic via a native adapter and all other providers via a shared OpenAI-compatible adapter.</desc>
|
|
4
|
+
|
|
5
|
+
<defs>
|
|
6
|
+
<marker id="fwd" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path d="M0,0 L9,4.5 L0,9 z" fill="#ffaf00"/></marker>
|
|
7
|
+
<marker id="back" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto"><path d="M0,0 L9,4.5 L0,9 z" fill="#3fb950"/></marker>
|
|
8
|
+
</defs>
|
|
9
|
+
|
|
10
|
+
<!-- panel -->
|
|
11
|
+
<rect x="6" y="6" width="908" height="458" rx="16" fill="#0d0f12" stroke="#262b33"/>
|
|
12
|
+
<rect x="34" y="34" width="14" height="14" rx="4" transform="rotate(45 41 41)" fill="#ffaf00"/>
|
|
13
|
+
<text x="60" y="40" fill="#ffaf00" font-size="17" font-weight="700">ada · architecture</text>
|
|
14
|
+
<text x="60" y="60" fill="#9aa3af" font-size="12">terminal client → routing backend → providers · one wire format throughout</text>
|
|
15
|
+
|
|
16
|
+
<!-- request / response lanes -->
|
|
17
|
+
<g font-family="ui-monospace, monospace" font-size="10.5">
|
|
18
|
+
<!-- top: request (gold, →) -->
|
|
19
|
+
<line x1="226" y1="200" x2="340" y2="200" stroke="#ffaf00" stroke-width="1.6" marker-end="url(#fwd)"/>
|
|
20
|
+
<text x="283" y="190" fill="#c5cdd6" text-anchor="middle">OpenAI Chat</text>
|
|
21
|
+
<text x="283" y="178" fill="#9aa3af" text-anchor="middle" font-size="9">Completions · HTTP</text>
|
|
22
|
+
<line x1="652" y1="200" x2="710" y2="200" stroke="#ffaf00" stroke-width="1.6" marker-end="url(#fwd)"/>
|
|
23
|
+
<text x="683" y="190" fill="#c5cdd6" text-anchor="middle">+ key</text>
|
|
24
|
+
|
|
25
|
+
<!-- bottom: response (green, ←) -->
|
|
26
|
+
<line x1="710" y1="320" x2="652" y2="320" stroke="#3fb950" stroke-width="1.6" marker-end="url(#back)"/>
|
|
27
|
+
<text x="683" y="338" fill="#7ee08a" text-anchor="middle">SSE</text>
|
|
28
|
+
<line x1="340" y1="320" x2="226" y2="320" stroke="#3fb950" stroke-width="1.6" marker-end="url(#back)"/>
|
|
29
|
+
<text x="283" y="338" fill="#7ee08a" text-anchor="middle">normalized OpenAI SSE</text>
|
|
30
|
+
</g>
|
|
31
|
+
|
|
32
|
+
<!-- client card -->
|
|
33
|
+
<rect x="42" y="138" width="184" height="212" rx="12" fill="#14171c" stroke="#262b33"/>
|
|
34
|
+
<text x="134" y="166" fill="#ffaf00" font-size="16" font-weight="700" text-anchor="middle">ada client</text>
|
|
35
|
+
<text x="134" y="183" fill="#9aa3af" font-size="10.5" text-anchor="middle">the terminal</text>
|
|
36
|
+
<g font-family="ui-monospace, monospace" font-size="11" fill="#c5cdd6" text-anchor="middle">
|
|
37
|
+
<text x="134" y="207">agentic loop · tools</text>
|
|
38
|
+
<text x="134" y="226">285 skills · MCP</text>
|
|
39
|
+
<text x="134" y="245">ask · plan · auto</text>
|
|
40
|
+
<text x="134" y="264">REPL · TUI · sessions</text>
|
|
41
|
+
<text x="134" y="283" fill="#6b7480">serve · SDK · ACP</text>
|
|
42
|
+
</g>
|
|
43
|
+
<rect x="80" y="303" width="108" height="22" rx="11" fill="#0d0f12" stroke="#262b33"/>
|
|
44
|
+
<text x="134" y="318" fill="#6b7480" font-size="10" text-anchor="middle" font-family="ui-monospace, monospace">holds no keys</text>
|
|
45
|
+
|
|
46
|
+
<!-- backend card -->
|
|
47
|
+
<rect x="346" y="118" width="306" height="244" rx="12" fill="#101318" stroke="#262b33"/>
|
|
48
|
+
<text x="499" y="146" fill="#ffaf00" font-size="15" font-weight="700" text-anchor="middle">ada backend</text>
|
|
49
|
+
<text x="499" y="163" fill="#9aa3af" font-size="10" text-anchor="middle">the one control point — holds every key</text>
|
|
50
|
+
<g font-family="ui-monospace, monospace" font-size="11.5">
|
|
51
|
+
<g><rect x="366" y="176" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="195" fill="#e6e9ee"><tspan fill="#ffaf00">1</tspan> auth · client key</text></g>
|
|
52
|
+
<g><rect x="366" y="214" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="233" fill="#e6e9ee"><tspan fill="#ffaf00">2</tspan> route · model id → provider</text></g>
|
|
53
|
+
<g><rect x="366" y="252" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="271" fill="#e6e9ee"><tspan fill="#ffaf00">3</tspan> adapt · one per wire format</text></g>
|
|
54
|
+
<g><rect x="366" y="290" width="266" height="30" rx="8" fill="#14171c" stroke="#262b33"/><text x="380" y="309" fill="#e6e9ee"><tspan fill="#ffaf00">4</tspan> normalize → OpenAI SSE</text></g>
|
|
55
|
+
</g>
|
|
56
|
+
|
|
57
|
+
<!-- providers card -->
|
|
58
|
+
<rect x="716" y="150" width="162" height="180" rx="12" fill="#14171c" stroke="#262b33"/>
|
|
59
|
+
<text x="797" y="180" fill="#e6e9ee" font-size="13" font-weight="700" text-anchor="middle">providers</text>
|
|
60
|
+
<text x="797" y="202" fill="#ff7a59" font-size="12" font-weight="700" text-anchor="middle" font-family="ui-monospace, monospace">Anthropic <tspan fill="#6b7480" font-weight="400" font-size="9">native</tspan></text>
|
|
61
|
+
<line x1="732" y1="214" x2="862" y2="214" stroke="#262b33"/>
|
|
62
|
+
<g font-family="ui-monospace, monospace" font-size="10.5" fill="#c5cdd6" text-anchor="middle">
|
|
63
|
+
<text x="797" y="234">OpenAI · Gemini · Groq</text>
|
|
64
|
+
<text x="797" y="252">Mistral · DeepSeek · xAI</text>
|
|
65
|
+
<text x="797" y="270">Together · DashScope</text>
|
|
66
|
+
<text x="797" y="288">Ollama · OpenRouter</text>
|
|
67
|
+
</g>
|
|
68
|
+
<text x="797" y="312" fill="#ffaf00" font-size="9.5" text-anchor="middle" font-family="ui-monospace, monospace">all but Anthropic: openai-compat</text>
|
|
69
|
+
|
|
70
|
+
<!-- footer note -->
|
|
71
|
+
<text x="460" y="406" fill="#9aa3af" font-size="11" text-anchor="middle" font-family="ui-monospace, monospace">a new model = 0 code · a new OpenAI-compatible provider = 2 lines · a new wire format = 1 adapter</text>
|
|
72
|
+
<text x="460" y="430" fill="#6b7480" font-size="10" text-anchor="middle">vendor SDKs load lazily — the Anthropic SDK never loads unless a Claude request arrives</text>
|
|
73
|
+
</svg>
|