Commit Graph
558 Commits
Author SHA1 Message Date
viettranx 9f80842bbc feat(telegram): add voiceguard error sanitization and STT concurrency control (#33)
Cherry-pick two features from PR #33:

- Voiceguard: intercept technical errors (rate limits, tool failures, exit codes)
  in voice agent replies and replace with user-friendly fallback messages.
  Configurable error markers and fallback templates via TelegramConfig.
- STT: shared HTTP client with connection pooling (sync.Once) and concurrency
  semaphore (max 4 concurrent calls) to prevent STT proxy overload.
2026-03-20 07:50:13 +07:00
viettranx a4a7a59b6a fix(sandbox): path isolation, DooD volume mounting, hints, and nginx DNS (#129, #136)
Address issues identified in PR #137 with a cleaner approach:

- Sandbox isolation: add SandboxCwd/ResolveSandboxPath helpers to map
  filesystem tool paths to agent-scoped container subdirectories,
  preventing cross-agent file access via read/write/edit/list tools
- DooD volume mounting: add resolveHostWorkspacePath with multi-strategy
  container ID detection (/proc/self/mountinfo, HOSTNAME, os.Hostname)
  and 5s timeout on docker inspect
- Sandbox hints: expand from 1 pattern (binary not found) to 6 patterns
  (permission denied, network disabled, read-only FS, missing file,
  resource limits) with MaybeFsBridgeHint for filesystem tools
- Nginx DNS: add Docker resolver (127.0.0.11) with dynamic upstream
  variable to handle backend container IP changes
- MCP args: switch from comma-separated to space-separated parsing
  with quote support for --flag="value with spaces" patterns
- Refactor: rename ExecTool.workingDir to workspace for consistency,
  extract sandbox.DefaultContainerWorkdir constant
2026-03-20 07:32:23 +07:00
viettranx a8fecfb3b1 refactor(ui): replace native window.confirm with ConfirmDialog for task deletion
Unify confirmation UX — task-list and board-container now use the shared
ConfirmDialog component instead of browser-native window.confirm().
2026-03-20 07:23:19 +07:00
Thieu Nguyenandviettranx d9dffc66e7 docs: restructure README — hub-and-spoke pattern, fix accuracy (#285)
* docs: restructure README with i18n, static diagrams, and accuracy fixes

Restructure:
- Reduce README from ~950 to ~280 lines (hub-and-spoke pattern)
- Move Project Status to CHANGELOG.md
- Add hero section: centered title, tagline, description, badges
- Add nav links: Documentation, Quick Start, Twitter/X (OpenFang pattern)
- Add Documentation table linking all docs.goclaw.sh sections
- Replace 3 mermaid diagrams with static images for consistent rendering

Accuracy fixes:
- Fix provider count: 13+ → 20+ (verified from gateway_providers.go)
- Fix "5-layer defense" → 5-layer permission system per policy.go
- Add missing features: Heartbeat, Scheduling/Cron, Observability
- Fix all docs URLs to docs.goclaw.sh hash routing
- Add VPS $5 minimum 2GB RAM note for Docker

Internationalization (30 languages, ZeroClaw coverage):
zh-CN, ja, ko, vi, tl, es, pt, it, de, fr, ar, hi, ru, bn, he,
pl, cs, nl, tr, uk, id, th, ur, ro, sv, el, hu, fi, da, nb
- Keep product feature names in English: Extended Thinking, Heartbeat
- Vietnamese README hand-tuned for natural phrasing

* docs: move translated READMEs to _readmes/ directory

Keep all 30 language translations but declutter the project root.
Fix relative links (_statics/, cross-language, main README) for new location.
Update main README language selector to point to _readmes/.

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-20 07:10:47 +07:00
viettranx 71af1a6bdd fix(i18n): add missing zh locale keys for ChatGPT OAuth setup 2026-03-20 06:56:25 +07:00
Plateau Nguyen 43990c7e56 Fix ChatGPT OAuth setup wizard flow (#289) 2026-03-20 06:54:11 +07:00
Plateau Nguyen c1893c73d1 fix: normalize delete confirmation matching (#290) 2026-03-20 06:48:48 +07:00
viettranx cc43f78b4b fix(agent): correct within-turn duplicate tool call ID pairing in sanitizeHistory
Replace single-value idRemap with queue-based idQueue so multiple tool
results sharing the same original ID pair correctly in encounter order.
Previously the map overwrote on duplicates, causing the second result to
be dropped and a synthetic placeholder to be emitted instead.
2026-03-20 06:39:58 +07:00
badgerbeesandviettranx 55bc752773 fix(agent): handle duplicate tool call IDs in OpenAI-compatible transcripts (#283)
* fix(agent): handle duplicate tool call IDs with occurrence-aware sanitization

* refactor(agent): simplify duplicate tool call ID handling

Replace complex occurrence-aware queue system with simpler approach:
- uniquifyToolCallIDs: append runID+iteration+index to all IDs at
  response time, guaranteeing cross-turn uniqueness via UUID
- sanitizeHistory: simple seen-set dedup for legacy sessions with
  pre-existing duplicate IDs, no queue/counter logic needed
- Restore full problem description in sanitizeHistory docstring
- Add unit tests for both dedup paths and edge cases

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-20 06:32:38 +07:00
viettranx eb39a46d57 fix: propagate IsError in parallel tool execution path
The squash merge of #291 missed the parallel tool execution path.
Tool errors running in parallel still displayed as "Done" instead
of "Failed" when reloading chat history.
2026-03-20 06:32:13 +07:00
chungtran4078andChung Tran 18211154d0 fix: correct tool calling error status display in chat history (#291)
Co-authored-by: Chung Tran <chung.tran@diqit.io>
2026-03-20 06:28:34 +07:00
viettranx e13db25919 fix(ui): wire drag-and-drop file upload in chat view
Lift file state from ChatInput to ChatPage so DropZone.onDrop can
append dropped files to the shared state. Previously drag-and-drop
showed the overlay but never passed files to the input.
2026-03-20 00:27:14 +07:00
badgerbees 9100f981d7 fix(providers): robust Gemini thought_signature detection and history mapping
Improves supportsThoughtSignature with providerType and model normalization.
Strengthens collapseToolCallsWithoutSig with TrimSpace and camelCase support
to handle 'Thinking=OFF' whitespace signatures and proxy key translations.
2026-03-20 00:14:33 +07:00
badgerbees bc16af3797 fix(agent): handle duplicate tool call IDs in OpenAI-compatible transcripts
Simplified approach to fix duplicate tool_call_ids that cause HTTP 400 on OpenAI-compatible APIs (OpenRouter, vLLM, DeepSeek).

- uniquifyToolCallIDs: appends runID+iteration+index to all IDs at response time, guaranteeing cross-turn uniqueness via UUID
- sanitizeHistory: simple seen-set dedup for legacy sessions with pre-existing duplicate IDs
- Anthropic guard: skips ID rewriting when RawAssistantContent is present
- Unit tests for both paths + edge cases

Closes #283
2026-03-20 00:10:52 +07:00
viettranx cb93559154 fix(channels): allow config field in channel instance updates
Add "config" to channelInstanceAllowedFields so channel config changes
from the UI are actually persisted to the database instead of being
silently dropped by the allowlist filter.
2026-03-19 23:47:51 +07:00
Goon 1454614ca8 feat: add MiniMax-M2.7 model, custom model input, combobox UX fix, mobile font-size audit (#282)
- Add MiniMax-M2.7 to minimax_native provider model list
- Fix combobox dropdown UX: show all options on re-focus instead of filtering by current selection
- Add allowCustom prop to combobox for typing custom model names not in the list
- Add i18n key useCustomModel for EN/VI/ZH
- Audit all raw input/select/textarea elements across web UI to use text-base (16px) on mobile, preventing iOS Safari auto-zoom on focus
2026-03-19 23:47:11 +07:00
viettranx 49540651af fix(ui): session title live update + solid card backgrounds
- Listen for session.updated event to update sidebar labels in-place
- Replace bg-muted/30 with bg-muted on chat cards so dotted background
  pattern does not bleed through
2026-03-19 23:34:57 +07:00
viettranx 4da85913a2 feat(chat): auto-generate conversation titles via lightweight LLM call
After the first agent run completes, generate a short title from the
user's message using a 10s/50-token LLM call. Title is stored in the
session label column and pushed to clients via session.updated event.
2026-03-19 23:34:45 +07:00
viettranx 24ad97af31 feat(agent): add read-only streak + same-result loop detection
Detect agents stuck in read-only loops (consecutive non-mutating tool
calls) and same-result patterns (identical outputs from different args).
Warns at threshold, force-stops at critical.
2026-03-19 23:34:34 +07:00
viettranx eec083c91a docs: add ErrorBoundary key + route params rules to CLAUDE.md 2026-03-19 22:39:41 +07:00
viettranx 886ef64aec feat(ui): delete chat conversation from sidebar
- Add deleteSession() to useChatSessions hook
- Trash icon on session rows (hover-reveal, always visible on mobile)
- Simple confirm dialog (no typing required)
- If active session deleted, switch to next or create new
- i18n strings for en/vi/zh
2026-03-19 22:39:34 +07:00
viettranx 45295bc75a fix(ui): eliminate full-page flash on chat session switch
Root cause: ErrorBoundary in AppLayout used key={location.pathname},
causing React to unmount/remount the entire page on every URL change.

- Add stableErrorBoundaryKey() that strips dynamic segments from pathname
- Merge /chat and /chat/:sessionKey into single /chat/:sessionKey? route
- Derive sessionKey from useParams() instead of duplicating into useState
  (dual state caused race condition: setState + navigate → B→A→B bounce)
- Move session reset from render-time setState to useEffect
- Only show loading spinner when messages array is empty
2026-03-19 22:38:06 +07:00
viettranx b80ee0ae43 feat(sandbox): hint LLM when tool/binary missing in sandbox container
Detect exit code 127 and "command not found" patterns in sandbox
execution paths and append a [SANDBOX] hint to the error output,
so the model can inform the user about sandbox environment limitations.

Only applies to sandbox execution — host paths are untouched.
2026-03-19 22:17:29 +07:00
viettranx 711395f81f fix(ui): chat polish — floating bar, dotted bg, tool icon, flash fix
- Chat input bar: floating with backdrop blur and rounded corners
- Chat thread: dotted background pattern matching kanban board
- Tool call cards: blue Wrench icon for completed (was green Check)
- Memo wrap ChatSidebar, SessionSwitcher, ChatThread to prevent re-renders
- Keep old messages visible during session switch to prevent flash
2026-03-19 21:47:46 +07:00
viettranx 8409db5890 feat(ui): adopt canonical WS session key format + channel filter
- buildNewSessionKey uses agent:{id}:ws:direct:{uuid} format
- sessions.list sends channel:"ws" to filter WS-only sessions
- isOwnSession supports both new and legacy key formats
- Read-only bar now floating with rounded corners
2026-03-19 21:47:35 +07:00
viettranx 6b747d7571 fix(sessions): auto-migrate legacy ws-{userId}-{ts} keys to ws:direct:{ts}
Runs idempotent regex migration at PGSessionStore init to convert
legacy WS session keys to canonical format. Handles multi-hyphen
userIDs (UUIDs) by matching last segment as timestamp.
2026-03-19 21:47:26 +07:00
viettranx 642797f079 feat(sessions): canonical WS session key format + channel/user filtering
- Add BuildWSSessionKey() and IsWSSession() helpers for ws:direct:{convId} format
- Change ChatID to userId (not clientID) for consistent team/workspace isolation
- Add Channel and UserID fields to SessionListOpts with dynamic WHERE builder
- Extract shared buildSessionFilter() for ListPaged and ListPagedRich
- Chat sidebar sends channel:"ws" to filter WS-only sessions per user
- Sessions admin page remains unfiltered (no channel param)
2026-03-19 21:47:15 +07:00
badgerbeesandviettranx 3f9401257c feat(telegram): networking isolation and sticky IPv4 fallback (#278)
* fix(telegram): isolated transport, sticky fallback, and overall timeouts

* fix(telegram): improve networking isolation for high-concurrency

- Tune MaxIdleConnsPerHost to 64 (default 2 starves concurrent sends)
- Fix data race in enableIPv4Only using sync.Once
- Add force_ipv4 config option for explicit IPv4-only mode
- Narrow auto-detect heuristic to "unreachable" only (avoid false-positive on timeouts)
- Use bot username instead of token prefix in logs
- Extract applyIPv4Dialer helper for reuse between config and runtime paths

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-19 20:45:49 +07:00
viettranx 1452d9e8f3 docs: add solution design guideline to CLAUDE.md
Require root cause analysis and production scenario thinking
(high concurrency, multi-tenant, failure cascades) before designing
fixes or features. Prefer explicit config over runtime heuristics.
2026-03-19 20:39:44 +07:00
viettranx 15916823e0 feat(ui): integrate chat redesign + file preview modal
- ChatThread: merge consecutive tool-only messages, use ActiveRunZone
- ChatPage: add ChatTopBar, DropZone, pass new hook state
- MessageBubble: compact tool-only layout, block reply support
- ToolCallCard: compact mode with smaller padding
- AgentSelector: show emoji from other_config
- SessionSwitcher: friendly labels (Chat xxx instead of raw keys)
- FileBlock: click opens rich content modal with download button
- MarkdownRenderer: intercept /v1/files/ links as file chips with
  inline download icon, modal preview for md/code/audio/video/image
2026-03-19 19:01:51 +07:00
viettranx a9ec6302ca feat(ui): redesign chat with real-time event handling
Add 8 new chat components and extend use-chat-messages hook to handle
block.reply, activity, run.retrying, and team.task.* events.

New components: ActiveRunZone, ActivityIndicator, BlockReplyBubble,
SystemNotification, TeamActivityPanel, MediaGallery, ChatTopBar, DropZone.
2026-03-19 19:01:37 +07:00
viettranx b1b7bfbe69 fix(ws): detach agent runs from HTTP request context
Agent runs were tied to the HTTP request context, so navigating away
cancelled the LLM stream. Now uses context.WithoutCancel() to survive
page navigation while preserving explicit chat.abort support.
2026-03-19 19:01:19 +07:00
viettranx 78ffc57a8e fix(ws): propagate origin_session_key for team task announces
Team task announces rebuilt session keys via BuildScopedSessionKey(),
producing different format than WS sessions (ws:direct:uuid vs
ws-userId-ts). Now stores and forwards origin_session_key through
task metadata and dispatch, matching subagent announce pattern.

Also adds "ws" to InternalChannels to suppress spurious warnings.
2026-03-19 19:01:10 +07:00
2c1efa29ec fix(memory): prevent silent data loss on memory file overwrites (#279)
* fix(memory): auto-backup + overwrite warning for memory files

When an agent writes to a memory file that already has content:
1. Old content is backed up to memory/.prev/{filename} (best-effort)
2. Write succeeds normally (no blocking)
3. Tool result includes warning with previous content (truncated to
   4000 chars) so the agent can notice and merge if needed

Backup files are hidden from list_files and not indexed/embedded.
No database migration needed - uses existing PutDocument.

* fix(memory): support append mode + fix UTF-8 truncation in overwrite warning

- Add appendMode parameter to MemoryInterceptor.WriteFile() so
  write_file(append=true) actually appends to memory files instead
  of silently replacing content. Uses "\n\n---\n\n" separator.
- Fix UTF-8 truncation in overwrite warning: use []rune instead of
  byte slicing to avoid cutting multi-byte characters.
- Fix char count in warning message: use len([]rune()) not len().
- Remove .prev/ backup mechanism (prevBackupPath, isPrevPath, backup
  writes, ListFiles filter) in favor of simpler approach: append
  mode prevents data loss, warning enables self-correction.

---------

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-19 17:42:03 +07:00
bb783b952c feat(feishu): add list_group_members tool + native @mention support (#280)
* feat(feishu): add list_group_members tool + native @mention support

Add agent tool to list all members in a Lark group chat via
GET /open-apis/im/v1/chats/{chat_id}/members with auto-pagination.

- New tool `list_group_members`: returns member IDs + display names
- Native @mention conversion: @ou_xxx in outbound messages becomes
  real Lark mentions (post: "at" element, card: <at> markdown tag)
- Auto-sync discovered members into ContactStore
- GroupMemberProvider interface on Channel for extensibility
- Add im:chat.members:read scope to channel setup UI

Requires Lark app scope: im:chat.members:read

* fix(feishu): URL-encode API params + channel-aware tool filtering

- URL-encode chatID (PathEscape) and pageToken (QueryEscape) in
  ListChatMembers to prevent path traversal and query corruption
- Add slog.Warn when ListGroupMembers fails for observability
- Add ChannelAware interface so tools can declare required channel types
- ListGroupMembersTool now declares RequiredChannelTypes=["feishu"]
- loop.go filters out channel-specific tools when channel type mismatches,
  so list_group_members only appears for Feishu conversations

---------

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-19 17:21:38 +07:00
viettranx ec24b982f3 fix(subagent): replace bare count with deterministic roster in announce messages
Subagent announce messages told the parent LLM "There are still X active
runs" — a bare number. The LLM had to reconstruct which subagents were
done vs running from conversation history, causing hallucination when
results arrived out of order.

Replace with a full roster listing each subagent by label and status,
including per-agent config limits. Remove dead CountRunningForParent()
and unused rosterFunc field on AnnounceQueue.
2026-03-19 16:33:54 +07:00
viettranx 941a9657ca docs: add heartbeat system documentation
Document the agent heartbeat check-in mechanism covering architecture,
configuration, ticker loop, execution flow, suppression, delivery,
RPC methods, agent tool, frontend integration, and heartbeat vs cron
comparison.
2026-03-19 14:34:10 +07:00
chungtran4078andChung Tran efd3d15c70 fix: agent add cron within invalid params (#277)
Co-authored-by: Chung Tran <chung.tran@diqit.io>
2026-03-19 14:15:46 +07:00
Luan VuandLuvu182 44197011f8 feat(feishu): include reply context when user replies to a message (#272)
When a Feishu/Lark user replies to an existing message, the agent now
sees the quoted message content via the GetMessage API, formatted as
[Replying to SenderName]...[/Replying] — matching the Telegram channel
behavior. Previously parent_id was parsed but the content was silently
discarded, so the agent had no idea what the user was replying to.

Requires im:message:readonly scope on the Lark app.

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-19 14:03:09 +07:00
0dd4ebd6e6 fix(channels): collect contacts for DM and group-mentioned messages (#271)
* fix(channels): collect contacts for DM and group-mentioned messages

Previously, EnsureContact was only called inside the "not mentioned →
record history → return" branch, so contacts were never saved for
messages that the bot actually processed (DMs and group @mentions).
This caused the contacts list to show empty names ("—") for active
users across all channels.

Move contact collection to the main processing path (before
PublishInbound / HandleMessage) so every processed message upserts
the sender's display name. The existing ContactCollector 30-minute
cache prevents redundant DB writes.

Affected channels: Feishu, Telegram, Discord, Slack, Zalo, WhatsApp.

* fix(slack): use clean userID for EnsureContact cache key

The senderID param in HandleMessage is the compound "U123|DisplayName"
form, which produces a different cache key than the clean "U123" used
in the group-history path (handlers.go:178). Use userID (extracted
clean ID) to ensure cache dedup works correctly.

---------

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-19 14:02:19 +07:00
Luan VuandLuvu182 a38d972438 fix: agent update API missing is_default, budget, subagents fields (#270)
The HTTP allowlist (agentAllowedFields) was missing three fields that
the web UI sends when saving agent settings: is_default,
budget_monthly_cents, and subagents_config. These fields were silently
filtered out by filterAllowedKeys(), so saves appeared successful but
values never persisted to the database.

Also adds exclusive-default logic: when setting is_default=true on an
agent, any previously-default agent is automatically unset first.

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-19 13:59:49 +07:00
Luan VuandLuvu182 73897b9481 refactor: replace magic numbers and hardcoded strings with named constants (#269)
Extract scattered magic numbers and hardcoded agent type strings into
centralized named constants to improve maintainability and prevent
silent inconsistencies when defaults need to change.

Changes:
- Add config/defaults.go: DefaultContextWindow, DefaultMaxTokens,
  DefaultMaxMessageChars, DefaultMaxIterations, DefaultTemperature,
  DefaultHistoryShare
- Add providers/defaults.go: DefaultHTTPTimeout, SSE/Stdio scanner
  buffer size constants
- Replace 6 hardcoded 200000 (context window) across agent/, http/,
  cmd/ with config.DefaultContextWindow
- Replace 4 hardcoded 32000/32_000 (max message chars) with constant
- Replace 3 hardcoded 20 (max iterations) with constant
- Replace 2 hardcoded 0.75 (history share) with constant
- Replace 3 hardcoded 300*time.Second (HTTP timeout) with constant
- Replace 5 hardcoded scanner buffer sizes with named constants
- Replace 10 hardcoded "predefined" string comparisons with
  store.AgentTypePredefined constant (already defined but unused)
- Use config.DefaultTemperature instead of hardcoded 0.7 in agent loop

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-19 13:59:32 +07:00
viettranx 2c530f67c3 fix(ui): agent delete dialog + channel managers cleanup + combobox iOS
- agents-page: ConfirmDeleteDialog with type-to-confirm, expanded warning
- channel-managers-tab: simplify add form (remove manual name/username
  fields, auto-fill from contact search), Loader2 spinner on refresh
- combobox: text-base md:text-sm to prevent iOS Safari auto-zoom
2026-03-19 13:35:57 +07:00
viettranx 8a63e38ecd feat(ui): redesign permissions tab with file writer support
- Add file_writer to CONFIG_TYPES with contextual descriptions
- Smart scope select: dynamic group scopes from existing rules + Combobox
  for custom group IDs (e.g. group:telegram:-100456)
- Auto-fill metadata (displayName/username) from contact selection
- Two-section display: File Writers grouped by scope, Config Permissions flat
- Add metadata field to ConfigPermission interface + grant()
- i18n: permission type descriptions + scope labels in 3 locales
2026-03-19 13:35:57 +07:00
viettranx 6595c0185a refactor: merge file writers into config permissions + agent hard delete
Migration 000023:
- Migrate group_file_writers data into agent_config_permissions (config_type='file_writer')
- Add FK CASCADE/SET NULL on 16 tables for agent hard delete
- Clean up soft-deleted zombie agents
- ALTER scope VARCHAR(100) → VARCHAR(255)
- Partial unique index on agent_key (allows reuse after delete)

Store layer:
- Remove GroupWriterCache, GroupFileWriterData, 5 AgentStore methods
- Add CheckFileWriterPermission (fail-open), ListFileWriters (cached)
- Add scope filter to ConfigPermissionStore.List()

Tools: Replace GroupWriterCache with ConfigPermissionStore in read_file,
write_file, edit, cron, context_file_interceptor

Agent loop: buildGroupWriterPrompt uses ListFileWriters + metadata parsing

Channels: Telegram commands rewritten to use configPermStore.Grant/Revoke/List
HTTP API: Writer endpoints rewired to configPermStore (same response shapes)

Hard delete: agents.go DELETE FROM instead of soft delete
2026-03-19 13:35:57 +07:00
viettranx 68a4ee39b4 feat: config permissions RPC + UI tab + contact search improvements
Backend:
- Add config.permissions.list/grant/revoke RPC methods
- Auto-fill granted_by from caller's context identity
- Fix Telegram contact display_name: FirstName + LastName (was FirstName only)
- Change contact search to prefix match (term%) for B-tree index usage

Frontend:
- Add Permissions tab to agent detail with inline add row layout
- Contact search combobox shows name, @username, sender_id, [channel]
- Reduce contact search debounce from 300ms to 150ms
- i18n keys for en/vi/zh
2026-03-19 13:35:57 +07:00
viettranx b6ff57ddab fix(ui): heartbeat logs crash + header/card improvements
- Fix HeartbeatLog interface field names (snake_case → camelCase) to match
  backend JSON tags — fixes white screen crash on logs dialog open
- Format duration with formatDuration(), show token usage per log entry
- Fix logs dialog padding to match standard pattern + close button overlap
- Show model override and last error on heartbeat card
- Replace status badge with colored dot in agent header
- Compact header badges on mobile (icon-only for evolving/static)
- Switch sidebar to tablet breakpoint (1024px) for earlier collapse
2026-03-19 13:35:57 +07:00
viettranx ef1a1463ac docs: add DB query reuse rule to post-implementation checklist 2026-03-19 13:35:57 +07:00
viettranx 4e9f155a4c feat(agent): adaptive tool timing with slow tool notification
Track per-tool execution time statistics in session metadata. When a tool
call exceeds its adaptive threshold (2x historical max, min 120s default),
send a direct outbound notification to the user.

- ToolTimingMap: parse/serialize/record/threshold from session metadata
- StartSlowTimer: fires once per tool call, auto-cancels on completion
- Team config: slow_tool toggle (default on, always direct, never leader)
- UI: toggle in team settings with i18n (en/vi/zh)
- Store: add GetSessionMetadata to session store interface
2026-03-19 13:35:57 +07:00
viettranx 0df619023c feat(tools): block binary in read_file, add workspace path to read_image
- read_file: reject binary files (images, audio, video, archives) with
  helpful error pointing to the correct specialized tool
- read_image: add optional `path` parameter to analyze workspace/generated
  images via vision API (with workspace restriction + denied path checks)
2026-03-19 13:35:57 +07:00