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:
@@ -5,7 +5,7 @@ The [React browser client](../../s2s-frontend) uses the
|
||||
`start_ui.sh` serves Vite on the existing public port `8420` and FastAPI on
|
||||
loopback port `8421`. Vite forwards backend routes and provides hot reload;
|
||||
Uvicorn reloads Python edits. The launcher supervises both processes.
|
||||
The speech pipeline and optional Node-RED reasoning service run separately.
|
||||
The speech pipeline runs separately.
|
||||
Runtime configuration comes from environment variables and the root `.env`.
|
||||
|
||||
```mermaid
|
||||
@@ -14,7 +14,7 @@ flowchart LR
|
||||
Vite[Vite on public port 8420]
|
||||
Server[Client FastAPI server]
|
||||
Speech[Realtime speech backend]
|
||||
Reasoning[Node-RED or HTTP reasoning provider]
|
||||
Reasoning[OpenAI-compatible HTTP reasoning provider]
|
||||
Tools[ApiPilot backend]
|
||||
Browser <-->|Frontend and HMR| Vite
|
||||
Vite -->|HTTP configuration and proxies| Server
|
||||
@@ -58,7 +58,6 @@ audio. It is not an unconditional byte-for-byte tunnel.
|
||||
| [components](../../s2s-frontend/src/components) | Chat, caller profile, settings and voice components |
|
||||
| [audio](../../s2s-frontend/src/audio) | TypeScript capture/playback worklets, PCM codec, and visualizer |
|
||||
| [legacy-theme.css](../../s2s-frontend/src/styles/legacy-theme.css) | Retained themes and responsive visual styles alongside Tailwind |
|
||||
| [flows.json](../../s2s-reasoning-engine/flows.json) | Node-RED reasoning and assistant-response logging |
|
||||
|
||||
## Server routes
|
||||
|
||||
@@ -66,7 +65,7 @@ audio. It is not an unconditional byte-for-byte tunnel.
|
||||
|---|---|
|
||||
| `GET /api/config` | Connection settings, primary prompt, reasoning/theme/start modes, and feature flags |
|
||||
| `WS /v1/realtime` | Local realtime proxy to `S2S_PROXY_TARGET` |
|
||||
| `POST /api/reasoning` | Node-RED or OpenAI-compatible HTTP reasoning; disabled in `PROXY` mode |
|
||||
| `POST /api/reasoning` | OpenAI-compatible HTTP reasoning; disabled in `PROXY` mode |
|
||||
| `GET /api/user/phone` | Configured caller profile lookup |
|
||||
| `GET /api/user/reports` | Configured scheduled report lookup, subject to report-injection controls |
|
||||
| `GET /api/apipilot/tools` | Tool discovery with optional authorization and cache refresh |
|
||||
@@ -104,10 +103,8 @@ and cancellation model is documented in [realtime API](../speech/realtime-api.md
|
||||
## Reasoning and context
|
||||
|
||||
The browser triggers external reasoning on completed user transcripts only in
|
||||
`OPENAI` or `NODE_RED` mode. Node-RED `log_only=true` responses leave native speech
|
||||
output running; an answer-producing response uses the external-answer path.
|
||||
The server can independently forward assistant text to Node-RED for paired
|
||||
conversation logs. These HTTP operations supplement the realtime audio path.
|
||||
`OPENAI` mode. A non-empty answer replaces the native response through the
|
||||
external-answer path. These HTTP operations supplement the realtime audio path.
|
||||
|
||||
Read [reasoning](reasoning.md), [context injection](context-injection.md), and
|
||||
[tool calling](tool-calling.md) for the conditions and limitations of each path.
|
||||
|
||||
@@ -62,11 +62,13 @@ existing error shapes; there is no new common error envelope.
|
||||
## Compatibility evidence
|
||||
|
||||
`tests/fixtures/legacy-contracts.json` was captured from the original monolithic
|
||||
server at commit `3d42df5`, before refactoring. Tests compare 86 HTTP scenarios,
|
||||
server at commit `3d42df5`, before refactoring. Tests compare 82 HTTP scenarios,
|
||||
including exact response text, statuses, selected headers, and outgoing mock
|
||||
HTTP requests. They also compare request OpenAPI definitions and representative
|
||||
realtime frames. Additional tests cover response validation and permissive
|
||||
upstream values; the original local HTTP/WebSocket tests remain in the suite.
|
||||
Four captures belonging exclusively to the retired workflow reasoning service
|
||||
were removed with that integration; all retained captures are unchanged.
|
||||
|
||||
The captures deliberately preserve unknown fields, omitted fields, unusual JSON
|
||||
values, queue beacon edge cases, permissive tool arguments, and known failures.
|
||||
|
||||
@@ -37,4 +37,3 @@ names shown in a deployment are configuration examples, not definitions.
|
||||
| Claim | The transition from a waiting ticket to an allocated realtime session |
|
||||
| At capacity | A full waiting queue that cannot accept another ticket |
|
||||
| Barge-in | User speech interrupts an active assistant response, coordinating playback clearing and backend cancellation |
|
||||
| Log-only reasoning | External transcript processing that observes/logs the turn without replacing native speech output |
|
||||
|
||||
+11
-34
@@ -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 |
|
||||
|
||||
@@ -109,9 +109,7 @@ 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.
|
||||
`/api/reasoning` returning 409 is expected in `PROXY` mode.
|
||||
In `OPENAI`, check the configured endpoint/model/key and provider logs; HTTP
|
||||
reasoning does not use the native session's tool array.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user