Commit Graph
1306 Commits
Author SHA1 Message Date
viettranx 7773fa01b8 test(providers/openai): failing tests for tool msg name field (Gemini 400 repro)
Reproduces trace 019d8f33-2de1-7ab2-9a32-9df92cd610dd where Google's
OpenAI-compat shim returns 400 'Name cannot be empty' on FunctionResponse
because role=tool wire messages omit the 'name' field.

- TestBuildRequestBody_ToolMessageIncludesName: expects 'name' on tool msg
- TestBuildRequestBody_ToolMessageNameLookupUsesRawID: long ToolCallID still resolves
- TestBuildRequestBody_ToolMessageWithoutMatchingCallOmitsName: orphan stays nameless
2026-04-15 12:33:08 +07:00
viettranx 48335d7797 feat(pruning)!: faithful port of TS context pruning + backfill migration
Port goclaw context pruning to match upstream TS design in
openclaw/src/agents/pi-hooks/context-pruning/:

- Opt-in default: prune only when mode="cache-ttl" (was opt-out)
- Remove Pass 0 per-result 30% guard (duplicated Pass 1 with different
  suffix, caused wobble)
- Dedupe double prune call per iteration: PruneStage owns the single
  entry point; loop_history only runs limitHistoryTurns + sanitizeHistory
- Add cache-TTL gate for Anthropic prompt cache: skip prune while cache
  is live, scoped per-session via sync.Map
- Add context.pruned event emission for observability
- Configurable TTL as Go duration string ("5m", "30s")

BREAKING CHANGE: context pruning now opt-in. Add
contextPruning.mode: "cache-ttl" to config.agents.defaults to restore.

Migration 51 / SQLite v19 backfills mode="cache-ttl" for agents with
existing custom context_pruning config missing the mode field, so
previously-configured agents keep pruning after the opt-in flip.
NULL configs stay NULL (new opt-in default applies).

Web UI adds Cache TTL input + toggle wiring mode to cache-ttl/off.
2026-04-15 11:24:57 +07:00
viettranx 8d9a7c127a feat(i18n): desktop tts namespace + STT form keys
Add tts namespace to desktop i18n (en/vi/zh). Extend tools.json with STT form keys including WhatsApp privacy banner. Mirrors web ui/web locale structure.
2026-04-15 11:24:57 +07:00
viettranx 033638533d feat(desktop): port voice picker + STT form from web
Port web voice picker and STT provider form to desktop frontend. Singleton audio preview (hide when preview_url null), whatsapp_enabled toggle with privacy banner. Reuses desktop's custom Combobox primitive. Voice id persists via other_config.tts_voice_id merge in AgentDetailPanel. ToolSettingsDialog routes stt tool to new SttProviderForm.
2026-04-15 11:24:57 +07:00
viettranx 4cd79eacd7 chore(desktop): add Vitest + testing-library
Install Vitest, @testing-library/react, jest-dom, jsdom. Add test + test:watch scripts. Mirrors ui/web vitest config.
2026-04-15 11:24:57 +07:00
viettranx 3b4004946e chore: apply go fix syntax upgrades (min/max, switch patterns)
Apply Go 1.21+ min/max builtins and improved switch pattern matching
across test files and utilities. No functional changes.
2026-04-15 11:24:57 +07:00
viettranx 77dfb97d89 docs: phase 5 channel STT migration
Document unified audio.Manager.Transcribe integration across Telegram,
Discord, Feishu, and optional WhatsApp STT. Update changelog with Phase 5
completion and audio manager consolidation notes.
2026-04-15 11:24:57 +07:00
viettranx 21801e2682 feat(i18n): add voice message fallback key
Add MsgVoiceMessageFallback key for unified voice message handling
across channels (Telegram, Discord, Feishu, WhatsApp). Translations:
EN "[Voice message]", VI "[Tin nhắn thoại]", ZH "[语音消息]".
2026-04-15 11:24:57 +07:00
viettranx 5e0a60da36 feat(channels): migrate STT to unified audio.Manager
Migrate Telegram, Discord, Feishu channels to audio.Manager.Transcribe
for consistent voice message handling. WhatsApp STT opt-in (default off;
Decision 6 — E2E encryption trade-off). Fix tenant-scoped context in
Discord factory. Remove per-channel STT implementations.
2026-04-15 11:24:57 +07:00
viettranx 4db33dc822 docs: sync changelog for STT Phase 04 completion 2026-04-15 11:24:57 +07:00
viettranx 5681ca284d feat(i18n): STT form labels (en/vi/zh)
Add STT provider form i18n translations for en, vi, zh locales:
- stt_provider_form.title
- stt_provider_form.model_label
- stt_provider_form.language_label
- stt_provider_form.api_key_label
- stt_provider_form.test_button

