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>
- Extract QueryTodaySummary to package-level so quota.usage returns
requestsToday/tokensToday even when QuotaChecker is nil (standalone mode)
- Enrich health RPC: version, uptime, mode, DB ping, tool count,
connected clients list with real IP and connectedAt
- Add handleStatus: sessions count, agentTotal from DB (managed mode)
- Extract client IP from X-Real-IP / X-Forwarded-For during WS upgrade
- Rebuild overview UI: live uptime, System Health panel, Connected Clients
panel, inline channel status with dots, auto-refresh 30s
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
When stream_options.include_usage is enabled, the OpenAI API sends the
final usage chunk with an empty choices array. The streaming parser
skipped chunks with no choices before checking for usage data, causing
token counts to always be 0 in traces.
Fix: extract usage data before the empty-choices skip.
Also fixes two related SSE parsing issues:
- SSE data prefix now handles both "data: " and "data:" (some providers
like Kimi omit the space after the colon, per SSE spec)
- Added scanner.Err() check to surface stream read errors (timeout,
connection reset) instead of silently returning partial results
Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Security: fix cross-agent MCP tool leak by cloning tool registry before MCP registration.
MCP: enforce mcp_ prefix on all tool names, add cache invalidation on server/grant changes,
add grant management endpoints, add group:mcp policy support for per-agent allowlisting.
Skills: persist full YAML frontmatter, auto-promote/demote visibility on grant/revoke,
simplify versioning, handle ZIP wrapper directories, expand tilde in skillsDir path.
Fixes: wrap DeleteSkill cascade in transaction, use atomic NOT EXISTS for revoke-demote,
create cancel context before storing server in map.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add CancelTask store method: guards against completed tasks, unblocks dependents, transitions blocked→pending
- Cancel running delegation when team task is cancelled via CancelByTeamTaskID
- Prevent delegate agents from completing/cancelling tasks directly
- Wire DelegateManager into TeamToolManager for task-delegation lifecycle
- Remove BOOTSTRAP.md from predefined agent seed (predefined agents already have full context)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DelegateAsync creates detached contexts (context.Background()) and runs
outside the scheduler, so /stopall's CancelSession() couldn't reach them.
Now /stopall also calls DelegateManager.CancelForOrigin() to cancel
active delegate tasks matching the origin channel+chatID.
Also silences context.Canceled errors in subagent/delegate announce
handlers to avoid sending spurious error messages after cancellation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add blocked_domains to web_fetch policy (always enforced regardless of allow_all/allowlist mode)
- Refactor domain matching into shared matchDomainList() for allowlist and blocklist
- Enhance server IP scrubbing: register decimal IP, dashed pattern, and reverse DNS hostnames
- Add SOUL.md scope enforcement to delegation ExtraPrompt so agents refuse out-of-scope tasks
- Add blocked domains UI textarea in dashboard tools config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Copy resp.Thinking to assistant message in agent loop so reasoning_content
is actually passed back to thinking models (Kimi, DeepSeek) on multi-turn
- Fix stripGarbledToolXML returning empty string when valid content remains
after stripping XML artifacts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add quota.usage RPC method backed by QuotaChecker.Usage() which queries
per-user request counts (hour/day/week) with resolved limits and today's
aggregate stats. Dashboard now shows summary cards, quota progress bars,
recent requests table, system health, and cron jobs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: TEAM.md instructed LLM to call team_tasks create + spawn
in the "SAME turn", but parallel tool execution caused LLM to
hallucinate task IDs. pendingTasksHint then leaked real task IDs
into error messages, causing cascade failures.
Changes:
- Auto-create team task when spawn is called without team_task_id
(subject from label param, fallback to task description)
- Remove pendingTasksHint() — stop leaking task IDs in error messages
- Update TEAM.md workflow to one-step delegation (just spawn)
- Orphan detection now queries DB for actual pending tasks
- Include team_task_id in spawn tool result for tracing
- Improve in-progress reminder wording
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Part A — Channel quota limiter (managed mode):
- DB-backed per-user/group request quotas with in-memory 60s TTL cache
- Config merge priority: Groups > Channels > Providers > Default
- Per-group quota override via channels.telegram.groups[chatID].quota
- Migration 000009: index on channel_requests for quota queries
- Hot-reload quota config via pub/sub (TopicConfigChanged)
Part B — Per-run tool call budget:
- Soft stop at configurable limit (default 25, per-agent override)
- MaxToolCalls field on AgentDefaults + AgentSpec + LoopConfig
- LLM gets one final call to summarize when budget exceeded
Part C — Web UI + config page refactor:
- QuotaSection with provider/channel dropdowns (useProviders, useChannelInstances)
- Config page refactored to vertical sidebar tabs layout
- Categories: General, Quota, Agents, Tools, Connections, Advanced, Raw Editor
- Fixed config.patch RPC to serialize raw JSON + baseHash correctly
- Config change pub/sub broadcast from handleApply/handlePatch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SSE: handle "data:" without space (Kimi and other providers)
- Add scanner.Err() check to detect stream read failures
- Echo reasoning_content for thinking models (Kimi, DeepSeek)
- Add Thinking field to Message struct for reasoning passback
- Add GOCLAW_OPENAI_BASE_URL env var override (parity with Anthropic)
Progress notifications are now grouped per source agent — one combined
message lists all active delegations instead of spamming per-task.
Agents can set estimated_duration (seconds) when spawning to control
the notification delay (default 90s). Uses dedup via progressSent map.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send a "still working" message to users after 45s if async delegation is
still running, using PublishOutbound directly. Also expand the team task
reminder to include in-progress tasks so lead agents wait for delegates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Override LLM-provided channel ID with context value to prevent
misrouted deliveries (LLM was confusing guild ID with channel ID)
- Send cron reminder message directly instead of agent response
so reminders appear as bot notifications in Discord
* fix(channels): start outbound dispatcher before channel check
StartAll() returned early when no channels existed at boot,
skipping the dispatchOutbound goroutine. Channels loaded later
via Reload() assumed the dispatcher was running, causing outbound
messages (agent responses) to never reach Telegram.
Move dispatcher startup before the empty-channel early return so
dynamically loaded channels always have a running consumer.
* feat(ui): add LLM provider warning on overview page and ignore plans dir
Show alert when no providers configured or all disabled, linking to provider settings. Add plans/ to .gitignore.
* feat(onboard): add provider connectivity verification and placeholder seeding
- Add onboard_verify.go: verify API keys via POST to chat/completions
endpoint (401/403 = fatal, 400/422 = key valid, 5xx = warn)
- Verify all configured providers before seeding in auto-onboard
- Seed disabled placeholder providers (OpenRouter, Synthetic, AliCloud
API/Sub) for UI discoverability after managed data seeding
* fix: use model ID as display name in OpenAI-compatible provider list
The `owned_by` field (e.g. "system") was incorrectly used as the model
display name, causing all models to show as "system" in the UI dropdown
for providers like AliCloud DashScope.
* fix(chat): show all active agents in chat dropdown
Chat agent selector showed "No agents available" because:
- WS agents.list only returned in-memory router cache (empty in managed mode)
- useEffect had stale [ws] dep that never re-fired after connect
Frontend: switch agent-selector from WS to HTTP /v1/agents API with
proper access control (ListAccessible). Backend: add store-backed
agents.list for WS consumers + Router.IsRunning() helper.
* fix(security): prevent agent list leaking on empty userID or store error
- Return error instead of falling through to unfiltered router cache
when userID is empty or DB query fails in managed mode
- Add empty-string guard to isOwnerUser to prevent false owner match
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: ntduc <ntduc@cpp.ai.vn>
Co-authored-by: viettranx <viettranx@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add injectDependencyResults() to auto-inject blocked_by task results
into delegation context, so delegatees receive prior results without
needing to search for them (orchestrator-worker pattern)
- Guard against spawning with completed/cancelled team_task_id to
enforce one-task-per-delegation rule
- Add cross-user scope guard in prepareDelegation() to prevent
cross-group task leak (delegate/system channels bypass by design)
- Track CompletedTaskIDs in DelegateArtifacts and include them in
announce messages so lead agent knows not to reuse completed IDs
- UI: reduce trace detail preview heights for better readability
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add sendMessageDraft transport (disabled pending Telegram client fix for
"reply to deleted message" artifact — tdesktop#10315, bugs.telegram.org/c/561)
- Split stream_mode into dm_stream/group_stream boolean flags (both default false)
- DM messages no longer set reply_to_message_id (cleaner UX, matching TS)
- Progressive placeholder editing for DMs: "Thinking..." → stream chunks → final
- Update web UI with separate DM/Group streaming toggles
fix(agent): prevent false MEDIA: detection in tool output
parseMediaResult() used strings.Index to find "MEDIA:" anywhere in tool output,
causing false positives when external content (e.g. GitHub releases page)
contained commit messages like "return MEDIA: path from screenshot".
Changed to strings.HasPrefix to only match at start of output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tasks from one Telegram group were being injected into another group's
session because the pending-task hint and /tasks command queried all
tasks team-wide without filtering by the group-scoped userID.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add new docs for agent teams (11) and extended thinking (12).
Major rewrite of channels/messaging (05) with Telegram forum topics,
Feishu streaming cards, Zalo Personal. Update providers (02), tools (03),
bootstrap/skills (07), security (09), architecture (00), scheduling (08),
and tracing (10) with current implementation details.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sync delegations inherited the caller's senderID, causing the delegate
agent to check group writer permissions against its own (empty) writer
list instead of bypassing like async delegations do. This resulted in
"permission denied: only file writers can modify files" errors when
delegate agents tried to write files.
Fix: clear senderID from the sync delegation context so it behaves
consistently with async delegations (context.Background has no
senderID). All 4 downstream usages of SenderIDFromContext are
group-writer-related and correctly bypass when senderID is empty.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two improvements to delegation UX:
1. When a delegation fails, the announce now instructs the coordinator
to send a brief friendly message to the user before retrying, so
users aren't left waiting in silence for minutes.
2. When spawn is called with a wrong team_task_id (LLM hallucinated
UUID), the error now includes a list of pending tasks so the model
can self-correct. Also refactored prepareDelegation to resolve team
once instead of 3 separate GetTeamForAgent calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Read limit: maxChars*4 → max(maxChars*10, 512KB) to handle pages with
large <head> sections (WordPress sites often have 30-50KB+ heads)
- Add warning message when HTML extraction returns empty despite non-empty
response body (bot protection, JS-only pages)
- Enable HTTP/2 via ForceAttemptHTTP2 on custom Transport
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LLM models often hallucinate UUIDs when delegating, passing a wrong
team_task_id that doesn't exist. Previously the error was bare
("task not found") with no guidance, causing the model to get stuck.
Now the error includes a list of pending tasks so the model can
self-correct. Also refactored prepareDelegation to resolve team once
instead of 3 separate GetTeamForAgent calls, and extracted
pendingTasksHint() to deduplicate hint-building logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regex-based htmlToMarkdown/htmlToText leaked CSS, JS, and non-content
elements. Replaced with golang.org/x/net/html DOM parser that extracts
<body> only and skips 16 non-content element types (script, style,
noscript, svg, template, iframe, form, nav, footer, etc.).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>