Tools
OpenCouch tools are app-owned capabilities exposed to model runtimes. Text exposes them as OpenAI Agents SDK function tools. Voice exposes a subset as OpenAI Realtime function schemas. Both call the same backend service functions so memory, lookup, crisis resources, therapeutic skill loading, and guided exercises behave consistently across surfaces.
Tools are deliberately narrow because every tool can change state, surface private context, add latency, or expand the safety surface. A new tool needs a clear owner, a structured result, explicit failure semantics, and tests for the service contract.
Transport bindings
| Binding | Used by | Where it lives |
|---|---|---|
| SDK function tools | Text runtime specialists and safe-turn branches | agent/tools/*.py via @function_tool builders |
| Realtime function schemas | Browser voice sessions | agent/voice/tools.py |
| Shared service functions | Text and voice | execute_*_tool(...), memory-control services, guided-exercise services, grounded lookup services |
The model-facing schemas differ by transport, but the side effects and state validation stay backend-owned.
Loads prompt-ready guidance for one response style and optional therapeutic approach. The tool is side-effect-free and gives the model the exact local skill context it should use before drafting the reply.
response_style + therapeutic_approachTherapeuticResponseSkillToolResultcontext.tool_results.therapeutic_response_skillresponse_styletherapeutic_approachTool vs gate vs dependency
Three things often look like "tools" but should be modeled differently in OpenCouch:
| Type | Example | Lives on |
|---|---|---|
| Injected dependency | memory_store, crisis_log_backend, embedding_provider, llm_client | WorkflowContext (frozen dataclass) |
| Gate / policy stage | crisis guardrail, text turn triage, Realtime voice session policy | agent/guardrails/, agent/specialists/triage.py, agent/voice/policy.py |
| Tool | lookup_crisis_resources, answer_grounded_lookup, memory-control actions, guided-exercise skill loading | agent/tools/ plus Realtime schemas in agent/voice/tools.py |
A capability qualifies as a tool when:
- It is conditionally invoked by a model runtime or transport policy.
- It returns structured data that the model or runtime uses to continue the turn.
- It either reaches outside the local model context, reads private app-owned state, or mutates app-owned state.
- It has explicit retry, failure, and empty-result semantics.
If a capability is used on every turn (like the memory store) or fails hard when unavailable (like the database), it's a dependency, not a tool. If it only decides where to route the turn without producing user-facing content, it's a gate or policy stage, not a tool.
Current tool families
| Family | Text binding | Voice binding | Notes |
|---|---|---|---|
| Therapeutic response skills | load_therapeutic_response_skill | load_therapeutic_response_skill | Side-effect-free prompt-local style guidance. |
| Memory control | SDK memory tools | Realtime persistent-only memory tools | List/status/recall/preference/delete flows with confirmation gates for destructive actions. |
| Grounded lookup | answer_grounded_lookup | answer_grounded_lookup | Explicit factual/current/source-backed requests only. |
| Crisis resources | lookup_crisis_resources, get_crisis_support_template | lookup_crisis_resources | Specific crisis resources must come from verified lookup results. |
| Guided exercises | Discovery, skill-load, and progress tools | Same core tool set filtered for voice-suitable exercises | Uses the shared exercise catalog and local state validation. |
Adding a new tool
- Create or extend the shared service function under
agent/tools/or the relevant plain service package. Return a Pydantic result or a plain dict with status fields for empty/no-result cases. - Add an SDK binding when text specialists need the capability.
- Add a Realtime schema in
agent/voice/tools.pyonly if voice needs the capability. - Put side-effect rules in the service layer, not in prompt text. Mark non-idempotent actions with clear retry semantics.
- Extend runtime state only for data that must survive the turn or be visible in diagnostics.
- Add focused unit tests for the shared service and transport binding. LLM-calling behavior belongs in live evals or dogfood checks.
Related
- Agent Graph — where tools fire from
- Voice Tools & Policy — Realtime tool surface
- Crisis Gate philosophy — why crisis-resource surfacing is worth an external call