Locales synced across all 3 catalogs.
2026-04-15 11:24:57 +07:00
viettranx 6c229e71c5 feat(ui): STT admin form mirror of TTS form
Add stt-provider-form.tsx React component with form fields for model, language, and API key configuration. Mirror TTS provider form structure for consistency. Integrate into builtin-tool-settings-dialog.tsx. Includes comprehensive unit tests for form validation, submission, and error handling.
2026-04-15 11:24:57 +07:00
viettranx b7002a67d1 feat(audio): wire Scribe STT + legacy bridge in gateway setup
Register ElevenLabs Scribe and proxy STT providers in gateway initialization. Auto-wire legacy STT bridge from existing channel STTProxyURL configs. Implement setupAudioExtras() with RegisterSTT and SetSTTChain calls. Maintains backward compat with per-channel configs.
2026-04-15 11:24:57 +07:00
viettranx 0977952110 feat(db): seed builtin_tools[stt] (PG + SQLite)
Add STT builtin tools seeding:
- PG: migration 000050 (49→50) with stt_scribe and stt_proxy entries
- SQLite: schema version 17→18 with inline seed
- Both: register in gateway_builtin_tools.go with encrypted API key support

Migrations support rollback. Version bumps gated to prevent schema drift.
2026-04-15 11:24:57 +07:00
viettranx e2075dc231 feat(i18n): STT message keys
Add 3 new i18n message keys for STT error handling:
- stt.error.audio_too_large: Audio exceeds 20MB limit
- stt.error.network: Network error during transcription
- stt.error.api: STT provider API error

