Files
alvaro dfed03ac7c chore(vocero): remove the legacy ApiPilot integration (#3)
Vocero now retrieves AquaPortal content through authenticated MCP. This removes the obsolete ApiPilot integration from the API and browser while preserving the separately deployed speech pipeline.

Release notes:

- Removed ApiPilot endpoints, configuration, credential overrides, and HTTP/realtime tool execution.
- Removed browser ApiPilot catalog loading and prompt generation while retaining authenticated MCP discovery.
- Updated regression coverage and operating documentation for the retired routes and settings.

Reviewed-on: AquaPortal/s2s#3
2026-10-08 11:23:41 -04:00

148 lines
7.4 KiB
Markdown

# Troubleshooting
Diagnose configuration, protocol events, execution and playback separately.
Use [architecture](architecture.md), [tool calling](tool-calling.md) and
[context injection](context-injection.md) to identify which path is active.
## Check configuration and connection first
Inspect the server configuration without printing secret environment files:
```bash
curl -fsS http://localhost:8420/api/config | jq
```
Confirm `s2sUrl`, `lb`, `reasoningType`, `injectProfile`, `mcp`, `theme`
and `startSessionMode`. A direct WebSocket URL bypasses the local relay's
server-side context injection and marker execution. For a local proxy, confirm
the server can resolve and reach `S2S_PROXY_TARGET`.
In browser DevTools, inspect the WebSocket handshake and `session.created`,
`session.update` and error events. Check that instructions and native tools are
inside `session`. A cached browser module can disagree with current server
code; inspect served asset versions and reload with cache disabled when needed.
## Launcher and hot reload
`start_ui.sh` serves Vite on `8420` and FastAPI on loopback port `8421` by
default. Check both processes in the launcher/PM2 logs. If either exits, the
launcher stops the other and returns a failure. Port conflicts are errors;
use distinct `UI_PORT` and `S2S_BACKEND_PORT` values for additional worktrees.
A Vite "Blocked request" response means the public hostname is missing from
`S2S_DEV_ALLOWED_HOSTS`. Configure it without a scheme or port and restart the
launcher. If the page loads but edits do not appear, check the browser's
`/__vite_hmr` WebSocket and the reverse proxy's upgrade handling. Speech uses
the separate `/v1/realtime` WebSocket on the same public origin.
For a startup dependency error, check uv 0.12.5 and Node/npm on the process
manager's PATH, plus `setsid`/`curl`. uv manages Python 3.12 in
`vocero-api/.venv` and checks the committed lock on every start. Frontend
dependencies are reused until their manifests change. Changes to root
`.env` or launcher settings require a restart.
## The assistant promises a tool but nothing happens
Follow the actual execution mechanism:
1. For a native tool, confirm it appears in the outbound `session.tools` array.
2. Find `response.function_call_arguments.done` with a tool name, `call_id`, and
JSON-string arguments.
3. Confirm the browser dispatched `toolcall` and the executor sent its request.
4. Confirm `function_call_output` and any required `response.create` were sent.
5. For MCP, inspect conversation creation, `/api/mcp/tools` discovery,
`mcp_tool_completed` logs, and the returned tool data/follow-up response.
Verify the conversation belongs to the browser and backend authorization
succeeds; do not retry with shared credentials or legacy content endpoints.
A spoken sentence such as “Voy a buscar el reporte” does not satisfy step 2.
If the function-call event is absent, inspect model/backend tool generation
before debugging a browser executor that has not been invoked.
Earlier local debug notes recorded a reproduction where tools and required
tool policy were sent but the model produced only spoken text. Those notes
refer to the retired MCP ranking path; they do not establish a current AquaPortal MCP
failure. Both local investigation notes remain marked `OPEN`. Their useful
lesson is to collect evidence at each boundary and reproduce against current
code before claiming a root cause is resolved.
## The assistant misses caller or report context
With MCP enabled, check that `/api/conversations` receives `report_id` or
`episode_id` from the page and completes before voice startup. Report IDs retain
their full prefix: `report-example` selects podcast `report:report-example`.
Link resolution uses the same user's backend session and has a ten-second
budget. An inaccessible or unavailable link produces a generic conversation,
not a fallback to the latest report. Login or catalog failures still block
startup. A report may exist without a podcast. To change the conversational
subject, the agent uses `select_content`; search and comparison calls do not
change it. MCP ignores the legacy injection flags below.
- Verify the page has an encoded `phoneNumber` or the intended `episode_id`.
- Inspect `/api/user/phone` and context-fetch logs for HTTP/JSON failures.
- Confirm profile injection is enabled; a visible profile alone does not prove
realtime instructions contain it.
- Reports need `S2S_INJECT_REPORTS=true`; `minimal` sends only labels and dates.
A historical script will not be in the prompt in that mode.
- Static summary text overrides the HTTP summary endpoint.
- Inspect the final `session.update` rather than only its browser base prompt.
The proxy can append and deduplicate context after the browser sends it.
`S2S_DEBUG_PROMPT=true` enables complete prompt logs, including caller information
and conversation text. Use summaries when full payloads are unnecessary. The
browser's application functions are module-scoped; do not assume names such as
`buildInstructions()` are available directly on `window` in DevTools.
## Short gaps or clipped words around tool results
The retained audio investigation found very low local serialization/render
times for one large tool result, while still observing audio interruptions.
That evidence ruled out a UI-render bottleneck for that reproduction; it does
not rule out rendering costs for all future payloads.
Useful checks are:
- Measure tool-result size, prompt length, serialization time and UI render time.
- Inspect whether result injection overlaps an active or pending response.
- Check whether a speculative response starts before its `response.created`
reaches the browser. Cancellation based only on an existing response ID can
miss that window.
- Inspect deferred text/response queues and whether they flush after
`response.done` rather than interrupting the active turn.
- Inspect playback prebuffering and queue underflow, especially when the first
words of every sentence are affected.
- Confirm oversized tool results are summarized or capped on the relevant
path rather than assuming every tool payload gets the same treatment.
The historical investigation introduced a 90ms playback prebuffer and reduced
MCP prompt reinjection. The old 150ms MCP fallback timer is historical, not a
current MCP configuration knob. Verify the live worklet and current relay
before changing audio timing based on those observations.
## External reasoning and startup
`/api/reasoning` returning 409 is expected in `PROXY` mode.
In `OPENAI`, check the configured endpoint/model/key and provider logs; HTTP
reasoning does not use the native session's tool array.
`TALK`/`TALKFIRST` attempt startup as soon as configuration and caller context
are ready. Browser microphone/audio policies can still require a gesture. If
audio is blocked, tap the main microphone button when the inline hint appears.
If microphone access fails, allow it in the browser's site permissions and use
the same button to retry. No startup dialog is shown.
## Local validation
From the repository root, run the frontend checks and local backend fixtures:
```bash
npm --prefix vocero-frontend run check
npm --prefix vocero-frontend run build
make -C vocero-api check
```
These checks cover frontend contracts and local session/queue/WebSocket
fixtures. They do not validate deployed services, real microphone hardware,
model output, or audio quality. Use a local browser/backend reproduction for
those paths before deployment.