Commit Graph
863 Commits
Author SHA1 Message Date
Kai (Tam Nhu) Tran 3fe0633d35 fix: auto-install deps on skill upload before archiving (#559)
Upload handler previously archived skills immediately when deps were
missing. Now calls InstallDeps() first (owner/master tenant only) and
falls back to archive on failure.

Changes:
- Auto-install missing deps during skill upload (same flow as seeder)
- Atomic DB persist: deps state written with CreateSkillManaged in one call
- Per-slug upload mutex prevents concurrent race conditions
- Frontend: warning state (amber triangle) instead of throwing error
- Non-cancellable context for DB write after dep install
- SQLite StoreMissingDeps now works for custom skills (not just system)
- Comprehensive unit + integration tests

Closes #468
2026-03-30 21:58:29 +07:00
Kai (Tam Nhu) Tran 4c60dd021e fix: clarify container-scoped runtime warnings for minimal images (#395)
* fix(ui): clarify container-scoped runtime warnings

* docs(runtime): clarify docker image variant expectations

* test(tools): align media path expectations with workspace policy

* docs(tests): narrow message media path contract wording
2026-03-30 21:44:53 +07:00
Kai (Tam Nhu) Tran 65d0d62acf fix(memory): guard provider embedding dimensions to 1536 schema (#563)
- 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
2026-03-30 21:36:09 +07:00
viettranx 53932cf532 fix(channels): include display name in [From:] annotation for Telegram and WhatsApp
Telegram: senderLabel now includes full name alongside username, e.g.
[From: @nguyennlt (Nguyễn Trần)] instead of just [From: @nguyennlt].
Also uses FirstName + LastName when no username is set.

WhatsApp: add missing [From:] annotation — was the only channel not
annotating sender identity for the LLM.
2026-03-30 21:24:39 +07:00
teexiii b38a078e70 fix(tools): delivered media tracker prevents duplicate file delivery (#579)
Replace naive HasPrefix("MEDIA:") self-send bypass with context-based
DeliveredMedia tracker (PendingTeamDispatch pattern).

write_file(deliver=true) marks paths → message self-send guard checks:
- Already delivered → blocked (no duplicate)
- Not delivered → allowed (fixes runaway retry loop)

Adds 8 test cases for self-send guard + tracker.
2026-03-30 21:13:27 +07:00
teexiii 88a5793030 fix(agents): sync IDENTITY.md Name field on agent rename (#582)
## Summary

- Agent rename now updates Name field in IDENTITY.md (agent-level + per-user copies for open agents) via both HTTP and WS paths
- Fixes lossy identity rebuild: previous logic reconstructed IDENTITY.md from only Name/Emoji/Avatar, silently dropping LLM-written fields (Creature, Purpose, Vibe, etc.)
- Uses targeted field replacement (bootstrap.UpdateIdentityField) preserving original formatting
- Adds ListUserContextFilesByName to AgentContextStore (PG + SQLite)
- Fixes LastIndex bug in UpdateIdentityField where values containing colons (e.g. Avatar URLs) would break field replacement
- Removes ~335 lines of dead config.json fallback code (agentStore is always set)
- Adds 9 unit tests for UpdateIdentityField covering plain/markdown formats, URLs, edge cases
2026-03-30 20:56:49 +07:00
Plateau Nguyenandviettranx 0e2db21345 fix(cron+providers): Run Now stuck fix, type safety, and claude-cli image format (#577, #568) (#580)
* fix(cron): Run Now executes correctly and reset stale running status (#568)

- PG store RunJob now sets next_run_at = NULL before executeOneJob so
  loadClaimedJob (which requires next_run_at IS NULL) succeeds instead
  of silently skipping the forced run
- recomputeStaleJobs on startup resets last_status 'running' → 'interrupted'
  for jobs that were mid-execution when the server crashed
- UI: add typed CronJobPatch interface matching backend store.CronJobPatch
  (deliverChannel/deliverTo/stateless) — replaces Record<string, unknown>
  on updateJob and onUpdate props across cron detail components
- UI: fix enabled/disabled label in overview tab to reflect local state
  instead of stale job prop

* fix(cron): add error handling for ExecContext calls per code review

- RunJob: return error if claiming job (next_run_at = NULL update) fails
  instead of silently proceeding to executeOneJob which would then skip
- recomputeStaleJobs: log warning on failure, log count of reset jobs
- Add log/slog import to cron_exec.go

* fix(providers): claude-cli ChatSync image format mismatch (#577)

When images are present, Chat() now uses stream-json output format to
match the stream-json input format required by Claude CLI >= v2.1.87.

Also adds concurrent execution guard to RunJob() preventing
double-execution when Run Now is clicked rapidly.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-30 20:37:49 +07:00
therichardngai-code 0ef30ad060 fix(ui): reduce KG graph INP from 808ms to <100ms (#581)
- Defer dialog open via setTimeout(0) on node click — decouples edge
  restyle from dialog mount (808ms → <100ms INP)
- Memoize relations table with React.memo + limit initial render to 50
  rows with "Show all" button (792ms table cell INP → <100ms)
- Added i18n key kg.entity.showAll for en/vi/zh

Based on upstream review fixes (989e4f3).
2026-03-30 20:21:48 +07:00
viettranx 989e4f3123 fix(ui): KG graph review fixes — edge colors, fetch limit, double fitView
- Fix hardcoded dark edge color on deselect — use neutral #64748b
- Reduce graph fetch limit 200→50 to match component render cap
- Fix O(n*m) node lookup on theme change — use Map for O(1)
- Remove double fitView (prop + manual call)
2026-03-30 16:53:14 +07:00
viettranx 88f4fa264a fix(ui): KG graph perf + theme support + entity limit
- Limit graph to 50 entities for smooth DOM-based rendering
- Dual-theme node colors (light: solid bg/dark text, dark: translucent/light)
- Follow user theme via colorMode (no hardcoded dark)
- Theme change updates node colors without re-layout or fitView
- Remove MiniMap, backdrop-filter blur, translateZ GPU layers
- Thicker edges (strokeWidth 2, opacity 0.6) for visibility
- Simplified footer: entity/relation counts + limit note
- memo EntityNode to prevent re-render during pan/zoom
- i18n: add limitNote/limitHint keys (en/vi/zh)
2026-03-30 16:46:25 +07:00
viettranx 1cb7d3cb70 perf(ui): optimize KG graph view for large graphs
- Add KGEdgeData interface replacing `as any` casts for type safety
- Use entityMap (useMemo Map) for O(1) entity lookup instead of O(n) find
- Pre-compute EDGE_STYLE_DEFAULT/FADED constants to reduce GC pressure
- Skip edge object recreation when style unchanged during selection
- Wrap EntityNode in memo() with memoized container style
- Cap force simulation ticks at 200 for graphs with 100+ nodes
2026-03-30 15:54:34 +07:00
therichardngai-code 540fc5e99b feat(ui): enhance knowledge graph with depth visualization and performance fixes (#572)
- Dark canvas with atmospheric radial gradient for depth effect
- Pill-shaped nodes with frosted glass, glow on hub nodes (4+ connections)
- Mass hierarchy in d3-force: org/project anchor center, tasks orbit out
- Degree centrality sizing: more connections = larger node
- Edge labels hidden by default, revealed on node selection with animation
- Deferred force layout via setTimeout(0) — toggle INP: 920ms → ~100ms
- useTransition for node clicks — edge restyle INP: 568ms → 160ms
- Disabled nodesConnectable + pointerEvents:none on handles — zero hover cost
- Added i18n key kg.graphView.selected for en/vi/zh
2026-03-30 15:38:38 +07:00
viettranx 3a6c63904c feat(cron): add stateless mode + promote payload fields to columns
- New `stateless` column: when true, cron runs skip session Reset/Save
  (fresh ephemeral session each run, saves tokens). Default true for new crons.
- Promote deliver, deliver_channel, deliver_to, wake_heartbeat from
  payload JSONB to dedicated columns for queryability and type safety.
- CronPayload now content-only: kind, message, command.
- PG migration 000033: backfills from JSONB, strips promoted keys.
- SQLite migration v2→v3: backfills with json_extract().
- Web UI: stateless toggle in advanced dialog, i18n (en/vi/zh).
- Desktop UI: types + i18n updated.
2026-03-30 15:24:41 +07:00
viettranx 014f74ec15 fix(agent): group session unresponsive during team task execution (#266)
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.
2026-03-30 15:20:01 +07:00
viettranx 24717b0f51 refactor(cron): normalize payload columns into dedicated DB fields (#33)
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.
2026-03-30 15:19:43 +07:00
viettranx d10236241e fix(agent): add panic recovery to prevent zombie state after agent loop crash (#39)
Root cause: runLoop() had no recover() — panics killed the goroutine while
leaving the session queue's activeRuns entry orphaned. Subsequent messages
to the same session would hang indefinitely (zombie state).

Fix: Two-layer panic recovery:
1. loop.go: runLoop() now returns error on panic instead of crashing goroutine,
   allowing normal cleanup flow (session queue, traces, events)
2. queue.go: executeRun() defense-in-depth recovery ensures activeRuns cleanup
   and scheduleNext() even if agent-level recovery fails
2026-03-30 14:36:25 +07:00
viettranx 4ac611530a fix(store): provider CreateProvider uses UPSERT to handle orphaned duplicates (#295)
CreateProvider now uses ON CONFLICT (tenant_id, name) DO UPDATE instead of
plain INSERT. When a provider with the same name already exists (e.g. orphaned
after agent deletion), it updates the existing record instead of failing with
a unique constraint violation.

Applied to both PG and SQLite implementations.
2026-03-30 14:29:33 +07:00
viettranx bdfc0fadfb fix(config): MCP env: resolution, channel field filter, orphan provider event, workspace fallback (#348, #297, #295, #431)
- manager.go: add resolveEnvVars() to expand env:VARNAME in MCP headers (copy-safe)
- manager_env_test.go: 3 test cases for env resolution
- validate.go: add "name" to channelInstanceAllowedFields
- validate_test.go: test channel instance name field retention
- bus/types.go: add TopicAgentDeleted event + AgentDeletedPayload
- agents_delete.go: emit agent:deleted event with provider name for async cleanup
- gateway.go: log-only subscriber for orphaned provider warning (no auto-delete — FK safety)
- resolver.go: fallback to deps.Workspace for master tenant agents with empty ag.Workspace
  (fixes filesystem escape where filepath.Join("","system") resolved to /system)
2026-03-30 14:12:18 +07:00
viettranx 8eb4ce6d6f fix(store): session Save() UPSERT fallback, memory index-all user_id header (#379, #517)
- sessions_list.go (PG): check rowsAffected after UPDATE, INSERT with ON CONFLICT DO UPDATE
  when session not yet in DB (cron/heartbeat sessions)
- sessions_ops.go (SQLite): same UPSERT pattern with ? placeholders
- memory_handlers.go: fallback to X-GoClaw-User-Id header when body.user_id is empty
2026-03-30 14:12:08 +07:00
viettranx ec060ad7e1 fix(agent): unblock stuck agent on /stop, auto-complete nil-result tasks, graceful shutdown (#527, #504, #39)
- 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
2026-03-30 14:12:00 +07:00
viettranx e1c52cbda8 fix(providers): prevent crash on cancel, capture thinking signature, nil guard (#287, #188, #566, #335)
- 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
2026-03-30 14:11:52 +07:00
viettranx 011f5f1a3d fix(security): harden env file permissions and block NUL byte injection (#306, #44)
- prepare-env.sh: chmod 600 after .env creation to prevent world-readable secrets
- shell.go: reject commands containing NUL bytes before execution
- credentialed_exec.go: defense-in-depth NUL check in credentialed path
- shell_deny_test.go: add TestExecute_RejectsNULByte with 6 test cases
2026-03-30 14:11:42 +07:00
viettranx 533ca44e99 fix(config): add GOCLAW_ALLOWED_ORIGINS env var for CORS config (#543)
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.
2026-03-30 12:06:51 +07:00
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