- toFileUrl: normalize backslashes, detect Windows drive-letter paths
- resolveFileUrl: strip MEDIA: prefix from tool results, Windows path support
- handleServe: skip prepending "/" for Windows drive-letter URL paths
Leader-created tasks copied media files to workspace and stored paths
in task metadata, but never inserted into team_task_attachments table.
Members got auto-attached via WorkspaceInterceptor context, but leaders
don't run inside a task context. Now explicitly call AttachFileToTask
after CreateTask succeeds. Dedup handled by ON CONFLICT DO NOTHING.
- Add TeamSettingsModal: editable name/description, member management
(add/remove with minimum 1 member guard), notification toggles (5 events
+ direct/leader mode)
- Extend backend teams.update to support name/description fields
- Add gear button + "+" info button to team board header
- Task detail modal: fetch full detail with attachments on open,
render attachment list with download links (resolved against local gateway)
- Chat view TaskPanel: clicking active tasks opens TaskDetailModal
- KanbanCard: show comment and attachment counts
- Extract 14 shared SVG icons to Icons.tsx, replace all inline SVGs
in team components (0 remaining)
- Extract TERMINAL_STATUSES and TeamNotifyConfig to shared types
- i18n: en/vi/zh settings, members, notification, attachment keys
Non-owner tenant switch set only tenant_hint in localStorage, but WS
Path 1 non-owner and HTTP client only read tenant_id — causing silent
fallback to MasterTenantID.
Frontend: always set TENANT_ID on switch; keep TENANT_HINT for pairing compat.
Backend: WS Path 1 non-owner now falls back to TenantHint before deprecated TenantScope.
When users send media in a group without mentioning the bot, store
Telegram file_ids as lightweight MediaRef in history entries (no
download). When the bot is mentioned, resolve refs by downloading
media and including them in the LLM context.
Safeguards: 5 MB file size cap, max 15 refs per mention, 30s batch
timeout. Mirrors existing CollectMedia pattern from Discord/Zalo.
- fix Rules of Hooks violation in chatgpt-oauth-routing-section
- add stale-while-revalidate with atomic dedup for RouteEligibility
- move raw SQL from HTTP handler to TracingStore.ListCodexPoolSpans
- persist round-robin state in Registry shared counter
- extract duplicated frontend helpers to agent-display-utils
- split oversized frontend files (964→214 lines max)
- add GIN indexes for spans.metadata and sessions.metadata
- fix tenant-aware provider lookup in handleQuota
- separate empty-role vs error handling in resolveTenantHint
- scope pool validation to chatgpt_oauth providers only
- wrap buildEntries in useCallback for stable useMemo deps
- document OAuth concurrent auth limitation and RoleAdmin breaking change
* feat(auth): support named chatgpt oauth providers
- add provider-scoped ChatGPT OAuth routes and CLI support
- persist refresh tokens per provider and reject provider-type collisions
- wire provider OAuth setup flows in the dashboard and setup UI
Refs #448
* feat(agent): add chatgpt oauth account routing
- add agent other_config routing for manual and round-robin selection
- reuse routed provider resolution across resolver and pending loaders
- add router, parser, and agent advanced dialog coverage for multi-account use
Refs #448
* docs(api): describe chatgpt oauth routing
- document named-provider ChatGPT OAuth auth routes
- describe agent-side account routing and round-robin behavior
- update OpenAPI agent config schema and provider type enum
Refs #448
* fix(store): add missing agent key context helpers
* feat(ui): clarify chatgpt oauth account setup and routing
* docs(providers): align chatgpt oauth alias examples
* feat(agent): add codex pool activity dashboard
* fix(providers): harden codex oauth alias setup
* feat(codex-pool): improve routing dashboard UX
- redesign the Codex/OpenAI pool page around saved-pool checkpoints and live evidence
- add clearer selection, attention, and recent-proof states for pool members
- make the lower panels fill the remaining desktop viewport while staying responsive
* fix(store): resolve context helper merge duplication
* feat(oauth): add codex pool quota and observation APIs
- add quota inspection and observation endpoints for ChatGPT Subscription (OAuth) providers
- teach codex routing to surface pool activity, observation metadata, and quota-aware readiness
- extend tests and HTTP docs/OpenAPI for the new pool monitoring flows
* feat(web): add codex pool quota monitor and controls
- add provider quota fetching, readiness badges, and live routing evidence on the account pool page
- redesign pool setup and activity panels for multi-account management with localized copy updates
- keep the live monitor internally scrollable and compact the account cards for better viewport fit
* fix(web): clarify pool routing labels
- rename the recent request badge from Direct to Selected
- restore compact quota bars in the live pool cards
* feat(codex-pool): add runtime health dashboard
- derive per-provider success and failure health from routed Codex traces
- surface routing, quota, and recent request evidence in the pool UI
- align provider alias guidance and owner access with the dashboard role model
* docs(auth): document tenant scoping and key roles
* fix(auth): harden tenant and codex pool access control
* fix(providers): align codex pool runtime defaults
* feat(ui): tighten codex pool responsive layout
* feat(chatgpt-oauth): refine codex pool management UX
* feat(chatgpt-oauth): surface quota bars on provider pages
- add compact quota bars to Codex provider rows and provider detail
- fetch quota only for ready visible provider rows and ready detail aliases
- fix managed-member detail visibility and tighten provider locale copy
* feat(telegram): add yield mention mode for multi-bot group support
- Add "yield" mention_mode: bot responds to all messages unless another
bot is explicitly @mentioned, enabling shared groups where bots coexist
- Skip messages from other bots (user.IsBot) in yield mode to prevent
infinite cross-bot loops
- Enter mention gate for yield mode even when require_mention is false
- Add display_name to channel instance update allowlist
- Change default dev postgres port to 5444 to avoid conflicts
* fix(telegram): address yield mode review — pairing guard, mention check, naming
- Add pairing guard to bot-skip path in yield mode (prevent history
recording in unpaired groups — matches existing security pattern)
- Check detectMention before skipping other bots' messages (allow
cross-bot @commands like "@my_bot help" from another bot)
- Rename hasOtherBotMention → hasOtherMention (function yields on any
@mention, not just bots — name now matches behavior)
- Remove dead MentionMode field from SlackConfig (no Slack handler uses it)
- Add mention_mode validation with warning log for unknown values
* fix(ui): swap mention_mode and require_mention field order
* fix(i18n): add translations for require_mention disabled hint
* fix(ui): apply mention_mode disabled hint to group override tab
* fix(i18n): improve mention_mode UI labels for clarity
Replace developer jargon (Strict/Yield) with user-friendly labels:
- "Mention Mode" → "Group Response Behavior"
- "Strict" → "Default (follow @mention setting)"
- "Yield" → "Multi-bot (respond unless another bot is @mentioned)"
---------
Co-authored-by: viettranx <viettranx@gmail.com>
- executeProgress: early-exit on terminal tasks using pre-fetched status,
check TaskActionFlags before re-querying DB, auto re-assign on stale recovery
- executeComplete: handle already-completed/failed/cancelled gracefully,
auto re-assign pending tasks reset by stale recovery ticker
- Increase taskLockDuration 30min→60min, heartbeat 5min (was 10min)
for 12x safety margin against stale recovery race conditions
- Add diagnostic logging in UpdateTaskProgress when 0 rows affected
runQRFlow stored context.CancelFunc directly in sync.Map and called
CompareAndDelete on cleanup. Function types are not comparable in Go,
causing a runtime panic: "comparing uncomparable type context.CancelFunc".
Wrap CancelFunc in a *cancelEntry struct pointer so sync.Map can compare
by pointer identity. This preserves the original semantics: CompareAndDelete
only removes the entry if it still belongs to the current QR flow, not a
newer retry.
Co-authored-by: Tobi <thinhdev@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Inject WithTenantSlug into both HTTP (enrichContext) and WS (MethodRouter.Handle)
context — previously WithTenantSlug was defined but never called, causing all
non-master tenants to share the same filesystem path (data isolation breach)
- Scope GetNextVersion, GetNextVersionLocked, and CreateSkillManaged version
queries by tenant_id to prevent cross-tenant version collision
- Make advisory lock tenant-aware (hash tenant_id + slug) so different tenants
uploading the same slug don't contend on the same lock
- Add agent tenant_id validation in GrantToAgent to prevent cross-tenant grant
injection
- Fix IsSystemSkill to filter by MasterTenantID only
- Fix StoreMissingDeps to work for both system and custom skills
GetByKey is fail-closed when tenant_id is missing from context, causing
all bot commands that resolve agents (/writers, /addwriter, /removewriter,
/reset, /tasks) to return "no agent" error.
DockerLocalhost() now rewrites both localhost and 127.0.0.1 to
host.docker.internal. Ollama registerInMemory() defaults to
http://localhost:11434/v1 when APIBase is empty, matching startup code.
Closes#470. registerInMemory() skipped Ollama because APIKey was empty.
Add Ollama special case before the key guard (mirrors startup code).
When running in Docker, rewrite localhost → host.docker.internal so the
container can reach the host Ollama instance. Extract InDocker() and
DockerLocalhost() into config/runtime.go for reuse.
Add extra_hosts to docker-compose.yml for Linux compatibility.
MCP tools (mcp_*) are user-defined external integrations where
read-heavy workflows are expected and legitimate. The read-only
streak detector was designed for filesystem tool loops but caught
MCP tools in the default fallback, triggering false positives on
workflows like "query inbox + read 10 emails + summarize."
Treat mcp_* tools as neutral (same as exec/bash) since GoClaw
cannot determine whether an MCP tool is read or write.
Closes#399
* feat(ui): add stop button for running traces on traces page
Allows admins to abort running agent runs directly from the traces page,
useful for stopping channel-originated runs (Telegram, Discord, etc.)
without needing access to the chat page.
* style(ui): match stop button style to chat destructive button
* fix(ui): fix abort response handling and variable declaration order
- Check aborted field from chat.abort response for accurate feedback
- Move useTraces() before handleAbortRun to fix block-scoped variable error
- Add abortNotFound i18n key for when run already finished
* fix(ui): remove invalid pending status check, add cursor-pointer
- Fix cross-scope move in team workspace "All" view (prevented invalid
nested paths by detecting mismatched chat_id scopes)
- Add error toast on move failure instead of silent catch
- Auto-create destination subdirectories on move (os.MkdirAll)
- Add admin bypass for team workspace HTTP auth (matching RPC pattern)
- Clear stale activePath after move in storage page
- Migrate file tree DnD from native HTML5 to @dnd-kit with:
- PointerSensor (distance=8 prevents accidental drags)
- DragOverlay via portal (fixes offset in Radix Dialog)
- Folder auto-expand on 800ms hover during drag
- Silent refresh after move to prevent tree flash/scroll loss
Skills page toggle was calling global /toggle endpoint (master-tenant-only),
returning 403 when owner switched to another tenant. Now uses per-tenant
override endpoints (PUT/DELETE /v1/skills/{id}/tenant-config) when scoped
to non-master tenant, matching builtin-tools page pattern.
- Add tenant_enabled merging to WS skills.list handler
- Add setTenantConfig/deleteTenantConfig to use-skills hook
- Add SkillTenantOverride component with badge + switch + reset
- Fix wrong MasterTenantID constant in both skills and builtin-tools pages
- Add i18n keys for en/vi/zh
- Fix chat layout overflow when TaskPanel sidebar is open by adding min-w-0
to flex containers in AppLayout and ChatPage
- Add conversation-wide image gallery with prev/next navigation (ArrowKeys)
and image counter — collects images from both mediaItems and markdown
- Rename task panel header from "Tasks" to "Running Tasks"
- Add chat.session.status RPC to restore isRunning and activity state on
session switch, preventing lost running indicators
- Add cancelled flag to session restore effect to prevent race conditions
on rapid session switching
- Add ChunkOverlap to MemoryConfig (default 200) for context continuity
at chunk boundaries during semantic search
- Implement overlap logic in ChunkText() with safety clamp at maxChunkLen/2
- Wire per-agent chunk_len/chunk_overlap overrides at IndexDocument time
via RunContext, falling back to global PGMemoryConfig defaults
- Add sync.RWMutex to PGMemoryStore for thread-safe config updates
- Persist chunk settings via system_configs (embedding.max_chunk_len,
embedding.chunk_overlap) with runtime refresh on config change
- Remove dead per-agent embedding_provider/embedding_model fields from
agent Memory UI (system uses single global provider)
- Show Memory section always-visible in agent config (no toggle needed)
- Add chunk_overlap fields to System Settings modal and Config AI Defaults
- Update i18n (en/vi/zh) for all new and removed keys
Screenshots saved to {workspace}/screenshots/, TTS audio to {workspace}/tts/.
Agents can now access these files via read_file. Falls back to os.TempDir()
when workspace is unavailable.
Replace inline workspace path computation in loop_context.go with composable
WorkspaceLayer pipeline (tenant → team → project → user/chat). Each layer is
a pure function that appends a path segment or is a no-op.
- New workspace_resolver.go: ResolveWorkspace, TenantLayer, TeamLayer,
ProjectLayer (future), UserChatLayer, SanitizePathSegment
- 16 unit tests covering all layer combinations
- Migrate loop_context.go, loop_history.go, team_tasks_mutations.go
- Move sanitizePathSegment from agent to tools package (exported)
- Zero behavior change — identical paths for all scenarios
Prevent resource leaks and hanging actions in the browser tool:
- Per-action context timeout (default 30s, configurable via timeoutMs param or config)
- Idle page reaper goroutine closes pages unused for 10min (configurable)
- Max pages per tenant (default 5) with LRU eviction
- RefStore cleanup on page close/evict/reap to prevent memory leaks
Message tool sent raw MEDIA: paths to channels when LLMs embedded them
in multi-line text instead of using standalone prefix. Also added tenant
validation to prevent agents from sending to channels belonging to other
tenants.
- Extract embedded MEDIA: tokens from message text, resolve as media
attachments, strip from visible content (keeps surrounding text)
- Add ChannelTenantChecker callback to validate channel belongs to
calling agent's tenant before any send path
- Add ChannelTenantID() to channel Manager for tenant lookup
- Fix sendMedia() missing ContentType on MediaAttachment
- Fix .docx/.xlsx MIME types to proper OpenXML values
SignFileURLs converts bare /app/workspace/ paths in markdown links to
/v1/files/ URLs so they can be served. File handler uses workspace root
for ft= auth fallback search (no tenant context with signed tokens).
Strip standalone media links from markdown when MediaGallery already
renders the same file (prevents image/file appearing twice). Backend
dedup uses URL-context basename matching to avoid false positives.