May 23–30 production batch: halo/transcript, story engine, Suno SFX, voice+timeout fixes, OpenClaw 5.7#323
Merged
Conversation
…ubble
Two related symptoms when running a turn on a non-streaming response path:
1. The thinking-dots bubble in the transcript persisted above the rendered
reply. The streaming path (startStreaming/finalizeStreaming) already
removes it, but the non-streaming path (data.response → addMessage)
skipped the removal. Fixed in addMessage by calling removeThinking()
for assistant messages before appending.
2. The halo-smoke orb face stayed in its dots animation after the response
was rendered. Root cause: HaloSmokeFace never implemented the BaseFace
setMood contract — it only exposed an ad-hoc setThinking(bool) side
channel. FaceModule.setMood propagated to BigHeadFace but not to halo.
When a turn ended and app.js called setMood('neutral'), halo never
heard it. EyeFace and BHB were unaffected because they implement the
contract properly.
Fix: add setMood(mood) to HaloSmokeFace that maps 'thinking' → dots and
anything else → idle, then propagate mood updates to it from FaceModule
the same way they're propagated to BigHeadFace.
manifest.json: halo-smoke's "moods": [] now lists the full VALID_MOODS
vocabulary with a "moods_visual_collapse" note describing the 2-state
rendering. Keeps the manifest honest about what setMood inputs are
accepted while documenting that the visual output collapses.
setThinking(bool) kept on HaloSmokeFace for backwards compatibility
with the scattered direct callers in app.js — those can be migrated to
setMood later, no urgency.
Affected paths: data.response (fast lane), websocket message events,
TTS finalize, abort handlers.
Tested on openvoiceui-azrim hot-patch — transcript bubble disappears
when reply renders, halo dots clear at end of turn.
POST /api/story/generate-scene generates the next story scene on demand:
- GPT-4o-mini writes scene JSON (title, image prompt, ambient, SFX, script, choices)
- FLUX.1-schnell generates scene image via HF router
- Suno V5_5 generates ambient loop + SFX clips in parallel
- Resemble Chatterbox pre-renders narration/dialogue per character voice
- Returns complete scene with resolved asset paths for the canvas player
All assets written to canvas-pages/stories/{story_id}/ with 777 permissions
so the node container process can write alongside host-created files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exposes sunoapi.org POST /api/v1/generate/sounds (2.5 credits, non-vocal SFX/stingers) through the shared /api/suno wrapper as action=sfx, so any agent/canvas can generate game sound effects without bespoke httpx code. Previously only routes/story.py called this endpoint directly; the global suno-music skill marked it 'not yet wrapped', so tenants like bhb (game soundboard) couldn't reach it. - _action_sfx: prompt (required, <=500) + optional title/loop/tempo/key → soundLoop/soundTempo/soundKey. model V5_5 to match the proven story.py path. - Reuses _action_status for polling + download; added sourceAudioUrl as a download fallback (additive — songs/jingles still prefer audioUrl). - Job registered with kind=sfx; clip saved to generated_music/ (server-side, never in-memory only). Verified live in openvoiceui-bhb: V5 and V5_5 both generate + download end to end (coin-blip + mallet-thwack mp3s saved to disk). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…L on failure The 'Report an issue' button 500'd with a PermissionError writing to /app/runtime/issue-reports (root:root 755 in the image — the dir was missing from the Dockerfile mkdir list so it never got the chown -R appuser). Flask's HTML 500 page then broke the frontend's res.json() with the cryptic "Unexpected token '<', \"<!doctype\"" error. - Dockerfile: add runtime/issue-reports to the mkdir before chown -R appuser (durable fix — created appuser-owned in the image). - report_issue.py: wrap local save in try/except; on OSError still accept the report (forward to feedback service) and return clean JSON, never an HTML 500. - app.js: guard res.json() so any non-JSON body yields a readable message instead of the JSON-parse error. Live containers hotfixed via chown; source fixes bake in at next image rebuild. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The transcript showed '🔀 Redirected.' / 'Task redirected by user' on EVERY aborted agentic request — including the 60s inactivity timeout that fires when the agent goes silent during long work (subagent spawns, batch file ops). Users saw 'redirected by user' when they did nothing. Tag each abort with its cause (_abortReason: user | inactivity | stop) and branch the label: only an explicit user interrupt says 'redirected by user'; inactivity shows a timeout notice; unknown/stop close the stream quietly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…run budget The client aborted the stream after 60s of no data, but the openclaw gateway run budget is 300s — so legitimate long silent work (subagent spawns, batch file ops) got cut at the client well before the server finished, surfacing as a (mislabeled) timeout/redirect. Match the client backstop to the server's 300s. Heartbeats (every 5-10s) still reset it in the normal case; 300s is the hard ceiling. Deployed to all live OVU containers + baked in source so image rebuilds keep it (it had silently drifted back to 60s everywhere). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…c library action=sfx previously saved into generated_music/ and registered in the music metadata + completed-songs queue, so generated sounds polluted the music player. Now SFX: - save to a dedicated generated_music/sfx/ subdir (served at /generated_music/sfx/, no mount/compose change — still under the mounted tree) - skip _add_song_to_metadata + completed_songs_queue (music-only) - omit callBackUrl so they complete via polling and never hit the webhook path that registers results as music Music/song/jingle behavior is unchanged. _action_list already skips the subdir (non-recursive iterdir + audio-suffix filter).
…start greetings Captures work that has been LIVE on the fleet since 2026-05-23 but was only hotpatched into containers, never committed — so a rebuild would silently revert it (the same drift documented in the inactivity-timeout incident). Verified live on dsf, test-dev, bhb, src, mike before committing. Two changes: 1. Slow-empty Z.AI-direct fallback. The fast-empty retry only covered <5s empties and the double-empty branch only covered post-_retried empties, leaving a 5-30s gap where a single non-retried slow empty fell straight to "No response from agent after recovery" (observed on bhb: 16882ms + 17370ms empties both fell through). Threshold lowered 30000ms -> 5000ms; on a non-session-start slow empty we now try Z.AI direct (bypasses the gateway and any poisoned openclaw session) before the spoken apology. 2. Remove the 5 hardcoded session-start fallback greetings. They masked LLM-empty failures on __session_start__ with canned text, making the broken state invisible. Now: if the LLM returns empty and there is no profile-defined greeting, surface silence + a warning log so the failure is visible. A tenant-owned profile conversation.greeting still wins — that's config, not hardcoded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ller paths Captures the OpenClaw version bump that is already LIVE in containers (verified: openclaw-test-dev and openclaw-dsf both run "OpenClaw 2026.5.7") but was never committed to source — so a rebuild would revert the pin. Keeps the three pinned installer paths in sync per the bump-script rule: - deploy/openclaw/Dockerfile (ARG OPENCLAW_VERSION) - docker-compose.yml (OPENCLAW_VERSION build arg default) - setup-sudo.sh (OPENCLAW_TESTED_VERSION) Plus services/gateways/compat.py OPENCLAW_TESTED_VERSION (warning-log baseline). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes
src/face/HaloSmokeFace.js— addedsetMood(mood)exported method mapping'thinking'→ dots, anything else → idle.setThinking(bool)side-channel kept for backwards compat with scattered direct callers in app.jssrc/app.js—FaceModule.setMoodnow propagates to HaloSmokeFace the same way it already did to BigHeadFacesrc/app.js—TranscriptPanel.addMessagecallsremoveThinking()for assistant messages before appending (matches what startStreaming already does)src/face/manifest.json— halo-smoke's"moods": []updated to the full VALID_MOODS vocab with a"moods_visual_collapse"note documenting the 2-state renderingScope
Single face brought into compliance with existing contract. No framework changes. No new abstractions. 23 lines added across 3 files.