Commit Graph
840 Commits
Author SHA1 Message Date
viettranx e27c2cc45e fix: add missing MigrateUserDataOnMerge to test stubs
Interface method added in agent-transfer branch was missing from
seedStubStore and createCaptureStore, breaking CI on main.
2026-03-30 11:49:48 +07:00
Thieu Nguyen 82e86bcce1 fix(cron): resolve default agent from DB and fix update payload (#549) (#562)
- 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
2026-03-30 11:45:54 +07:00
viettranx 216b8abac6 fix: Telegram @mention linking + conditional media read prompts
- Convert @mentions to <a href="https://t.me/username"> in HTML formatter
  (Telegram Bot API does NOT auto-link @username in parse_mode: HTML)
- Protect @mentions from italic regex mangling underscored usernames
- Change read_image/read_audio/read_video system prompt from "REQUIRED"
  to conditional — model only reads media when relevant to user's question
- Annotate history media tags so model distinguishes group context images
  from current-turn images
2026-03-30 11:45:33 +07:00
Thieu Nguyenandviettranx e7afa83245 fix: dep_scanner false positive — JS import inside Python f-string (#564)
* fix: skip JS ES module imports in Python string literals during dep scan

dep_scanner falsely matched JS `import mermaid from '...'` inside Python
f-strings as a pip dependency, causing functional skills to be archived.

Add jsFromStringRe check: if a line matching pyImportRe also contains
`from '...'`/`from "..."` (JS ES module pattern), skip it. Valid Python
`import X` never has `from '...'` on the same line.

Closes #544

* fix: add missing stub method + additional edge case tests

- Add MigrateUserDataOnMerge to stubAgentStore in context_file_interceptor_test.go
  (fixes CI build failure — stub was missing new AgentStore interface method)
- Add TestScanFile_MultipleJSImportsInsidePythonString for broader false positive coverage

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 08:37:30 +07:00
viettranx 7f897fe9f5 fix: propagate TenantID in team task dispatch InboundMessage
dispatchTaskToAgent() constructed InboundMessage without TenantID,
causing DB-level MCP servers to be invisible when dispatching team
tasks from the dashboard. Same root cause as #560.
2026-03-30 08:13:36 +07:00
daleandClaude Opus 4.6 7b066b7056 fix: propagate TenantID in channel InboundMessage for tenant-scoped MCP resolution (#561)
All channel handlers (Telegram, Discord, Slack, Feishu) bypassed
BaseChannel.HandleMessage() and manually constructed InboundMessage
without setting TenantID. This caused the consumer to fall back to
MasterTenantID, making DB-level MCP server grants invisible on
non-master tenants while config-file MCP servers worked fine.

Closes #560

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:12:00 +07:00
daleandClaude Opus 4.6 4ac9e01288 fix(secutiry): include tenant ID header in skill upload requests (#558)
The upload() method in http-client.ts was manually building headers
(only Authorization + User-Id), missing X-GoClaw-Tenant-Id. This caused
custom skills to always be created on the Master tenant. Replace with
authHeaders() which includes all required headers.

Closes #557

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:06:13 +07:00
Keithandviettranx 172684a5a7 Add prepare-compose.sh for composable docker-compose (#363)
* Add prepare-compose.sh for composible modules, options and overlays

* feat(prepare-compose): add --quiet and --skip-validation flags

Add loud() function for conditional output. Use --quiet to suppress
normal output, --skip-validation to bypass docker compose config check.

* chore: add mise config to gitignore

* chore: add GOCLAW_DIR env var and update context paths

- Add GOCLAW_DIR to prepare-compose.sh for .env generation
- Fix context paths in docker-compose files to use ${GOCLAW_DIR:-.}
- Restore symlinks in compose.d/ and compose.options/

* fix: broken symlink, safe .env update, export COMPOSE_FILE before validate

- Fix compose.d/00-goclaw.yml symlink: docker-compose.yml → ../docker-compose.yml
- Add compose.d/.gitkeep so directory is tracked
- Export COMPOSE_FILE before running docker compose config validation
- Replace rm+sed .env update pattern with safe temp file approach
- Quote GOCLAW_DIR value in .env to handle paths with spaces

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 08:02:57 +07:00
viettranx 23c227e18d fix(ui): combobox viewport flip, multi-user picker, merge data migration
- fix(ui): combobox dropdown flips above input near viewport bottom using
  bottom-anchored positioning so filtered items shrink upward correctly
- fix(ui): add onSelect callback to Combobox for commit-only events,
  preventing keystroke-adds-badge bug in multi-select mode
- feat(ui): MultiUserPicker shared component for allow/deny user fields
- fix(ui): migrate channel allow_from textarea, team allowed/denied users,
  and config allow_from input to MultiUserPicker with unified search
- fix(ui): remove dead getKnownUsers from use-teams hook
- feat: migrate per-user data on contact merge (context files, overrides,
  profiles, memory) with DO NOTHING conflict strategy — canonical tenant
  user data always wins over newly merged contact data
2026-03-29 23:51:53 +07:00
viettranx 63ed4e9351 fix: filter channel team task events from web UI chat
Admin users were seeing team task notifications from other channels
(Discord, Telegram, Lark) in their web UI chat due to bypassing the
UserID event filter. Added channel check to handleTeamTaskEvent matching
the existing pattern in handleAgentEvent.
2026-03-29 22:37:01 +07:00
viettranx 21b6c454ca feat: merge pipeline, per-user credentials, unified picker, group contacts
- 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
2026-03-29 22:33:17 +07:00
viettranx 4cb6991fc6 fix: default noisy team notifications to off
Disable progress, failed, commented, and slow_tool notifications
by default — these are too verbose for most teams.
2026-03-29 19:41:35 +07:00
Viet Tran db7a34e4f3 feat: standalone Import & Export page with Teams, Agents, Skills & MCP
Refactors Agent Transfer into standalone /import-export page with 3 scope tabs.

Teams: auto-bundle member agents (config, context files, memory, KG, cron, profiles, workspace). 
Agents: section picker with presets, merge mode support.
Skills & MCP: custom skills + MCP server configs (stripped secrets), conflict detection.

Security: scopeClauseAlias for JOINs, tenant scope on all queries, zip bomb protection, adminMiddleware on import routes.
DRY: shared storeExportToken + readTarGzEntries helpers.
i18n: complete en/vi/zh coverage.
2026-03-29 18:01:08 +07:00
Thieu Nguyen 7b42ab04ab fix(desktop): use 127.0.0.1 instead of localhost and suppress lite startup logs (#546)
- 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)
2026-03-29 16:03:09 +07:00
viettranx b59a623649 fix(deps): upgrade major packages across web and desktop UIs
Web UI:
- i18next 25→26, react-i18next 16→17
- lucide-react 0.468→1.7 (no brand icons used)
- tailwind-merge 2→3 (Tailwind CSS 4 compat)
- typescript 5.7→6.0 (remove deprecated baseUrl from tsconfig)

Desktop UI:
- i18next 25→26, react-i18next 16→17
- immer 10→11 (internal perf improvements)
- react-markdown 9→10, react-syntax-highlighter 15→16
- typescript 5.9→6.0
- Fix MarkdownRenderer: wrap ReactMarkdown in div for className (v10 removed prop)

Both: build verified, pnpm audit 0 vulnerabilities
2026-03-29 13:03:39 +07:00
viettranx d803539f1c fix(ui): correct context pruning default toggle state
Backend enables pruning by default (only skips when mode="off"), but
UI showed toggle OFF when no config was saved (null). Also fixed global
config dropdown defaulting to "off" instead of "auto".
2026-03-29 13:00:19 +07:00
viettranx c5cd1ad412 fix(deps): upgrade Vite 6→8, plugin-react 4→6, and patch/minor updates
Desktop + Web UI:
- @vitejs/plugin-react ^4.3.4 → ^6.0.1 (Vite 8 compat)
- vite ^6.0.0 → ^8.0.3 (CVE: Rollup path traversal, Picomatch ReDoS)
- tailwindcss/vite 4.2.0 → 4.2.2, tailwindcss 4.2.0 → 4.2.2

Web UI patch/minor:
- @tanstack/react-query 5.90→5.95, react-router 7.13.0→7.13.2
- recharts 3.8.0→3.8.1, zustand 5.0.11→5.0.12, ws 8.19→8.20
- i18next 25.8→25.10, react-i18next 16.5→16.6, framer-motion 12.34→12.38

Both: pnpm audit reports 0 vulnerabilities
2026-03-29 12:59:04 +07:00
viettranx db41e58319 fix(security): SSRF validation, path hardening, and dependency CVE fixes (#525)
Provider SSRF prevention:
- Add validateProviderURL() blocking internal/private network targets
- Whitelist http/https schemes only (blocks file://, gopher://, etc.)
- Normalize IPv6-mapped IPv4 (::ffff:127.0.0.1) before private IP check
- Validate both api_base and base_url fields on create and update

Path hardening:
- Symlink resolution in DooD workspace resolver (resolve-then-match)
- Strict regex for media ID validation (replaces ad-hoc string checks)

Dependency CVE fixes:
- Upgrade Vite 6→8 (Rollup path traversal, Picomatch ReDoS)
2026-03-29 12:54:12 +07:00
Kai (Tam Nhu) Tran a524b457ba feat(providers): add provider-level Codex pool activity monitor (#539)
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
2026-03-29 12:46:23 +07:00
Kai (Tam Nhu) Tran 789c9613be fix(cron): harden toggle and scheduler state (#540)
- recompute next_run_at transactionally on toggle/update instead of non-atomic read/compute/write
- keep repeated EnableJob(true) idempotent by preserving existing next_run_at
- reject re-enabling expired one-shot at jobs with ErrCronJobNoFutureRun
- claim due jobs conditionally, reload before execution, conditional writeback
- align PG and SQLite behavior with shared helpers (DRY)
- atomic scheduler writeback via single UPDATE with CASE expression

Closes #378
2026-03-29 12:43:19 +07:00
viettranx 2e869f4ece feat(kg): add tsvector FTS, entity deduplication, and embedding fixes
- 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
2026-03-29 12:15:21 +07:00
Luan VuandLuvu182 97f4942943 fix(channels): add display_name to session metadata for Feishu, Zalo, Slack (#536)
Sessions page shows raw IDs instead of sender names because these channels
didn't include display_name in their message metadata. The gateway's
extractSessionMetadata() already looks for this key but it was missing
from Feishu, Zalo Personal, and Slack message payloads.

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-29 11:25:05 +07:00
viettranx a506b297cf fix(i18n): update maxHistoryShare tooltip from 0.75 to 0.85 default 2026-03-29 10:18:27 +07:00
viettranx 3695353de7 refactor(providers): extract Novita defaults into constants and add to desktop UI
DRY: replace hardcoded Novita API base/model across 3 files with
store.NovitaDefaultAPIBase and store.NovitaDefaultModel constants.
Add Novita to desktop frontend provider list.
2026-03-29 10:16:28 +07:00
Alex bd1411028b feat(providers): add Novita AI as new LLM provider (#444)
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
2026-03-29 10:15:14 +07:00
viettranx 0c6cd02285 refactor(compaction): remove minMessages guard, use token-only threshold
Message count-based compaction trigger (default 200) was a legacy safety
net from when token estimation was unreliable. With calibrated overhead
estimation using actual LLM PromptTokens, the token threshold alone is
sufficient — matching industry standard (Claude Code, Anthropic API,
LangChain all use token-only).

Also fixes EstimateTokens vs EstimateHistoryTokens inconsistency in
end-of-run overhead calculation (loop_history.go), and updates stale
CLAUDE.md docs from 75% to 85%.
2026-03-29 10:14:52 +07:00
viettranx db03bf92e0 feat(web): add KG extraction settings to system settings modal and tighten code block spacing
- Knowledge Graph section: provider/model picker + min confidence threshold
- Saves via builtin tools API (knowledge_graph_search settings)
- Reduce code block vertical margin and padding in markdown renderer
2026-03-29 09:24:06 +07:00
viettranx 028ea8a7d8 fix(security): elevate management HTTP routes from Operator to Admin role
Management endpoints (MCP, Agents, Skills, Channels, Builtin Tools)
previously used auto-detect auth which allowed Operator-level users
to perform CRUD operations. Now consistent with WS policy: Admin+
required for writes, Viewer+ for reads.

Also moves WS skills.update to isAdminMethod and improves 403 error
messages to include required role info.
2026-03-29 09:02:48 +07:00
viettranx 8b75e095e9 feat(cancel): add run.cancelled event and fix stop across web UI, desktop, and channels
- Add distinct `run.cancelled` agent event to differentiate user-initiated
  cancellation from real errors (previously both emitted `run.failed`)
- Fix desktop stop button: wire onStop callback to InputBar, add abort()
  function in useChat hook, restore isRunning state on session switch
- Fix web UI: handle run.cancelled without showing error message, preserve
  partial streamed content on cancel
- Fix hanging chat.send promise: send {cancelled: true} OK response instead
  of silently dropping (was hanging 600s until timeout)
- Fix channel stream cleanup: handle run.cancelled for stream stop + run
  context deletion (prevents memory leak) + reaction status clear
- Fix child trace status: cancelled subagent runs now correctly get
  TraceStatusCancelled instead of TraceStatusError
- Add run.cancelled to all event consumers: query invalidation, session
  detail refresh, trace dialog refresh, gateway activity clearing
2026-03-29 09:00:06 +07:00
viettranx 635870acd2 fix(agent): prevent premature compaction by separating overhead from history tokens
Root cause: compaction threshold compared total prompt tokens (including
system prompt, tool definitions, context files) against budget. Sessions
with only 50-60k of conversation could trigger compaction when overhead
pushed total to 120k+.

Changes:
- Enable context pruning by default for all providers (was Anthropic-only)
- Add EstimateHistoryTokens() that excludes system messages from count
- Fix EstimateTokens() to include ToolCall argument sizes
- Calibrate overhead on first LLM response, subtract from threshold checks
- Mid-loop: prune old tool results first (at 70% budget), compact only if
  still over budget after pruning
- maybeSummarize: subtract overhead from calibration base
- Remove applyContextPruningDefaults() (Anthropic-only auto-enable)
- Simplify context pruning UI: show only Keep Last Assistants by default,
  hide advanced params behind collapsible, remove Mode selector
2026-03-29 07:50:00 +07:00
viettranx f8278cfaff fix(mcp): strip placeholder values from optional tool args and guide LLMs on optional params
LLMs often send empty strings, "null", "SHOULD_NOT_BE_HERE" etc. for optional
MCP tool parameters instead of omitting them, causing servers to reject invalid
values (e.g. UUID validation fails on "").

- Add stripEmptyOptionalArgs() to clean optional args before MCP calls
- Detect known placeholders (null/none/nil) and all-caps patterns
- Add system prompt guidance for optional parameter handling
- Empty string "" is intentionally NOT stripped (may be valid for text fields)
2026-03-29 07:48:19 +07:00
viettranx 243656a7b6 feat(mcp): add reconnect button to evict stale MCP connections
When MCP servers update their tools externally, the gateway keeps
stale cached connections. Add POST /v1/mcp/servers/{id}/reconnect
endpoint that evicts the pooled connection, forcing re-discovery
on next agent use. Exposed via reconnect button on both web and
desktop MCP management pages.
2026-03-29 07:15:03 +07:00
viettranx 985d2fa50d fix(heartbeat): log provider override and include in trace tags 2026-03-28 22:55:11 +07:00
viettranx 5c8e0b7af2 fix(heartbeat): apply provider override from heartbeat config
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.
2026-03-28 22:48:27 +07:00
viettranx 175e05287a fix(cache): heartbeat/cron used UUID in session keys causing stale cache after agent update
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
2026-03-28 19:02:53 +07:00
viettranx 3d84e72934 fix(build): filter git describe to exclude desktop lite-v* tags
Add --match "v[0-9]*" so VERSION only picks up server release tags,
preventing lite-v* desktop tags from being used as the build version.
2026-03-28 18:58:39 +07:00
viettranx c70e50c96a fix(tools): harden session tools — phantom sessions, JSON injection, fail-closed checks
- session_status: GetOrCreate → Get to prevent phantom session creation
- sessions_history: replace string concat with json.Marshal (2 paths) to prevent JSON injection
- sessions_send: use s.Label from List() directly (eliminates N+1 Get calls), add self-send protection, use json.Marshal for response
- All tools: fail-closed agentID check (error when empty instead of skipping validation)
- Add 22 unit tests covering all session tools
2026-03-28 18:25:03 +07:00
viettranx 90b7396d74 fix(bus,cron): panic recovery + deadlock fix + unit tests for 9 packages
Bug fixes:
- bus: add panic recovery in Broadcast() — panicking subscriber no longer
  crashes entire event bus goroutine
- cron: fix deadlock in RunJob() — recordRun called while holding mutex,
  extracted recordRunLocked for callers already holding lock
- cron: add run log recording to executeJobByID — automatic scheduler
  was not populating run log, only manual RunJob did

New tests (~170 cases across 9 packages):
- crypto: roundtrip, key derivation (hex/b64/raw), nonce uniqueness,
  backward compat, wrong key, corruption
- permissions: role hierarchy, RoleFromScopes, CanAccess, scope precedence
- bus: pub/sub delivery, buffer full, panic recovery, concurrent safety
- providers/retry: IsRetryableError, backoff, jitter, Retry-After, context
  cancellation, hook callback
- sessions: idempotency, concurrent writes, defensive copy, save/load
  roundtrip, metadata accumulation
- scheduler: draining, drop policies, adaptive throttle, stale completion,
  lane concurrency, debounce, interrupt mode
- config: JSON5 parsing, env overrides, FlexibleStringSlice, owner IDs
- cron: schedule validation, computeNextRun, CRUD, job execution, failure
  tracking, persistence roundtrip
- agent: history sanitization edge cases — all-tool history, partial results,
  cross-turn dedup, orphaned tools, 1000-msg performance
2026-03-28 18:15:46 +07:00
viettranx a7800604b6 fix(web): streaming broken on first chat send due to expectingRunRef race
When sending the first message (no session key), handleSend calls
navigate() then send(). The navigation triggers a session-change effect
that resets expectingRunRef=false before run.started arrives, causing
all streaming events to be silently dropped.

Only reset expectingRunRef when switching between existing sessions,
not on the "" → new-key transition that is part of the send flow.
2026-03-28 18:14:08 +07:00
viettranx 2d344e4f35 fix(tools): block message tool self-send to prevent duplicate media delivery
When a team member creates an image and completes a task, the announce
flow already carries media to the leader agent, which dispatches it to
the channel via ForwardMedia. If the leader also calls the message tool
to send the same image to its own chat, the image appears twice.

Block message tool calls where channel+target match the agent's own
context, returning an error that guides the LLM to include content in
its normal response instead.
2026-03-28 17:35:51 +07:00
viettranx 78253f1841 refactor: decompose consumer, agent loop, team tools, and MCP manager
6-phase pure refactor — zero behavior change, all tests pass.

Phase 1: DRY event payloads + metadata keys
- BuildTaskEventPayload() helper with functional options replaces 24 inline constructions
- 26 metadata string constants replace ~66 magic strings across dispatch/consumer

Phase 2: Consumer handler decomposition
- ConsumerDeps struct collapses 11-13 positional params to 3 per handler
- Extract startTaskLockRenewal() and resolveTeamTaskOutcome()

Phase 3: loop.go extraction (978→686 LOC)
- enrichInputMedia(): media persistence, ref collection, tag enrichment
- injectTeamTaskReminders(): leader/member task context injection
- buildFilteredTools(): policy, bootstrap, channel, iteration filtering
- collectRefsByKind() helper eliminates 3x copy-paste

Phase 4: team_tasks_mutations split (630→318 LOC)
- executeCreate extracted to team_tasks_create.go
- resolveTeamAndTask() helper used by 13 execute* functions

Phase 5: MCP LoadForAgent split (~90→~15 LOC body)
- resolveServerCredentials() + connectAndFilter() helpers

Phase 6: Comments + DI
- 5 inaccurate comments fixed
- ToolExecutor interface for dependency inversion (Loop.tools field)
- FilterTools accepts ToolExecutor instead of concrete *Registry
2026-03-28 17:25:59 +07:00
viettranx 4b6ed8cfce fix(agent): broken cache invalidation + WS handler parity gaps
Root cause: InvalidateAgent() and Remove() used plain agentKey
for cache deletion, but Get() stores with tenant-scoped key
"tenantID:agentKey" — invalidation never matched, so old
provider/model persisted up to 10min (TTL).

Also fixed:
- WS agents.update missing provider, status, context_window,
  max_tool_iterations, frontmatter, is_default, budget fields
- WS agents.create ignoring user provider/model (hardcoded defaults)
- WS channel_instances.update bypassing column allowlist (security)
- HTTP agentAllowedFields missing sandbox_config, context_pruning
2026-03-28 16:55:59 +07:00
viettranx 040ced0a29 fix(desktop): allow scrolling long text in chat input
Change textarea overflow from hidden to auto so users can scroll
through long messages. Align attach/send buttons to bottom.
2026-03-28 15:08:49 +07:00
viettranx 40e32cf239 fix(agent): uniqueness-aware loop detector + auto-fail killed team tasks (#506)
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
2026-03-28 14:53:43 +07:00
Duc Nguyen 8b5a05a4b7 fix(web): sign media_refs paths in session history delivery (#519) (#520)
File downloads in web chat returned 401 when loading session history
because MediaRefs paths were not signed with ?ft= HMAC tokens.

- Add SignMediaPath() to clean legacy corrupted paths (stacked
  /v1/files/ prefixes, stale ?ft= tokens) and produce fresh signed URLs
- Sign MediaRefs in chat.history and sessions.get WS handlers
- Strip ?ft= from filename display in frontend
- Add path traversal defense-in-depth check
- Add unit tests for SignMediaPath legacy data healing

Closes #519
2026-03-28 13:33:25 +07:00
therichardngai-code 6bfad07ed8 fix(docker): restore base capabilities in sandbox overlay (#523)
Sandbox overlay's cap_add replaces (not merges) the base compose, dropping
SETUID, SETGID, CHOWN. This causes credential copy to fail with Permission
denied when combining sandbox + claude-cli overlays.

Changes:
- Re-include base capabilities in sandbox overlay's cap_add
- Use umask 077 for atomic permission-safe credential copy
- Add ENABLE_CLAUDE_CLI build arg to pre-install Claude CLI in image
- Add runtime warning when credentials mounted but CLI binary missing
- Add WITH_CLAUDE_CLI to Makefile for overlay consistency
- Add security warning comment for sandbox overlay attack surface
2026-03-28 13:17:08 +07:00
viettranx 0cfe5800ca feat(web): pre-fill "system" user ID on login form with hint note
Default User ID to "system" and add i18n hint text explaining it
grants full system access, reducing friction for admin login.
2026-03-28 12:57:52 +07:00
viettranx 06ee648392 fix(kg): add 3-tier fallback for traversal + cap output limits
KG traversal only followed outgoing edges, returning empty results for
entities with only incoming relations (e.g. Kuwait had 1 incoming but 0
outgoing). Add 3-tier fallback: (1) outgoing deep traversal, (2) direct
connections via ListRelations (bidirectional, cap 10), (3) search query
fallback. Also cap traversal results at 20 and search relations at 5 per
entity with hints for the model to query further.
2026-03-28 12:19:52 +07:00
viettranx 407b2a3ed3 feat(desktop): add DB reset in About tab + complete onboarding i18n
About tab:
- Show clickable database path that opens data folder
- Add "Reset Database" button with RESET confirmation modal
- Reset deletes DB files and restarts app via RestartApp()
- Add GetDataDir/ResetDatabase Wails bindings

Onboarding i18n:
- Replace all hardcoded English strings in ProviderStep,
  ModelVerifyStep, and AgentStep with t() calls
- Add missing i18n keys to en/vi/zh common.json and desktop.json
2026-03-28 12:03:12 +07:00
viettranx ea60397754 fix(desktop): fix media chain settings not editable on reopen + add drag-drop
- Fix model Combobox permanently disabled on reopen: load models for
  existing chain entries once providers list is fetched
- Add drag-and-drop reordering via @dnd-kit/sortable (matching web UI)
- Use stable UUIDs as React keys instead of array indices
- Show model display names (e.g. "Gemini 2.0 Flash") instead of raw IDs
- Disable Save button when any entry is missing provider or model
- Extract MediaProviderChainForm into its own file
2026-03-28 09:19:00 +07:00