When a user refreshes the page and resumes an existing chat session,
the frontend agentId could default to "default" instead of the correct
agent embedded in the session key. This caused the backend to resolve
the wrong agent, blocking MCP tools that were granted to the intended
agent.
Backend: parse agent key from session key format "agent:{key}:{rest}"
when agentId param is empty in chat.send.
Frontend: initialize agentId from URL session key on page load and
sync it when selecting a different session.
Two bugs in Zalo personal channel policy:
1. Group pairing bypass: checkGroupPolicy() called IsAllowed(groupID)
directly, which returns true when allowlist is empty — effectively
skipping pairing for all groups. Fixed to match the DM pairing
pattern: HasAllowList() && IsAllowed(groupID).
2. Wrong thread type for group pairing reply: sendPairingReply() always
used ThreadTypeUser even when replying to a group. Now detects
group sender IDs (prefixed "group:") and uses ThreadTypeGroup.
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>
Try generating all context files (SOUL.md, IDENTITY.md, USER_PREDEFINED.md)
in a single LLM call with 120s timeout. On timeout/retryable errors, fall
back to the existing 2-call sequential approach. Non-retryable errors fail
immediately.
- Restore buildCreatePrompt for single-call path
- Add isRetryableError helper (context deadline, net timeout)
- Extract finishSummon and loadExistingFiles helpers
- Update Tiểu La preset to image generation specialist
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
- Fix CI: use %s for json.Number in e2e test (was %d)
- Fix path traversal in parseMediaPath: restrict to os.TempDir()
- Add 25MB file size limit (checkFileSize) before upload reads
- Drain stale uploadCallbacks on Listener.reset() to prevent leaks
- Split send.go (688 LOC) into send.go, send_image.go, send_file.go, send_helpers.go
- Add unit tests for parseMediaPath (12 cases incl. traversal attacks)
The list pages had ConfirmDialog for deletion wired up but no UI
element to trigger it. Detail pages had no delete option at all.
- Add delete button with trash icon to agent and team cards
- Wire onDelete callbacks to existing setDeleteTarget state
- Add delete button + confirm dialog to agent detail page header
- Add delete button + confirm dialog to team detail page header
Closes#17
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Split agent summoning into two sequential LLM calls:
- Step 1: Generate SOUL.md (personality)
- Step 2: Generate IDENTITY.md + USER_PREDEFINED.md using SOUL.md as context
This enables real-time progress updates in the UI as each file completes.
On retry, previously generated files are detected by comparing against
the default template and skipped, so only missing files are regenerated.
Also increase HTTP client timeout from 120s to 300s for both OpenAI and
Anthropic providers. Some models (e.g. Kimi) with deep reasoning can
take 160s+ for non-streaming requests, which exceeded the 120s limit
and caused cascading retry failures until the context deadline expired.
Add info tooltip on the Members label in team create dialog and team
members tab, explaining that only predefined agents can be added as
team members since open agents lack shared context for collaboration.
Default bufio.Scanner limit (64KB) can truncate large SSE lines from
tool call arguments or thinking content, causing silent parse failures.
Set buffer to 1MB to match the scale of extended thinking responses.
Also remove a duplicate scanner.Err() check that was accidentally left in.
Backend: include all slog attrs in WS payload with sensitive key redaction,
add 100-entry ring buffer for replay on subscribe, support per-client level
selection via logs.tail { level: "debug" }.
Frontend: move log state to Zustand store so tailing persists across page
navigation, add level selector, client-side level filter, text search, and
inline attr rendering.
Add shared agent-level USER_PREDEFINED.md file for predefined agents to define
baseline user-handling rules (owner info, audience, language, communication norms)
that apply to ALL users. Individual USER.md per-user supplements but never overrides.
- Seed USER_PREDEFINED.md template in SeedToStore for new predefined agents
- Backfill existing agents via ensureUserPredefined in summon/regenerate flows
- AI optionally generates/updates the file when description mentions people/user context
- Add to context file interceptor, RPC allowlist, and system prompt injection
- Update summoning modal with optional file progress tracking
- Show estimated token count (Unicode-aware) instead of bytes in file sidebar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove hardcoded "personal assistant running inside GoClaw" identity.
Replace with channel+peer-aware context: "running in Telegram (a group chat)".
Remove model name from Runtime section to prevent leaking provider info.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ~60% redundant content from AGENTS.md (safety, bootstrap, tools, workspace
sections already covered by system prompt). Add Conversational Style rules to reduce
bot-like behavior. Add customizable Style section to SOUL.md template with summoner
metaprompt support. Migration 000010 force-updates all existing AGENTS.md in DB.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: add message to run.started, content to run.completed,
arguments to tool.call events. Frontend: fix arrow direction
(agent → tool), compact card layout (badge+content+timestamp in
single row), show subtype in outer badge for agent events, fix
JSON dialog newline consumption in regex.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split agent event cards into RunEventCard and ToolEventCard with full
context rows (channel, delegation, parent agent, team task, call ID).
Add channel badge and delegation ID to delegation lifecycle cards,
completed task count to announce cards, task ID to task/message cards.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a new "Realtime Events" tab in team detail page that displays WS events
in real-time via a centralized Zustand store + wildcard listener. Includes
structured card components for delegation, task, message, agent, and CRUD
events with agent name resolution from TanStack Query cache. Each card is
clickable to show raw JSON with syntax highlighting and copy support.
Also removes byte-based task truncation in delegation event payloads that
was corrupting multi-byte UTF-8 characters — now sends full task content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added progress_notifications to agent_teams.settings JSONB so teams can
opt-in to periodic "Your team is working on it..." chat messages during
async delegations. Global default is OFF.
Backend: progressEnabled resolved per-delegation from team settings,
falling back to global default. Frontend: checkbox toggle in team
settings page.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Concurrent announce runs (delegate + subagent) on the same leader session
could read stale session history because the agent loop reads at start and
writes at end. Added per-session mutex via sync.Map to serialize announces,
ensuring each reads up-to-date history.
Also removed unnecessary task preview truncation in delegation events
(WS clients handle display formatting).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 16 new event constants and typed payload structs for full WS
visibility into team agent operations. Enrich AgentEvent with delegation
and routing context (delegationId, teamId, parentAgentId, userId,
channel, chatId). Emit thinking/chunk events for non-streaming runs
so delegate member agents also produce WS events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use variant="outline" and useMinLoading for proper spin animation,
matching the pattern used across other pages (traces, channels, etc.).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove card wrapper from team tabs to fix scroll-Y inside tabs
- Add overflow-y-hidden to TabsList to prevent vertical scrollbar leak
- Widen task detail dialog to match trace detail (95vw/max-w-4xl)
- Add max-h-[85vh] + overflow-y-auto to task detail dialog
- Add global thin scrollbar styling (scrollbar-width: thin)
- Add refresh buttons to Tasks and Delegations tabs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add max-w-4xl to agent/channel/team detail card so tabs hug content
- Add TaskDetailDialog for viewing full task info on click
- Add click-to-detail on Team Delegations tab reusing DelegationDetailDialog
- Add overflow-x-auto + min-w on task list for mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mobile sidebar drawer, chat sidebar drawer, and responsive layouts
- Fix hooks: useApprovals stale closure, useClipboard cleanup, error states
- Expand cache invalidation for cron/health/usage events, add staleTime
- Create toast notification system (Zustand store + Toaster component)
- Integrate toast into 7 mutation hooks (providers, agents, cron, mcp, etc.)
- Enforce service layer: move all useHttp calls from pages to hooks
- Replace inline SVGs with Lucide icons
- Fix modal mobile support: responsive max-w, grid-cols, padding
- Reduce dialog padding on mobile (p-4 sm:p-6)
- Add responsive grid stacking in agent/provider/custom-tool forms
- Fix trace detail span tree indent and token display on mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add GitHub Actions CI with parallel Go (build/test -race/vet) and Web UI (pnpm build) jobs
- Add Makefile targets: test, vet, check-web, setup, ci
- Fix data race in typing keepalive: remove nil assignment after close(keepaliveDone)
so the goroutine can safely read the channel without holding the mutex
Co-Authored-By: Duc Nguyen <me@vanducng.dev>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Reset RefStore when connection drops to avoid stale DOM node refs
- Add auto-reconnect logic to ListTabs for consistency with getPage
- Remove console from auto-start list (no browser needed for empty msgs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(browser): add remote Chrome sidecar support for Docker deployments
When running in Docker, Chrome is not installed in the runtime image.
This adds support for connecting to a remote Chrome via CDP (Chrome
DevTools Protocol) using a Docker Compose sidecar overlay, following
the existing pattern used by sandbox, OTel, and Tailscale overlays.
Changes:
- Add RemoteURL field to BrowserToolConfig
- Add GOCLAW_BROWSER_REMOTE_URL env var (auto-enables browser tool)
- Browser Manager: remote CDP connection with hostname-to-IP resolution
(required by Chrome M113+ DNS rebinding protection), auto-reconnect
on dead connections, disconnect-only on Stop (sidecar stays alive)
- Auto-start browser on first tool action (no explicit "start" needed)
- Add docker-compose.browser.yml overlay (zenika/alpine-chrome:124)
- Add unit tests for CDP resolution and Manager lifecycle
Usage:
docker compose -f docker-compose.yml -f docker-compose.managed.yml \
-f docker-compose.browser.yml up -d --build
Closes#56
* feat(browser): fix onboard summary and config serialization for remote mode
- onboard.go: show "remote: ws://..." instead of "headless" when RemoteURL is set
- onboard_auto.go: serialize remote_url field in generated config
---------
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Replace the fixed 90s one-shot timer with a 30s periodic ticker so users
see real-time elapsed updates as delegation progresses. Agents that complete
disappear from the list, and notifications stop when all delegations finish.
Also adds taskCtx.Done() listener to prevent goroutine leaks on cancel/stopall.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Revoke paired device now force-closes the active WebSocket connection
via pubsub (EventPairingRevoked → Server.DisconnectByPairing)
- Add group-level pairing policy ("pairing") to Discord, WhatsApp, and
Zalo Personal channels (matching existing Telegram/Feishu pattern)
- Block inactive agents at resolver level (chat, cron, delegation all
reject with "agent is inactive")
- Cascade: setting agent status to "inactive" auto-disables linked
channel instances via EventAgentStatusChanged pubsub
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The memory interceptor handled read_file/write_file for memory paths
but list_files hit the filesystem, returning "Directory does not exist".
Now list_files queries memory_documents from PostgreSQL via the existing
ListDocuments store method.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reorganize layout: System Health full-width grid, 2-column Clients+Cron,
Recent Requests moved above Quota Usage. Extract 8 modules from 768-line
monolith (overview-page.tsx now 212 lines).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>