Skip to content

feat(ui): Deepgram branding for Control UI#32

Open
billgetman wants to merge 49 commits intomainfrom
feature/deepgram-branding
Open

feat(ui): Deepgram branding for Control UI#32
billgetman wants to merge 49 commits intomainfrom
feature/deepgram-branding

Conversation

@billgetman
Copy link
Copy Markdown
Collaborator

Summary

  • Replace OpenClaw's red accent color scheme with Deepgram's visual identity across the entire Control UI
  • Add Roobert typeface via local @font-face declarations (replacing Google Fonts CDN import)
  • Replace favicon and topbar brand with Deepgram D icon, update title to "DEEPCLAW Control"
  • Update full CSS custom property palette for both dark and light themes (spring green #13ef93 primary, Deepgram blues, semantic colors)
  • Remove all hardcoded red/orange rgba values from CSS files and inline styles in usage charts

Files changed (20)

Assets (new): Roobert font files (6), Deepgram SVG icons (4)
Styles: base.css, components.css, config.css, chat/grouped.css, chat/layout.css
Templates: app-render.ts (topbar brand), usage.ts (chart colors), index.html, manifest.json, favicon.svg

Test plan

  • pnpm ui:dev — verify dark theme: green accent, Roobert font, D icon in topbar/favicon
  • Toggle to light theme: dark green accent, correct contrast ratios
  • Theme toggle animation still works
  • Chat bubbles, buttons, pills, nav items all use new colors (no red remnants)
  • Usage charts/heatmaps render in green palette
  • Config panel subnav active state, changes badge, diff panel use green accent
  • Font loading confirmed in Network tab (font-display: swap)
  • pnpm ui:build succeeds

🤖 Generated with Claude Code

billgetman and others added 30 commits February 13, 2026 15:00
Proxy-based filler injection design for the Deepgram sidecar voice agent.
Detects slow OpenClaw responses at the /v1/chat/completions proxy and
injects filler phrases via Deepgram's InjectAgentMessage protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TDD implementation plan with 6 tasks: config, session registry, filler
module, bridge integration, proxy instrumentation, and verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Corrects test assertions that referenced stale config structure
(think.provider.url → think.endpoint.url), wrong default voice model
(aura-2-apollo-en → aura-2-thalia-en), and missing USER_MD_PATH mocks.
Updates proxy test to match streaming build_request/send interface.
Cleans up import ordering and unused imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ports identity extraction, user profile, and call summary from the
TypeScript voice-call extension into standalone Python modules in the
Deepgram sidecar. Direct Anthropic API (Sonnet), direct filesystem
writes, fire-and-forget from the bridge finally block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8-task TDD plan for porting identity extraction, user profile, and call
summary into the Python Deepgram sidecar. Includes complete test code,
implementation code, and exact commands for each step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TranscriptEntry/CallInfo dataclasses, path resolution, file I/O,
transcript formatting, Anthropic API caller, and JSON response parsing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TIMEZONE, CALLS_MAX_ENTRIES, POST_CALL_EXTRACTION env vars with test
defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracts plain-text summary via Sonnet, appends timestamped entry,
trims to max entries. 8 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parses USER.md, extracts profile via Sonnet JSON, merges with fill-only
semantics, placeholder detection. 17 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parses IDENTITY.md, extracts identity via Sonnet JSON, merges with
fill-only semantics, generic name filtering. 12 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nd first-caller bootstrap

Replace flat system prompt in build_settings_config() with a structured
prompt builder that reads USER.md, IDENTITY.md, and CALLS.md from the
workspace. Returning callers get personalized context (name, notes,
recent calls) and action nudges. First-time callers get bootstrap
instructions (name exchange, show value quickly). Adds configurable
nudge windows and ENABLE_ACTION_NUDGES toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Capture ConversationText events during bridge session
- Fire call_summary, user_profile, and agent_identity extraction
  concurrently in the finally block (inbound calls only)
- Pass caller phone number from Twilio webhook through to extraction
- 3 new tests for transcript capture

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ANTHROPIC_API_KEY on Fly is a LiteLLM proxy key, not a direct
Anthropic key, so hitting api.anthropic.com returns 401. Route filler
generation through localhost:18789 (OpenClaw gateway) instead, which
handles provider auth via its own config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation

Route post-call services (call_summary, user_profile, agent_identity)
through the local OpenClaw gateway instead of hitting api.anthropic.com
directly -- same fix as filler generation. The ANTHROPIC_API_KEY on Fly
is a LiteLLM proxy key, not a direct Anthropic key.

Fix filler cancellation: only cancel the filler timer when the SSE
stream contains actual content text, not on the initial empty delta
chunk. Previously the first SSE byte (role-only delta) would cancel the
filler immediately even when the real response took 15+ seconds.

Add filler logging throughout the pipeline for better observability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ionTimers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…m bridge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wrap inject_message in try/except in exit handlers so hangup always
  completes even if message injection fails
- Replace fragile `or` lambda with tuple indexing for end_call callback
- Use asyncio.get_running_loop() instead of deprecated get_event_loop()
- Remove unused POST_FAREWELL_DELAY_S constant

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bump gateway RPC failure logging from debug to warning with status code
and response body. Add XML escaping for caller phone in TwiML parameters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The OpenClaw gateway exposes methods (sessions.list, agent) over WebSocket,
not HTTP. Replace the broken httpx POST to /rpc with a websockets-based
client that performs the connect handshake and JSON-RPC round-trip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dynamic filler has a 2s timeout but the inject timer fires at 1.5s,
so the dynamic phrase is never ready in time. Add a 500ms grace period
(only when dynamic generation was started) before falling back to static.
Bump filler.py failure logs from debug to warning so timeouts and errors
are visible in production.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
billgetman and others added 19 commits February 13, 2026 17:29
Log timer lifecycle (start, cancel, fire), gateway WebSocket handshake
and method calls, child session notification flow, and timer config at
bridge startup for production observability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gateway validates client.id against a strict allowlist. Change from
"deepgram-sidecar" (rejected) to "gateway-client" (the standard backend
client ID).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ogging

Static fallback was empty because FILLER_PHRASES env var isn't set on Fly.
Add hardcoded defaults so filler always works even when dynamic Haiku times
out. Add detailed INFO/WARNING logs throughout the Haiku filler lifecycle
(request start, POST sent, response status, generated phrase, failures).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log server version and connId on successful handshake, request params
before sending, and response payload preview on success.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gateway is always congested when filler is needed (busy with the main
LLM + tool call request), so the Haiku filler request always timed out.
Bypass the gateway entirely and call the Anthropic Messages API directly.
Add ANTHROPIC_BASE_URL config for custom endpoints. Verbose request
lifecycle logging (url, status, elapsed ms, generated phrase).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewrite _generate_next_greeting to call Anthropic Messages API directly
(bypassing gateway), same pattern as filler phrases — prevents timeout
when gateway is busy with long tool calls.

Add background task prompting to voice prompt instructing the agent to
use sessions_spawn for research/analysis instead of blocking the caller.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upgrade AGENT_THINK_MODEL default from claude-haiku-4-5 to
  claude-sonnet-4-5 for better reasoning and tool use
- Pass transcript and caller name to greeting generation so Haiku
  can produce context-aware greetings instead of confused responses
- Add tool_calls detection in the /v1/chat/completions proxy stream
  to log when the agent uses tools like sessions_spawn

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gateway `agent` method requires `idempotencyKey` — add it to fix
"must have required property 'idempotencyKey'" error when notifying
child sessions that the voice call ended.

Add verbose logging: child session keys found, caller phone, notification
success/failure, post-call task start context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r sub-agents

Include caller_phone in the voice prompt's background task section so
the agent can pass it to sub-agents via sessions_spawn. Add explicit
curl command for send-sms action endpoint — sub-agents were using the
generic message tool which requires channels not configured in the
container.

Also update child session notification to include the curl command
instead of just "use the twilio action" which the sub-agent couldn't
figure out.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vice

Log TWILIO_PROXY_URL, target URL, request/response details, and control
plane response body in the send-sms action and outbound_sms service to
debug 502 Bad Gateway from deepclaw-control.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agent was hallucinating phone numbers because caller_phone was buried
in the background task spawning instructions. Move it up to the voice
constraints section so the agent always knows who to text. Also add the
send-sms curl command as a top-level instruction, not just for sub-agents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gateway crashes were undetected because PID 1 was uvicorn, not a
supervisor. Now entrypoint.sh runs a restart loop with exponential
backoff (1s→30s, reset after 60s stable), and /health returns 503
when the gateway is unreachable so Fly can restart the container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When TWILIO_PROXY_URL is empty, outbound SMS and voice calls now go
directly to the Twilio REST API using TWILIO_ACCOUNT_SID,
TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER. This removes the hard
dependency on deepclaw-control for local development with ngrok.

Also restores and updates rebuild-openclaw-gateway.sh to start the
Deepgram voice sidecar alongside the Docker gateway.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	Deepgram/deepgram_handler/app/config.py
#	Deepgram/deepgram_handler/app/routers/actions.py
#	Deepgram/deepgram_handler/app/services/outbound_sms.py
Adds a task-manager extension with CRUD tools (task_add, task_list,
task_update, task_remove), gateway RPC methods, and a cron-based
reminder service that can trigger calls or messages at due time.

Wires the Tasks tab into the Control UI with form, status filters,
inline editing, and archive support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…leanup

- Auto-load tasks list on gateway hello (app-gateway.ts)
- Add tool display entries for task_add/list/update/remove in chat view
- Gitignore workspace runtime artifacts and local test scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace cron-based agent-mediated reminders with direct SMS/call delivery
through the Twilio sidecar. Reminders are now deterministic — the delivery
loop checks every 5s for due tasks and hits the sidecar endpoints directly,
with retry logic (3 attempts max) and delivered/error tracking on each task.

- Add plugin config: ownerPhone, fromPhone, sidecarUrl
- Replace channel/cronJobId fields with to/delivered/deliveryError
- Remove all cron scheduling logic from task-manager
- Add from_number param to sidecar outbound call/SMS endpoints
- Fix httpx form encoding (urlencode + BasicAuth)
- Add SMS channel context to sms_context prompts
- Plumb CronService into plugin service context for future use
- Improve cron logging with subsystem logger (stdout + JSON)
- Add sidecar log tailing to rebuild script

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ivery

- Register send_sms and make_call as proper agent tools (single-object
  pattern with inline execute) so any session — including sub-agents
  spawned via sessions_spawn — can send texts and place calls through
  the Twilio sidecar.
- Fix tool.execute is not a function bug: was using two-arg registerTool
  signature instead of the correct single-object pattern.
- Update voice prompt to tell sub-agents to deliver results via task_add
  with an immediate dueAt + reminder, so the delivery loop texts the
  caller automatically (deterministic, no LLM hop for delivery).
- Update child session post-call notification with same task_add pattern.
- Simplify deliverReminder body: use reminder.note directly as SMS body
  when present (sub-agent results), fall back to "Reminder: <title>".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace OpenClaw's red accent scheme with Deepgram branding:
- Roobert typeface (local @font-face, replacing Google Fonts CDN)
- Spring green (#13ef93) accent color across dark and light themes
- Deepgram D icon favicon and topbar brand
- Full color palette update (backgrounds, borders, text, semantic colors)
- Remove all hardcoded red/orange rgba values from CSS and inline styles

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant