- bundle/bundle.md: Add provider-anthropic with source URL and orchestrator config override
to disable extended_thinking (foundation enables it by default, causes empty text
responses for simple queries)
- Dockerfile: Add amplifier-module-provider-anthropic pip install for container
- backend/agui_adapter.py: Fix thinking block handling and empty text block rendering
- Thinking blocks no longer fall through to text handler
- Text blocks only emit START when actual content arrives
- Handle amplifierd wire format (block_index/block_type, complete text in content_block:end)
- frontend/src/hooks/useChat.ts: Reset assistantId on TEXT_MESSAGE_END to prevent stale
message IDs across turns
- tests/test_agui_adapter.py: Add extended thinking test coverage
Chat functionality now works end-to-end. Verified: login -> create session -> send message -> receive AI response visible in chat UI.
Generated with Amplifier
Sequential build failures fixed:
1. uv run playwright install chromium → playwright not in pyproject.toml/venv
Fix: npm install -g @playwright/cli playwright && playwright install chromium
Also installs @playwright/cli (the browser CLI used by research agents)
2. uv pip install amplifierd → package not on PyPI
Fix: uv pip install --system from github.com/microsoft/amplifierd
Also installs amplifier-foundation (also not on PyPI, git-only dep)
Uses uv (not plain pip) to respect [tool.uv.sources] resolution
3. COPY frontend/dist/ → dist is gitignored, breaks fresh-clone builds
Fix: build the frontend inside Docker using the installed Node.js
(npm ci + npm run build); removes the pre-built dist assumption
Other fixes:
- Add git to apt-get (required for pip/uv git+https installs)
- Fix entrypoint.sh: amplifierd uses 'serve' subcommand and NAME=URI
bundle format — was: amplifierd --port ... --bundle /path
now: amplifierd serve --port ... --bundle name=/path --default-bundle name
- Add .dockerignore to exclude node_modules, .venv, dist, .git, etc.
(keeps build context small and avoids stale artifacts in COPY steps)
- Extract parseA2UIBlocks() from A2UIRenderer.tsx into its own
frontend/src/lib/a2ui.ts module to satisfy react-refresh/only-export-
components ESLint rule (A2UIRenderer should only export React components)
- Update ChatPanel.tsx and test files to import from lib/a2ui
- Split ChatPanel.test.tsx mock: separate vi.mock for lib/a2ui
(parseA2UIBlocks) and A2UIRenderer (component only)
- Remove unused 'import re' from tests/test_runtime_html.py (ruff F401)
All 216 frontend tests and 242 bash tests still pass. TypeScript and
Vite builds are clean. Remaining ESLint warnings (react-hooks/set-state-
in-effect in MCPAppRenderer and useSessions) are pre-existing patterns
not introduced by Phase 3.
- Fix a2ui-format.md schema to match renderer: rename 'options' → 'filters' in
filters block, replace 'active: boolean' with 'value: string' in filter options,
update form select options from string[] to {label, value}[] objects (Critical #1)
- Fix 3 failing tests in test_researcher_agent.sh to use @mention paths without .md
extension (Important #2)
- Complete pop-out feature in VisualBlock.handlePopOut() by posting render message
to popup window after 500ms initialization delay (Important #3)
- Update test_context_files.sh to match new a2ui-format.md schema (filters array
key check, value field check)
- RightPanel: replace placeholder content with BrowserPanel + ArtifactsPanel
components, routing sessionId to whichever tab is active
- ChatPanel: import A2UIRenderer + parseA2UIBlocks; render A2UI blocks between
markdown and tool-call cards in assistant messages; onAction sends
'[action] {json}' back via onSend
- ChatPanel: add parseVisualBlocks() helper, VisualBlock wrapper component
(loads runtime.html via MCPAppRenderer, view-source toggle, pop-out),
rendered after A2UI blocks in assistant messages
- MCPAppRenderer: on ui/initialize route runtime='visual-artifact' data to a
render dispatch instead of tool/input; add render forwarding case
- Fix pre-existing TS6133 unused-import errors in A2UIRenderer + BrowserPanel test
- All 216 tests pass; npm run build succeeds
The prior review fix (#4) removed the redundant `await refresh()` call from
the onCreate handler, but left `refresh` in the useSessions() destructure.
TypeScript (noUnusedLocals) flagged it as an error, breaking the build.
Remove the unused binding to restore a clean build.
- ChatPanel: add 'chat-message ${role}' CSS classes to message wrappers
so .chat-message.user and .chat-message.assistant rules apply correctly
- LoginPage: rename className 'login-error' -> 'error' to match the
.login-card .error selector in globals.css
- MCPAppRenderer: verify event.source matches iframe contentWindow before
processing postMessage to close cross-window injection vector
- App: remove redundant await refresh() after createNew() since
createNew() already calls refresh() internally
- useArtifacts: wrap listArtifacts call in try/catch with console.error,
matching the error-handling pattern already used in useSessions
- backend/app.py: add Depends(_require_auth) to /api/copilotkit endpoint (critical
security fix — endpoint was fully unprotected; now requires valid session cookie)
- backend/app.py: move 'from ag_ui.core import RunStartedEvent' from inline function
body to top-level imports (style consistency)
- backend/auth.py: remove dead AUTH_PASS_HASH module-level constant (verify_password
already reads from os.environ at call time; the cached binding was unused dead code)
- backend/artifacts.py: add path traversal guards to list_artifacts, get_artifact,
and save_artifact — resolve paths and verify they stay within ARTIFACTS_DIR
- entrypoint.sh: health-check loop now sets READY flag and exits 1 if amplifierd
fails to start within 30s (previously fell through silently, causing 502s)
- tests/test_app.py: add TestCopilotKitAuth — verifies unauthenticated requests to
/api/copilotkit return 401; includes note explaining why streaming is not tested here
- tests/test_structure.sh: update to reflect that Dockerfile and entrypoint.sh now
exist (created in Tasks 7+8); convert absent-checks to presence-checks
Co-authored-by: Amplifier <amplifier@anthropic.com>
- Renamed repo from car-help to research-workbench
- Remote now points to git.ampbox.io/ken/research-workbench
- cloudflared: research.ampbox.io (app) + vnc.ampbox.io (browser)
- Updated all references from browser.ampbox.io to research.ampbox.io
- Search box: type anything, toggle filter pills (hybrid, price range, distance, etc.)
- Backend calls Anthropic to parse query into search params
- Playwright crawls Craigslist, CarGurus, AutoTempest with dynamic URLs
- Results scored/ranked with car-specific scoring engine
- Second Anthropic call generates a custom buying guide from actual results
- Guide sections: top picks, checklist, mechanics, negotiation, budget
- All visible live in the browser panel via noVNC
- FastAPI httpx proxy can't handle WebSocket upgrades (status 101)
- noVNC iframe now points to vnc.ampbox.io (port 6080 via cloudflared)
- App UI stays at browser.ampbox.io (port 8080 via cloudflared)
- Auto-detects local vs ampbox.io for iframe src
- Parse .cl-search-result inner text for title, price, location
- Fallback to URL slug extraction for missing titles
- Capture listing images for display in UI
- AutoTempest scraper also improved with better selectors