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.
LLM summarization (30-120s) was blocking HTTP response causing browser
timeouts. Now runs in goroutine and returns immediately. UI polls every
5s until completion.
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.
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.
The `allowEmpty` prop on `ProviderModelSelect` was defined but the
Select dropdown still auto-selected the first provider when the value
was empty, and there was no way to reset back to empty (auto-detect).
- Map empty provider to a sentinel so Radix Select can represent it
- Show an "(auto)" option in the dropdown when `allowEmpty` is set
- Pass `allowEmpty` from both embedding config callers
- Skip clearing the model on provider change in allowEmpty mode to
avoid a stale-closure bug where the second setState overwrites the
provider update
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
* feat(cron): configurable default timezone for cron expressions
Cron expressions (e.g. "0 8 * * *") are evaluated relative to a timezone.
Without an explicit per-job timezone, they default to the server's system
timezone, which may not match the user's local time — especially in Docker
containers (default UTC) or multi-region deployments.
This adds a `default_timezone` setting to `CronConfig` (IANA format, e.g.
"Asia/Ho_Chi_Minh") that is applied as fallback when a cron job has no
explicit `schedule.tz`. The setting is configurable via the UI config page
(Integrations → Cron Scheduler) and hot-reloads on config changes.
Backend:
- Add `DefaultTimezone` field to `CronConfig`
- Add `SetDefaultTimezone()` to `CronStore` interface + PG implementation
- Apply default TZ in `AddJob()` when `schedule.TZ` is empty
- Wire at startup + subscribe to config change events for hot reload
- Update cron tool description so LLM knows about gateway default
Frontend:
- Add timezone dropdown (20 common IANA timezones) to Cron config section
- Add i18n keys for en, vi, zh
* fix(cron): apply default timezone to existing jobs via computeNextRun
Pass defaultTZ as fallback to computeNextRun so existing cron jobs
(with timezone = NULL in DB) also use the gateway's configured default
timezone when computing next_run_at. This ensures old jobs benefit
from the timezone setting without needing a DB migration or backfill.
---------
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
* feat(providers): add Ollama local and Ollama Cloud provider support
Adds two new provider variants:
ollama — local/self-hosted Ollama instance
- Gated on providers.ollama.host in config (or GOCLAW_OLLAMA_HOST env)
- No API key required; Ollama's OpenAI-compat endpoint accepts any Bearer value
- Defaults to http://localhost:11434/v1 (configurable for LAN/remote hosts)
- Default model: llama3.3
ollama-cloud — Ollama Cloud (managed remote inference)
- Gated on providers.ollama_cloud.api_key (or GOCLAW_OLLAMA_CLOUD_API_KEY env)
- Bearer token from ollama.com/settings/keys
- Default base URL: https://ollama.com/v1 (overridable via api_base)
- Default model: llama3.3
Both variants use the existing NewOpenAIProvider (OpenAI-compat) — no new
provider struct needed. Both are registered from config file and DB (via
llm_providers table with ProviderOllama / ProviderOllamaCloud types).
OllamaCloud.APIKey follows all existing secret handling patterns:
MaskedCopy, StripSecrets, StripMaskedSecrets.
* feat(providers): wire Ollama into web UI and fix DB registration
- Add ollama + ollama_cloud to PROVIDER_TYPES constants (dropdowns)
- Fix setup wizard: skip API key requirement for Ollama local (isOllama)
- Fix bootstrap status: recognize Ollama local as no-API-key provider
- Add ollama_cloud to config-page KNOWN_PROVIDERS list
- Fix gateway_providers.go: move ProviderOllama before APIKey=='' guard
so DB-registered local Ollama providers actually register at startup
(same pattern as ClaudeCLI, which also needs no API key)
The onboard wizard sets GOCLAW_PROVIDER and GOCLAW_MODEL in .env for
initial bootstrap. Previously these env vars always overrode the config
file value via envStr(), making it impossible to change the default
provider/model through the Dashboard — every save was silently reverted
by ApplyEnvOverrides().
Change envStr to envFallback for these two fields: the env var is only
applied when the config file has no value (empty string). Once the user
saves a provider/model via the Dashboard, the config-file value wins.
Also:
- Stabilize ProviderModelSelect auto-select effect (useRef + useMemo)
- Add toast feedback on config save success/failure
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Flush threshold (176K) was higher than compaction threshold (150K), so
flush was always skipped. Removed independent threshold calculation —
flush now always runs before compaction, gated only by enabled check and
per-cycle dedup guard. Also localized hardcoded compaction tooltips
(en/vi/zh), fixed inaccurate Memory Flush description, and removed dead
reserveTokensFloor/softThreshold UI inputs.
Backend defaults memoryFlush.enabled to true when config is nil
(memoryflush.go:39-46), but UI used `?? false` showing OFF.
Also fix sub-fields visibility to show when flush is defaulted ON.
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Add Provider, Model, MaxTokens to PendingCompactionConfig so users can
override the LLM used for pending message summarization via the config
UI. Falls back to agent's provider/model when not set. Increase default
max_tokens from 512 to 4096. Add allowEmpty prop to ProviderModelSelect
to prevent auto-selecting first provider when empty means "use default".
- Fix compact endpoint using random provider instead of agent's configured provider+model
- Wire auto-compaction for all 5 channel types (telegram, discord, slack, feishu, zalo_personal)
via PendingCompactable interface and InstanceLoader
- Add global PendingCompactionConfig (threshold, keep_recent) to ChannelsConfig
- Wire global config through InstanceLoader and PendingMessagesHandler
- Increase compaction timeout from 45s to 180s for slow providers
- Add pending compaction config card to Behavior tab in config page
- Add HowItWorksCard (expanded by default) and toast notifications to pending messages page
- Add i18n support for all new strings (en/vi/zh)
- Add reviewer role to team system (backend + UI) for evaluate_loop workflows
- Fix handoff/evaluate_loop/delegate_search system prompt entries (were showing as custom tool)
- Filter inactive agents from delegation queries (DelegateTargets, SearchDelegateTargets)
- Fix agent link direction display (flip outbound→inbound when viewed from target side)
- Improve builtin tool seed descriptions with detailed action-oriented text
- Add i18n support for builtin tool descriptions (en/vi/zh frontend locale files)
- Notify LLM when KG extraction triggered on memory write
* fix(i18n): add missing config.json locale files
The config namespace was registered in i18n/index.ts but the actual
JSON files were never created, breaking the UI Docker build (tsc error).
Also fix .gitignore: config.json → /config.json so only the root
gateway config is ignored, not the i18n locale files.
Closes#107
* feat(ui): replace language cycle button with dropdown select
Users can now pick a language directly from a dropdown instead of
cycling through all options on each click.
* fix(i18n): keep "Subagent" in Vietnamese translations
"Agent con" and "sinh sản" sound unnatural; keep the English term.
* chore: align .dockerignore config.json pattern with .gitignore
- Add tool status display on channels during tool execution (streaming preview + reactions)
- Emit agent.activity events at phase transitions (thinking, tool_exec, compacting)
- Enrich delegation progress with per-member activity and tool info
- Add LLM-based intent classifier for DM status queries when agent is busy
- Keyword fast-path for cancel/status patterns (no LLM cost)
- Falls back to LLM classification with 5s timeout
- Supports status_query (immediate reply) and cancel (abort run) intents
- Register/unregister runs in makeSchedulerRunFunc for channel inbound tracking
- Add sessionRuns secondary index in Router for O(1) IsSessionBusy lookups
- Add intent_classify config toggle (global default + per-agent override)
- Add tool_status config toggle for channel tool status display
- Add i18n keys and translations (en/vi/zh) for status messages
- Add web UI config toggles for intent_classify and tool_status
* feat: add Z.ai provider support (general API + coding plan)
Add Z.ai (GLM) as a new LLM provider with two variants:
- `zai`: general API (api.z.ai/api/paas/v4)
- `zai_coding`: coding plan (api.z.ai/api/coding/paas/v4)
Reuses OpenAIProvider — Z.ai API is OpenAI-compatible with Bearer
token auth, SSE streaming, and reasoning_content support.
Includes: store constants, config struct fields, env var loading
(GOCLAW_ZAI_API_KEY, GOCLAW_ZAI_CODING_API_KEY), secret masking,
config + DB registration, onboard wizard, and UI provider types.
Default model: glm-5
Closes#100
* docs: add Z.ai provider entries to providers documentation
- Add "do silently" instruction to BOOTSTRAP.md templates so agents
don't narrate internal file processing steps to users
- Rename channel instance form label from "Name" to "Key" for clarity
- Recognize claude_cli and chatgpt_oauth as valid providers without API keys
- Skip API key validation and show CLI-specific UI when provider is claude_cli
- Clear API key state when switching provider type
- Update bootstrap status check to handle keyless provider types
Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
Fixes#87. crypto.randomUUID() is unavailable in browsers older than
Chrome 92 / Firefox 95 / Safari 15.4, causing an uncaught TypeError
that crashes the React tree and renders a blank page when opening
builtin-tool settings or MCP grant dialogs.
Add a uniqueId() helper that uses crypto.randomUUID() when available
and falls back to a Math.random-based UUID v4 generator otherwise.
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
- Add /cron/:id detail page with job info, payload, run history
- Make cron.run async: respond immediately, execute in background
- Set last_status="running" before execution, emit CronEvent via WS
- Add CronEvent (running/completed/error) broadcast to all WS clients
- Add server-side pagination to GetRunLog (offset + total count)
- Show loading spinner on Run button when job is running (list + detail)
- Enrich CronRunLogEntry with duration, input/output tokens
- Make job names clickable in overview card → /cron/:id
- Fix refresh button animation using isFetching instead of isPending
Replace simple JSON settings modal with sortable provider chain cards for
media tools. Each card supports provider/model selection, timeout, retries,
and typed provider-specific params via schema.
- Add @dnd-kit/core + @dnd-kit/sortable for drag-and-drop reordering
- New media-provider-chain-form.tsx: sortable card list with DnD
- New media-provider-params-schema.ts: typed params per tool x provider_type
- Combobox: add portalContainer prop to escape dialog overflow clipping
- Title Case formatting for dialog titles
Show skill name instead of raw "use_skill" tool name, amber-colored
text, "activated" badge, and skip displaying raw arguments for skill
activation events.
Add a no-op use_skill tool that generates tool.call/tool.result events
in tracing spans and realtime, making skill activations visible in
observability. The actual skill loading still happens via read_file.
Web UI renders use_skill events with a distinct Zap icon and skill name
instead of the generic wrench icon.
- Add read_audio tool with Gemini File API, OpenAI input_audio, and fallback support
- Add read_video tool with Gemini File API and base64 fallback for video analysis
- Add create_video tool with Gemini Veo and OpenRouter chat completions support
- Add shared gemini_file_api.go for upload → poll → generateContent pipeline
- Add shared openai_compat_call.go for custom JSON chat completions
- Fix system prompt showing denied tools: use filteredToolNames() instead of tools.List()
- Wire audio/video MediaRef context propagation in agent loop
- Register new tools in seed data, policy groups, and web UI settings
- Enforce duration (max 30s) and aspect_ratio limits on create_video
Self-Evolution: predefined agents can now optionally evolve their SOUL.md
(communication style/tone only) when self_evolve is enabled in other_config.
Identity, name, and operating instructions remain locked. Context propagation
flows through LoopConfig → Loop → context.WithValue → interceptor carve-out.
System prompt guides the agent on what it can/cannot evolve.
Instances Tab: new HTTP endpoints and UI tab for viewing/editing per-user
USER.md files on predefined agents. Includes owner-only access checks,
fileName validation (USER.md only), and cache invalidation.
UI: self-evolve toggle in General tab, create dialog, and setup wizard.
Agent type and evolve/static badges with tooltip explanations on cards
and detail header. TooltipProvider added to agents list and detail pages.