Includes translations for en, vi, zh catalogs.
2026-04-15 11:24:57 +07:00
viettranx 371dcd3acd feat(audio): legacy STT bridge for per-channel STTProxyURL
Implement legacy STT bridge adapter to support existing per-channel STTProxyURL database configuration. Wraps arbitrary proxy endpoints and auto-registers them via Manager at boot. Includes integration tests for URL validation, authentication, and error handling.
2026-04-15 11:24:57 +07:00
viettranx 8c8849365f feat(audio): Manager STT dispatch with channel override
Add Transcribe() method to Manager with STT provider dispatch and channel-specific overrides. Implements channelSTTOverrides map, WithChannel context propagation, RegisterChannelSTT registration, and resolveSTTChain fallback logic. Includes manager-level unit tests.
2026-04-15 11:24:57 +07:00
viettranx 9f88f12c2a feat(audio): proxy STT wrapper
Implement STT proxy provider that wraps arbitrary HTTP-based STT services. Ported 12 test cases from legacy Telegram STT integration to validate multipart/form-data submission, language/model overrides, and API error handling.
2026-04-15 11:24:57 +07:00
viettranx 37224937c6 feat(audio): ElevenLabs Scribe STT provider
Implement native ElevenLabs Scribe STT provider with POST /v1/speech-to-text endpoint. Supports 20MB audio cap, multipart form submission, configurable model and language. Includes comprehensive unit tests for happy path, audio size validation, API errors, and edge cases.
2026-04-15 11:24:57 +07:00
viettranx 96f11720e8 feat(audio): finalize STT types
Add STTInput, STTOptions, and TranscriptResult types to support native STT providers (ElevenLabs Scribe). Includes audio_duration_secs JSON tag for transcription metadata.
2026-04-15 11:24:57 +07:00
viettranx c3167a44cc refactor(audio): update ElevenLabs SFX provider with Manager integration 2026-04-15 11:24:57 +07:00
viettranx 695eba2150 docs: sync changelog + tools-system for audio manager Phase 03 2026-04-15 11:24:57 +07:00
viettranx 201facd2f1 chore: remove Suno provider at all sites 2026-04-15 11:24:57 +07:00
viettranx aeef3396e4 refactor(tools): create_audio delegates to audio.Manager 2026-04-15 11:24:57 +07:00
viettranx 545c27beb5 feat(audio): Manager dispatch for Music + SFX with fallback chain 2026-04-15 11:24:57 +07:00
viettranx d3f226c7a7 feat(audio): add MiniMax Music provider 2026-04-15 11:24:57 +07:00
viettranx 5001059e76 feat(audio): add ElevenLabs Music provider 2026-04-15 11:24:57 +07:00
viettranx cf16cf53db docs: phase 02 completion — voice/audio system docs + architecture updates
Update architecture overview with streaming TTS provider layer. Expand tools
system docs with voice/model resolution. Update HTTP and WebSocket RPC
documentation for voice endpoints. Record Phase 02 completion in changelog.
Update CLAUDE.md with voice picker and streaming TTS patterns.
2026-04-15 11:24:57 +07:00
viettranx a7c8170c4a feat(agent): audio config context propagation in tool callbacks
Add audio config context helpers in pipeline callbacks. Propagate voice/model
selections through agent loop resolver for tool invocation.
2026-04-15 11:24:57 +07:00
viettranx 8d187ca074 feat(ui): voice picker component with preview button
Add VoicePicker with live search and preview button. Integrate into prompt
settings section. Add voice API hooks (useVoices, useRefreshVoices). Localize
UI strings for en/vi/zh. Fix snake_case JSON field mapping (voice_id, preview_url).
2026-04-15 11:24:57 +07:00
viettranx 28a70fd4f0 feat(tools): TTS voice/model resolver with agent-level precedence
Add context helpers for audio config routing. Implement resolveVoiceAndModel
with agent→user→global precedence. Add 5 precedence tests covering inheritance
and override scenarios.
2026-04-15 11:24:57 +07:00
viettranx 1b6e7115c7 feat(i18n): add TTS model validation messages (en/vi/zh)
Add MsgTtsUnknownModel and MsgVoicesListFailed keys with translations for
English, Vietnamese, and Chinese locale catalogs.
2026-04-15 11:24:56 +07:00
viettranx c7f2a260e8 feat(gateway): /v1/voices HTTP + WS RPC endpoints
Add ListVoices and RefreshVoices methods to RPC protocol. Implement HTTP
/v1/voices endpoint with provider-aware voice listing and filtering.
2026-04-15 11:24:56 +07:00
viettranx d97dcf252c feat(audio): ElevenLabs streaming TTS with model validation
Implement streaming TTS synthesis for ElevenLabs. Add model validation to
buffered path. Add characterization tests for latency and error scenarios.
2026-04-15 11:24:56 +07:00
viettranx daa5adb88b feat(audio): streaming TTS provider interface + voice cache + ElevenLabs models
Add StreamingTTSProvider interface for audio streaming support. Implement voice
caching with TTL+LRU. Add ElevenLabs model validation and voice list retrieval.
2026-04-15 11:24:56 +07:00
viettranx 0760c3664f docs(claude): add plan verification rules for multi-phase workflows
Encode 12 trust-but-verify checkpoints between scout → planner → final
plan. Captures lessons from the elevenlabs-audio-manager plan audit:
re-grep factual claims, re-scout on scope change, enumerate delete
scope deep, verify external APIs via docs-seeker, cross-phase gates
explicit, separate desktop/web scouts, i18n key ordering, signature
caller enumeration, zero-coverage characterization tests, context key
conventions, alias symbol coverage, and mandatory verify pass after
rewrite.
2026-04-15 11:24:56 +07:00
viettranx b1b77597a9 docs: note audio manager refactor and backward-compat tts alias
Update module map to list internal/audio/ (unified manager, TTS active,
STT/Music/SFX stubbed/partial) and clarify internal/tts/ as a
24-symbol backward-compat alias layer. Add changelog entry for Phase 1.
2026-04-15 11:24:56 +07:00
viettranx b0b87da7cd feat(config): add optional Audio config for STT/Music
Add optional Audio *AudioConfig pointer field on Config with STT and
Music sub-structs. Nil-safe — absent in JSON5 decodes as nil, no
breaking change. cfg.Tts retained unchanged for backward compat.
setupAudioExtras stub wired for Phase 3/4 STT/Music provider
registration.
2026-04-15 11:24:56 +07:00
viettranx 8fc4e5dea9 refactor(tools): delegate ElevenLabs SFX to audio.SFXProvider
Rewrite create_audio_elevenlabs.go as a thin shim calling
elevenlabs.NewSFXProvider(...).GenerateSFX(ctx, audio.SFXOptions{...}).
Preserves 30s duration cap, 60s timeout, and byte-identical request
body. Phase 3 removes the shim and wires audio.Manager.GenerateSFX
directly.
2026-04-15 11:24:56 +07:00
viettranx 214bd83bde refactor(tts): replace per-provider files with 24-symbol alias layer
internal/tts becomes a thin backward-compat alias over internal/audio:
15 type aliases, 6 constants, 5 constructors, 5 compile-time signature
guards. All pre-refactor callers compile unchanged. alias_test.go
enforces symbol coverage and type identity. Old per-provider files
(manager, types, elevenlabs, openai, edge, minimax) are removed in
the same commit to keep history bisectable.
2026-04-15 11:24:56 +07:00
viettranx f4cc595e50 feat(audio): add unified audio manager with 4 provider interfaces
Introduce internal/audio package with Manager orchestrating TTS, STT,
Music, and SFX providers via 4 interfaces. Phase 1 wires TTS providers
(ElevenLabs, OpenAI, Edge, MiniMax) and ElevenLabs SFX; STT/Music
wiring deferred to later phases. ElevenLabs TTS and SFX share an
xi-api-key HTTP client.
2026-04-15 11:24:56 +07:00
therichardngai-codeandGitHub e79a8bbd39 fix(mcp): wire per-user MCP tool discovery into agent pipeline
MCP servers with require_user_credentials (e.g. Notion) were defined
but never loaded into the agent's tool registry. Three gaps:

