Files
vocero-client/docs/client/troubleshooting.md
T

134 lines
6.5 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`, `apipilot`, `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 Node/npm on the process manager's PATH,
Python venv support, and `setsid`/`curl`. The first start installs dependencies;
later starts reuse them until frontend 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 ApiPilot, inspect discovery, marker detection, authorization/schema
validation, execution, and second-pass result injection instead.
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 ApiPilot
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
- 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
`effectiveInstructions()` 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 ApiPilot 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 `NODE_RED`, check
that `S2S_REASONING_NODE_RED_URL` is reachable from the server and whether the
response is `log_only=true`. An empty answer is valid only in log-only mode.
In `OPENAI`, check the configured endpoint/model/key and provider logs; HTTP
reasoning does not use the native session's tool array.
For `TALK`/`TALKFIRST`, the two-second warmup does not override browser
microphone/audio permissions. If automatic startup fails, use the unlocker
gesture and inspect the permission error rather than increasing the timer
without evidence.
## Read-only source checks
From the repository root, useful syntax checks are:
```bash
node --check s2s-client/main.js
node --check s2s-client/ws/s2s-ws-client.js
python -m py_compile s2s-client/server.py
```
Syntax checks do not validate microphone access, network services, model output,
or audio quality. Collect a fresh browser/backend reproduction for those paths.