Commit Graph
1312 Commits
Author SHA1 Message Date
viettranx 5689d168e6 test: failing tests for softened predefined bootstrap prompt 2026-04-15 12:41:00 +07:00
viettranx 6544999779 fix(pipeline): treat gemini tool_calls+empty-args as truncation retry
Gemini returns finish_reason="tool_calls" (not "length") even when the
thinking budget exhausted max_tokens before tool arguments could be
emitted. Extend the existing truncation retry condition to detect this
case via an allowlist of mutating tools (write_file, edit, exec,
create_image, read_file) that virtually never legitimately call with
empty args. Nullary tools (datetime, heartbeat) pass through unchanged.

Trace: 019d8f33-2de1-7ab2-9a32-9df92cd610dd
2026-04-15 12:39:56 +07:00
viettranx 5c229bed59 test: failing tests for scoped truncation retry on mutating tools 2026-04-15 12:38:55 +07:00
viettranx 2fcdbec22c fix(providers/openai): forward thinking_level to Gemini via reasoning_effort
Gemini 3 defaults to "high" thinking budget internally when no
reasoning_effort is set, consuming the full max_tokens budget and
leaving no tokens for tool call arguments on small models. Map
OptThinkingLevel to reasoning_effort on Gemini routes (native endpoint
or proxy-by-model), with "medium" downgraded to "high" per Gemini 3
Preview constraint. Non-Gemini OpenAI-compat hosts unchanged.

Trace: 019d8f33-2de1-7ab2-9a32-9df92cd610dd
2026-04-15 12:37:43 +07:00
viettranx a9b97fad2d test: failing tests for gemini thinking_level forwarding 2026-04-15 12:36:45 +07:00
viettranx 498abb27d9 fix(providers/openai): include name on tool role messages (Gemini 400 fix)
Google Gemini's OpenAI-compat shim maps role=tool messages to native
FunctionResponse{name, response}; an empty name trips HTTP 400
("Name cannot be empty"). Build raw-ID → tool-name index at serialize
time and populate the name field on role=tool wire messages.

Trace: 019d8f33-2de1-7ab2-9a32-9df92cd610dd
2026-04-15 12:35:47 +07:00
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-code 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