Commit Graph
118 Commits
Author SHA1 Message Date
Viet TranandGitHub cc00a6f193 fix: route delegate session keys to correct agent loop (#127)
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.
2026-03-11 07:57:51 +07:00
Thieu NguyenandGitHub 8ad580521d refactor: deprecate standalone mode, managed mode is now default (#126)
* 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.
2026-03-11 07:27:38 +07:00
viettranx c5b886048e fix(cron): inject delivery context into cron job system prompt
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
2026-03-11 07:26:43 +07:00
viettranx b9e9e6e34a refactor(media): migrate builtin tool settings from legacy flat to chain format
- 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()
2026-03-10 22:54:52 +07:00
9a0557c7a3 fix(tools): allow read_file to access CLI workspaces directory (#122)
- 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>
2026-03-10 20:58:10 +07:00
viettranx 23f1957c56 feat(channels): wire contact auto-collector across all channel handlers
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.
2026-03-10 18:46:44 +07:00
25fd9c9d6d feat(cron): configurable default timezone for cron expressions (#117)
* 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>
2026-03-10 18:44:28 +07:00
therichardngai-codeandGitHub d874266e87 feat(providers): add Ollama local and Ollama Cloud provider support (#113)
* 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)
2026-03-10 18:43:02 +07:00
viettranx c8dc9917fe feat(contacts): channel contacts table, auto-collector, contacts page & managers tab redesign
- Add channel_contacts migration (000014) with UNIQUE(channel_type, sender_id)
- Add ContactStore interface with UPSERT, list, count, merge operations
- Add ContactCollector with 30-min TTL cache to skip redundant DB writes
- Wire auto-collection into gateway consumer on every inbound message
- Add GET /v1/contacts API with pagination, search, channel_type & peer_kind filters
- Rename Writers tab → Managers tab (UI-only; backend routes unchanged)
- Extract InlineAddForm with scoped state, debounce cleanup, aria-expanded
- Add Combobox contact picker with debounced search + auto-fill
- Add Contacts page with server-side pagination, filters, i18n (en/vi/zh)
- Add shared ChannelContact type, sidebar nav entry, route & query keys
- Fix ILIKE wildcard escape, log CountContacts errors, extract shared type
2026-03-10 14:29:01 +07:00
viettranx 1ddd2e547a feat(compaction): configurable provider, model & max_tokens for pending message compaction
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".
2026-03-10 14:27:15 +07:00
viettranx 3b6bf645f3 feat(channels): pending message compaction — fix provider, wire auto-compact, add global config & UI
- 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)
2026-03-10 12:49:12 +07:00
viettranx e2015835b4 fix(agents): team reviewer role, tool prompting, inactive agent filter, link direction & i18n
- 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
2026-03-10 10:55:30 +07:00
5f7f4eb204 fix(gateway): scoped group writer prompt for system runs + media forwarding gaps (#104)
* fix(gateway): extract media forwarding helper and fix group writer cron/media gaps

- Extract appendMediaToOutbound() helper to deduplicate media attachment conversion across all outbound paths
- Add media forwarding to cron job handler, handoff announce, and teammate message flows
- Fix silent reply suppression to allow media-only responses (no text content)
- Skip group writer refusal prompt for system-initiated runs (cron, delegate, subagent) with empty senderID

* fix(agent): protect identity files in system-initiated group writer runs

- Move writer list lookup before senderID check so cron/delegate/subagent
  runs still load group writer config
- Inject file protection prompt for system-initiated runs instead of
  skipping entirely, preventing modification of SOUL.md, IDENTITY.md,
  AGENTS.md, and USER.md
- Retain fail-open behavior when writer list is unavailable

---------

Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
2026-03-10 10:12:33 +07:00
SpencerSwaggerandGitHub 885814ddd1 fix: spawn tool not registered when providers configured via database (#103) 2026-03-10 09:54:27 +07:00
viettranx 4df60649e5 feat(channels): real LLM compaction for web UI compact endpoint
Extract CompactGroup() from runCompaction() for shared use by both
auto-compact and HTTP compact endpoint. Wire provider registry into
PendingMessagesHandler so /v1/pending-messages/compact performs actual
LLM summarization (keep 15 recent + summary) instead of hard delete.

Add rows-affected guard in Compact() to prevent duplicate summaries
when concurrent compactions race on the same key.
2026-03-10 00:29:48 +07:00
viettranx bdb60de7ae chore: upgrade Go 1.25 → 1.26 and apply go fix modernizations
- Update go.mod and Dockerfile to Go 1.26
- Apply `go fix ./...` stdlib modernizations across 170+ files
- Add `go fix` to post-implementation checklist in CLAUDE.md
- Fix go fix misapplied rewrite in loop_history.go
2026-03-10 00:09:15 +07:00
viettranx e593b9cf22 feat(channels): real-time agent activity status & intent classification
- 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
2026-03-09 23:58:56 +07:00
Duc NguyenandGitHub e63ff014cb feat: add Z.ai provider support (general API + coding plan) (#102)
* 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
2026-03-09 22:28:18 +07:00
viettranx 3187196bd8 refactor(onboard): simplify to DB + keys only, delegate setup to web UI
Remove the 700+ line interactive wizard (provider, model, channels, TTS,
features) since the web UI setup wizard already handles all of this.

The onboard command now only: prompts for Postgres DSN, tests connection,
generates gateway token + encryption key, runs migrations, seeds placeholder
providers, and saves .env.local with the 3 required secrets.

Delete 8 helper files: onboard_auto, onboard_verify, onboard_models,
onboard_resolve, onboard_claude_cli, onboard_tts, onboard_feishu, onboard_zalo.
2026-03-09 20:01:05 +07:00
viettranx 63eff188ad feat(kg): add knowledge graph with LLM extraction, traversal, and graph visualization
- KnowledgeGraphStore interface + PostgreSQL implementation (recursive CTE traversal, 5s timeout)
- LLM entity extraction pipeline triggered on memory writes (background goroutine)
- knowledge_graph_search agent tool with search + traversal modes
- HTTP API: CRUD entities, traverse, extract, stats, graph endpoints
- Web UI: KG tab on memory page with table/graph toggle, entity detail, manual extraction
- Force-directed graph visualization using @xyflow/react + d3-force
- Builtin tool seed with configurable provider/model/confidence settings
2026-03-09 17:11:20 +07:00
11bed0cc01 fix(mcp-bridge): per-session security context + media forwarding (#91)
* fix(mcp-bridge): add per-session agent context and HMAC verification

- Add per-session MCP config with X-Agent-ID/X-User-ID headers instead
  of shared global config file
- Sign bridge context headers with HMAC-SHA256 to prevent forgery
- Add bridgeContextMiddleware to verify signatures on MCP bridge requests
- Store MCP configs in ~/.goclaw/mcp-configs/ outside agent workDir
- Use atomic writes (tmp + rename) for MCP config files
- Fix provider rename leaving ghost registry entries
- Remove provider_type from mutable fields on update
- Tighten temp dir permissions from 0755 to 0700

* feat(mcp-bridge): propagate channel routing context through MCP bridge

- Pass channel, chat_id, and peer_kind from agent loop to CLI provider options
- Inject X-Channel, X-Chat-ID, X-Peer-Kind headers in bridge context middleware
- Add BridgeContext struct to bundle per-call context for MCP config generation
- Include channel routing headers in per-session MCP config files
- Expose "message" tool via MCP bridge for cross-channel messaging
- Add extract helpers for new option keys in claude_cli_session.go

* feat(mcp-bridge): forward media attachments to outbound message bus

- Wire MessageBus into gateway server and MCP bridge handler
- Publish tool result media files to outbound bus for channel delivery
- Extract channel/chatID/peerKind from tool context for proper routing
- Add mimeFromExt helper for content-type detection on attachments

* feat(mcp-bridge): inject per-agent DB-backed MCP servers into Claude CLI config

- Add MCPServerLookup type to resolve agent-specific MCP servers from DB
- Wire MCPServerStore through provider registration and HTTP handler
- Extract mcpServerEntryToConfig helper to deduplicate transport config logic
- Add JSON-to-Go helpers (jsonToStringSlice, jsonToStringMap) for DB fields
- Merge per-agent MCP servers at config write time without overriding static entries

* fix(mcp-bridge): use Media struct fields and prefer explicit MimeType

- Map Media.Path to attachment URL instead of treating Media as string
- Use Media.MimeType when available, fall back to extension-based detection

* refactor(providers): deduplicate option extractors and extract bridge media forwarding

- Replace per-field extractors (extractSessionKey, extractAgentID, etc.) with generic extractStringOpt/extractBoolOpt
- Add bridgeContextFromOpts helper to build BridgeContext in one call
- Extract forwardMediaToOutbound from inline block in makeToolHandler
- Change NewBridgeServer msgBus param from variadic to explicit pointer

* fix(providers): validate provider_type on update instead of silently dropping it

- Add explicit validation against ValidProviderTypes with 400 response
- Remove silent delete(updates, "provider_type") that hid invalid values
- Caller now receives clear error when submitting unsupported provider_type

* fix(providers): add header injection validation to MCP bridge headers

- Extend CRLF/null-byte checks to agentID, channel, chatID, and peerKind
- Previously only userID had header injection prevention
- Prevents HTTP header injection via crafted values in MCP config

* fix(mcp-bridge): sign all context fields in HMAC and remove legacy code

- Sign all 5 bridge context fields (agentID|userID|channel|chatID|peerKind)
  in HMAC instead of only agentID|userID to prevent channel routing forgery
- Propagate context.Context into MCPServerLookup to respect request
  cancellation instead of using context.Background()
- Remove legacy BuildCLIMCPConfig, WithClaudeCLIMCPConfig, mcpConfigPath,
  and mcpCleanup (dead code since system is PG-only)
- Use mime.TypeByExtension before custom fallback in mimeFromExt
- Add debug log when media forwarding is skipped due to missing context
- Add thread-safety comment to SetMCPServerLookup

---------

Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-09 15:23:56 +07:00
viettranx b284f963f5 feat(memory): add memory management page with CRUD, search, and indexing
Add full-stack memory document management:
- Backend: extend MemoryStore with admin queries (ListAllDocumentsGlobal,
  GetDocumentDetail, ListChunks), HTTP handler with auth middleware
- Frontend: memory page with agent/scope filters, document table with
  pagination, view/edit dialog with content and chunks tabs, create dialog
  with scope selection, semantic search dialog
- UI fixes: reduce input/textarea focus ring width, prevent ring clipping
  in dialog scroll containers, widen memory dialogs on desktop
2026-03-09 14:54:41 +07:00
viettranx 5f7ca84876 feat(channels): persist pending messages to PostgreSQL with Web UI
- Add channel_pending_messages table with UUID v7 PK, sender_id tracking
- Implement PendingMessageStore interface with batched flush (3s/20 msgs)
- Add LLM-based auto-compaction when entries exceed threshold (50)
- Wire persistent history into all channel factories (Telegram, Discord, Slack, Feishu, Zalo)
- Extract channel type constants (TypeTelegram, TypeDiscord, etc.) to eliminate magic strings
- Add HTTP API endpoints for pending messages management (list, view, compact, clear)
- Add Pending Messages dashboard page with group titles resolved from session metadata
- Track sender_id across entire pipeline (migration → store → history → handlers)
2026-03-09 12:39:43 +07:00
viettranx 967f7ae46f refactor: split gateway, consumer, onboard, and agent loop into smaller files
Extract helper functions and move existing functions to dedicated files:
- cmd/gateway.go → gateway_channels_setup.go (channel registration, RPC wiring, event subscribers)
- cmd/gateway_consumer.go → gateway_consumer_helpers.go, gateway_consumer_process.go
- cmd/gateway_managed.go → gateway_http_handlers.go (wireHTTP)
- cmd/onboard.go → onboard_resolve.go (API key resolution helpers)
- internal/agent/loop.go → loop_run.go (Run entry point)

No logic changes — only code movement between files within the same package.
2026-03-09 10:49:58 +07:00
viettranx 3c03d1f482 feat(cron): add detail page, running status, realtime events, and pagination
- 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
2026-03-09 09:44:57 +07:00
viettranx 08ca343972 fix(cron): deliver agent response instead of raw payload message 2026-03-09 09:44:45 +07:00
Duc NguyenandGitHub e05a4018c9 fix: use platform type instead of instance name in system prompt + Zalo group routing (#90)
* fix(agent): use ChannelType in system prompt for proper channel context

The system prompt was using the channel instance name (e.g. "zep-lao") instead
of the platform type (e.g. "zalo_personal"), causing the LLM to not understand
which messaging platform it's running on. This led to context confusion where
the bot would ask users which channel to send to instead of using the current one.

Changes:
- Add ChannelType field to RunRequest and SystemPromptConfig
- Thread channel type from consumer/cron → agent loop → system prompt
- Add WithToolChannelType/ToolChannelTypeFromCtx for tool context
- Register channel types for both config-based and DB-loaded instances
- Fix Zalo group thread type detection with approvedGroups cache
- Update cron handler to resolve channel type for cron-triggered runs

* refactor(channels): add Type() to Channel interface, remove channelTypes map

Move channel type from a separate map in Manager to the Channel interface
itself. BaseChannel.Type() falls back to Name() for config-based channels
where name == type. Extracts resolveChannelType helper to DRY up 6
repeated resolution blocks across consumer and cron handlers.

* feat(zalo): add pending group history for conversation context

Zalo personal groups now record non-@mentioned messages in a ring buffer
(default 50, configurable via history_limit). When the bot IS mentioned,
pending history is flushed as context — matching Telegram/Discord/Feishu.

Separated mention gating from policy gating in checkGroupPolicy for
cleaner control flow.
2026-03-09 08:30:45 +07:00
SpencerSwaggerandGitHub 3f850bc713 fix(docker): remove gateway config check, unnecessary anymore (#88) 2026-03-09 07:09:15 +07:00
Duc NguyenandGitHub 137a986d4f feat(channels): add Slack channel (#83)
* feat(channels): add Slack channel via Socket Mode (#37)

Implement Slack integration using Socket Mode (xapp-/xoxb- tokens):
- Event-driven messaging via app_mention + message events
- Policy checks: open, pairing, allowlist, disabled (DM + group)
- Thread participation with configurable TTL
- Markdown-to-mrkdwn formatting pipeline
- Streaming support (edit-in-place + native ChatStreamer)
- SSRF-protected file downloads
- Debounce, dedup, reactions, group history context
- 170 unit tests (format, helpers, stream, SSRF)

Fix BaseChannel.HandleMessage allowlist to also check chatID,
enabling group allowlist with channel IDs across all channels.

Closes #37

* feat(slack): add file/media support and edit-to-mention handling

- Wire inbound file download into handleMessage (images, audio, documents)
- Add media.go with resolveMedia, classifyMime, buildMediaTags
- Extract shared ExtractDocumentContent to channels/media_utils.go (DRY with Telegram)
- Support file_share and message_changed subtypes
- Handle edit-to-mention: respond when user edits old message to add @bot
- Add MediaMaxBytes config field (default 20MB)
- Fix debounce media accumulation (was silently dropping files)
- Add 60s HTTP client timeout on file downloads
- Refactor downloadFile signature for slack.File compatibility
2026-03-09 07:02:37 +07:00
viettranx d839e034af feat(tools): add exec path exemptions and tool arguments in events
- Add AllowPathExemptions to ExecTool for fine-grained deny bypass (skills-store)
- Include tool call arguments in tool.result event payloads
2026-03-08 22:40:09 +07:00
viettranx 6345df3136 feat(tools): add create_audio tool for music and sound effects
New tool supporting MiniMax music generation, ElevenLabs sound effects,
and Suno music (stub). Registers Suno as a valid provider type.

- create_audio.go: tool definition with provider chain for music, direct ElevenLabs for SFX
- create_audio_minimax.go: MiniMax music API (/music_generation)
- create_audio_elevenlabs.go: ElevenLabs sound effects API (/v1/sound-generation)
- create_audio_suno.go: stub for future Suno integration
- Add ProviderSuno type to store and gateway registration
2026-03-08 20:10:00 +07:00
viettranx 5536313335 feat(tools): add use_skill marker tool for skill activation observability
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.
2026-03-08 16:45:26 +07:00
viettranx 62c28e1b3e feat(channels): unified media pipeline for Discord, Feishu, and WebSocket
Extract shared media utilities (MediaInfo, BuildMediaTags, TranscribeAudio,
DetectMIMEType) into internal/channels/media/ and refactor Telegram to use
them. Add full inbound/outbound media support to Discord and Feishu channels
(STT transcription, document extraction, media tags, voice agent routing).
Add WebSocket media upload/serve endpoints and MIME-aware media tags in
chat.send. Split large channel files for maintainability.
2026-03-08 16:39:46 +07:00
viettranx 47cc11bfc0 feat(metadata): add JSONB metadata to sessions, profiles, and pairing
Persist friendly names (display_name, username, chat_title) from channel
handlers into sessions, user profiles, and pairing records. Web UI renders
metadata with graceful fallback to raw IDs.

- Add migration 000011: metadata JSONB columns on sessions,
  user_agent_profiles, pairing_requests, paired_devices
- Extend SessionStore/AgentStore/PairingStore interfaces with metadata ops
- Extract and persist channel metadata in gateway consumer
- Extend sessions.patch and add PATCH instances metadata HTTP endpoint
- Update frontend sessions page, detail page, and instances tab
- Delete legacy file-based internal/pairing/service.go
- Update docs references to reflect DB-backed pairing
2026-03-08 15:42:44 +07:00
viettranx 691ddce8fb feat(tools): add read_audio, read_video, create_video tools and fix system prompt tool filtering
- 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
2026-03-08 14:43:18 +07:00
viettranx 0f2737ce53 feat(media): persistent media storage, read_document tool, and pipeline refactor
- Add persistent media storage (internal/media/) replacing temp file deletion
- Add MediaRef type for lightweight media references in session messages
- Refactor media pipeline to use bus.MediaFile{Path, MimeType} across all channels
- Add read_document builtin tool for PDF/DOCX/XLSX analysis via Gemini native API
- Move image sanitization from Telegram to shared agent/media layer
- Add media reload for multi-turn conversations (images from last 5 messages)
- Add reply-to-message media resolution for Telegram (re-download on reply)
- Add media inventory to compaction summary to preserve awareness after truncation
- Fix coreToolSummaries for read_image, read_document, create_image tools
- Add real-time trace update events via WebSocket broadcast
- Improve trace detail UI with media refs and tool result display
2026-03-08 14:00:34 +07:00
viettranx d9cdbb8e6e feat(storage): add workspace file browser with delete and size display
Add Storage page under Monitoring menu to browse, view, and manage
files inside ~/.goclaw/. Skills directories are visible but
deletion-protected. Extract shared file browser components from
skills page for reuse.
2026-03-08 13:18:18 +07:00
viettranx a53f3e092f fix(media): use absolute paths and relative URLs for WS media delivery
- FilesHandler now serves files by absolute path (auth-token protected)
  instead of requiring a workspace root, supporting multiple agent workspaces
- mediaToMarkdown generates relative URLs (/v1/files/...) instead of
  absolute http://host:port URLs so images work from any client origin
- Deduplicate media collection in agent loop: prefer result.Media over
  MEDIA: prefix parsing to prevent duplicate images
2026-03-08 00:41:38 +07:00
viettranx 56dd8b5885 fix(ws-media): plumb subagent media paths through announce to inbound message
Root cause: SubagentTask had no Media field. Tool results with media
(e.g. image generation) captured result.Media but it was discarded.
AnnounceQueueItem also had no Media field, so PublishInbound for
subagent announces always had empty Media — ContentSuffix never triggered.

Changes:
- Add Media []string to SubagentTask (subagent.go)
- Capture result.Media from tool executions in subagent_exec.go
- Add Media []string to AnnounceQueueItem (announce_queue.go)
- Pass task.Media through direct publish and batched announce drain
- Collect batch media in gateway.go announce queue drain callback
2026-03-07 23:41:14 +07:00
viettranx 9897dd77ed fix(ws-media): use ContentSuffix to inject images into session before run.completed
Previous approach failed because:
1. PublishOutbound with channel "ws" is silently dropped (no handler)
2. LLM strips image URLs despite instruction text
3. Post-run AddMessage races with frontend loadHistory()

New approach: ContentSuffix field on RunRequest is appended to the
assistant response inside the agent loop BEFORE saving to session
and BEFORE emitting run.completed. This guarantees image markdown
is in the session when frontend calls loadHistory().

Only affects WS channel — other channels still use ForwardMedia
and their respective outbound handlers.
2026-03-07 23:08:13 +07:00
viettranx 892ee8ea70 feat(ws-chat): add HTTP file serving, WS media delivery, and streaming UX improvements
- Add GET /v1/files/{path} endpoint with Bearer token + query param auth
- Pre-convert media to markdown HTTP URLs in announce messages for WS channel
- Add HideInput flag to skip persisting system messages in session history
- Add fallback to append image URLs if LLM strips them from announce response
- Fix stream-to-history DOM flash by promoting streamed text locally
- Fix tool call card word-wrap and expandable arguments panel
- Fix snake_case mismatch in Message types (toolCalls → tool_calls)
- Add clickable image rendering in markdown renderer
2026-03-07 22:46:04 +07:00
viettranx b62d46e50e refactor(lint): apply Go best practices across codebase
- Use errors.Is() instead of direct sentinel comparison (13 instances)
- Convert if/else-if chains to switch/case for same-variable comparisons
- Remove redundant bitwise OR with zero
- Add post-implementation checklist to CLAUDE.md
2026-03-07 20:51:39 +07:00
viettranx 0d3230b2bf feat(cache): add build-tag-gated Redis cache backend
Add optional Redis cache support via `go build -tags redis`, following
the same paired-stub pattern as OTel and Tailscale. The Cache[V] interface
is unchanged; Redis and in-memory implementations are injected at startup
without altering usage logic.

- Add RedisCache[V] implementation with JSON serialization, fail-open on errors
- Add gateway_redis.go / gateway_redis_noop.go paired wiring files
- Refactor GroupWriterCache and ContextFileInterceptor to accept injected caches
- Add GOCLAW_REDIS_DSN env var, docker-compose.redis.yml overlay
- Update Dockerfile and GitHub Actions with ENABLE_REDIS build arg
- Add Redis variant to CI matrix (5 variants: latest, otel, tsnet, redis, full)
2026-03-07 19:27:24 +07:00
viettranx 01e40a92b0 feat(mcp): add dynamic tool search and shared connection pool
MCP tool search mode: when an agent has >30 MCP tools, tools are
deferred and a single mcp_tool_search meta-tool is registered instead.
Uses BM25 index for keyword search, activating matched tools on demand.

Shared connection pool: introduces Pool that maintains one physical
connection per MCP server name, shared across all agents via refcount.
Eliminates N×M duplicate connections (N agents × M servers).
2026-03-07 18:52:37 +07:00
Songlin YangandGitHub af85b0c354 chore: remove unused code (#78) 2026-03-07 15:58:42 +07:00
viettranx 0473b9a334 feat(mcp): add test connection, server tools endpoint, and grants UX
Backend:
- Add POST /v1/mcp/servers/test endpoint reusing DiscoverTools()
- Add GET /v1/mcp/servers/{id}/tools for discovered tool listing
- Add MCPToolLister interface and wire through gateway

Frontend:
- Add Test Connection button with success/error feedback in MCP form
- Replace agent ID text input with agent select dropdown in grants dialog
- Replace tool allow/deny text inputs with multi-select from server tools
- Add MCP tools dialog for viewing connected server tools
- Widen MCP dialogs to sm:max-w-xl
2026-03-07 14:55:28 +07:00
viettranxandnhokboo b2c4d543aa feat(providers): add Claude CLI provider with MCP bridge (#61)
Add Claude CLI as an LLM provider (subscription-based, no API key needed).
The CLI manages session history, tool execution, and context while GoClaw
forwards messages and streams responses.

Key features:
- Claude CLI provider with session persistence (--resume)
- MCP bridge server exposing GoClaw tools to CLI via streamable-http
- Security hooks (shell deny patterns, workspace path restrictions)
- Per-session mutex preventing concurrent CLI calls
- Onboard wizard for Claude CLI setup and auth verification
- Web UI for adding/managing Claude CLI provider with auth status
- Provider registry Close() for proper shutdown cleanup

Security:
- CLI path validation (only "claude" or absolute paths from DB)
- Token auth middleware for MCP bridge endpoint
- Shell injection prevention in hook scripts (single-quoted paths)
- Relative path resolution before workspace boundary checks
- Resource leak prevention on provider replace/unregister

Co-authored-by: nhokboo <nhokboo@users.noreply.github.com>
2026-03-07 02:06:39 +07:00
viettranx faa47abfb6 feat(block-reply): deliver intermediate text during tool iterations with 2-tier config (#55)
Add block.reply event that delivers intermediate assistant text to non-streaming
channels during multi-tool iterations. Includes 2-tier config toggle:
gateway-level default (disabled) + per-channel override (inherit/on/off).

Backend:
- Emit block.reply events from agent loop between tool iterations
- Add BlockReply *bool to GatewayConfig and all 6 channel config structs
- Add BlockReplyChannel interface with ResolveBlockReply() resolution
- Guard delivery in HandleAgentEvent by RunContext.BlockReplyEnabled
- Resolve config at RegisterRun time, pass to consumer goroutine
- Conditional dedup: skip final message if identical to last block reply

UI:
- Gateway settings: Switch toggle for global default
- Per-channel: tri-state select (Inherit from gateway / Enabled / Disabled)
- Protocol: BLOCK_REPLY constant in AgentEventTypes
- Form: coerceBoolSelects for proper JSON boolean serialization
2026-03-07 01:06:10 +07:00
Songlin YangandGitHub 3dfdc8ca39 fix: add scroll when too many option in select (#66) 2026-03-07 00:46:29 +07:00
Ken HughesandGitHub 0bef45e6a9 fix: add missing /v1 to anthropic default API base URL (#68) 2026-03-07 00:45:44 +07:00