plugins/phonic: add configs_for_tools for per-tool behavior overrides - #6634
Conversation
…ll_after_speech)
Replace the forbid_speech_after_tool_call: list[str] option with configs_for_tools:
list[PhonicToolConfig] — one object per tool ({name, ...}) carrying up to the full
behavior set (wait_for_speech_before_tool_call, forbid_speech_after_tool_call,
forbid_tool_call_after_speech, allow_tool_chaining); omitted fields fall back to the
plugin defaults. The plugin forwards each object as the tool's Phonic tool_config
(passthrough) and reads forbid_speech_after_tool_call for its own assistant-turn logic.
Adds forbid_tool_call_after_speech (echo drops the tool call if the agent spoke that
turn). Supersedes the un-PR'd arun/phonic-forbid-speech-after-tool-call branch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or-tools # Conflicts: # livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py
Add the remaining per-tool field (require_speech_before_tool_call) and move the per-field behavior docs out of inline comments/docstrings into the plugin README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…configurable Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| return | ||
|
|
||
| self._tools = llm.ToolContext(tools) | ||
| self._forbid_speech_after_tool_call = set( | ||
| self._opts.forbid_speech_after_tool_call | ||
| if is_given(self._opts.forbid_speech_after_tool_call) | ||
| else [] | ||
| self._configs_for_tools = ( | ||
| {c["name"]: c for c in self._opts.configs_for_tools} | ||
| if is_given(self._opts.configs_for_tools) | ||
| else {} | ||
| ) |
There was a problem hiding this comment.
🟡 Leaving out a tool's name in the new per-tool settings crashes the session start with an unclear error
A per-tool settings entry with no tool name is looked up by name without a fallback (c["name"] at livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:463) while the type definition marks every field as optional, so a misconfigured entry aborts session setup with an unhelpful crash instead of a clear message.
Impact: Users who omit a tool name see an opaque failure when the agent starts instead of a readable configuration error.
TypedDict total=False makes `name` optional to the type checker, so the missing key is only caught at runtime
PhonicToolConfig is declared TypedDict, total=False (livekit-plugins/livekit-plugins-phonic/livekit/plugins/phonic/realtime/realtime_model.py:59-66), so mypy accepts {"forbid_speech_after_tool_call": True} without name, even though the docstring and README state name is required. update_tools then builds the lookup with {c["name"]: c for c in ...} which raises KeyError: 'name'. Making name a required key (e.g. a total=True base TypedDict inherited by the optional-field TypedDict) would surface the mistake statically and avoid the runtime crash. Duplicate name entries also silently overwrite each other in the same comprehension.
Was this helpful? React with 👍 or 👎 to provide feedback.
Re-add the removed forbid_speech_after_tool_call: list[str] option for backwards compatibility. It logs a deprecation warning and folds each listed tool into configs_for_tools (an explicit configs_for_tools entry wins). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tinalenguyen
left a comment
There was a problem hiding this comment.
lgtm, left a small comment!
Parity with the JS plugin's realtime index export so callers can import the per-tool config type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
Adds
configs_for_toolsto the Phonic realtime model — per-tool behavior overrides forwarded to Phonic's tool config. One entry per tool (keyed byname); each may setrequire_speech_before_tool_call,forbid_speech_after_tool_call, andforbid_tool_call_after_speech. Omitted fields fall back to the plugin defaults; tools with no entry are unchanged.wait_for_speech_before_tool_call(on) andallow_tool_chaining(off) remain fixed by the plugin.This generalizes the existing
forbid_speech_after_tool_call: list[str]option into a single per-tool config object, and addsforbid_tool_call_after_speech(drop a tool call if the agent already spoke that turn). See the plugin README for the field reference.