- Add absolute path exemption for dataDir/skills-store/ (fixes skill
scripts using absolute paths like /app/data/skills-store/ being denied)
- Strip surrounding quotes before prefix matching (LLMs often quote paths)
- Reject path traversal ("..") in exempt fields to prevent escape
- Switch from "any field exempt → skip" to per-field matching: only exempt
if ALL fields that match the deny pattern are individually exempt
- Closes pipe/comment bypass vectors where an exempt path in one argument
would exempt the entire command including non-exempt paths
Includes 27 test cases covering: legitimate access, quoted paths,
path traversal, unicode bypass, pipe/comment bypass, mixed args.
* fix(ci): skip CI condition in semantic-release for main branch
go-semantic-release auto-detects the default branch from GitHub API
(which is dev), but releases are cut from main. The CI condition
rejects runs on non-default branches. Use --no-ci to bypass this
check since the workflow already gates on push to main.
* docs: document CI/CD pipelines, release flow, and v2.66.0 changelog
- CLAUDE.md: add CI/CD & Releases section with workflow table, tag
patterns, Docker variants, beta/desktop release commands
- CONTRIBUTING.md: expand Releases section with standard (auto),
beta (manual tag), and desktop release workflows
- docs/17-changelog.md: add v2.66.0 entry covering IDOR fix, BytePlus
provider, per-agent grants, beta pipeline, and CI fixes
* fix(telegram): handle group-to-supergroup migration seamlessly
When a Telegram group upgrades to a supergroup, the chat ID changes and
all existing references become stale. This caused send failures (400),
orphaned sessions, and required manual re-pairing.
Add dual-path migration handling:
- Proactive: intercept inbound MigrateToChatID before isServiceMessage
- Reactive: detect 400 + MigrateToChatID on send, migrate DB, retry
DB migration updates in a single transaction (scoped by tenant + channel):
- paired_devices: sender_id, chat_id
- sessions: session_key, user_id
- channel_contacts: sender_id
- channel_pending_messages: history_key
Also invalidates in-memory caches (approvedGroups, pairingReplySent,
groupHistory) and handles media sends via migration retry in Send().
* feat(providers): add OpenRouter identification headers (#704)
Add HTTP-Referer and X-Title headers to OpenRouter API requests
for rankings and analytics visibility on openrouter.ai.
---------
Co-authored-by: viettranx <viettranx@gmail.com>
chat.history, chat.inject, chat.abort, and chat.session.status accepted
any sessionKey without verifying the caller owns the session. A non-admin
user could read, write, or disrupt another user's conversations by
supplying their sessionKey.
Apply the same requireSessionOwner() guard already used by sessions.*
methods: canSeeAll() bypass for admin/owner, sess.UserID match for
regular users. Extracted shared helper to access.go to reduce duplication.
Also fixes: handleSessionStatus i18n compliance (was hardcoded English),
and closes runId-only abort gap (non-admin must provide sessionKey).
Add BytePlus ModelArk as a new OpenAI-compatible provider for Seed 2.0
models (chat, vision). Two provider types: standard API and Coding Plan
(separate base URLs, same auth).
Integrate Seedream image generation (sync API) and Seedance video
generation (async polling) into the builtin media tool chain, following
the established DashScope/Gemini patterns.
- Add WithAuthPrefix option to OpenAIProvider for future non-standard auth
- Add ProviderBytePlus/ProviderBytePlusCoding store constants and config
- Register provider from config.json and llm_providers DB table
- Add BytePlus to media chain routing, priority lists, and dispatch
- Create create_image_byteplus.go (Seedream, sync response)
- Create create_video_byteplus.go (Seedance, async poll with 5min timeout)
- Add BytePlus to web and desktop UI provider type dropdowns
- Update provider docs with BytePlus entries
Closes#686
Replace agent_id column on secure_cli_binaries with is_global flag
and new secure_cli_agent_grants table for per-agent access control
with optional deny_args, deny_verbose, timeout_seconds, tips overrides.
- Migration 000036: create grants table, migrate agent-specific rows,
dedup binaries, drop agent_id, add is_global
- Store layer: SecureCLIAgentGrantStore interface + PG implementation,
LookupByBinary with LEFT JOIN grant merge, ListForAgent
- HTTP API: CRUD endpoints at /v1/cli-credentials/{id}/agent-grants
- Agent loop: buildCredentialCLIContext uses ListForAgent for scoped
system prompt (agents only see authorized CLIs)
- Web UI: grants dialog with card list + inline form, is_global toggle
replaces agent dropdown, i18n for en/vi/zh
- Write-time normalization via normalizeOllamaAPIBase() on create/update
- Read-time safety net in resolveAPIBase() for pre-existing DB records
- Covers both ProviderOllama and ProviderOllamaCloud
- Stop hardcoding +"/v1" in registerInMemory/startup registration
Closes#654
Post-merge cleanup for #634 channel health diagnostics:
Backend:
- Extract health types, ClassifyChannelError, mergeChannelHealth,
buildRemediation into internal/channels/health.go
- Fix case-true anti-pattern → default in Slack config
- Remove duplicate connection-refused case in ClassifyChannelError
- Remove unused _ bool param from BaseChannel.setHealth
- Fix snapshot.Enabled == false → !snapshot.Enabled
Web UI:
- Extract channel status utilities to channels-status-utils.ts
- Extract ChannelDiagnosticsCard from channel-detail-page.tsx
- Extract ChannelAttentionPanel from system-health-card.tsx
Desktop UI:
- Extract shared getChannelStatusDisplay() to utils/channel-status.ts
- Add explicit stopped state case for visual consistency with web UI
- Add missing vi/zh locale keys for new health status states
* feat: add channel health diagnostics
* fix(channels): harden startup failure reporting
- sanitize operator-facing failure details instead of exposing raw upstream errors
- keep registered channel instances failed during reload/startup errors and clean up pre-registration failure entries
- stop Telegram warning states from reporting running=true after polling or startup failures
* feat(channels-ui): surface actionable health diagnostics
- expand channel and overview views with richer health summaries, remediation hints, and failure history
- refine the channel dashboard layout so diagnostics are easier to scan instead of reading a wall of text
- keep shared web and desktop channel types aligned with the new health payload
* fix(web): harden channel health diagnostics states
- treat enabled channels without backend status as checking instead of stopped\n- align fallback remediation and overview attention synthesis with channel reality\n- localize diagnostics copy and reject invalid channel detail tabs\n\nRefs #628\nRefs #633
* docs(pr-assets): add channel diagnostics visual review pack
Pass threadID and threadType to EnsureContact across all channel integrations:
- Discord, Feishu, Slack, Telegram, WhatsApp, Zalo
- Include General topic in contact collection
- Remove auto-add logic that granted file_writer permission to the first
group/guild member who chatted with the bot
- Add ConfigTypeFileWriter and ConfigTypeHeartbeat constants, replace all
hardcoded config_type strings across callers
- Add bootstrap exception: /addwriter and !addwriter allow first writer
to be added when no writers exist yet
- Optimize writer commands: reuse cached ListFileWriters result for both
permission check and last-writer guard, reducing DB queries per command
- Add freshness directive to file writer system prompt so bot prioritizes
current list over stale references in conversation history
Prevent invalid UTF-8 from being persisted when auto-setting followups by sanitizing message content and truncating by rune count. Add regression tests for emoji truncation and malformed byte sequences.
- New /subagents and /subagent <id> commands for viewing subagent tasks
from the persistent DB table
- Inline keyboard with sa: callback prefix for detail view
- Refactor telegram.New() to functional options pattern (WithAgentStore,
WithTeamStore, WithSubagentTaskStore, WithPendingMessageStore)
- Wire SubagentTaskStore via WithSubagentTaskStore option
- Token cost tracking: accumulate input/output tokens per subagent,
include in announce messages and persist to DB
- Per-edition rate limits: MaxSubagentConcurrent/Depth on Edition struct,
tenant-scoped concurrency enforcement in Spawn/RunSync
- WaitAll action: spawn(action=wait, timeout=N) blocks until all
children complete, returns merged summary
- Auto-retry: configurable MaxRetries (default 2) with linear backoff
for transient LLM failures
- Producer-consumer announce queue: merges staggered subagent results
into single LLM run (same pattern as team task announces)
- Raw metadata in bus messages to prevent double-formatting
- Fire-and-forget DB persistence with detached context + tenant scope
- Split oversized files for <200 line compliance
* feat(reasoning): add capability-aware effort resolution
- resolve requested reasoning levels against exact model capabilities
- persist requested effort on agents and expose effective effort in traces
- add backend tests for provider models, agent store, and resolution logic
Refs #591
* feat(ui): gate reasoning controls by model capabilities
- only show supported reasoning levels when provider model metadata is available
- preserve expert reasoning selections during async model loading
- surface effective reasoning details in trace dialogs and localized copy
Refs #591
* docs(api): document capability-aware reasoning controls
- describe exact-match capability lookup and downgrade behavior
- update provider model metadata and trace response documentation
- refresh the generated OpenAPI spec for the new reasoning fields
Refs #591
* feat: add provider-first reasoning controls
* docs: refresh PR 593 UI evidence callouts
* refactor: deduplicate reasoning normalize functions and remove PR evidence
- Export NormalizeReasoningEffort/NormalizeReasoningFallback from providers
package; store package now delegates instead of duplicating
- Store reasoning fallback constants alias providers canonical definitions
- Export deriveLegacyThinkingLevel from types/provider.ts; remove local
copies from agent-advanced-dialog and provider-overview
- Remove unused _providerType param from useProviderModels hook
- Fix reasoning debug log to fire for all cases with a reason (not just
non-off efforts)
- Remove docs/pr-593-evidence/ binary screenshots from repo
---------
Co-authored-by: viettranx <viettranx@gmail.com>
Port missing group chat style guidance from OpenClaw TS:
- "Write like a human" — prevents robotic/formal GPT responses
- "Avoid Markdown tables" — GPT tends to spam tables in groups
- "Use real line breaks sparingly"
These instructions exist in OpenClaw TS (groups.ts buildGroupIntro)
but were missing in GoClaw's group prompt.
- Reject incompatible explicit provider embedding dimensions on create/update
- Ignore previously saved incompatible dimensions at runtime, fall back to 1536
- Share RequiredMemoryEmbeddingDimensions constant from store package
- Remove dimensions input from provider UI (always 1536 per pgvector schema)
- Add HTTP, runtime, and validation unit tests
Closes#548
Supersedes #410
Two fixes:
1. Remove assistant prefill from team task reminders. The injected
[user]+[assistant]+[user] pattern caused LLMs to treat the canned
ack as "turn complete", returning NO_REPLY for every user message
in group sessions with active tasks. Reminders are now merged into
the user message as prefix tags.
2. Add PeerKind propagation to team notification routing. TaskTicker
and progress notifications were missing PeerKind on InboundMessage,
causing them to route to phantom DM sessions instead of the correct
group session. PeerKind is now carried through event payloads,
notify queue metadata, and all inbound message publications.
Extract wake_heartbeat and stateless from JSON payload into first-class
columns on cron_jobs. Adds migration 000033 with backfill from existing
payload data. Updates PG + SQLite stores, RPC handlers, and UI i18n.
- loop.go: replace blocking range with select+ctx.Done() for parallel tool collection;
document finalization trade-off on early cancel
- loop_cancel_test.go: tests for context cancellation and normal completion paths
- gateway_consumer_post_turn.go: always auto-complete team task in default case,
fallback message when outcome.Result is nil
- gateway.go: call sched.Stop() with 5s drain before context cancel on shutdown
- anthropic_stream.go: check ctx.Err() in scanner loop, bounds check toolCallJSON index,
accumulate signature_delta events into ThinkingSignature
- anthropic_request.go: include signature field in buildRawBlock for thinking blocks
- types.go: add ThinkingSignature field to ChatResponse
- loop_run.go: nil guard on result before FinishTrace access
- gateway.go: defensive ApplyDBSecrets before setupTTS in config reload subscriber
Add env var support for gateway.allowed_origins so container deployments
can set CORS origins reliably even if config file is overwritten by UI
save cycles. Follows same pattern as GOCLAW_OWNER_IDS.
- Backend: resolve real default agent UUID from DB when cron job has no
agent_id, instead of using literal "default" string that fails lookup
- UI: replace free-text agent input with dropdown in create form
- UI: wrap update params in `patch` object matching backend expectation
- UI: send empty string for agentId to explicitly clear agent selection
- UI: add name attribute to Select elements to fix form field warning
- Enable merge UI for linking channel contacts to tenant_users
- Contact → tenant_user resolution with cached lookup (60s TTL)
- MCP per-user credentials via user-keyed connection pool
- Secure CLI per-user credentials with AES-256-GCM encryption
- Unified UserPickerCombobox searching contacts + tenant_users
- Group contact collection with chat title in all channels
- Group permission inheritance via wildcard user_id="*"
- Fix heartbeat using wrong userID in group chats
- Filter internal senders from contact collection
- Add contact_type column (user/group) to channel_contacts
- SQLite schema v2 migration for desktop edition
- GetGatewayURL/IsGatewayReady: use 127.0.0.1 to avoid WebKit resolving
localhost to ::1 (IPv6) when gateway only binds IPv4, causing "Load failed"
- Skip CORS warning for lite edition (localhost-only, no production exposure)
- Skip server IP detection for lite edition (no multi-tenant risk, avoids
leaking user's public IP in logs and unnecessary network calls)
Add provider-scoped runtime monitor for Codex pool owners:
- New `GET /v1/providers/{id}/codex-pool-activity` endpoint aggregates pool health across all agents
- New Pool Activity section on provider detail page (pool owners only)
- Shows aggregate member health, recent requests, top agents with drill-down links
- 7-day time window on provider-scoped span query for performance
- Reuses `buildCodexPoolActivity()` — zero duplicated aggregation logic
- i18n complete (en/vi/zh), accessible markup
Closes#499
- Replace ILIKE search with PostgreSQL tsvector/GIN full-text search
for KG entities (migration 000031)
- Add entity deduplication system with dual-threshold strategy:
auto-merge at 0.98+ similarity with Jaro-Winkler name match,
flag 0.90-0.98 as candidates for manual review
- Add ScanDuplicates for bulk on-demand duplicate detection
- Add MergeEntities with advisory lock and tenant-scoped relation
re-pointing (delete-then-update to avoid ON CONFLICT on UPDATE)
- Wire dedup inline after KG extraction pipeline
- Fix BackfillKGEmbeddings: was failing silently due to
context.Background() missing tenant_id; now runs cross-tenant
- Fix BackfillKGEmbeddings: break on error → continue with failed
ID tracking and max consecutive error cap
- Add EmbedEntity helper; UpsertEntity now generates embeddings
in background goroutine
- Add HTTP endpoints: POST /kg/dedup/scan, GET /kg/dedup,
POST /kg/merge, POST /kg/dedup/dismiss
- Add web UI: Dedup dialog with Scan All button, side-by-side
entity comparison, merge/dismiss actions
- Add Jaro-Winkler similarity algorithm with 34 unit tests
- Update IngestExtraction to return upserted entity IDs
- Bump RequiredSchemaVersion to 31
DRY: replace hardcoded Novita API base/model across 3 files with
store.NovitaDefaultAPIBase and store.NovitaDefaultModel constants.
Add Novita to desktop frontend provider list.
Add Novita AI as a new LLM provider with OpenAI-compatible API endpoint.
- Add ProviderNovita constant and valid type entry
- Add Novita to ProvidersConfig with APIBaseForType and HasAnyProvider
- Register Novita provider in gateway startup (config and DB paths)
- Add Novita case in HTTP handler's registerInMemory
- Add Novita to UI provider selection dropdown
Default model: moonshotai/kimi-k2.5
Default endpoint: https://api.novita.ai/openai
Heartbeat's ProviderID was stored in DB but never used during execution —
the agent's default provider always won. Add ProviderOverride to RunRequest,
resolve hb.ProviderID in the ticker, and use the override in the agent loop.
Session keys must use agentKey (human-readable, e.g. "default") not UUID.
Cache invalidation via InvalidateAgent(agentKey) only matches agentKey suffix,
so UUID-keyed entries were never cleared — causing stale provider/model after
agent updates from the web UI.
- heartbeat: use agentKey (already resolved) instead of UUID for session key
and HasActiveSessionsForAgent check
- cron: resolve agentKey from UUID via agentStore before building session key
- agents_update: also invalidate by UUID as safety net for legacy entries
- startup migration: auto-fix existing UUID-based session keys in DB
- tests: 7 new tests covering session key format and cache invalidation
Read-only streak detector was a dumb counter that killed agents exploring
unique files (12 reads = kill regardless of uniqueness). Team tasks were
then falsely auto-completed with the kill message as "result."
Changes:
- Add uniqueness ratio to read-only streak: exploration mode (>60% unique)
uses relaxed thresholds (warn=24, kill=36) vs stuck mode (warn=8, kill=12)
- Classify team_tasks by action: list/get/search=read-only, progress=neutral,
create/complete/cancel/comment/etc.=mutating
- Add LoopKilled flag to RunResult, propagated through all 3 kill paths
- Consumer routes LoopKilled to FailTask (not CompleteTask) with clear signal
- 40 tests covering uniqueness detection, team_tasks classification,
exact #506 trace replay, boundary values, and edge cases
Root cause: pool.go applied busy_timeout PRAGMA via db.Exec() which only
affects one connection in the pool. Other connections had no busy_timeout,
causing immediate SQLITE_BUSY errors during concurrent startup operations
(agent creation, WebSocket connect, health checks). This silently aborted
context file seeding — BOOTSTRAP.md, USER.md, AGENTS.md all missing from
system prompt on first interaction.
Fix (3 layers):
1. pragmaConnector: wraps sql.Driver to apply PRAGMAs (busy_timeout, WAL,
etc.) on every new connection, not just one. All SQLite queries benefit.
2. CacheInvalidateFunc: clears ContextFileInterceptor cache after seeding
so LoadContextFiles sees newly seeded files on the first turn.
3. fallbackBootstrap: if DB seed still fails, injects embedded templates
in-memory so the first turn still gets onboarding. Clears after use.
Team members dispatched via team tasks can now read the leader's memory
files (MEMORY.md, memory/*.md) as a fallback when they have no own
memory. Memory writes are blocked for members — only the leader can
save memory files. This follows the existing team_workspace context
propagation pattern: dispatch metadata → RunRequest → context → tools.
Affected tools: read_file (interceptor), memory_get, memory_search,
list_files (interceptor). All include leader fallback with per-user →
global scope cascade.
- Add filteredToolNamesForChannel() so system prompt Tooling section
excludes channel-specific tools for wrong channels (e.g. list_group_members
hidden for Telegram, create_forum_topic hidden for Feishu)
- Add ChannelAware interface to CreateForumTopicTool (Telegram-only)
- Add coreToolSummaries for list_group_members and create_forum_topic
(were showing as "(custom tool)")
- Inject group chat title into system prompt identity line
(e.g. "telegram (group chat \"My Group\")" instead of "a group chat")
- Sanitize ChatTitle to prevent prompt injection (strip quotes/newlines,
truncate to 100 chars)
SetOnRequest was only wired for PGPairingStore via concrete type assertion.
Use interface-based assertion so SQLitePairingStore also gets the callback.
This fixes desktop app not receiving real-time pairing request notifications.
- Split EnsureUserFilesFunc into EnsureUserProfileFunc (profile + workspace)
and SeedUserFilesFunc (context file seeding) for single-responsibility
- Merge userWorkspaces + userFilesSeeded sync.Maps into unified userSetups
struct to prevent desync between workspace and seeding state
- Add skipIfAnyExist param to SeedUserFiles to encapsulate the
"seed only for brand-new users" logic within the bootstrap package
- Extract getOrCreateUserSetup helper for clean per-user initialization
- Add bootstrap state tests covering all 4 system prompt branches
- Keep legacy EnsureUserFilesFunc as fallback for backward compatibility
- Separate file seeding from workspace resolution so agents without
workspace still get BOOTSTRAP.md and USER.md seeded
- Always seed context files for existing profiles that have zero files
(handles EnsureUserProfile pre-creation via HTTP API)
- Add persistent "USER PROFILE INCOMPLETE" nudge in system prompt when
BOOTSTRAP.md is cleaned up but USER.md remains blank
- Move bootstrap auto-cleanup nudge before session flush so the reminder
is persisted to history
- Add userFilesSeeded sync.Map to avoid redundant seeding calls
- Capture workspace from seeding call to eliminate double DB roundtrip
The case expression `taskActionFlags.Progressed || ...` always evaluates
to `true/false`, never matching the switch value. Merge it into the
default branch so non-terminal actions consistently auto-complete.
- 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
- 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