Commit Graph
510 Commits
Author SHA1 Message Date
viettranx c636dde54e fix(delegation): scope sibling counting by origin conversation
Delegations from different channels/chats sharing the same source agent
were incorrectly treated as siblings. This caused cross-session artifact
accumulation: media from a Telegram delegation could be routed to WS
and vice versa, with the first-completing delegation's announce being
suppressed entirely.

Add originKey() (sourceAgentID:channel:chatID) to DelegationTask and
use it for ListActiveForOrigin, accumulateArtifacts, collectArtifacts.
2026-03-07 23:32:35 +07:00
viettranx 27f2c0d80a fix(delegation): auto-fail team task when async delegation fails
When an async delegation failed, the team task stayed in_progress
forever because only the success path called autoCompleteTeamTask().
Now autoFailTeamTask() marks the team task as failed, stores the
error message, unblocks dependents, and logs an audit trail message.
2026-03-07 23:20:01 +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 df684e2582 refactor(security): fix false positives and deduplicate web security hardening
- Fix opacity/font-size zero detection false positives (0.5, 0.8 matched as zero)
- Extract scanWebToolResult helper to eliminate DRY violation in agent loop
- Move hidden element detection to dedicated web_fetch_hidden.go file
- Replace map false-entries with comments for hiddenClasses documentation
2026-03-07 19:35:19 +07:00
b901a82551 fix(security): harden web fetch/search against prompt injection and cache poisoning (#80)
- Scan web_fetch/web_search tool results for prompt injection patterns via inputGuard
- Strip hidden HTML elements (display:none, aria-hidden, sr-only classes) during conversion
- Scope web tool caches per channel to prevent cross-channel cache poisoning
- Enforce domain blocklist and allowlist checks on HTTP redirect targets
- Add untrusted content reminder to external content wrapper
- Log redirect source URL in fetch results for transparency

Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
2026-03-07 19:31:56 +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 7ea27c4c16 fix(ui): align chat send button and widen team members table
- Chat: change send/stop buttons from size-icon (36px) to size-icon-lg
  (40px) to match textarea height with py-3 padding
- Teams: remove max-w-2xl on members tab to fill parent width
2026-03-07 19:15:00 +07:00
viettranx d850467175 fix(ui): eliminate loading flicker on page refresh
Root cause: ws object is a stable ref — useCallback deps never changed
when WS connected, so useEffect never re-fired to fetch data.

Fix: subscribe to reactive `connected` state from auth store in all
data-loading hooks. For manual hooks, add connected to useCallback deps
and initialize loading=true. For TanStack Query hooks, add
enabled: connected and use isPending (true while disabled with no cache).

Detail pages now use DetailPageSkeleton matching final layout shape
instead of DeferredSpinner to prevent layout shift.
2026-03-07 19:14:47 +07:00
viettranx 2bebe76439 feat(ui): require typed confirmation for critical entity deletion
Add ConfirmDeleteDialog component that requires typing the entity name
to confirm deletion, preventing accidental misclicks. Applied to agents,
teams, providers, MCP servers, channels, and skills. Remove redundant
agent danger tab (delete button in header is sufficient).
2026-03-07 19:14:32 +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 f747133155 fix(ui): default Telegram reaction level to full 2026-03-07 15:51:41 +07:00
viettranx 13dc762432 fix(ui): default channel policies to pairing for secure-by-default
Changed group_policy and dm_policy defaults from "open" to "pairing"
for telegram, discord, feishu, and whatsapp channel creation forms.
2026-03-07 15:27:01 +07:00
viettranx 6a82381b13 fix(channels): coerce string booleans in channel instance config
Older UI versions saved select-based bool fields (block_reply, etc.)
as strings ("true"/"false") instead of JSON booleans. This caused
json.Unmarshal to fail when loading channel instances. Normalize
config in loadInstance before passing to factories.
2026-03-07 15:20:43 +07:00
viettranx 5176716ba1 fix(mcp): encrypt headers/env on server update
UpdateServer type-asserted json.RawMessage but json.Decoder into
map[string]interface{} produces map[string]interface{} for nested
objects — so the assertion always failed and encryption was silently
skipped. Marshal any type to []byte before encrypting.
2026-03-07 15:13:54 +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
viettranx 8efa34fff7 feat(chat): show tool calls with expandable arguments in message history
Render tool-call-only assistant messages as compact cards with wrench
icon instead of empty bubbles. Click to expand and view tool arguments
as formatted JSON. Make thinking block full-width in chat thread.
2026-03-07 14:55:19 +07:00
viettranx 612d9fa965 style(ui): reduce focus ring width and fix dialog overflow clipping
Reduce ring-[3px] to ring-2 on Input and ToolNameSelect for a subtler
focus indicator. Add px-0.5 -mx-0.5 to scrollable form dialog bodies
so the focus ring is not clipped by overflow-y-auto.
2026-03-07 14:55:14 +07:00
viettranx 009df13fe8 fix(chat): extract agentId from session key when resuming sessions
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.
2026-03-07 14:40:19 +07:00
Duc NguyenandGitHub 84113cff2f fix(channels): fix Zalo personal group pairing bypass and reply thread type (#76)
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.
2026-03-07 07:12:47 +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 39e906e5d4 fix(summoner): increase single-call timeout to 300s
Some models (e.g. Kimi deep reasoning) need 160s+, 120s was too aggressive.
2026-03-07 01:29:41 +07:00
viettranx e6e582e9eb refactor(summoner): optimistic single-call with 2-call fallback
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
2026-03-07 01:28:29 +07:00
viettranx f7a3360ff7 style: Update --destructive-foreground CSS variable to a new oklch color value. 2026-03-07 01:15:24 +07:00
Songlin YangandGitHub fadc9377f9 fix(ut): remove legacy function TestSeedUserFiles_PredefinedAgent_BootstrapUsesCorrectTemplate (#67) 2026-03-07 01:11:52 +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
Luan VuandGitHub 7d744eb4f2 refactor(oauth): DB-backed token storage, split codex.go, remove file-based artifacts (#65)
Replace file-based OAuth token storage with DB-backed storage using
llm_providers (access token) + config_secrets (refresh token).

- Store: Add Settings JSONB field, chatgpt_oauth provider type
- OAuth: DBTokenSource backed by provider + secrets stores
- HTTP: oauth.go uses DB stores + registers provider in-memory
- Providers: chatgpt_oauth support in registerInMemory/registerProvidersFromDB
- Config: Remove HasOAuthToken, revert envFallback→envStr
- CLI: auth commands call HTTP API on running gateway
- Split codex.go (478→189 LOC) into codex.go + codex_build.go + codex_types.go
- Frontend: Remove fake OAUTH_PROVIDER_ID, use real DB-backed providers
- Tests: Rewrite with mock stores, fix SSE mock servers
2026-03-07 00:15:30 +07:00
viettranx 519ecd1eac fix(zalo): address PR #62 review findings — security, reliability, modularity
- 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)
2026-03-06 23:21:16 +07:00
Luan VuandGitHub 95885da14e feat(zalo): add file and image upload/send support (#62)
## Summary
- Implement UploadImage, SendImage, UploadFile, SendFile in Zalo Personal protocol
- Handle WebSocket control events (cmd=601) for async file upload callbacks
- Add media attachment routing in channel.Send() — auto-detects image vs file
- Add MEDIA: prefix support in message tool for agent file attachments
- Add group_id metadata routing for correct Zalo group API selection

## Review fixes (dc475bc)
- Fix CI: %s for json.Number (was %d)
- Fix path traversal: parseMediaPath restricted to os.TempDir()
- Add 25MB file size limit before upload reads
- Drain stale uploadCallbacks on Listener.reset()
- Split send.go (688 LOC) into send.go, send_image.go, send_file.go, send_helpers.go
- Add 12 unit tests for parseMediaPath
2026-03-06 23:20:50 +07:00
viettranx d35046a224 fix(ui): set is_default on setup agent creation and unify workspace path
- Pass is_default: true when creating agent in setup wizard
- Remove special workspace path for default agents, always use {key}-workspace
2026-03-06 23:01:13 +07:00
1ebbe53093 fix(ui): add missing delete buttons for agents and teams (#63)
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>
2026-03-06 22:56:40 +07:00
Viet TranandGitHub 6041c683cb fix(summoner): sequential file generation with progress + HTTP timeout (#74)
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.
2026-03-06 22:39:33 +07:00
Viet TranandGitHub 66b0de0ac2 fix(ui): add tooltip explaining predefined-only team members (#73)
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.
2026-03-06 22:39:25 +07:00
Viet TranandGitHub 3dcbc72ddd fix(openai): increase SSE scanner buffer to 1MB and remove duplicate error check (#72)
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.
2026-03-06 22:39:21 +07:00
viettranx a7dcefde95 refactor: keep only Tiểu Hồ, Tiểu La, Mễ Mễ predefined agent presets 2026-03-06 19:51:48 +07:00
viettranx e0da99d150 feat: enhance log tailing with attrs, redaction, ring buffer, level control and persistent UI
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.
2026-03-06 19:41:49 +07:00
viettranx c5127733a0 feat: Implement real-time pending pairing request count and notifications in the UI, backed by WebSocket event broadcasting. 2026-03-06 19:31:59 +07:00
Viet TranandGitHub 6895e369f6 refactor: remove standalone mode, consolidate to managed-only (PostgreSQL) (#70)
- Remove standalone mode code: file-based stores, standalone gateway,
  heartbeat service, SQLite memory, standalone docker-compose
- Rename docker-compose.managed.yml → docker-compose.postgres.yml
- Clean up ~130 Go comments referencing "managed mode" qualifier
- Simplify docker-compose.yml env vars (providers/channels via web UI)
- Update .env.example to essential vars only (token + encryption key)
- Add setup wizard UI (provider → agent → channel bootstrap flow)
- Add logs.tail WebSocket handler for live log streaming
- Add cursor-pointer to interactive UI components
- Clean up config page (remove standalone-only sections)
- Update README and docs for managed-only architecture
2026-03-06 18:51:11 +07:00
viettranx 0f44f18b0c feat: Introduce .repomixignore for repomix-specific exclusions and update .gitignore to include release-manifest.json. 2026-03-06 14:42:06 +07:00
viettranxandClaude Opus 4.6 d49596a805 feat: Add USER_PREDEFINED.md for predefined agents with token count sidebar
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>
2026-03-06 12:27:43 +07:00
viettranx 4e7d55ff37 feat: Add user and chat ID filtering to the events page and store event user/chat IDs. 2026-03-05 19:43:18 +07:00
viettranx c8cd63dbe8 feat: Deny team_message tool for team leads and update string truncation to handle Unicode characters. 2026-03-05 19:24:35 +07:00
viettranxandClaude Opus 4.6 8862842b46 feat: add runKind field to differentiate delegation/announce runs from user-initiated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:59:51 +07:00
viettranxandClaude Opus 4.6 5664135c8a enhance: channel-aware identity line, remove model leak from system prompt
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>
2026-03-05 18:59:29 +07:00
viettranxandClaude Opus 4.6 5a4d40f458 enhance: rewrite AGENTS.md for managed mode, add Style section to SOUL.md
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>
2026-03-05 18:33:23 +07:00
viettranx 99cab86373 fix: Simplify config leak detection to a single gate, triggering on 3+ distinct internal file name mentions without requiring list patterns. 2026-03-05 18:17:20 +07:00