1. getUserMCPTools was defined but never called — add call in
   makeBuildFilteredTools before FilterTools runs each iteration.

2. hasMCPTools stayed false when only user-credential servers existed,
   so agentToolPolicyWithMCP never injected "group:mcp" into alsoAllow.
   Now set true when mcpUserCredSrvs is non-empty.

3. Per-user BridgeTools were registered in the registry but never added
   to the "mcp" tool group, so expandSpec("group:mcp") returned empty.
   Add MergeToolGroup helper for additive group updates.

Also add debug log when getUserMCPTools skips due to empty userID.
2026-04-15 04:09:11 +07:00
viettranx 7d6fcc3b7e docs: add journal on trace stop/abort cascade redesign 2026-04-14 19:58:25 +07:00
viettranx b68b3b12d7 fix(trace): disable stale recovery loop until last_span_at lands
Stale recovery sweeps traces by `start_time < NOW() - threshold`, which
measures trace age rather than inactivity. Any threshold low enough to
be useful (2-10 min) kills legitimate long-running agent runs: research
chains, large code generation, extended shell commands routinely exceed
10 minutes.

Disabled in Start() — function kept in place for easy re-enable once a
`last_span_at` column is added so recovery can gate on "no activity for
N minutes" instead of "started > N min ago".

Trade-off: zombie traces from gateway crashes may remain `running` in
DB. Accepted: primary abort path (router 2-phase + trace.status WS
event) handles the common case; safety-net gap preferred over false
kills of healthy runs.

Integration test RecoverStaleNow() still works (manual trigger, not
loop-dependent) so coverage of the recovery function itself is
preserved for when it's re-enabled.
2026-04-14 19:53:11 +07:00
viettranx 1ac08155b0 feat(trace): reliable stop/abort with ctx-aware streams and 2-phase router
Makes the Stop button on the traces page actually stop running traces.
Seven-phase implementation across provider HTTP, agent router, trace
persistence, WS events, tool exec, i18n, and integration tests.

- Provider HTTP+SSE ctx-aware: close socket on cancel via CtxBody wrapper
- Router 2-phase abort: CAS state machine, 3s grace, force-mark fallback
- Trace retry: 3 inline retries + 10-max retry queue, stale recovery 10min
- trace.status WS event: real-time UI updates (invalidates query on receive)
- Tool exec: process-group kill (SIGTERM→3s→SIGKILL), Rod page ctx watch
- i18n: 6 abort toast variants in en/vi/zh
- Integration: 9 scenarios, -race clean

