agentbridge-cli 0.1.13__tar.gz → 0.1.15__tar.gz
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_cli-0.1.13 → agentbridge_cli-0.1.15}/.codex/skills/build-release/SKILL.md +4 -6
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.codex/skills/build-release/scripts/release_build.py +4 -2
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.github/workflows/release.yml +0 -2
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/PKG-INFO +6 -5
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/README.md +5 -4
- agentbridge_cli-0.1.15/agentbridge/_build_info.py +1 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/dashboard.py +12 -7
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/server.py +43 -70
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/chat.html +138 -40
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/page.html +75 -19
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/requests.html +12 -11
- agentbridge_cli-0.1.15/design-qa.md +55 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/README.md +6 -6
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/StatusPopover.swift +1 -2
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/pyproject.toml +1 -1
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/scripts/build_macos_app.sh +5 -5
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_dashboard.py +134 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_server.py +21 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/uv.lock +1 -1
- agentbridge_cli-0.1.13/agentbridge/_build_info.py +0 -1
- agentbridge_cli-0.1.13/design-qa.md +0 -58
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.codex/config.toml +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.codex/skills/build-release/agents/openai.yaml +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.env.example +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.github/dependabot.yml +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.github/workflows/ci.yml +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.github/workflows/dependency-review.yml +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/.gitignore +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/AGENTS.md +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/CLAUDE.md +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/LICENSE +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/Makefile +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/TODO.txt +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/__init__.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/config.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/models.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/pool.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/android-chrome-192.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/android-chrome-512.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/apple-touch-icon.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/favicon-16.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/favicon-32.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/favicon-48.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/favicon.ico +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/favicon.svg +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/static/brand/site.webmanifest +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/base.html +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/detail.html +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/agentbridge/templates/dashboard/pool.html +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/architecture.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/agentbridge-popover-final.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/agentbridge-popover-normalized.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/agentbridge-popover-pass-1.jpeg +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/implementation-header-activity.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-header-activity.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-inactive-menu-icons.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-inactive-telegram-badge-normalized.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-inactive-telegram-badge.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-low-contrast-arrows-normalized.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-low-contrast-arrows.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-panel.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-telegram-badge-normalized.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/reference-telegram-badge.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/status-item-active-workers.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/status-item-arrow-contrast-comparison.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/status-item-badge-comparison.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/status-item-inactive-comparison.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/design-qa/status-item-no-workers.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/docs/plans/2026-02-14-dashboard-design.md +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/docs/plans/2026-02-14-dashboard-implementation.md +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/hatch_build.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/apple-store/app-store-icon-1024.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/icon/icon-1024.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/logo/logo-1024.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/manifest.json +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/icon-source-keyed.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/icon-source.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/logo-source-keyed.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/logo-source.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/social-background-source.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/sources/social-source.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/android-chrome-192.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/android-chrome-512.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/apple-touch-icon.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/favicon/favicon-16.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/favicon/favicon-32.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/favicon/favicon-48.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/favicon/favicon.ico +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/favicon/favicon.svg +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/og-image-1200x630.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/image-assets/web-seo/site.webmanifest +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/logo.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Package.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/AgentBridgeMenuBarApp.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/BrandMark.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/HealthClient.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/MenuBarStatusPresenter.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/ServerController.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/ServerLauncher.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/SettingsView.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Sources/AgentBridgeMenuBar/StatusModels.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/macos/Tests/AgentBridgeMenuBarTests/StatusModelsTests.swift +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/scripts/dashboard_load_test.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/scripts/verify_macos_app.sh +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/fixtures/ocr_test_document.png +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_config.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_dependency_security.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_image_utils.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_model_mapping.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_models.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_pool.py +0 -0
- {agentbridge_cli-0.1.13 → agentbridge_cli-0.1.15}/tests/test_session_logger.py +0 -0
|
@@ -9,7 +9,7 @@ Use the repository-owned GitHub Actions workflow and PyPI Trusted Publishing.
|
|
|
9
9
|
Do not create a local tag or upload with local credentials: pushing a new
|
|
10
10
|
`pyproject.toml` version to `main` triggers `.github/workflows/release.yml`,
|
|
11
11
|
which tests, scans, builds, creates `v<version>`, creates the GitHub Release,
|
|
12
|
-
publishes `agentbridge-cli`, and attaches ad-hoc-signed arm64
|
|
12
|
+
publishes `agentbridge-cli`, and attaches an ad-hoc-signed arm64 DMG.
|
|
13
13
|
|
|
14
14
|
Use the next unused patch version unless the user requests another valid,
|
|
15
15
|
unused semantic version. Treat an untagged version absent from PyPI as pending.
|
|
@@ -54,8 +54,8 @@ The preflight requires macOS. It checks consistent project and lock metadata, an
|
|
|
54
54
|
unused PyPI version and tag, clean patch formatting, a frozen lock, Python 3.12
|
|
55
55
|
and 3.13 tests, Ruff, Swift tests, a self-contained app/DMG build for the current
|
|
56
56
|
Mac architecture, app signature and embedded-runtime smoke tests, wheel and
|
|
57
|
-
sdist audits, and a wheel installation smoke test. CI builds
|
|
58
|
-
|
|
57
|
+
sdist audits, and a wheel installation smoke test. CI builds the arm64 macOS
|
|
58
|
+
artifact with an ad-hoc signature. Stop at the exact failed gate.
|
|
59
59
|
|
|
60
60
|
4. Review and publish the release commit:
|
|
61
61
|
|
|
@@ -92,9 +92,7 @@ python3 .codex/skills/build-release/scripts/release_build.py wait-pypi --version
|
|
|
92
92
|
gh release view v<version> --json url,tagName,assets
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
Require
|
|
96
|
-
`AgentBridge-<version>-macos-arm64.dmg` and
|
|
97
|
-
`AgentBridge-<version>-macos-x86_64.dmg` plus their `.sha256` files in the
|
|
95
|
+
Require `AgentBridge-<version>-macos-arm64.dmg` and its `.sha256` file in the
|
|
98
96
|
release assets. Do not report success until PyPI returns exact-version files and
|
|
99
97
|
all required GitHub assets exist. If the workflow fails, inspect
|
|
100
98
|
`gh run view <run-id> --log-failed` and report the failed gate before considering
|
|
@@ -313,8 +313,10 @@ def preflight_macos_app(version: str) -> dict[str, object]:
|
|
|
313
313
|
raise SystemExit("the AgentBridge release preflight requires macOS for app validation")
|
|
314
314
|
|
|
315
315
|
architecture = platform.machine()
|
|
316
|
-
if architecture
|
|
317
|
-
raise SystemExit(
|
|
316
|
+
if architecture != "arm64":
|
|
317
|
+
raise SystemExit(
|
|
318
|
+
f"unsupported macOS release architecture: {architecture}; AgentBridge requires arm64"
|
|
319
|
+
)
|
|
318
320
|
|
|
319
321
|
run(["swift", "test", "--package-path", "macos"])
|
|
320
322
|
run(["scripts/build_macos_app.sh"])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentbridge-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
4
4
|
Summary: Bridge OpenAI tools to Claude Code SDK, Codex CLI, and OpenRouter
|
|
5
5
|
Project-URL: Homepage, https://github.com/tsilva/agentbridge
|
|
6
6
|
Project-URL: Repository, https://github.com/tsilva/agentbridge
|
|
@@ -46,10 +46,10 @@ It supports streaming and non-streaming responses, image and PDF inputs where th
|
|
|
46
46
|
|
|
47
47
|
### macOS menu-bar app
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
On an Apple silicon Mac, download the arm64 DMG from the GitHub Release, drag
|
|
50
50
|
`AgentBridge.app` to Applications, and open it. The app is ad-hoc signed rather
|
|
51
51
|
than Apple-notarized, so on first launch macOS may require you to Control-click
|
|
52
|
-
the app, choose **Open**, and confirm.
|
|
52
|
+
the app, choose **Open**, and confirm. Intel Macs are not supported.
|
|
53
53
|
|
|
54
54
|
You can also build the app locally on macOS 13 or later. This requires
|
|
55
55
|
[uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but not an
|
|
@@ -177,6 +177,7 @@ uv build # build wheel and source d
|
|
|
177
177
|
- 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.
|
|
178
178
|
- 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.
|
|
179
179
|
- 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.
|
|
180
|
+
- Streaming provider failures emit an OpenAI-shaped `error` object as an SSE `data` event before `[DONE]`; they are not returned as assistant message text.
|
|
180
181
|
- 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.
|
|
181
182
|
|
|
182
183
|
## Publishing
|
|
@@ -185,8 +186,8 @@ Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing
|
|
|
185
186
|
for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`,
|
|
186
187
|
repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no
|
|
187
188
|
PyPI API token is required. GitHub Releases contain the Python distributions
|
|
188
|
-
plus ad-hoc-signed arm64
|
|
189
|
-
|
|
189
|
+
plus an ad-hoc-signed arm64 macOS DMG and SHA-256 checksum. The DMG is not
|
|
190
|
+
Apple-notarized and requires no Apple Developer credentials. Releases
|
|
190
191
|
through `0.1.10` remain available under the previous `agentbridge-py`
|
|
191
192
|
distribution name.
|
|
192
193
|
|
|
@@ -14,10 +14,10 @@ It supports streaming and non-streaming responses, image and PDF inputs where th
|
|
|
14
14
|
|
|
15
15
|
### macOS menu-bar app
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
On an Apple silicon Mac, download the arm64 DMG from the GitHub Release, drag
|
|
18
18
|
`AgentBridge.app` to Applications, and open it. The app is ad-hoc signed rather
|
|
19
19
|
than Apple-notarized, so on first launch macOS may require you to Control-click
|
|
20
|
-
the app, choose **Open**, and confirm.
|
|
20
|
+
the app, choose **Open**, and confirm. Intel Macs are not supported.
|
|
21
21
|
|
|
22
22
|
You can also build the app locally on macOS 13 or later. This requires
|
|
23
23
|
[uv](https://docs.astral.sh/uv/) and the Xcode Command Line Tools, but not an
|
|
@@ -145,6 +145,7 @@ uv build # build wheel and source d
|
|
|
145
145
|
- 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.
|
|
146
146
|
- 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.
|
|
147
147
|
- 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.
|
|
148
|
+
- Streaming provider failures emit an OpenAI-shaped `error` object as an SSE `data` event before `[DONE]`; they are not returned as assistant message text.
|
|
148
149
|
- 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.
|
|
149
150
|
|
|
150
151
|
## Publishing
|
|
@@ -153,8 +154,8 @@ Releases use the `Release` GitHub Actions workflow and PyPI Trusted Publishing
|
|
|
153
154
|
for the `agentbridge-cli` project. The publisher is scoped to owner `tsilva`,
|
|
154
155
|
repository `agentbridge`, workflow `release.yml`, and environment `pypi`; no
|
|
155
156
|
PyPI API token is required. GitHub Releases contain the Python distributions
|
|
156
|
-
plus ad-hoc-signed arm64
|
|
157
|
-
|
|
157
|
+
plus an ad-hoc-signed arm64 macOS DMG and SHA-256 checksum. The DMG is not
|
|
158
|
+
Apple-notarized and requires no Apple Developer credentials. Releases
|
|
158
159
|
through `0.1.10` remain available under the previous `agentbridge-py`
|
|
159
160
|
distribution name.
|
|
160
161
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
GIT_HASH = "690c228"
|
|
@@ -225,6 +225,8 @@ def _parse_log_file(path: Path) -> dict | None:
|
|
|
225
225
|
|
|
226
226
|
def _get_recent_logs(limit: int = 20) -> list[dict]:
|
|
227
227
|
"""Read recent session log files, newest first."""
|
|
228
|
+
if limit <= 0:
|
|
229
|
+
return []
|
|
228
230
|
log_dir = session_log_dir()
|
|
229
231
|
if not log_dir.exists():
|
|
230
232
|
return []
|
|
@@ -242,10 +244,12 @@ def _get_recent_logs(limit: int = 20) -> list[dict]:
|
|
|
242
244
|
)
|
|
243
245
|
|
|
244
246
|
results = []
|
|
245
|
-
for path in log_files
|
|
247
|
+
for path in log_files:
|
|
246
248
|
parsed = _parse_log_file(path)
|
|
247
249
|
if parsed is not None:
|
|
248
250
|
results.append(parsed)
|
|
251
|
+
if len(results) >= limit:
|
|
252
|
+
break
|
|
249
253
|
|
|
250
254
|
return results
|
|
251
255
|
|
|
@@ -366,10 +370,11 @@ def create_dashboard_router(
|
|
|
366
370
|
if log.get("duration_ms") is None:
|
|
367
371
|
log["duration_ms"] = timing.get("duration_ms", 0)
|
|
368
372
|
if log.get("input_tokens") is None:
|
|
369
|
-
usage_data =
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
+
usage_data = (
|
|
374
|
+
log.get("usage") if isinstance(log.get("usage"), dict) else {}
|
|
375
|
+
)
|
|
376
|
+
log["input_tokens"] = usage_data.get("input_tokens")
|
|
377
|
+
log["output_tokens"] = usage_data.get("output_tokens")
|
|
373
378
|
|
|
374
379
|
merged = active + completed
|
|
375
380
|
return merged[:limit]
|
|
@@ -441,8 +446,8 @@ def create_dashboard_router(
|
|
|
441
446
|
if parsed is None:
|
|
442
447
|
raise HTTPException(status_code=404, detail="Request not found")
|
|
443
448
|
|
|
444
|
-
timing = parsed.get("timing", {}
|
|
445
|
-
usage = parsed.get("usage", {}
|
|
449
|
+
timing = parsed.get("timing") if isinstance(parsed.get("timing"), dict) else {}
|
|
450
|
+
usage = parsed.get("usage") if isinstance(parsed.get("usage"), dict) else {}
|
|
446
451
|
return templates.TemplateResponse(
|
|
447
452
|
request,
|
|
448
453
|
"detail.html",
|
|
@@ -686,6 +686,23 @@ OPENROUTER_TIMEOUT = int(
|
|
|
686
686
|
)
|
|
687
687
|
|
|
688
688
|
|
|
689
|
+
def _stream_error_event(
|
|
690
|
+
message: str,
|
|
691
|
+
*,
|
|
692
|
+
error_type: str = "server_error",
|
|
693
|
+
code: str | None = None,
|
|
694
|
+
) -> str:
|
|
695
|
+
"""Return a machine-readable OpenAI-shaped error in an SSE data event."""
|
|
696
|
+
payload = ErrorResponse(
|
|
697
|
+
error=ErrorDetail(
|
|
698
|
+
message=message,
|
|
699
|
+
type=error_type,
|
|
700
|
+
code=code,
|
|
701
|
+
)
|
|
702
|
+
)
|
|
703
|
+
return f"data: {payload.model_dump_json()}\n\n"
|
|
704
|
+
|
|
705
|
+
|
|
689
706
|
class BridgeHTTPException(HTTPException):
|
|
690
707
|
"""HTTPException with request_id for error tracing."""
|
|
691
708
|
|
|
@@ -1863,18 +1880,13 @@ async def stream_openrouter_api(
|
|
|
1863
1880
|
)
|
|
1864
1881
|
dashboard_state.request_errored(request_id, f"{type(e).__name__}: {error}")
|
|
1865
1882
|
_dashboard_handled = True
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
delta=DeltaMessage(content="\n\n[Error: OpenRouter request failed.]"),
|
|
1873
|
-
finish_reason=None,
|
|
1874
|
-
)
|
|
1875
|
-
],
|
|
1883
|
+
yield _stream_error_event(
|
|
1884
|
+
"OpenRouter request timed out."
|
|
1885
|
+
if isinstance(e, asyncio.TimeoutError)
|
|
1886
|
+
else "OpenRouter request failed.",
|
|
1887
|
+
error_type="timeout_error" if isinstance(e, asyncio.TimeoutError) else "server_error",
|
|
1888
|
+
code="timeout_error" if isinstance(e, asyncio.TimeoutError) else "provider_error",
|
|
1876
1889
|
)
|
|
1877
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
1878
1890
|
yield "data: [DONE]\n\n"
|
|
1879
1891
|
finally:
|
|
1880
1892
|
if not _dashboard_handled:
|
|
@@ -2186,23 +2198,11 @@ async def stream_claude_sdk(
|
|
|
2186
2198
|
)
|
|
2187
2199
|
dashboard_state.request_errored(request_id, f"Timeout after {CLAUDE_TIMEOUT}s")
|
|
2188
2200
|
_dashboard_handled = True
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
choices=[
|
|
2194
|
-
StreamChoice(
|
|
2195
|
-
delta=DeltaMessage(
|
|
2196
|
-
content=(
|
|
2197
|
-
"\n\n[Error: Request timed out. Increase CLAUDE_TIMEOUT "
|
|
2198
|
-
"env var for longer requests.]"
|
|
2199
|
-
)
|
|
2200
|
-
),
|
|
2201
|
-
finish_reason=None,
|
|
2202
|
-
)
|
|
2203
|
-
],
|
|
2201
|
+
yield _stream_error_event(
|
|
2202
|
+
"Request timed out. Increase CLAUDE_TIMEOUT env var for longer requests.",
|
|
2203
|
+
error_type="timeout_error",
|
|
2204
|
+
code="timeout_error",
|
|
2204
2205
|
)
|
|
2205
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
2206
2206
|
yield "data: [DONE]\n\n"
|
|
2207
2207
|
return
|
|
2208
2208
|
except HTTPException as he:
|
|
@@ -2213,16 +2213,11 @@ async def stream_claude_sdk(
|
|
|
2213
2213
|
)
|
|
2214
2214
|
dashboard_state.request_errored(request_id, f"HTTP {he.status_code}: {he.detail}")
|
|
2215
2215
|
_dashboard_handled = True
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
choices=[StreamChoice(
|
|
2221
|
-
delta=DeltaMessage(content=f"\n\n[Error: {he.detail}]"),
|
|
2222
|
-
finish_reason=None,
|
|
2223
|
-
)],
|
|
2216
|
+
yield _stream_error_event(
|
|
2217
|
+
str(he.detail),
|
|
2218
|
+
error_type="invalid_request_error" if he.status_code < 500 else "server_error",
|
|
2219
|
+
code="invalid_request_error" if he.status_code < 500 else "server_error",
|
|
2224
2220
|
)
|
|
2225
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
2226
2221
|
yield "data: [DONE]\n\n"
|
|
2227
2222
|
return
|
|
2228
2223
|
except Exception as e:
|
|
@@ -2237,16 +2232,11 @@ async def stream_claude_sdk(
|
|
|
2237
2232
|
)
|
|
2238
2233
|
dashboard_state.request_errored(request_id, f"{type(e).__name__}: {e}")
|
|
2239
2234
|
_dashboard_handled = True
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
choices=[StreamChoice(
|
|
2245
|
-
delta=DeltaMessage(content="\n\n[Error: An internal error occurred.]"),
|
|
2246
|
-
finish_reason=None,
|
|
2247
|
-
)],
|
|
2235
|
+
yield _stream_error_event(
|
|
2236
|
+
"An internal error occurred.",
|
|
2237
|
+
error_type="server_error",
|
|
2238
|
+
code="server_error",
|
|
2248
2239
|
)
|
|
2249
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
2250
2240
|
yield "data: [DONE]\n\n"
|
|
2251
2241
|
return
|
|
2252
2242
|
finally:
|
|
@@ -2482,23 +2472,11 @@ async def stream_codex_cli(
|
|
|
2482
2472
|
)
|
|
2483
2473
|
dashboard_state.request_errored(request_id, f"Timeout after {CODEX_TIMEOUT}s")
|
|
2484
2474
|
_dashboard_handled = True
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
choices=[
|
|
2490
|
-
StreamChoice(
|
|
2491
|
-
delta=DeltaMessage(
|
|
2492
|
-
content=(
|
|
2493
|
-
"\n\n[Error: Request timed out. Increase CODEX_TIMEOUT "
|
|
2494
|
-
"env var for longer requests.]"
|
|
2495
|
-
)
|
|
2496
|
-
),
|
|
2497
|
-
finish_reason=None,
|
|
2498
|
-
)
|
|
2499
|
-
],
|
|
2475
|
+
yield _stream_error_event(
|
|
2476
|
+
"Request timed out. Increase CODEX_TIMEOUT env var for longer requests.",
|
|
2477
|
+
error_type="timeout_error",
|
|
2478
|
+
code="timeout_error",
|
|
2500
2479
|
)
|
|
2501
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
2502
2480
|
yield "data: [DONE]\n\n"
|
|
2503
2481
|
return
|
|
2504
2482
|
except Exception as e:
|
|
@@ -2514,16 +2492,11 @@ async def stream_codex_cli(
|
|
|
2514
2492
|
)
|
|
2515
2493
|
dashboard_state.request_errored(request_id, f"{type(e).__name__}: {e}")
|
|
2516
2494
|
_dashboard_handled = True
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
choices=[StreamChoice(
|
|
2522
|
-
delta=DeltaMessage(content="\n\n[Error: An internal error occurred.]"),
|
|
2523
|
-
finish_reason=None,
|
|
2524
|
-
)],
|
|
2495
|
+
yield _stream_error_event(
|
|
2496
|
+
"An internal error occurred.",
|
|
2497
|
+
error_type="server_error",
|
|
2498
|
+
code="server_error",
|
|
2525
2499
|
)
|
|
2526
|
-
yield f"data: {error_chunk.model_dump_json()}\n\n"
|
|
2527
2500
|
yield "data: [DONE]\n\n"
|
|
2528
2501
|
return
|
|
2529
2502
|
finally:
|