first
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# Debug Session: mcp-tool-not-called
|
||||
|
||||
Status: [OPEN]
|
||||
|
||||
## Symptom
|
||||
- The voice assistant says it will call an MCP tool, but no MCP tool call is observed.
|
||||
- No useful runtime log or call attempt is visible from the current instrumentation.
|
||||
|
||||
## Expected
|
||||
- When the model decides to use an MCP tool, the client should emit a tool-call event, execute the MCP proxy request, and produce visible debug evidence for each stage.
|
||||
|
||||
## Hypotheses
|
||||
1. The realtime model is not actually emitting `response.function_call_arguments.done`, so the spoken promise to use a tool is plain text, not a real function call.
|
||||
2. The MCP tools are not present in the effective session state at the moment of the request, so the model cannot legally call them.
|
||||
3. The session instructions are updated too late or with the wrong content, so the model receives guidance text but not usable tool declarations.
|
||||
4. The browser receives a tool-call event, but the handler path fails before logging or before `execRemoteMcpTool()` starts.
|
||||
5. The MCP proxy request starts, but the current logs do not surface pre-call or failure details, making the attempt invisible.
|
||||
|
||||
## Evidence Plan
|
||||
- Instrument session bootstrap, tool declaration updates, transcript-based MCP ranking, tool-call event handling, and MCP proxy fetch lifecycle.
|
||||
- Reproduce with a prompt that should match one MCP tool by description.
|
||||
- Compare whether the model emits only assistant transcript text or a real tool-call event.
|
||||
|
||||
## Notes
|
||||
- First code change in this session must remain instrumentation only.
|
||||
|
||||
## Evidence Summary
|
||||
- `api/config` loads correctly with `searchMcpEnabled=true`, `agentToolCount=16`, and a non-empty primary prompt.
|
||||
- Transcript-time MCP ranking is active and produces ranked candidates such as `get_api_info`, `get_report_detail`, and `get_public_day_report` for relevant spoken requests.
|
||||
- No `response.function_call_arguments.done` event was recorded in the current reproduction.
|
||||
- No `toolcall` event, no `runTool()` start, and no MCP proxy fetch were recorded in the current reproduction.
|
||||
|
||||
## Hypothesis Status
|
||||
| ID | Hypothesis | Status | Evidence |
|
||||
|----|------------|--------|----------|
|
||||
| A | The model speaks about tool use but does not emit a real function call | CONFIRMED | The log file contains transcript/ranking events only; no `function_call_arguments.done` entry was produced in the reproduced turn. |
|
||||
| B | MCP tools are missing from runtime state | PARTIAL | `api/config` proves the remote profile exposes 16 tools, but the current run lacks direct evidence from live `session.update`. |
|
||||
| C | MCP guidance reaches the session too late for the same voice turn | LIKELY | Ranking is computed from the live user transcript; current code only pushes updated instructions on the final transcript, which can miss the active turn. |
|
||||
| D | The browser gets the toolcall event but fails before execution | REJECTED (current run) | There is no `toolcall` event at all in the current reproduction. |
|
||||
| E | The MCP proxy request starts but is invisible | REJECTED (current run) | No pre-fetch or post-fetch MCP proxy log was emitted. |
|
||||
|
||||
## Minimal Fix
|
||||
- Push the computed MCP-guidance instructions to the live session as soon as ranked tool suggestions appear on partial user transcripts, instead of waiting only for the final transcript.
|
||||
- Track the last live instruction snapshot to avoid redundant `session.update` spam.
|
||||
- Add client-construction instrumentation so the next run proves which tools/instructions are present at session start.
|
||||
|
||||
## Post-Fix Evidence
|
||||
- The live session is created with 17 tools and non-empty instructions.
|
||||
- During matching turns, the client now narrows the tool set down to the strongest MCP candidates and sends `tool_choice="required"`.
|
||||
- Example evidence from the latest run:
|
||||
- `get_api_info` is selected as the top candidate with strong score (`29`).
|
||||
- The client sends `setTools(..., "required")` with `["get_api_info", ...]`.
|
||||
- The client sends updated instructions immediately after.
|
||||
- Even with `tool_choice="required"` and a narrowed tool list, no `response.function_call_arguments.done` event is emitted.
|
||||
- Therefore no browser `toolcall`, no `runTool()`, and no MCP proxy request can happen.
|
||||
|
||||
## Updated Hypothesis Status
|
||||
| ID | Hypothesis | Status | Evidence |
|
||||
|----|------------|--------|----------|
|
||||
| A | The model speaks about tool use but does not emit a real function call | CONFIRMED | Even after forcing `tool_choice="required"` and narrowing the tool list, no `function_call_arguments.done` event appears. |
|
||||
| B | MCP tools are missing from runtime state | REJECTED | The client sends 17 initial tools and later sends narrowed MCP-only tool lists, including `tool_choice="required"`. |
|
||||
| C | MCP guidance reaches the session too late for the same voice turn | REJECTED | The client now pushes guidance and tool policy during partial transcripts, before the turn finishes. |
|
||||
| D | The browser gets the toolcall event but fails before execution | REJECTED | No upstream function-call event is emitted at all. |
|
||||
| E | The MCP proxy request starts but is invisible | REJECTED | The MCP proxy is never reached because the model never initiates a tool call. |
|
||||
|
||||
## Current Root Cause
|
||||
- The speech-to-speech realtime model path in the current backend stack is not performing actual function calling for these MCP tools in this conversation flow, even when tools are declared and `tool_choice="required"` is sent.
|
||||
- The spoken assistant text is therefore behaving like a promise in natural language, not a real tool invocation.
|
||||
|
||||
## Backend Branch B
|
||||
- Added relay-side instrumentation in `demo/server.py` to report:
|
||||
- Outbound client text events forwarded to upstream, including `session.update` summaries with `toolCount`, `toolNames`, `toolChoice`, and instruction length.
|
||||
- Inbound upstream text events forwarded back to the client, including `session.updated`, `response.function_call_arguments.done`, and `error` summaries when present.
|
||||
- Binary frame forwarding in both directions and client disconnects.
|
||||
- No new runtime evidence has been collected from this instrumentation yet; a fresh reproduction is required with the patched relay active.
|
||||
Reference in New Issue
Block a user