refactor(reasoning)!: remove Node-RED engine and integrations

BREAKING CHANGE: NODE_RED reasoning is no longer supported. Unsupported
mode values fall back to PROXY. PROXY and OPENAI remain available.
This commit is contained in:
2026-10-06 18:58:54 -03:00
parent 77b60622e9
commit e0304b2bdb
31 changed files with 129 additions and 1138 deletions
+11 -34
View File
@@ -1,17 +1,15 @@
# Reasoning modes
Reasoning determines the assistant's response text. The realtime backend always
provides the speech channel; optional HTTP reasoning can observe a transcript or
produce a separate answer. Set `S2S_REASONING_TYPE` to select the mode.
provides the speech channel; optional HTTP reasoning produces a separate answer
from a transcript. Set `S2S_REASONING_TYPE` to select the mode.
| Mode | Response owner | HTTP hook |
|---|---|---|
| `PROXY` (default) | Realtime backend | Browser does not call `/api/reasoning`; that endpoint returns 409 |
| `NODE_RED` | Realtime backend for `log_only=true`; external answer otherwise | Server forwards to `S2S_REASONING_NODE_RED_URL/api/reasoning` |
| `OPENAI` | OpenAI-compatible Chat Completions response | Server calls `OPENAI_BASE_URL/chat/completions` |
The mode is normalized case-insensitively. `NODERED` and `NODE-RED` resolve to
`NODE_RED`; unknown values resolve to `PROXY`.
The mode is normalized case-insensitively. Unknown values resolve to `PROXY`.
## Shared instruction assembly
@@ -40,30 +38,6 @@ Using a direct browser URL bypasses local WebSocket proxy processing. Browser
instructions still apply, but server-side session context and marker execution
require the local `/v1/realtime` route.
## Node-RED reasoning
Configure a Node-RED base URL reachable by the UI server:
```env
S2S_REASONING_TYPE=NODE_RED
S2S_REASONING_NODE_RED_URL=http://localhost:1881
```
`VoiceController.reason()` in [controller.ts](../../s2s-frontend/src/realtime/controller.ts)
handles both external modes. It runs after a complete user transcript and posts a body with
`transcript`, `instructions`, `language`, `user_context`, `phoneNumber`, and
`episode_id`. The server builds context and forwards the reasoning fields to
Node-RED with a 30-second timeout.
The checked-in Node-RED flow exposes `POST /api/reasoning` and
`POST /api/log/system-response`. Its reasoning response uses `log_only=true` and
an empty answer. The browser returns early in that case, preserving the native
backend's response. Assistant-text logging is forwarded separately by the relay
and is not an audio transport.
An answer-producing flow must return a non-empty `answer` and omit `log_only` or
set it to `false`. That activates the external-answer behavior below.
## OpenAI-compatible HTTP reasoning
```env
@@ -76,13 +50,17 @@ OPENAI_REASONING_MODEL=gpt-4.1-mini
`OPENAI_ORGANIZATION` and `OPENAI_PROJECT` are optional headers. The model value
is a runtime default, not a recommendation about provider availability.
`VoiceController.reason()` in [controller.ts](../../s2s-frontend/src/realtime/controller.ts)
runs after a complete user transcript and posts a body with `transcript`,
`instructions`, `language`, `user_context`, `phoneNumber`, and `episode_id`.
The server combines instructions and context into model messages, requests a
final answer, and returns `answer` with available usage metadata. ApiPilot can
final answer with a 30-second timeout, and returns `answer`. ApiPilot can
append discovery instructions, execute a detected call marker, and request a
second response based on the tool result. The endpoint does not forward the
browser's native `session.tools` catalog as OpenAI Chat Completions `tools`.
second response based on the tool result, including available `usage_pass2`
metadata. The endpoint does not forward the browser's native `session.tools`
catalog as OpenAI Chat Completions `tools`.
For a non-log-only answer, the browser cancels/suppresses the active native
For an external answer, the browser cancels/suppresses the active native
response and appends the external assistant text. It uses browser
`SpeechSynthesis` when available. The React client adds the answer to the realtime
conversation as an assistant item; without browser speech synthesis it remains
@@ -101,5 +79,4 @@ realtime backend instead.
| Change browser context assembly | `buildInstructions()` in `s2s-frontend/src/lib/context.ts` |
| Change HTTP provider messages | `reasoning()` in `s2s-client/s2s_client/services/reasoning.py` |
| Change external-answer rendering | `VoiceController.reason()` and `RealtimeClient.renderExternalAnswer()` |
| Change Node-RED processing | `s2s-reasoning-engine/flows.json` |
| Change native model/tool generation | `speech_to_speech/LLM` and realtime handlers |