agentbridge-cli 0.1.11__py3-none-any.whl
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.
- agentbridge/__init__.py +8 -0
- agentbridge/_build_info.py +1 -0
- agentbridge/config.py +85 -0
- agentbridge/dashboard.py +494 -0
- agentbridge/models.py +334 -0
- agentbridge/pool.py +338 -0
- agentbridge/server.py +2881 -0
- agentbridge/templates/dashboard/base.html +160 -0
- agentbridge/templates/dashboard/chat.html +1361 -0
- agentbridge/templates/dashboard/detail.html +142 -0
- agentbridge/templates/dashboard/page.html +900 -0
- agentbridge/templates/dashboard/pool.html +9 -0
- agentbridge/templates/dashboard/requests.html +67 -0
- agentbridge_cli-0.1.11.dist-info/METADATA +157 -0
- agentbridge_cli-0.1.11.dist-info/RECORD +18 -0
- agentbridge_cli-0.1.11.dist-info/WHEEL +4 -0
- agentbridge_cli-0.1.11.dist-info/entry_points.txt +2 -0
- agentbridge_cli-0.1.11.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{% set capacity_available = size - in_use %}
|
|
2
|
+
{% set at_capacity = size > 0 and capacity_available <= 0 %}
|
|
3
|
+
<div class="pool-status">
|
|
4
|
+
<span class="pool-health{% if at_capacity %} error{% endif %}">
|
|
5
|
+
<span class="pool-dot {% if at_capacity %}empty{% else %}available{% endif %}"></span>
|
|
6
|
+
{% if at_capacity %}Busy{% else %}Healthy{% endif %}
|
|
7
|
+
</span>
|
|
8
|
+
<span class="pool-count">{{ [capacity_available, 0]|max }}/{{ size }} capacity</span>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<h3 class="request-list-title">Requests</h3>
|
|
2
|
+
{% if requests %}
|
|
3
|
+
{% set active_requests = requests|selectattr("is_active")|list %}
|
|
4
|
+
{% set failed_requests = requests|rejectattr("is_active")|selectattr("error")|list %}
|
|
5
|
+
{% set completed_requests = requests|rejectattr("is_active")|rejectattr("error")|list %}
|
|
6
|
+
|
|
7
|
+
{% macro request_row(req) -%}
|
|
8
|
+
<div class="request-row{% if req.is_active %} request-row-active{% endif %}" data-request-id="{{ req.request_id }}" hx-get="/dashboard/request/{{ req.request_id }}" hx-target="#detail" hx-swap="innerHTML">
|
|
9
|
+
<div class="request-main">
|
|
10
|
+
<div class="request-title">
|
|
11
|
+
<span class="status-dot {% if req.is_active %}streaming{% elif req.error %}error{% else %}idle{% endif %}"></span>
|
|
12
|
+
<span class="request-id">{{ req.request_id }}</span>
|
|
13
|
+
{% if req.is_active %}
|
|
14
|
+
<span class="badge badge-active">streaming</span>
|
|
15
|
+
{% elif req.error %}
|
|
16
|
+
<span class="badge badge-err">error</span>
|
|
17
|
+
{% else %}
|
|
18
|
+
<span class="badge badge-ok">ok</span>
|
|
19
|
+
{% endif %}
|
|
20
|
+
</div>
|
|
21
|
+
<div class="request-model">{{ req.model }}</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="request-metrics">
|
|
24
|
+
<div>{% if req.is_active %}{{ req.elapsed_s }}s{% else %}{{ req.duration_ms }}ms{% endif %}</div>
|
|
25
|
+
<div>{% if not req.is_active and (req.input_tokens is not none or req.output_tokens is not none) %}{{ (req.input_tokens or 0) + (req.output_tokens or 0) }}t{% else %}-{% endif %}</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
{%- endmacro %}
|
|
29
|
+
|
|
30
|
+
{% if active_requests %}
|
|
31
|
+
<section class="request-group">
|
|
32
|
+
<h4 class="request-group-title">
|
|
33
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>
|
|
34
|
+
Active ({{ active_requests|length }})
|
|
35
|
+
</h4>
|
|
36
|
+
{% for req in active_requests %}
|
|
37
|
+
{{ request_row(req) }}
|
|
38
|
+
{% endfor %}
|
|
39
|
+
</section>
|
|
40
|
+
{% endif %}
|
|
41
|
+
|
|
42
|
+
{% if completed_requests %}
|
|
43
|
+
<section class="request-group">
|
|
44
|
+
<h4 class="request-group-title">
|
|
45
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>
|
|
46
|
+
Completed ({{ completed_requests|length }})
|
|
47
|
+
</h4>
|
|
48
|
+
{% for req in completed_requests %}
|
|
49
|
+
{{ request_row(req) }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
</section>
|
|
52
|
+
{% endif %}
|
|
53
|
+
|
|
54
|
+
{% if failed_requests %}
|
|
55
|
+
<section class="request-group">
|
|
56
|
+
<h4 class="request-group-title">
|
|
57
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>
|
|
58
|
+
Failed ({{ failed_requests|length }})
|
|
59
|
+
</h4>
|
|
60
|
+
{% for req in failed_requests %}
|
|
61
|
+
{{ request_row(req) }}
|
|
62
|
+
{% endfor %}
|
|
63
|
+
</section>
|
|
64
|
+
{% endif %}
|
|
65
|
+
{% else %}
|
|
66
|
+
<p class="empty-state">No requests</p>
|
|
67
|
+
{% endif %}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentbridge-cli
|
|
3
|
+
Version: 0.1.11
|
|
4
|
+
Summary: Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter
|
|
5
|
+
Project-URL: Homepage, https://github.com/tsilva/agentbridge
|
|
6
|
+
Project-URL: Repository, https://github.com/tsilva/agentbridge
|
|
7
|
+
Project-URL: Issues, https://github.com/tsilva/agentbridge/issues
|
|
8
|
+
Author: tsilva
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: anthropic,api,bridge,claude,claude-code,codex,fastapi,llm,openai,streaming
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Framework :: FastAPI
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: claude-agent-sdk>=0.1.0
|
|
21
|
+
Requires-Dist: fastapi>=0.115.0
|
|
22
|
+
Requires-Dist: jinja2>=3.1.0
|
|
23
|
+
Requires-Dist: openrouter==0.9.1
|
|
24
|
+
Requires-Dist: pillow>=11.2
|
|
25
|
+
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
|
28
|
+
Requires-Dist: pytest>=8.0.0; extra == 'test'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
<img src="./logo.png" alt="agentbridge" width="512" />
|
|
33
|
+
|
|
34
|
+
**🌉 Bridge OpenAI tools to Claude Code SDK, Codex CLI, or OpenRouter — use your subscriptions anywhere 🔌**
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
agentbridge is a local API bridge for developers who want to connect OpenAI-compatible apps to Claude Code, Codex, or OpenRouter. Run one server, choose a backend with a namespaced model ID, and point existing Chat Completions clients at `http://localhost:8082/api/v1`.
|
|
38
|
+
|
|
39
|
+
It supports streaming and non-streaming responses, image and PDF inputs where the backend accepts them, native Codex image editing, strict JSON Schema output, OpenAI-style tool calls, a live dashboard, and local JSON session logs.
|
|
40
|
+
|
|
41
|
+
> **Legal notice:** agentbridge can use Claude Code SDK and Codex CLI access through your local subscriptions, and can forward requests to OpenRouter when configured. You are responsible for determining whether your use complies with each service's terms. Use it conservatively and at your own risk.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv tool install agentbridge-cli
|
|
47
|
+
agentbridge
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If you installed an earlier release under the previous PyPI distribution name,
|
|
51
|
+
migrate once with:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv tool uninstall agentbridge-py
|
|
55
|
+
uv tool install agentbridge-cli
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Python import and executable remain `agentbridge`.
|
|
59
|
+
|
|
60
|
+
Open the [dashboard](http://localhost:8082/dashboard), try the built-in [chat](http://localhost:8082/dashboard/chat), or use `http://localhost:8082/api/v1` as an OpenAI-compatible base URL.
|
|
61
|
+
|
|
62
|
+
Authenticate at least one backend before sending requests:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
claude login # for claudecode/* models
|
|
66
|
+
codex login # for codex/* models
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For OpenRouter, start agentbridge once and add `OPENROUTER_API_KEY` to `~/.config/agentbridge/.env`.
|
|
70
|
+
|
|
71
|
+
To work on the repository itself:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/tsilva/agentbridge.git
|
|
75
|
+
cd agentbridge
|
|
76
|
+
uv sync --extra test
|
|
77
|
+
uv run agentbridge
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
curl http://localhost:8082/api/v1/chat/completions \
|
|
84
|
+
-H "Content-Type: application/json" \
|
|
85
|
+
-d '{"model":"claudecode/sonnet","messages":[{"role":"user","content":"Hello!"}]}'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Every request requires one of these model namespaces:
|
|
89
|
+
|
|
90
|
+
- `claudecode/<model>` — `opus`, `sonnet`, `haiku`, or a namespaced Claude slug containing one of those names.
|
|
91
|
+
- `codex/<model>` — passed directly to Codex CLI. `gpt-5.6-sol` and `gpt-5.5` default to high reasoning effort unless the request overrides it.
|
|
92
|
+
- `openrouter/<provider>/<model>` — passed to the official OpenRouter Python SDK.
|
|
93
|
+
|
|
94
|
+
OpenAI SDKs may use any placeholder API key:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from openai import OpenAI
|
|
98
|
+
|
|
99
|
+
client = OpenAI(base_url="http://localhost:8082/api/v1", api_key="not-needed")
|
|
100
|
+
response = client.chat.completions.create(
|
|
101
|
+
model="codex/gpt-5.6-sol",
|
|
102
|
+
reasoning_effort="high",
|
|
103
|
+
messages=[{"role": "user", "content": "Hello from Codex!"}],
|
|
104
|
+
)
|
|
105
|
+
print(response.choices[0].message.content)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Codex can also edit one bounded PNG, JPEG, or WebP reference through the
|
|
109
|
+
purpose-built image route. The request is non-persistent and returns one base64
|
|
110
|
+
raster:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
curl http://localhost:8082/api/v1/images \
|
|
114
|
+
-H "Content-Type: application/json" \
|
|
115
|
+
-d "{\"model\":\"codex/gpt-5.6-sol\",\"prompt\":\"Make this look like a scanner capture without changing any content.\",\"input_references\":[{\"type\":\"image_url\",\"image_url\":{\"url\":\"data:image/png;base64,$PAGE_DATA\"}}],\"n\":1,\"store\":false}"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`GET /api/v1/capabilities` reports whether the local Codex CLI is available,
|
|
119
|
+
authenticated, and supports the strict image and JSON-schema profiles.
|
|
120
|
+
|
|
121
|
+
## Commands
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
agentbridge # start on 127.0.0.1:8082
|
|
125
|
+
agentbridge --port 8083 # choose another port
|
|
126
|
+
agentbridge --workers 3 # set Claude pool and Codex concurrency to 3
|
|
127
|
+
agentbridge --version # print package and git version
|
|
128
|
+
uv run --frozen --extra test pytest -q # run tests
|
|
129
|
+
uv run --frozen --extra test ruff check agentbridge tests # lint Python
|
|
130
|
+
uv lock --check # verify the lockfile
|
|
131
|
+
uv build # build wheel and source distribution
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Notes
|
|
135
|
+
|
|
136
|
+
- Python 3.12+ and at least one authenticated backend are required.
|
|
137
|
+
- Public routes include `POST /api/v1/chat/completions`, `POST /api/v1/images`, `GET /api/v1/models`, `GET /api/v1/capabilities`, `GET /health`, `/dashboard`, and `/dashboard/chat`.
|
|
138
|
+
- `PORT`, `POOL_SIZE`, `CLAUDE_TIMEOUT`, `CODEX_TIMEOUT`, `CODEX_IMAGE_TIMEOUT`, and `OPENROUTER_TIMEOUT` control the server port, pool size, and provider timeouts. `--workers` overrides `POOL_SIZE`; Codex chat and native image generation default to 600-second timeouts, while Claude and OpenRouter default to 120 seconds.
|
|
139
|
+
- `MAX_IMAGE_INPUT_BYTES`, `MAX_IMAGE_OUTPUT_BYTES`, and `MAX_IMAGE_PIXELS` bound native image requests. Defaults are 64 MiB input, 32 MiB output, and 40 million pixels.
|
|
140
|
+
- `AGENTBRIDGE_CONFIG_DIR` moves the user configuration directory. `LOG_DIR` moves session logs, and `MAX_LOG_FILES` limits retained JSON logs.
|
|
141
|
+
- `OPENROUTER_API_KEY`, `OPENROUTER_SITE_URL`, and `OPENROUTER_APP_NAME` configure OpenRouter requests. Process environment variables take precedence over the user `.env` file.
|
|
142
|
+
- Claude clients are created lazily, reused by model, and capped by the worker count. Claude sessions do not load filesystem settings and run with built-in tools disabled.
|
|
143
|
+
- Codex runs one ephemeral `codex exec` process per request in a temporary directory with read-only sandboxing, no approvals, and project rules ignored. Multimodal structured-output calls also ignore user config and disable execution and image-generation tools. Native image calls use the same strict profile, keep execution disabled, and enable the image-generation capability needed for the edit.
|
|
144
|
+
- Claude and Codex function calls are represented through prompted JSON; OpenRouter tool calls pass through its SDK. Session logs and extracted image or PDF attachments are saved under `~/.config/agentbridge/logs/sessions` by default.
|
|
145
|
+
- Set `store: false` on chat requests to suppress session-log artifacts. The native image route requires `store: false`, accepts data URLs only, validates both rasters, locates the result from the structured Codex thread ID, and removes that thread's generated-image directory after the request.
|
|
146
|
+
|
|
147
|
+
## Publishing
|
|
148
|
+
|
|
149
|
+
Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`, repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no PyPI API token is required. Releases through `0.1.10` remain available under the previous `agentbridge-py` distribution name.
|
|
150
|
+
|
|
151
|
+
## Architecture
|
|
152
|
+
|
|
153
|
+

|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
agentbridge/__init__.py,sha256=n9GlIClgTwfovU-dZJTI7wHhPT7VrYHgBnnoM42grg8,253
|
|
2
|
+
agentbridge/config.py,sha256=9hwXPbXb34Gf4ESyY__VzbfmXlIgC3N2bzpCLQYFULA,2711
|
|
3
|
+
agentbridge/dashboard.py,sha256=lNqRydgiX8nnOrslBX48-JAvg4QioKtOlFGTLjpHD8Y,17483
|
|
4
|
+
agentbridge/models.py,sha256=17_hohGps1uYoIwfeeSHC5bvwSxuYrTi3hgJ_ZvghNE,9215
|
|
5
|
+
agentbridge/pool.py,sha256=KtZ--b1RlT5zm1brP1kgFjpSV3d-Ay85CV38m1vJXHo,12602
|
|
6
|
+
agentbridge/server.py,sha256=6p-t1nVbm3CNVdS5w-JEGCWHPOpUgnMH5lmIB6iqUCw,106493
|
|
7
|
+
agentbridge/templates/dashboard/base.html,sha256=mDmBa7XsYRFRv6otvoethxitTe89qdNYF-k2EbIb2aw,5005
|
|
8
|
+
agentbridge/templates/dashboard/chat.html,sha256=xmgK3y2FD6c3WCWbDLYP6uTdO6G7ZvypHoe4C5JisX0,48224
|
|
9
|
+
agentbridge/templates/dashboard/detail.html,sha256=n2c86asWtuluP9ecncDLbZbDgRr_G35sGJwV10VZE-s,7310
|
|
10
|
+
agentbridge/templates/dashboard/page.html,sha256=KMQtjycFki_6C4g-2s_5FhNDIBX3418tJvw8SrtKBkA,27426
|
|
11
|
+
agentbridge/templates/dashboard/pool.html,sha256=Cj82bQvM-sllWPE8LfzCtUwT8m3De08in9MqcPlTLz4,465
|
|
12
|
+
agentbridge/templates/dashboard/requests.html,sha256=VYNPSb_Vdqkn_7l1zjg_mWAyxhI_W63OK1GQEWeDNII,3038
|
|
13
|
+
agentbridge/_build_info.py,sha256=u78KhLyvgyWjUoCs30k7OxpPsuL-xdvmXoUoRn3hk4Q,21
|
|
14
|
+
agentbridge_cli-0.1.11.dist-info/METADATA,sha256=RSnmYPclW1cUjDTzobWXaz4Om1ULu9j5ooR7YfDfWIA,8076
|
|
15
|
+
agentbridge_cli-0.1.11.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
16
|
+
agentbridge_cli-0.1.11.dist-info/entry_points.txt,sha256=S1bW9OBjg8rfmiOw6i45uGs_dZnHoKxG4YkB5wb106c,56
|
|
17
|
+
agentbridge_cli-0.1.11.dist-info/licenses/LICENSE,sha256=bep-KRGnKqbtPrVpJlAfWnx2eMzwCcTHxNcT8f2QYGo,1063
|
|
18
|
+
agentbridge_cli-0.1.11.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tsilva
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|