Fixes tenant-ctx loss in forceMarkTraceAborted and retry worker broadcast
(caught by code-reviewer: C1/C2). Stale threshold intentionally 10min
because start_time-based; last_span_at migration is a follow-up.
2026-04-14 18:28:31 +07:00
viettranx 677396c71d fix(secure-cli): prevent deny_verbose from blocking --version via substring match
matchesBinaryDeny used unanchored regex on joined args, causing `-v` pattern
to false-positive on `--version`. Split deny_verbose into matchesBinaryVerbose
with start-anchored per-arg matching: `-v` blocks `-v`, `-vv`, `-v=1` but not
`--version`. deny_args keeps joined matching for multi-token patterns.
2026-04-14 10:46:53 +07:00
viettranx 221cd78fcf fix(agent): emit tool.call event in parallel tool execution path
v3 pipeline's parallel path (makeExecuteToolRaw) skipped the tool.call
WebSocket event, so web UI and desktop UI silently dropped tool cards
during real-time streaming. Only page refresh (which reloads history)
revealed the tool calls. Both UIs rely on tool.call to create entries
that later tool.result events can update.

Fix: mirror the sequential path's emission in makeExecuteToolRaw.
Bus.Broadcast is RWMutex-guarded, safe to call from parallel goroutines.

Add tests at two layers to prevent regression:
- Pipeline layer (stages_test.go): guards the dispatch contract —
  multiple tool calls route through ExecuteToolRaw + ProcessToolResult
  rather than ExecuteToolCall. Previously the parallel path had zero
  test coverage, which is why this bug escaped.
- Agent layer (loop_pipeline_tool_callbacks_test.go): guards the
  emission contract — both sequential and parallel wrappers emit
  tool.call with correct payload and routing context. Mutation-verified.
2026-04-14 10:09:45 +07:00
viettranx 619b253b82 fix(tasks): inject tenant ctx in task ticker to prevent nil panic
Root cause: ticker's recoverCtx had no tenant → PGTeamStore.GetTeam returned silent (nil, nil) → team.LeadAgentID nil-deref panic

- Fix notifyLeaders: composite cache keys {TeamID, TenantID}, inject scopeCtx = store.WithTenantID(ctx, scope.TenantID) before GetTeam/GetByID/GetTask, nil-check team + lead agent
- Fix processFollowups: per-team scopeCtx from teamTasks[0].TenantID, nil-check team before followupInterval(*team)
- Add TenantID field to TeamTaskData + scan paths in PG and SQLite stores
- Bonus: GetTask(scopeCtx, ...) propagates tenant for peerKind session routing (related #266)
- Tests: upgrade stub to function-based dispatch + ctx capture, add 6 regression tests (nil-team no-panic, multi-tenant cache isolation, cache hit dedup, multi-tenant ctx in processFollowups)
- Docs: scheduling-cron guide notes tenant-ctx injection requirement for background workers
2026-04-14 10:05:57 +07:00
viettranx 2e0f3a5a19 fix(vault): suppress stale error toast on stop + count unenriched docs in scan
- AddError() now skips broadcast after Finish() to prevent cancelled
  goroutines from emitting error events to UI after user stops enrichment
- batchSummarize skips AddError when context is cancelled (expected on stop)
- Rescan always re-enqueues unenriched docs alongside new/updated files,
  worker-level dedup prevents double-processing
2026-04-13 21:42:17 +07:00
2fee42dc32 fix: handle ignored errors, unsafe type assertions, missing panic recovery (#854)
* fix: handle ignored errors, unsafe type assertions, missing panic recovery

- Cron scheduler (PG + SQLite): check all ExecContext errors in
  recomputeStaleJobs, run log insert, job delete, and post-run update.
  Previously these errors were silently discarded, which could leave
  job state inconsistent without any log trace.

- Discord: use comma-ok type assertions on sync.Map placeholder loads
  to prevent potential panics from bare type assertions.

- Slack: use comma-ok type assertions in sweepMaps for dedup and
  thread participation eviction to prevent potential panics.

- Feishu: add safego.Recover to WebSocket goroutine so a panic in
  the WS client doesn't silently kill the goroutine.

- Agent export: add tenant owner/admin permission check to canExport.
  Previously only agent owner and system owner could export — tenant
  admins were incorrectly denied.

- Channel health: use errors.Is/errors.As for context.DeadlineExceeded,
  net.DNSError, and net.OpError before falling back to string matching.
  DNS NXDOMAIN is now correctly classified as non-retryable.

* fix(review): revert export to system-only + add missing rows.Err check

- Revert canExport tenant role check — export/import is restricted to
  agent owner and system owner by design
- Add rows.Err() check after recomputeStaleJobs loop in PG cron
  (parity with SQLite implementation)

---------

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-04-13 21:29:11 +07:00