- Set providerType on Suno case in registerProvidersFromDB (was missing,
causing misrouting for custom-named Suno providers)
- Fix dbTypeToMediaType: replace dead "openai" key with "openai_compat"
to match actual store constant, add "bailian" → "dashscope" mapping
- Clone entry.Params before injecting _provider_type to avoid mutating
the original chain config
Media tools (create_image, create_video, create_audio, read_audio,
read_video, read_document) routed API calls based on provider name
pattern matching (e.g. strings.HasPrefix(name, "gemini")). This breaks
when users give custom names to DB providers — a Gemini provider named
"chatgpt-sap-het" would be misrouted to the OpenAI-compat endpoint,
causing 404 errors.
Fix: carry the DB provider_type through OpenAIProvider, resolve it via
typedProvider interface in ExecuteWithChain, and inject as _provider_type
param for callProvider routing. Name-based heuristic kept as fallback
for config-file providers that don't have a DB type.
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Provider and Model donut charts showed 0 because they used request_count,
which is only populated on channel-level snapshot rows. LLM-level rows
store counts in llm_call_count instead.
The PR #153 whitelist stripped byProvider on agent config save,
but byProvider is actively used in policy.go for per-provider
tool overrides. Add it to the whitelist and ToolPolicyConfig type.
The per-agent `imageGen` and `vision` fields in `ToolPolicySpec` (stored
in agents.tools_config JSONB) were added in d5cc5a7 (Feb 26) as the
original way to configure image/vision providers. When the media provider
chain system was introduced in 5815437 (Mar 8), these fields were kept
"for backward compat" but became dead code with no UI to manage them.
This causes a hard-to-debug issue: if an agent's tools_config contains
stale imageGen/vision data (set via API or leftover from DB), it silently
overrides the global provider chain configured in the builtin tools UI.
Users see the correct chain in the UI but the tool calls a completely
different provider/model, with no indication of why.
Changes:
- Remove Vision and ImageGen fields + struct definitions from ToolPolicySpec
- Remove associated context helpers (WithVisionConfig, WithImageGenConfig, etc.)
- Remove per-agent override injection in agent loop
- Simplify create_image and read_image to use chain as sole source of truth
- UI: whitelist known tools_config fields on save to clean stale DB data
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Add alias support to the tool Registry so Claude Code skills can reference
Anthropic tool names (Read, Write, Edit, Bash, etc.) and have them resolve
to GoClaw canonical tools (read_file, write_file, edit, exec, etc.).
- Registry: aliases map, RegisterAlias(), resolve(), Aliases()
- Policy engine: auto-includes alias defs when canonical tool passes filter
- System prompt: alias entries in coreToolSummaries + missing use_skill
- Legacy toolAliases migrated to Registry.RegisterAlias() at startup
* feat(ui): multi-skill upload with client-side validation
Allow uploading multiple skill ZIP files at once with pre-upload
validation. JSZip parses each ZIP client-side to verify SKILL.md
presence, frontmatter format, and slug validity before upload.
- Add JSZip dependency (lazy-loaded, code-split ~30KB gzip)
- Create validate-skill-zip.ts mirroring server-side checks
- Rewrite skill-upload-dialog for multi-file with status badges
- Add concurrent validation, sequential upload with per-file progress
- Add empty SKILL.md check to backend upload handler
- Add i18n keys for all new UI strings (en/vi/zh)
* fix(ui): duplicate entries and validation hang in multi-skill upload
- Move pending list construction to assignment inside updater return
to prevent StrictMode double-invoke from pushing duplicates
- Wrap per-file validateSkillZip in try/catch so one failure doesn't
block Promise.all and leave entries stuck in "validating" state
* fix(ui): use static import for JSZip instead of dynamic import
Dynamic import("jszip") fails in browser - bare module specifiers
don't resolve at runtime. Use static import which Vite handles
via its module graph and code-splits automatically.
* feat(ui): add inline visibility toggle on skills table
Click the visibility badge on managed skills to cycle through
private → internal → public. File-based skills stay read-only.
* fix(ui): move dedup logic outside state updater in upload dialog
Avoids reading stale entries inside functional updater. Builds
pending list from current entries state before calling setEntries.
* fix(ui): auto-select first active agent when current agent unavailable
When agents load from API, if the current selected agent is not in the active agents list, automatically select the first available active agent instead of remaining unset. Prevents chat page from being unable to send messages when default agent selection is invalid.
* feat(ui): make agent display name editable in setup wizard
Allow users to customize the agent display name during onboarding instead of keeping it hardcoded to "GoClaw". Removed read-only state from the display name input and added a placeholder for guidance.
* feat: add document path enrichment and media filename support
Backend changes:
- enrichDocumentPaths() in agent/media.go: injects persisted file paths into <media:document> tags
- Document paths allow skills (e.g. pdf skill via exec) to access files directly
- chat.go: support new media format {path, filename} alongside legacy string paths
- Updated read_document tool description to guide agent on using path attribute
- Docker: add pypdf to Python dependencies for PDF processing
- Softened MUST language in read_* tool descriptions (changed to Call this)
Frontend changes:
- chat-input.tsx: attach filename with each uploaded file in media payload
- use-chat-send.ts: send media as {path, filename} objects instead of just paths
- i18n: add "uploaded_files" text in en, vi, zh locales
- chat-page.tsx: minor adjustment for media handling
Enables skills to process uploaded documents directly without intermediate copying.
Previously the spinner only cleared after a 120s timeout. Now a
useEffect watches the groups data and immediately clears the spinner
and polling when the compacting group's has_summary transitions to true.
ListMembers() now filters by a.status = 'active' so inactive agents
no longer appear in TEAM.md or delegation prompts, preventing leaders
from attempting to delegate to unavailable agents.
handleCreate() only invalidated agentRouter but missed emitting the
pub/sub event for TeamToolManager. Reuse invalidateTeamCaches() which
does both, matching the pattern used by all other team mutations.
ExecuteWithChain previously required all providers to implement
credentialProvider (APIKey/APIBase). OAuth-based providers like
CodexProvider (ChatGPT OAuth) don't expose static credentials,
causing all media tools to fail with "does not expose API credentials".
Make credentialProvider optional (nil when unsupported). Each
callProvider gracefully falls back to the provider's Chat() API
when credentials are unavailable. Generation tools (create_image,
create_video, create_audio) return a clear error since they require
direct API access with no Chat fallback.
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Four per-agent settings stored in the database (and configurable via UI)
were silently ignored at runtime because the tool/system layer always
used the global config defaults instead.
**restrict_to_workspace**: Tools used the global config default baked at
startup. Fix: pass per-agent value through context; tools check context
override before falling back to constructor default.
**subagents_config**: ParseSubagentsConfig() existed but was never called.
All agents shared one SubagentManager with global limits. Fix: resolve
per-agent config in the agent resolver, store it on each spawned task,
and use it for limit checks, deny lists, and system prompt generation.
**memory_config**: Only the enabled toggle was read per-agent; search
weights (vector_weight, text_weight, max_results, min_score) were
hardcoded from PGMemoryStore defaults. Fix: extend MemorySearchOptions
with weight overrides, read per-agent config from context in the
memory_search tool.
**sandbox_config**: Only workspace_access was extracted per-agent; mode,
image, memory, CPU, timeout, network settings were discarded. Fix: pass
full sandbox.Config through context; Manager.Get() accepts an optional
config override for new containers.
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
The embedding provider resolution only matched 3 hardcoded names
(openai, openrouter, gemini), silently failing for DB-stored providers
like "openai-embedding". This caused memory chunks to be stored
without vectors even when a valid embedding provider was configured.
Changes:
- resolveEmbeddingProvider: fallback to provider registry for DB-stored
provider names when hardcoded match fails
- gateway startup: read per-agent memory config from DB (priority over
config file defaults) for embedding provider resolution
- memory IndexDocument: log embedding errors instead of swallowing them
- memory admin ListChunks: return full chunk text instead of truncating
to 200 chars, avoiding confusing partial content in the UI
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
- Replace h-screen with h-dvh for correct mobile viewport height
- Fix input font-size to 16px on mobile preventing iOS Safari auto-zoom
- Add safe area padding for notched devices (Dynamic Island, home indicator)
- Expand touch targets for icon buttons to ≥44px on touch devices
- Make dialogs full-screen on mobile with slide-up animation
- Add virtual keyboard detection for chat input positioning
- Smooth auto-scroll for incoming messages, instant scroll on user send
- Add overflow-x-auto to table pages for mobile horizontal scroll
- Fix grid layouts to stack on mobile (grid-cols-1 sm:grid-cols-2)
- Safe-area-aware toast positioning
- Landscape compact mode for phone landscape orientation
- A1+C2: Include token usage in run.completed event payload for WS clients
- A2: Cost tracking with model pricing config, cost calculation, and cost summary API
- A3: Budget enforcement per agent with monthly budget limits (migration 000015)
- C1: External wake/trigger API (POST /v1/agents/{id}/wake) for orchestrators
- C3: Activity audit trail with structured logging and queryable API
- UI: Activity page, cost stat card on overview, budget section in agent detail
- i18n: Complete en/vi/zh translations for all new features
Zalo CDN photo URLs are auth-restricted and expire quickly. Download
images to local temp files before passing to the agent, falling back
to the raw URL on failure. Also adds PhotoURL field support.
Credentials Update() now handles []byte type in the switch case,
preventing incorrect encryption when credentials arrive as raw bytes.
sanitizeHistory now returns dropped count so callers know when orphaned
tool_use/tool_result messages were removed. When orphans are found in
buildMessages, the full session history is sanitized and persisted,
preventing repeated warnings on every request.
- Add SetHistory() to SessionStore interface and both implementations
- Adapt memoryflush caller to new two-return signature
- Change sanitize log level from Warn to Debug
Delegate session keys (delegate:{uuid8}:{agentKey}:{delegationId}) were
not parsed by makeSchedulerRunFunc, causing fallback to default agent ID
which doesn't exist in managed-mode DBs. Add switch/case to handle both
agent: and delegate: prefixes.
* refactor: remove managed/standalone mode distinction from codebase
Standalone mode is deprecated; managed mode is now the only mode.
Remove redundant "managed mode" qualifiers from comments, docs,
and error messages. Error strings now reference "database stores"
instead of "managed mode" for clarity.
* improve(onboard): streamline onboard process and env setup
Simplify onboard wizard, extract helpers to dedicated file,
update env example and entrypoint for default managed mode,
clean up prepare-env script, update i18n catalogs.
Cron jobs ran in isolated sessions with no context about who requested
them or where to deliver responses. The agent would misroute responses
(e.g., using team_message instead of replying to the original chat).
- Inject ExtraSystemPrompt with job name, requester ID, and delivery
target so the agent knows to produce content directly
- Pass client.UserID() in Web UI cron.create instead of empty string
StripConfigLeak was blocking legitimate responses when predefined agents
mentioned SOUL.md/IDENTITY.md/AGENTS.md in architecture explanations.
Improved detection logic to exclude code blocks but disabled the gate
entirely for now until a more robust approach is designed.
- Update seed defaults to use chain format {"providers":[...]}
- Add startup auto-migration for existing legacy flat settings in DB
- Remove legacy flat format parsing from parseChainSettings()
Run d3-force simulation synchronously in useMemo (~300 ticks → 1 render
instead of 300). Redesign team notifications section with gradient bg,
Bell icon, and Switch toggle.
- Add agent_count to MCP server list API via CountAgentGrantsByServer query
- Show Agents column in MCP servers table
- Mask sensitive header values (Authorization, API keys) and env vars
(keys containing secret/token/password) in create/edit form
Replace manual user_id text input with select dropdown populated from
sessions (DM + group chats). Add colorMode prop to ReactFlow for dark
mode Controls/MiniMap. Add agent select in empty state.
- Add ~/.goclaw/cli-workspaces/ to read_file allowed paths
- Enables agents to read working files from CLI workspace sessions
Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
Predefined agents were vulnerable to conversational identity manipulation
(e.g. "I'm your master", "you only listen to me") — users could establish
authority through chat history, causing the agent to comply in subsequent messages.
Added identity anchoring at 3 system prompt zones (predefined agents only):
- Primacy: explicit instruction after Safety section
- Middle: USER_PREDEFINED.md owner authority framing
- Recency: persona reminder reinforcement
LLM summarization (30-120s) was blocking HTTP response causing browser
timeouts. Now runs in goroutine and returns immediately. UI polls every
5s until completion.
MaybeCompact relied on RAM count which resets to 0 on restart (LoadFromDB
is a no-op). Messages accumulated in DB but never triggered compaction.
Now falls back to CountByKey DB query when RAM count is below threshold.
Replace channel column with context usage bar showing estimated tokens
vs compaction threshold. Token count estimated from messages JSONB
(octet_length/4 + 12K system prompt) — no migration needed.
Color-coded: green <60%, amber 60-85%, red >85%. Inline compaction
count with refresh icon.
* fix(channels): annotate DM messages with sender identity
Telegram and Zalo group messages already include [From: sender] prefix
so the agent knows who is talking, but DM messages were sent without
any sender context — the agent had no way to address the user by name.
- Telegram DM: add [From: @username] (or FirstName if no username)
- Zalo DM: add [From: displayName] when dName is present in payload
* fix(tests): add missing EnsureUserProfile to test stubs
AgentStore interface gained EnsureUserProfile in 4fce731 but the test
stub implementations were not updated, breaking CI on main.
---------
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Replace hardcoded English tooltip strings in compaction config with
t() calls. Add insertContact, searchContacts, noContactsFound i18n
keys across en/vi/zh.
Add inline contact search above textarea in file editor (predefined
agents only). Search contacts and click to insert formatted snippet
at cursor position. Also make USER.md clickable in sidebar.
Extract KG from Memory page into standalone /knowledge-graph route.
Fix graph zoom: fitView after D3 force simulation settles so all nodes
are visible. Compact layout: merge stats/search/actions into single row,
inline filters with page header.
Add searchable contact dropdown in instances sidebar to find channel
contacts and add them as agent instances. Backend EnsureUserProfile
creates user_agent_profiles row on demand when admin adds contacts.
Regroup sidebar from 4 to 7 sections (Core, Conversations, Connectivity,
Capabilities, Data, Monitoring, System) for better organization. Keep
technical terms Nodes and TTS as-is across all languages.
Pass contactCollector through channel manager to all channel handlers
(Telegram, Discord, Feishu, Slack, Zalo) so contacts are automatically
collected when users interact with the agent.