[2547 by Claude Opus 5] Bundle Agent Tank into the unified agent image and add a three-state (disabled / bundled / external) integration mode - #2555
Conversation
Three-state mode
- `packages/shared/src/agentTank.ts` (new): `AGENT_TANK_MODES`, `normalizeAgentTankMode`, `isAgentTankMode`, `agentTankModeFromLegacyEnabled` — one vocabulary for core/API/CLI/UI.
- `configManagerAgents.ts`: `AgentTankSettings` gains `mode`; `enabled` stays as a derived read-only field so all existing call sites keep working. `loadAgentTankSettings` reads the persisted value as `unknown` and normalizes, so a legacy `{enabled:true,url}` loads as `{mode:'external',url}` and `{enabled:false}` as `disabled`. `AGENT_TANK_MODE` is an env fallback only when no record exists.
Bundled runner
- `agentTankBundledRunner.ts` (new): builds the config, runs `agent-tank --once --json --config …` in the configured agent image with each enabled agent's credential dir bind-mounted `:ro` at `CONTAINER_CONFIG_PATHS`, parses output, and owns the 60s TTL cache + in-flight coalescing. Every failure path returns `undefined` and leaves the prior snapshot intact.
- I verified the config/output schema against `integry/agent-tank` rather than using the issue's speculative one. Upstream takes `agents: [{ provider, id, configPath }]` (not `name`/`home`), where `configPath` becomes `CLAUDE_CONFIG_DIR`/`CODEX_HOME`/`GEMINI_CLI_HOME`; `--once --json` prints a bare status map. Published version is 0.9.10, so that's the pin (not `1.4.0`). OpenCode/Vibe are excluded — upstream rejects unknown providers, which would fail the whole run.
- `agentTankTypes.ts` (new): the provider-key mapping and `AgentStatusResponse` moved here so the runner and the transport router don't import each other in a cycle; `agentTankService` re-exports them unchanged.
Surfaces
`agentTankService` routes by mode (bundled `refreshAgent` only *schedules*; `getStatus` is cache-only bounded by a 90s delta-freshness window) and gains `getAllStatuses`. API routes read/write `mode` and still accept legacy `{enabled}` bodies, preserving a saved URL when none is sent. `propr tank bundled|external|off` with `on` as a deprecated alias for `external`. MCP `update_provider_policy` takes `mode`, requiring `url` only for external. Settings UI is a radio group; the URL field exists only in external mode and bundled gets its own "ready/unavailable" wording.
Image
`Dockerfile.agent` gets an `agent-tank-cli` stage pinned at `ARG AGENT_TANK_CLI_VERSION=0.9.10` (so it feeds the bundle content hash), a label, the bin link and a `--version` check. `agent-entrypoint.sh` dispatches `agent-tank` directly — skipping every per-agent ownership repair — and drops to `node` if root. `build-images.sh` passes the matching build arg.
Verification
- New tests: settings migration (9), bundled runner incl. 10-concurrent-refresh → 1 container (9), mode routing (9), API routes (2), CLI (5), UI section (6), plus supply-chain and bundle-tag-changes assertions. 58 pass across the agent-tank suites.
- `npx tsc --noEmit` clean in root, api, cli, propr-ui; lint clean in root, core, api, cli, propr-ui. Full UI vitest suite: 1411 passed.
- Docs rewritten: `agent-tank.md` restructured around the three modes, `configuration-reference.md` documents the new env vars, plus `propr-cli.md`, `observability.md`, `mcp-coverage.md`, `dockerhub/agent.md`.
- I captured Playwright previews of the new settings section in all three states (a new `e2e/agent-tank-modes.pw.ts` follows the repo's existing `PROPR_CAPTURE_PREVIEWS` pattern).
One thing I could not verify: `docker run --rm propr/agent:<tag> agent-tank --version` needs an actual image build, which isn't possible here. The Dockerfile `RUN` itself asserts `agent-tank --version` in both the install stage and the final stage, so a build failure would surface at build time.
Also worth flagging: `test/ciRunnerRouting.test.mjs` fails on this branch, but it's unrelated to this work — it hard-codes two `apps/desktop/scripts/*electron*.test.mjs` files while a third (`published-preview-electron.test.mjs`, added in commit b59b10c6) now exists. My changes touch nothing under `apps/` or `.github/`.
|
/ultrafix goal=9 max=3 |
|
🔄 Ultrafix loop started (goal: 9/10, max cycles: 3) First action:
|
|
CI failed: Full Test Suite Shard 4/4 Please investigate and fix this CI failure.
Failure evidence
|
|
✅ Applied the requested follow-up changes in commit 2deac23 Summary of ChangesCause of the shard 4 failure Shard 4 reported 138 passed / 1 failed; the only failing unit was The Fix ( Derive the expectation from the repository the same way the workflow does, instead of a hand-maintained list: collect every Verification
Shards 1–3 and the docs job were still queued in that run, so only shard 4's result was available to diagnose; no other failures were reported. No preview files were created — this is a CI test-assertion fix with no user-visible surface. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
**Cause of the shard 4 failure**
Shard 4 reported 138 passed / 1 failed; the only failing unit was `test/ciRunnerRouting.test.mjs` → *"requires real hosted native Electron assertions on both routes"*:
```
+ 'apps/desktop/scripts/published-preview-electron.test.mjs' (actual)
```
The `native-electron` job in `.github/workflows/pr-test-on-label.yml:396` discovers its units dynamically (`grep -l 'prepareNativeElectronTest(' apps/desktop/scripts/*.test.mjs`, minus the harness's own unit), but the test pinned that discovery to a two-file literal. Commit `b59b10c56` (on `main`, merged into this branch's base) added a third native probe, `apps/desktop/scripts/published-preview-electron.test.mjs`, without updating the literal — so the assertion went stale. Nothing in this PR's Agent Tank work is involved; the job's own Electron run (`Full Test Suite Native Electron (hosted)`) passed with all three units.
**Fix** (`test/ciRunnerRouting.test.mjs:533`)
Derive the expectation from the repository the same way the workflow does, instead of a hand-maintained list: collect every `apps/desktop/scripts/*.test.mjs` that calls `prepareNativeElectronTest(`, assert the harness's own unit is discoverable and excluded from the hosted route, and compare the remainder against the workflow's `mapfile` output. The guard still fails if discovery stops picking up a native probe or starts pulling in the harness unit, but a newly added probe no longer breaks it.
**Verification**
- `test/ciRunnerRouting.test.mjs`: 44 tests, 44 pass (was failing on this commit).
- Sibling CI-contract suites `ciFullSuiteSelection`, `ciWorkflowDeduplication`, `ciChangeClassification`, `testSuiteRunner`: 170 tests, all pass.
- This branch's Agent Tank units (`agentTankBundledRunner`, `agentTankService`, `agentTankSettingsMigration`, `agentDockerfileSupplyChain`, `configRoutesAgentTank`, `tankCommands`): 6/6 units pass.
Shards 1–3 and the docs job were still queued in that run, so only shard 4's result was available to diagnose; no other failures were reported. No preview files were created — this is a CI test-assertion fix with no user-visible surface.
PR: #2555
Comment by: @propr-dev[bot] (ID: 5849359335)
Model: claude-opus-5
|
/merge |
|
🔀 Resolved merge conflicts from Conflicting Files
Resolution SummaryResolved the single conflict in test/ciRunnerRouting.test.mjs.
Verification: syntax check passed, all 44 tests passed, and 🤖 Resolution Details
System-triggered merge conflict resolution |
…nt-tank-into-th-20260926-1849-t18 Automatically resolved merge conflicts after merging target branch into PR branch. Resolved conflicts in: - test/ciRunnerRouting.test.mjs PR: #2555 Model: gpt-6-astra
|
CI failed: Full Test Suite Shard 4/4 Please investigate and fix this CI failure.
Failure evidence
|
|
✅ Applied the requested follow-up changes in commit db58429 Summary of ChangesWhat failedShard 4/4 passed all 139 of its 139 test units ( Two defects, both fixed: 1. The zombie was manufactured by the container's own health check.
2. Teardown failing an otherwise-green shard. I also added an init-binary check to Verification
Three new/extended tests cover it, using the existing Docker CLI double: teardown tolerates an unkillable owned container and retries on the next stop; The change is CI-only (shell scripts, tests, docs) with nothing visually perceptible, so I did not generate preview files. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
|
CI failed: Run Full Test Suite Please investigate and fix this CI failure.
Failure evidence
|
Full Test Suite ResultsValidation did not complete successfully (shards: failure, docs: success, native Electron: success).
|
|
/merge |
## What failed Shard 4/4 passed **all 139 of its 139 test units** (`Shard 4/4: 139/139 passed in 459.8s`, every suite reporting `# fail 0`). The job failed in the *teardown* step afterwards: ``` Run ./scripts/ci-redis.sh stop Error response from daemon: cannot remove container "8dc535d37f1d…": could not kill container: container 8dc535d37f1d PID 2029746 is zombie and can not be killed. Use the --init option when creating containers… ##[error]Process completed with exit code 1. ``` Two defects, both fixed: **1. The zombie was manufactured by the container's own health check.** `ci-redis.sh` starts Redis with a `redis-cli ping` health check every 2s and no init process. Each health-check process is reparented to PID 1 in the container's namespace when its runc parent exits, and `redis-server` does not reap children — so a ~7.5 minute shard accumulated hundreds of zombies against a `--pids-limit 64`, ending with a PID 1 the rootless daemon could not kill. `scripts/ci-redis.sh:186` now passes `--init`, making tini PID 1 so it reaps them. `--init` is already used throughout this repo's Docker invocations, so runner support is established. **2. Teardown failing an otherwise-green shard.** `stop` runs after the tests have already decided the job result, and no step in the job can reap a zombie PID. `remove_container` now returns a distinct status (`UNREMOVABLE_STATUS=3`) when ownership verifies fully but the daemon still refuses removal, and a new `stop_for_teardown` turns only that case into a `::warning::` annotation and exit 0, leaving the container for host cleanup. The state file is kept so a later teardown of the same owner retries. Ownership violations, and removal failures during `start` (where reusing the name would collide), still fail as before. I also added an init-binary check to `scripts/ci-rootless-preflight.sh`, so a daemon that cannot run `--init` containers names that prerequisite instead of failing every shard's Redis start with an opaque OCI error. ## Verification - `node --test test/ciRunnerRouting.test.mjs test/testSuiteRunner.test.mjs` — 66/66 pass. - Negative-checked each new assertion by restoring the original scripts: the two new `ci-redis.sh` tests and the extended preflight case fail without the fix (`# fail 2` and `# fail 1` respectively), then pass with it. - `shellcheck --exclude=SC2016` (the same exclusion `pr-build-check.yml` uses) clean on both scripts; `eslint` clean on the test file. Three new/extended tests cover it, using the existing Docker CLI double: teardown tolerates an unkillable owned container and retries on the next stop; `start` and ownership violations still fail; and `--init` is asserted in the run arguments. `docs/ci-runners.md` documents the cause, the `--init` remedy and the precise scope of the teardown tolerance. The change is CI-only (shell scripts, tests, docs) with nothing visually perceptible, so I did not generate preview files. PR: #2555 Comment by: @propr-dev[bot] (ID: 5850397831) Model: claude-opus-5
|
❌ Failed to resolve merge conflicts from System-triggered merge conflict resolution |
|
🔀 Resolved merge conflicts from Conflicting Files
Resolution SummaryResolved the single conflict in test/ciRunnerRouting.test.mjs.
Verification: syntax check passed, all 46 tests passed, and 🤖 Resolution Details
System-triggered merge conflict resolution |
…nt-tank-into-th-20260926-1849-t18 Automatically resolved merge conflicts after merging target branch into PR branch. Resolved conflicts in: - test/ciRunnerRouting.test.mjs PR: #2555 Model: gpt-6-astra
|
❌ Failed to apply follow-up changes requested by @propr-dev[bot], @github-actions[bot] An error occurred while processing your request: Comment IDs: 5850399048✓, 5850399435✓ |
|
/ultrafix |
|
🔄 Ultrafix loop started (goal: 8/10, max cycles: 10) First action:
|
|
✅ AI Code Review Complete requested by @propr-ultrafix Posted 1 review: |
🔍 AI Code Review — codex:gpt-6-astraOverall EvaluationThe PR implements the three integration modes across configuration, API, CLI, and UI, but needs changes before merge: the final agent image cannot build as written, and generated configuration permissions can prevent bundled execution. ✅ Compatible migration — Legacy ✅ Bounded container creation — The bundled runner coalesces concurrent refreshes and reuses recent snapshots. The supplied checks show 36 passed, one pending, and no failures. This review uses static analysis only; no commands were run. Merge blockersEvery finding below was introduced by this PR and must be resolved before merging. F1: 🔴 Link Agent Tank’s executable in the final image
F2: 🔴 Make generated configuration readable by the container user
SuggestionsThese are optional follow-ups and are not sent to S1: 🟢 Verify temporary-file visibility across containersThe runner creates its configuration under backend-local S2: 🟢 Verify snapshot identity before recording deltas
ScoreThe migration and transport separation are sound, but image construction and configuration readability block reliable bundled execution. Passing checks do not cover these demonstrated boundaries. Score: 4/10 🤖 Review Details
🤖 Review by ProPR |
|
✅ Applied the requested follow-up changes in commit ea4599e
Summary of ChangesBoth selected findings are fixed, each with a regression that fails without the fix. F1 — F2 — config readable by the container user ( Tests
Verification: 🤖 Implementation Details
💡 ProPR Slash Commands
🤖 Generated by ProPR |
…at fails without the fix.
Both selected findings are fixed, each with a regression that fails without the fix.
**F1 — `agent-tank` executable link (`Dockerfile.agent:262`)**
Added `link_npm_bin agent-tank agent-tank` to the final stage's linking chain, before the `agent-tank --version` verification. Confirmed against the registry that `agent-tank@0.9.10` declares `bin: { "agent-tank": "bin/agent-tank.js" }`, so the helper resolves a valid target. Completeness sweep of the final stage: `claude`, `codex`, `opencode` use `link_npm_bin`, `vibe`/`vibe-acp`/`uv` are copied as `/usr/local/bin` binaries, `agy` is symlinked from `/home/node/.local/bin` — Agent Tank was the only verified command with no executable in that stage.
**F2 — config readable by the container user (`packages/core/src/services/agentTankBundledRunner.ts:238`)**
The generated `config.json` is now written `0o444` with an explicit `chmodSync` after the write (the `writeFileSync` mode alone is umask-dependent), so the `node` user inside the image can read it regardless of the backend process UID. The mount stays `:ro`, and the mode itself carries no write bits. The temp directory is also chmodded `0o755`, matching the sibling pattern in `writeVibePromptFile`, which matters for rootless/userns daemons that resolve the bind source as a non-root user. The file contains only provider keys and container paths — no secrets — and cleanup still removes it after every run. This runner is the only place in the PR's changed behavior that generates a bind-mounted file; `configRoutesAgentTank.ts`, `agentTankService.ts` and `tankCommands.ts` write nothing.
**Tests**
- `test/agentDockerfileSupplyChain.test.ts`: new test extracts every `--version` check in the final stage and asserts each command has a link/copy in that same stage — it reports `agent-tank is verified in the final stage but nothing links its executable there` when the new line is removed.
- `test/agentTankBundledRunner.test.ts`: the docker mock now captures the config file's mode at run time (the runner deletes it afterwards); one test asserts world-readable and non-writable, another asserts the file and its directory are removed after the run. The permission test fails when the mode is reverted to `0o600`.
Verification: `npx tsx --experimental-test-module-mocks --test test/agentTankBundledRunner.test.ts` → 11/11 pass; `npx tsx --test test/agentDockerfileSupplyChain.test.ts` → 11/11 pass; `tsc --noEmit -p packages/core/tsconfig.json` clean. I did not build the image (no Docker daemon here), so the `agent-tank --version` step in the final stage is verified statically, not by an actual build. No preview files: both changes are a Dockerfile link and file permission bits, with nothing visually perceptible.
PR: #2555
Comment by: @propr-ultrafix (ID: 0)
Model: claude-opus-5
|
✅ AI Code Review Complete requested by @propr-ultrafix Posted 1 review: |
|
CI failed: Validate unsigned darwin-arm64 package Please investigate and fix this CI failure.
Failure evidence
|
|
✅ Applied the requested follow-up changes in commit 1b381ea Summary of ChangesFixed the dependency audit failure by updating vulnerable Verified:
The full native ARM64 packaging job still needs a CI rerun. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
|
CI failed: Validate unsigned darwin-x64 package Please investigate and fix this CI failure.
Failure evidence
|
|
CI failed: Finalize unsigned validation checksums Please investigate and fix this CI failure.
Failure evidence
|
…ip-address` and `undici` resolutions in `package-lock.json`. Fixed the dependency audit failure by updating vulnerable `ip-address` and `undici` resolutions in `package-lock.json`. Verified: - Runtime audit: zero vulnerabilities. - Desktop packaging audit: zero vulnerabilities. - `npm ci --dry-run`: passed. The full native ARM64 packaging job still needs a CI rerun. PR: #2555 Comment by: @propr-dev[bot] (ID: 5886827871) Model: gpt-6-astra
|
ℹ️ Analyzed the follow-up request by @propr-dev[bot] Analysis SummaryAll four failures stemmed from the dependency audit rejecting vulnerable The branch already includes the fix in Verified:
The updated packaging CI run is in progress. No code changes were necessary based on the current state of the branch. 🤖 Analysis Details
💡 ProPR Slash Commands
🤖 Generated by ProPR |
|
CI failed: Packaged Connect (darwin-x64) Please investigate and fix this CI failure.
Failure evidence
|
|
CI failed: Packaged Connect Discovery Guard Please investigate and fix this CI failure.
Failure evidence
|
|
✅ Applied the requested follow-up changes in commit e625322 Summary of ChangesFixed a smoke-fixture race: successful Added regression coverage. All 80 Connect tests and 35 UI tests pass; browser reproduction confirms the crash is resolved. The native macOS check still requires a CI rerun. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
|
CI failed: Full Test Suite Shard 2/4 Please investigate and fix this CI failure.
Failure evidence
|
|
CI failed: Full Test Suite Shard 3/4 Please investigate and fix this CI failure.
Failure evidence
|
|
CI failed: Run Full Test Suite Please investigate and fix this CI failure.
Failure evidence
|
Full Test Suite ResultsValidation failed during: Test shard (shard 2), Test shard (shard 3).
View shard 2/4 outputView shard 3/4 outputDetails truncated; see the uploaded artifacts for complete failure rows and logs. |
… crash the dashboard before `REACT_CONNECTED`. Unimplemented endpoints now return 404, using existing renderer error handling.
Fixed a smoke-fixture race: successful `{}` responses could crash the dashboard before `REACT_CONNECTED`. Unimplemented endpoints now return 404, using existing renderer error handling.
Added regression coverage. All 80 Connect tests and 35 UI tests pass; browser reproduction confirms the crash is resolved.
The native macOS check still requires a CI rerun.
PR: #2555
Comment by: @propr-dev[bot] (ID: 5886943427)
Model: gpt-6-astra
|
✅ Applied the requested follow-up changes in commit 547e284 Processed 5 comments:
Summary of ChangesFixed both API test failures by updating mode expectations and sharing persisted settings with the real status service. Validated 115 tests across 10 files; all passed. The packaged discovery fix already exists on this branch, and its regression tests pass. Native macOS confirmation requires a CI rerun. No visual changes or previews. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
…and sharing persisted settings with the real status service. Fixed both API test failures by updating mode expectations and sharing persisted settings with the real status service. Validated 115 tests across 10 files; all passed. The packaged discovery fix already exists on this branch, and its regression tests pass. Native macOS confirmation requires a CI rerun. No visual changes or previews. PR: #2555 Comment by: @propr-dev[bot] (ID: 5886944530) Comment by: @propr-dev[bot] (ID: 5886982688) Comment by: @propr-dev[bot] (ID: 5886993658) Comment by: @propr-dev[bot] (ID: 5886996318) Comment by: @github-actions[bot] (ID: 5886996859) Model: gpt-6-astra
|
agent-tank version 0.9.11 is now available, which is the one that should be bundled and can be verified against |
|
✅ Applied the requested follow-up changes in commit 6290009 Summary of ChangesUpdated Agent Tank to 0.9.11 in both Dockerfile pins, the build-script default, and verification fixtures. All 68 focused tests passed. The published CLI installed successfully and reported 0.9.11. Authenticated container verification remains unrun because Docker is unavailable here. No visual changes. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
…he build-script default, and verification fixtures. Updated Agent Tank to **0.9.11** in both Dockerfile pins, the build-script default, and verification fixtures. All **68 focused tests passed**. The published CLI installed successfully and reported 0.9.11. Authenticated container verification remains unrun because Docker is unavailable here. No visual changes. PR: #2555 Comment by: @integry (ID: 5887274083) Model: gpt-6-astra
…app’s runtime stage at the expected hash path. Strengthened the packaging regression to verify runtime-stage placement and destinations. Addressed F1 only: added the helper COPY to the production app’s runtime stage at the expected hash path. Strengthened the packaging regression to verify runtime-stage placement and destinations. All 14 bundle-content and supply-chain tests passed; `git diff --check` passed. No visual preview was needed. PR: #2623 Comment by: @integry (ID: 5889350886) Model: gpt-6-astra
Fix bundled Claude and Codex usage with isolated provider state
|
/review astra fable |
|
✅ AI Code Review Complete requested by @integry Posted 2 reviews: |
🔍 AI Code Review — astraOverall EvaluationThis PR adds Agent Tank 0.9.11 to the unified image and implements disabled, bundled, and external modes across configuration, API, CLI, MCP, and UI. It needs changes before merge: background observers still use HTTP in bundled mode, and per-call tracking can attribute another account’s usage to a task. ✅ Upgrade compatibility — Legacy enabled settings retain external mode and their URL; newer clients reject bundled mode against older backends. ✅ Credential isolation — Credential mounts are read-only, and Claude/Codex receive private authentication copies without host sessions or plugin configuration. ✅ Focused regression coverage — Tests cover refresh coalescing, repeated snapshots, rejected settings writes, and UI write ordering. The supplied current-head status reports no failures, with five checks pending. This review is a static analysis of the supplied code; no commands were run. Merge blockersEvery finding below was introduced by this PR and must be resolved before merging. F13: 🔴 Route background observers through bundled transport
F14: 🔴 Preserve account identity in per-call tracking
SuggestionsThese are optional follow-ups and are not sent to S4: 🟢 Require bundled runtime during release verificationThe release workflow invokes the verifier with its default ScoreThe implementation has substantial compatibility and regression coverage, but two integration gaps undermine live updates and account-correct usage reporting. The supplied pending checks do not independently reduce the score. Score: 6/10 🤖 Review Details
🤖 Review by ProPR |
🔍 AI Code Review — fableOverall EvaluationThis PR bundles the Agent Tank CLI into the unified The implementation is thorough and generally high quality, but there is one internal inconsistency in the new bundled transport: two existing ✅ Version pin cannot silently drift — ✅ Alias provenance for one-account-per-provider snapshots — ✅ Ordered, rollback-capable settings writes in the UI — Merge blockersEvery finding below was introduced by this PR and must be resolved before merging. F15: 🔴 Bundled mode still drives the HTTP-only usage observers at
|
|
/fix |
|
✅ Applied the requested follow-up changes in commit b8ba253
Summary of ChangesImplemented F13, F14, and F15 only.
Validation: 72 focused tests passed, core build passed, and repository typecheck passed. Captured sidebar previews showing an event-driven usage update. Visual previewBundled usage before updateReal sidebar with fixture bundled usage at 42% session consumption. Original unavailable: managed storage is unavailable or the upload has expired. Bundled usage after server triggerThe same sidebar rereads usage after a usage:update socket event and shows 58%, without manual refresh. Fixture transport; backend sampler behavior is covered by focused regressions. Original unavailable: managed storage is unavailable or the upload has expired. 🤖 Implementation Details
Undo Changes • View Task Execution 💡 ProPR Slash Commands
🤖 Generated by ProPR |
Implemented F13, F14, and F15 only. - Both observers use the shared transport router, detecting bundled usage changes without HTTP requests. - All six provider tracking callers pass account aliases; bundled probes verify provenance before and after execution. - Added regressions for account isolation, refresh interleavings, disabled mode, and shutdown. Validation: 72 focused tests passed, core build passed, and repository typecheck passed. Captured sidebar previews showing an event-driven usage update. PR: #2555 Comment by: @integry (ID: 5891440464) Model: gpt-6-astra


AI Implementation Summary
Closes #2547
Branch:
2547/claude-opus-5-bundle-agent-tank-into-th-20260926-1849-t18Commits: ✅ Changes committed (ef92288)
AI Processing Completed
Execution Details:
Summary:
Implementation complete. Summary of what I built for #2547:
Three-state mode
packages/shared/src/agentTank.ts(new):AGENT_TANK_MODES,normalizeAgentTankMode,isAgentTankMode,agentTankModeFromLegacyEnabled— one vocabulary for core/API/CLI/UI.configManagerAgents.ts:AgentTankSettingsgainsmode;enabledstays as a derived read-only field so all existing call sites keep working.loadAgentTankSettingsreads the persisted value asunknownand normalizes, so a legacy{enabled:true,url}loads as{mode:'external',url}and{enabled:false}asdisabled.AGENT_TANK_MODEis an env fallback only when no record exists.Bundled runner
agentTankBundledRunner.ts(new): builds the config, runsagent-tank --once --json --config …in the configured agent image with each enabled agent's credential dir bind-mounted:roatCONTAINER_CONFIG_PATHS, parses output, and owns the 60s TTL cache + in-flight coalescing. Every failure path returnsundefinedand leaves the prior snapshot intact.integry/agent-tankrather than using the issue's speculative one. Upstream takesagents: [{ provider, id, configPath }](notname/home), whereconfigPathbecomesCLAUDE_CONFIG_DIR/CODEX_HOME/GEMINI_CLI_HOME;--once --jsonprints a bare status map. Published version is 0.9.10, so that's the pin (not1.4.0). OpenCode/Vibe are excluded — upstream rejects unknown providers, which would fail the whole run.agentTankTypes.ts(new): the provider-key mapping andAgentStatusResponsemoved here so the runner and the transport router don't import each other in a cycle;agentTankServicere-exports them unchanged.Surfaces
agentTankServiceroutes by mode (bundledrefreshAgentonly schedules;getStatusis cache-only bounded by a 90s delta-freshness window) and gainsgetAllStatuses. API routes read/writemodeand still accept legacy{enabled}bodies, preserving a saved URL when none is sent.propr tank bundled|external|offwithonas a deprecated alias forexternal. MCPupdate_provider_policytakesmode, requiringurlonly for external. Settings UI is a radio group; the URL field exists only in external mode and bundled gets its own "ready/unavailable" wording.Image
Dockerfile.agentgets anagent-tank-clistage pinned atARG AGENT_TANK_CLI_VERSION=0.9.10(so it feeds the bundle content hash), a label, the bin link and a--versioncheck.agent-entrypoint.shdispatchesagent-tankdirectly — skipping every per-agent ownership repair — and drops tonodeif root.build-images.shpasses the matching build arg.Verification
npx tsc --noEmitclean in root, api, cli, propr-ui; lint clean in root, core, api, cli, propr-ui. Full UI vitest suite: 1411 passed.agent-tank.mdrestructured around the three modes,configuration-reference.mddocuments the new env vars, pluspropr-cli.md,observability.md,mcp-coverage.md,dockerhub/agent.md.e2e/agent-tank-modes.pw.tsfollows the repo's existingPROPR_CAPTURE_PREVIEWSpattern).One thing I could not verify:
docker run --rm propr/agent:<tag> agent-tank --versionneeds an actual image build, which isn't possible here. The DockerfileRUNitself assertsagent-tank --versionin both the install stage and the final stage, so a build failure would surface at build time.Also worth flagging:
test/ciRunnerRouting.test.mjsfails on this branch, but it's unrelated to this work — it hard-codes twoapps/desktop/scripts/*electron*.test.mjsfiles while a third (published-preview-electron.test.mjs, added in commit b59b10c6) now exists. My changes touch nothing underapps/or.github/.Detailed Logs:
5f8b3aa7-f046-4296-913d-9a40c5db94feLog files stored at:
/tmp/claude-logs/issue-2547-2026-09-26T19-26-45-505Z-conversation.json/tmp/claude-logs/issue-2547-2026-09-26T19-26-45-505Z-output.txtLatest Conversation Messages
This PR was created automatically by ProPR after processing issue #2547.
💡 Need changes?
Comment on this PR to request refinements — the AI agent monitors comments and will update the implementation based on your feedback. Keep iterating until you're satisfied!
Visual preview
Settings — Agent Tank bundled mode
Bundled mode selected. The Daemon URL field is hidden because no URL is used, and the status reads "Bundled Agent Tank ready" rather than talking about an unreachable daemon.
Original unavailable: managed storage is unavailable or the upload has expired.
Settings — Agent Tank disabled (default)
The LLM Usage Tracking section on a fresh install: a three-mode radio group with Disabled selected and no Daemon URL field.
Original unavailable: managed storage is unavailable or the upload has expired.
Settings — Agent Tank external mode
External mode selected. Only here does the Daemon URL field appear, pre-filled with the saved endpoint an upgraded installation migrates over.
Original unavailable: managed storage is unavailable or the upload has expired.