Commit Graph

143 Commits

Author SHA1 Message Date
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 1e2ca2df7c fix(agent): improve team lead delegation messaging + group chat reply hint
- Team lead: no completion language after delegating, no question phrasing
- Group chat: inject reply context hint (NO_REPLY when reply addresses others)
- Both v1 and v2 team lead sections updated
2026-03-19 13:35:57 +07:00
viettranx 5b349db7eb feat(heartbeat): provider/model override + fix cache invalidation
- Add ProviderModelSelect to heartbeat config dialog (allowEmpty, verify button)
- Backend: accept providerName in HEARTBEAT.SET, resolve to UUID via GetProviderByName
- Add ModelOverride to RunRequest, used by Loop when set (cheaper model for heartbeat)
- Ticker passes heartbeat model override to agent RunRequest
- Fix: InvalidateCache after UpdateState so ListDue picks up new next_run_at immediately
- i18n: add sectionModel/modelHint keys (en/vi/zh)
2026-03-18 23:02:48 +07:00
Duc Nguyen dc51018563 fix: subagent provider routing + api_base fallback (#262)
* fix(subagent): inherit parent agent's provider instead of alphabetical fallback

Subagents previously used a fixed provider (alphabetically first from the
registry, often "anthropic") regardless of which provider the parent agent
used. This caused invalid combos like anthropic/glm-5 when a zai-coding
agent spawned subagents.

- Pass provider registry to SubagentManager for runtime resolution
- Inject parent provider name into context (WithParentProvider)
- Resolve activeProvider from parent context before LLM call
- Fix trace spans to show actual resolved provider, not default

* fix(providers): api_base fallback from config/env for DB providers

DB providers with empty api_base now inherit from config/env vars
(e.g., GOCLAW_ANTHROPIC_BASE_URL). Prevents proxy API keys from being
sent to the real provider API endpoint.

- Add APIBaseForType() method on ProvidersConfig
- registerProvidersFromDB falls back to config when api_base is empty
- ProvidersHandler uses resolveAPIBase() for model listing
- Add api_base, display_name, settings to provider validation whitelist

* fix(tracing): pass resolved provider name to subagent span emitters

- emitSubagentSpanStart now accepts providerName param instead of
  reading sm.provider.Name() — ensures root subagent span reflects
  the inherited parent provider, not the fallback default
- registerInMemory now uses resolveAPIBase() so DB providers with
  empty api_base inherit the config/env fallback (same as startup path)

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-18 22:40:49 +07:00
viettranx 2504095dfe fix(agents): complete shell deny groups propagation chain
ShellDenyGroups was defined in SystemPromptConfig but lacked full propagation
through parser, Loop fields, context injection, and system prompt population.
Per-agent overrides from other_config JSONB had zero runtime effect.

Changes:
- agent_store.go: Add ParseShellDenyGroups() to extract overrides from JSONB
- loop_types.go: Add shellDenyGroups field to Loop and LoopConfig, wire in NewLoop
- resolver.go: Wire agent-parsed shell deny groups into LoopConfig
- loop.go: Inject shellDenyGroups into context via store.WithShellDenyGroups
- loop_history.go: Populate ShellDenyGroups in system prompt config
- message_test.go: Fix macOS symlink path normalization in test expectations

Fixes test failures on macOS where /var/folders symlinks to /private/var/folders.
2026-03-18 17:04:26 +07:00
viettranx 1b27fa7a9b feat(agents): inject team members into system prompt
Team agents now see a ## Team Members section listing all teammates with
agent_key, display_name, role, and frontmatter excerpt. This allows the
agent to correctly assign tasks via team_tasks instead of guessing keys.
2026-03-18 16:38:03 +07:00
viettranx 29816db0ab feat(heartbeat): cron wakeMode, queue-aware scheduling, lightContext
- CronPayload.WakeHeartbeat triggers heartbeat immediately after cron job completes
- Cron tool supports wake_heartbeat param on add/update actions
- Scheduler.HasActiveSessionsForAgent() detects busy agents for heartbeat skip
- RunRequest.LightContext skips loading context files during heartbeat runs
2026-03-18 13:11:58 +07:00
viettranx 08a2d95c0c feat: agent heartbeat system — periodic proactive check-ins (#245)
Phase 1 (Core):
- Migration 000022: agent_heartbeats, heartbeat_run_logs, agent_config_permissions tables
- HeartbeatStore + ConfigPermissionStore interfaces with PG implementations
- HeartbeatTicker: background poll → active hours filter → queue-aware skip → run → smart suppression → deliver/log
- Heartbeat tool: status/get/set/toggle/set_checklist/get_checklist/test/logs actions
- Permission check with wildcard scope matching + TTL cache (60s)
- RPC methods: heartbeat.get/set/toggle/test/logs/checklist.get/checklist.set
- HEARTBEAT.md routed via context file interceptor (read/write for both open + predefined agents)
- Session keys: agent:{id}:heartbeat or agent:{id}💓{ts} (isolated)
- PromptMinimal for heartbeat sessions (like cron/subagent)
- Event broadcasting + cache invalidation via bus (heartbeat + config_perms)
- Gateway wiring: ticker init, event wiring, graceful shutdown

Phase 2 (Integration):
- wakeMode: CronPayload.WakeHeartbeat triggers heartbeat after cron job completes
- Queue-aware: Scheduler.HasActiveSessionsForAgent() skips busy agents
- Stagger: deterministic FNV offset spreads heartbeats across interval
- lightContext: RunRequest.LightContext skips context files, only injects checklist
- System prompt distinguishes cron (user-scheduled tasks) vs heartbeat (autonomous monitoring)
2026-03-18 13:11:44 +07:00
viettranx c7d0bc19f8 fix(teams): auto-copy media files to team workspace on task creation, scope task_number per chat
- Add RunMediaPaths context key to track media files from current run
- Collect persisted media paths in agent loop after enrichment
- Auto-copy media files to {workspace}/attachments/ when leader creates task
- Append attached files hint in dispatch content so members know what to read
- Scope task_number per (team_id, chat_id) instead of global per team
- Fix NULL chat_id comparison with COALESCE
- Use hard link first, copy fallback to save disk space
- Validate filenames and use restrictive file permissions (0640)
2026-03-18 12:58:09 +07:00
viettranx 48ebcf999b fix(tools): add append mode to write_file, warn about content size limits
- Add append=true parameter for chunked file writing
- Add ~12000 char warning in tool description and system prompt
- Helps models avoid API truncation on large file writes
2026-03-18 11:05:09 +07:00
viettranx 49441f7305 refactor: remove dead delegate code, rename lane/channel to team/teammate
- Remove handleDelegateAnnounce() dead code (no sender emits delegate:* messages)
- Remove delegate tool reference from intent_classify.go
- Rename LaneDelegate → LaneTeam with backward-compat env var fallback
- Rename ChannelDelegate → ChannelTeammate across all team tool files
- Comment out lifecycle guards in team_tasks_lifecycle.go (TODO: reviewer workflow)
- Update string literals in cron.go, task_ticker.go
- Gate tool_status placeholder_update to non-streaming runs only
- Skip FinalizeStream on tool.call to prevent mid-run content loss
2026-03-18 11:04:45 +07:00
viettranx 120fc2d09c fix(media): chain provider format, post-write verification, group media history (#206)
Cherry-picked valuable changes from PR #206:
- hasReadImageProvider supports chain format {"providers":[...]} config
- create_image/video/audio verify file persistence after write with diagnostic logging
- HistoryEntry gains Media field + CollectMedia() for group media context on @mention
- Zalo extractContentAndMedia refactored: all media types via DetectMIMEType/BuildMediaTags, 20MB limit
- Discord/Zalo pass media paths to Record() and collect historical media on @mention
- Zalo send_helpers logs directory contents when checkFileSize stat fails
2026-03-18 08:12:10 +07:00
viettranx 06e995ce03 feat: Add legacy and Claude Code tool aliases to the system prompt. 2026-03-18 07:38:41 +07:00
viettranx 843b550651 feat: runtime packages UI, pkg-helper, configurable shell deny groups (#244)
Runtime package management with security hardening:

- pkg-helper: root-privileged daemon for apk install/uninstall via Unix socket
- HTTP API: /v1/packages (list/install/uninstall/runtimes), admin role required for writes
- Shell deny groups: 15 configurable groups (per-agent overrides via context)
- Packages UI: Web page for managing system/pip/npm packages with confirmation dialogs
- Docker: privilege separation (root entrypoint → su-exec drop), init for zombie reaping
- Security: umask socket creation, persist file validation, deny pattern hardening
  (Node.js fetch/http, Python from/import, curl localhost, sensitive env vars)
- Auth: empty gateway token → admin role (dev/single-user mode)
2026-03-17 19:50:26 +07:00
viettranx b231878a85 feat(teams): add limit param to ListTasks + lightweight get-light endpoint
- Add limit parameter to ListTasks interface (dashboard=200, agent=30)
- Add teams.tasks.get-light WS method returning task only (no comments/events)
- Truncate dashboard response to exact limit (fix off-by-one from limit+1)
- Update all 7 ListTasks callers with explicit limit values
2026-03-17 18:03:10 +07:00
viettranx 70f3e1f5d5 feat(tools): auto-deliver write_file results as channel attachments
Flip write_file deliver param default from false to true so result files
(reports, articles, generated content) are automatically sent as document
attachments to chat channels without requiring explicit LLM opt-in.
Add .md MIME type to mimeFromExt for proper markdown file delivery.
2026-03-17 15:43:24 +07:00
teexiii 99dd363b13 feat(mcp): lazy-activate deferred tools on direct call in search mode (#235)
* feat: Implement MCP manager for server connections, tool registration, and deferred tool loading for agents.

* feat: Add tests for deferred tool activation logic within the tool registry and agent loop.

* fix(mcp): prevent deny list bypass via lazy activation + fix idempotency race

- Add PolicyEngine.IsDenied() to check deny patterns (incl. group: expansion)
  before allowing lazily-activated deferred tools to execute
- Check IsDenied() in both single-tool and parallel execution paths in loop.go
- Make ActivateToolIfDeferred idempotent by checking activatedTools before
  returning false, preventing concurrent goroutines from being blocked
- Add tests for deny-on-first-call, group deny patterns, and idempotent
  concurrent activation

---------

Co-authored-by: viettranx <viettranx@gmail.com>
2026-03-17 13:18:27 +07:00
viettranx 97cacfe68b feat(teams): member task progress reminder + fix broken progress notifications
- Fix progress event payload missing TaskNumber, Subject, OwnerAgentKey,
  ProgressPercent, ProgressStep — notifications were rendering empty
- Fix progress notification format to include task name (consistent with
  dispatched/failed) and guard empty ProgressStep
- Change percent tool schema from number to integer for clarity
- Add pre-run member task reminder injecting task context before LLM loop
- Add mid-loop progress nudge every 10 iterations with suggested percent
  based on iteration ratio (handles maxIter=0 unlimited case)
- Enhance leader cross-session reminder to show progress % when available
- Strengthen TEAM.md member guidance: focus, result quality, progress rules
- Add progress bar to task list table view (matches kanban card pattern)
2026-03-17 12:43:09 +07:00
viettranx d205691a13 fix(skills): hide skill_manage from LLM when skill_evolve is off
- skill_manage builtin tool default Enabled: true (available in registry)
- When skill_evolve=false: filter skill_manage from both tool definitions
  (API params) and system prompt tooling section — agent has zero awareness
- When skill_evolve=true: tool visible + system prompt guidance + nudges
- Update UI hints to reflect tool is available by default
2026-03-17 12:05:48 +07:00
viettranx b2a74ba487 feat(skills): skill_manage tool + skill_evolve learning loop (#218)
Adds skill_manage — a first-class agent tool for creating, updating, and
deleting skills from within a conversation — paired with per-agent
skill_evolve that nudges predefined agents to capture reusable workflows.

Tool (skill_manage):
- create: write skill from SKILL.md content string (auto-grant, dep scan)
- patch: find/replace producing new immutable version (advisory-locked)
- delete: soft-delete (archive in DB, move to .trash/)
- Security guard: 25 regex patterns block shell injection, credential exfil,
  path traversal, SQL injection, privilege escalation
- Ownership enforced: only skill owner can patch/delete (admin bypass)
- Content size limit: 100KB; companion file copy: 20MB, symlink-safe (WalkDir)
- Enabled: false by default — admin opt-in per agent

Learning loop (skill_evolve, predefined agents only):
- System prompt: SHOULD/SHOULD NOT guidance for skill creation
- Budget nudges: [System] prefix at 70%/90% iteration budget (ephemeral, i18n)
- Postscript: once-per-run suggestion with explicit user consent
- Config: other_config.skill_evolve + skill_nudge_interval (default 15)

Security hardening (pre-existing + new):
- CreateSkillManaged: RETURNING id + pg_advisory_xact_lock (atomic upsert)
- GetNextVersionLocked: advisory lock for race-safe patch versioning
- Ownership checks on HTTP update/delete, gateway update, 4 grant/revoke handlers
- copyOtherFiles: filepath.WalkDir for real symlink detection

UI: Skill Learning toggle + nudge interval in Agent General Tab
i18n: backend (en/vi/zh catalogs) + frontend (en/vi/zh locale files)
2026-03-17 11:38:35 +07:00
viettranx ca44b7279f feat(bootstrap): predefined agents keep full system prompt during onboarding
Predefined agents now retain all tools and system prompt sections when
BOOTSTRAP.md is present, instead of entering slim mode with only write_file.
Open agents keep the existing slim bootstrap mode.

- Gate tool filtering and IsBootstrap on agentType != "predefined"
- Add FIRST RUN reminder for predefined agents (without tool restriction)
- Skip bootstrap/user seeding for team-dispatched sessions (IsTeamSession)
- Group chats skip BOOTSTRAP.md entirely
- Track bootstrapWriteDetected + inject nudge after 2 turns without write_file
- Update templates: never reveal process, no capability listing, no "locked"
- Cache LoadContextFiles via existing agentCache/userCache (TTL 5min)
2026-03-17 09:25:23 +07:00
viettranx eee79d111e feat(teams): granular progress notifications with direct/leader mode
- Replace progress_notifications toggle with granular config:
  dispatched (on), progress (on), failed (on) + delivery mode
- Direct mode: outbound to channel, no AI processing
- Leader mode: inject into leader session with NO-ACTION instructions
- Add consumer.team-notify subscriber for event forwarding
- Enrich TeamTaskEventPayload with TaskNumber, ProgressPercent/Step
- Add auto-status system prompt section
- UI: card-select for delivery mode (Zap/Bot icons), 3 toggles
2026-03-16 22:46:51 +07:00
viettranx 3f2b6e258e chore(teams): remove deprecated delegation tools
Remove delegate_search, evaluate_loop, handoff from:
- Seed data, system prompt, i18n keys/catalogs, channel events
- Consumer handler (handleHandoffAnnounce), handoff route lookup
- HandoffRouteData struct + PG implementation
- Protocol events, MCP bridge comment
- Web UI locale files (en/vi/zh)
2026-03-16 22:46:18 +07:00
viettranx 514c5e0bfc refactor(teams): batch TaskTicker queries + leader notifications
- Replace per-team loop with batch SQL (v2 filter in JOIN)
- RecoverAllStaleTasks/ForceRecoverAllTasks/MarkAllStaleTasks return
  RecoveredTaskInfo for notification routing
- Notify leaders per (teamID, channel, chatID) scope with actionable hints
- Fix notifyLeaderCycleError routing (was silently DROPPED)
- Stale threshold: 24h → 2h default
- Remove per-session RecoverStaleTasks from loop.go (ticker handles it)
- Add rows.Err() check to scanRecoveredTaskInfoRows
2026-03-16 22:46:00 +07:00
viettranx 50a42ad110 feat(agent): team workspace resolution for lead/member agents
- Lead agents: auto-resolve team workspace as default (relative paths)
- Dispatched members: team workspace as default via req.TeamWorkspace
- Direct-chat members: own workspace default, team workspace accessible
- Add dataDir field to Loop/LoopConfig for global workspace root
- System prompt shows team workspace absolute path for model guidance
- Remove orphan task detector (superseded by post-turn dispatch)
- Log warning on OpenAI tool call argument parse failures
2026-03-16 20:06:01 +07:00
viettranx 27fb900510 refactor(tools): remove workspace_read/workspace_write, use file tools for team workspace
Remove dedicated workspace tools in favor of making existing file tools
(read_file, write_file, list_files, edit) team-workspace-aware.

- Delete workspace_tool_read.go and workspace_tool_write.go
- Clean up workspace_dir.go: export WorkspaceDir, remove dead code
  (workspaceRelPath, sanitizeFilePath, inferMimeType, templates, etc.)
- Remove workspace tool registration from gateway_managed.go
- Remove workspace tool references from policy, subagent, MCP bridge
- Add PathAllowable/PathDenyable to types.go for interface abstraction
2026-03-16 20:05:26 +07:00
viettranx 8d6729e959 feat(teams): improve task dispatch, concurrency, and tool ergonomics
- Move task dispatch from mid-turn to post-turn to prevent dependent
  tasks from completing before the current agent's run finishes
- Add team create lock to serialize list→create flows across concurrent
  group chat sessions, preventing duplicate task creation
- Require list-before-create gate: agents must call team_tasks(list)
  before creating tasks
- Make assignee required on task creation
- Add pagination (50 per page) to task list with offset support
- Slim task list/get/search responses with dedicated structs to reduce
  context token usage
- Add task board snapshot in announce messages to leader
- Workspace: allow subdirectory paths in read/delete, show directories
  in list output
- UI: reduce kanban card title font size for better visual balance
2026-03-16 15:26:25 +07:00
viettranx 0dc3124607 fix(teams): propagate peer_kind and local_key through task dispatch chain
Team task announce was writing to wrong session (direct instead of group)
because origin_peer_kind was hardcoded as "direct" in dispatch metadata.
This caused leaders to miss completed task results in group conversations.

- Store peer_kind and local_key in task metadata at creation time
- Resolve peer_kind from context → metadata → "direct" fallback in all
  dispatch paths (tool, gateway, unblocked)
- Use actual origPeerKind in announce handler session key + request
- Add origin_local_key to gateway dispatch for forum topic routing
- Clarify ask_user guidance: bot must present question directly
- Guide members to use team_tasks progress instead of team_message
- Improve error message when non-owner calls progress action
2026-03-16 09:01:13 +07:00
viettranx 0857321a6b fix(providers): correct Anthropic prompt caching + add datetime tool
- Move cache_control from request root (ignored by API) to per-block
  placement on last system block and last tool definition
- Change system prompt time format to date-only for better cache stability
- Add builtin datetime tool for precise timestamps (cron, memory, etc.)
- Add atMs past-time validation in cron handleUpdate (was only in handleAdd)
- Update cron description to guide model to use datetime tool first
2026-03-16 08:14:03 +07:00
viettranx 9468aae422 refactor(providers): simplify DashScope per-model thinking guard
Remove ModelThinkingCapable interface and ChatRequest.ModelSupportsThinking
hint field — DashScope handles per-model checks internally via its own
whitelist. Fix double applyThinkingGuard on ChatStream→Chat tool fallback
by calling OpenAIProvider.Chat directly.
2026-03-16 07:55:25 +07:00
hoangvinh14 a44dbf2ba4 feat(providers/dashscope): add Qwen 3.5 series support with per-model thinking capability (#215)
* feat(providers/dashscope): guard enable_thinking injection by per-model capability check
Introduces ModelThinkingCapable interface and ModelSupportsThinking field
on ChatRequest so DashScope can skip thinking-param injection for models
that do not support it (e.g. qwen3-plus, qwen3-turbo), preventing
\"model not supported\" API errors.
- types.go: add ModelThinkingCapable interface + ModelSupportsThinking *bool on ChatRequest
- dashscope.go: add dashscopeThinkingModels whitelist + ModelSupportsThinking(); honour pre-computed hint
- loop.go: detect ModelThinkingCapable and set hint on ChatRequest before LLM call
- provider_models.go: add qwen3.5-plus / qwen3.5-turbo to DashScope model list
- dashscope_test.go: full test suite for whitelist, injection, hint override, budget mapping

* Fix review code.

---------

Co-authored-by: Nguyen Gia Hoang Vinh <vinhngh@runsystem.net>
2026-03-16 07:43:08 +07:00
viettranx e138ac7676 fix(teams): validate blocked_by terminal state + improve leader orchestration prompt
- Add terminal-state check in executeCreate(): reject blocked_by
  referencing completed/cancelled/failed tasks with actionable error
- Add full validation in executeUpdate(): batch query via GetTasksByIDs,
  check existence + team membership + terminal state
- Add GetTasksByIDs batch query to TeamStore interface + pg implementation
- Refactor: modularize gateway, skills store, and team tools into
  focused files
- Update TEAM.md leader prompt: prefer delegation, plan full task graph
  upfront, create tasks in order with blocked_by UUIDs
2026-03-15 23:16:16 +07:00
Goon 75c570e951 feat(security): credentialed exec + HTTP RBAC + API key cache (#197)
- Secure CLI credential injection via AES-256-GCM encrypted env vars
- API key management with fine-grained RBAC scopes
- resolveAuth/requireAuth middleware across all 25+ HTTP handlers
- In-memory API key cache with TTL, negative caching, pubsub invalidation
- Sandbox-first execution (fails if unavailable, no silent fallback)
- Credential scrubbing, constant-time token comparison, Admin-only CLI creds
- SQL migration 000020: secure_cli_binaries + api_keys tables
- 14 unit tests for cache and RBAC with race detector

Closes #197
2026-03-15 20:13:18 +07:00
viettranx 3cfe31523c feat(teams): redesign teams list with card/list toggle, agent emoji, and member enrichment
- Add card/list view toggle on teams page (matching agents page pattern)
- Card view: member chips with emoji/Bot icon, frontmatter, crown for lead
- List view: comma-separated member names with frontmatter tooltip on hover
- Show version badge from team settings in both views
- Enrich ListTeams API to bulk-fetch members with emoji from other_config
- Add agent emoji field (other_config.emoji) to create/update forms
- Show emoji in team members dialog instead of Bot icon when available
- Force restrict_to_workspace=true system-wide, remove UI toggle
- Add i18n keys for all 3 locales (en/vi/zh)
2026-03-15 18:04:02 +07:00
viettranx 8053acfe8c fix(storage): fix subtree lazy-loading and preserve workspace media files
- Fix storage file listing to skip subtree root when ?path= is used,
  preventing duplicate folder nesting in the file browser tree
- Comment out os.Remove calls in persistMedia to keep original workspace
  files after persisting to media store
2026-03-15 17:26:09 +07:00
Viet Tran 9a9744077e refactor(teams): v2 system cleanup — remove legacy tools, fix followup, add events API (#210)
Major refactoring of the team system with multiple improvements:

## Removed legacy delegation tools
- Delete `delegate.go`, `delegate_async.go`, `delegate_sync.go`, `delegate_events.go`,
  `delegate_policy.go`, `delegate_prep.go`, `delegate_state.go`, `delegate_search_tool.go`
- Delete `evaluate_loop_tool.go`, `handoff_tool.go`
- Remove all references and registrations from tool manager and policy
- Clean up TEAM_PLAYBOOK_IDEAS.md and TEAM_SYSTEM.md (moved to docs)

## Rename await_reply → ask_user
- Rename action `await_reply` → `ask_user`, `clear_followup` → `clear_ask_user`
- Rename functions `executeAwaitReply` → `executeAskUser`, `executeClearFollowup` → `executeClearAskUser`
- Update system prompt with stronger wording to prevent model misuse
- Model was confusing "await_reply" with general waiting; "ask_user" is unambiguous

## Fix auto-followup false positives
- Add `HasActiveMemberTasks(ctx, teamID, excludeAgentID)` store method
- Guard `autoSetFollowup()` in consumer: skip when lead has active member tasks
- Prevents auto-followup when lead is orchestrating teammates (not waiting for user)

## Task identifier zero-padding
- Change format from `T-1-xxxx` → `T-001-xxxx` (3-digit minimum)

## Refactor workspace WS handlers to filesystem-only
- Rewrite `teams.workspace.list/read/delete` to use pure filesystem (os.ReadDir/ReadFile/Remove)
- Remove DB dependency from workspace WS handlers
- Consistent with storage handler and workspace tools
- Simplify TeamWorkspaceFile type and frontend hook

## Add team events listing API
- New WS method `teams.events.list` with team_id, limit, offset params
- New HTTP endpoint `GET /v1/teams/{id}/events` with bearer auth
- New `ListTeamEvents(ctx, teamID, limit, offset)` store method
- JOIN with team_tasks for team-wide event filtering

## Extract team access policy
- New `team_access_policy.go` — centralized team tool access control

## Migration 000019: team_id columns
- Add team_id foreign key columns to relevant tables

## Other improvements
- Add team_id propagation through agent loop, tracing, sessions
- Update i18n locale files (en/vi/zh) for new tool labels
- Update frontend builtin-tools page and require-setup component
- Bump RequiredSchemaVersion for migration 000019
2026-03-15 14:53:19 +07:00
viettranx 08823c057e fix(agent): prevent team V2 leads from manually creating tasks before spawn
Strengthen TEAM.md prompt with WRONG/CORRECT examples and NEVER wording
to stop models from calling `team_tasks create` before `spawn` in V2.

Prompt changes:
- V2 leads: explicit WRONG/CORRECT pattern, NEVER create before spawn
- V1 leads: separate workflow with manual create→spawn instructions
- team_tasks summary: de-emphasize "create", highlight auto-creation
- spawn team_task_id: clarify "omit to auto-create (recommended)"

Backend guards:
- Reject spawn with in-progress team_task_id (prevents reuse)
- Log warning on early claim race instead of silently ignoring
2026-03-14 14:23:15 +07:00
viettranx b6df6c9286 refactor(agent): consolidate system prompt sections into AGENTS.md template
Merge §5 (Memory Recall), §9 (Messaging), §12 (Silent Replies) from
hardcoded system prompt into AGENTS.md — single source of truth.
Add recency reinforcement at §16 to compensate for mid-prompt position.
Clean up SOUL.md and IDENTITY.md template duplication.

Saves ~175 tokens/turn across all LLM calls.
2026-03-14 10:30:35 +07:00
viettranx e485549407 Refactor: Simplify runtime package installation hints by removing dynamic detection and providing a static message. 2026-03-14 10:00:17 +07:00
Goon 19786166c1 fix(agent): enrich <media:image> tags with persisted media IDs for Discord image attachments (#179)
* fix(agent): enrich <media:image> tags with persisted media IDs for Discord image attachments

Discord image attachments were downloaded and persisted correctly, but
<media:image> tags in the message content remained bare (no ID attribute),
unlike <media:audio> and <media:video> tags which get enriched with media
IDs. This made it harder for the LLM to confirm image receipt and
reference specific images.

Add enrichImageIDs() that embeds persisted media IDs into <media:image>
tags, matching the existing enrichAudioIDs()/enrichVideoIDs() pattern.
Iterates refs in reverse order to correctly map multiple image refs to
their positional tags when users attach several images at once.

Closes #178

https://claude.ai/code/session_01KkE9UxcNB8eXpqRiJHRqeB

* style(agent): add missing continue in enrichImageIDs for consistency with enrichVideoIDs

https://claude.ai/code/session_01KkE9UxcNB8eXpqRiJHRqeB

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Viet Tran <viettranx@gmail.com>
2026-03-13 23:01:59 +07:00
Viet Tran 1a42dc93a6 feat(teams): team system v2 with bug fixes, workspace scope, versioning, and prompt optimization (#183)
* feat(workspace): add team shared workspace for file collaboration

- Add workspace_write and workspace_read tools for agents to share files across team members
- Create team_workspaces DB table with migration 000017 (file metadata, pinning, tags)
- Implement PostgreSQL store layer for workspace CRUD operations
- Add RPC handlers for workspace list/read/delete from web UI
- Build React workspace tab with file listing, content preview, and delete
- Propagate workspace channel/chatID scope through delegation chain
- Auto-allow workspace tools in agent tool policy when agent belongs to a team
- Inject team workspace guidance into system prompt for team agents
- Add /reset command handler for clearing session history
- Harden MCP bridge context middleware to reject headers when no gateway token
- Add i18n strings for workspace UI in en/vi/zh locales

* feat(teams): add comprehensive task management with followup reminders and recovery

- Add task followup/reminder system with auto-set on lead agent reply and auto-clear when user responds on channel
- Add task recovery ticker to re-dispatch stale/pending tasks periodically
- Add task scopes, filtering by status/channel/chatID, and task events
- Add WS RPC handlers for task CRUD, assignments, comments, events, and bulk operations (teams_tasks.go)
- Add task detail dialog, settings UI for followup config, and scope filtering in web dashboard
- Add migrations 000018 (team_tasks_v2) and 000019 (task_followup)
- Extend team_tasks_tool with await_reply, clear_followup actions
- Auto-complete/fail team tasks when delegate agent finishes
- Add workspace file listing and team tool manager enhancements

* docs(teams): add team system architecture and playbook ideas documentation

- Add TEAM_SYSTEM.md with full architecture design covering task management, shared workspace, and delegation engine subsystems
- Add TEAM_PLAYBOOK_IDEAS.md outlining future team coordination layers (playbook, member capabilities, auto-learned patterns)
- Document data models, status flows, tool actions, followup reminder system, task ticker, execution locking, and workspace scope model

* fix(teams): resolve 6 critical bugs in team task system

- Fix unblock SQL: check array_length after array_remove (not before)
- Enforce single-team leadership in team creation
- Add requireLead() for approve/reject tool actions
- Validate cross-team dependency references in blocked_by
- Add team_id to handoff route for multi-team isolation
- Set blocked_by DEFAULT '{}' to prevent NULL array issues

* refactor(workspace): use stable userID as scope key instead of connection UUID

Workspace scope changed from (team_id, channel, chat_id) to (team_id, userID).
Fixes workspace fragmentation across WS tab refreshes and reconnections.

* feat(teams): add V1/V2 versioning with feature gating and optimized prompts

- IsTeamV2() helper gates advanced features (locking, followup, review, audit)
- V2 tool actions rejected for V1 teams with clear error message
- Ticker, gateway consumer, delegation hooks respect version flag
- TEAM.md renders v1/v2 sections conditionally
- Tool descriptions and params optimized (~38% token reduction)
- UI: version toggle in settings, V2 Beta badge, conditional rendering
- i18n: version modal keys for en/vi/zh

* fix(migration): use VARCHAR(255) for user ID columns and add metadata JSONB

- assignee_user_id, user_id, actor_id: TEXT → VARCHAR(255)
- Add metadata JSONB to team_task_comments and team_task_attachments

---------

Co-authored-by: Nam Nguyen Ngoc <namnn.0911@gmail.com>
2026-03-13 22:41:32 +07:00
viettranx ddd4565380 fix(tools): add negative guidance for message tool and disable handoff by default
Message tool prompting now explicitly tells the LLM not to use it for
replying to the user — prevents false activations on phrases like
"gởi lại cho tôi" (send it back to me).

Handoff tool disabled by default since it's rarely used and causes
confusion with spawn. Admins can re-enable via DB/UI if needed.
2026-03-13 16:15:33 +07:00
viettranx 52c56978c5 fix(tools): improve workspace path guidance to reduce LLM path guessing
Agents were guessing absolute paths for file/exec tools, causing failed
tool calls and wasteful retries. Strengthen LLM guidance at three levels:

- System prompt: instruct to use relative paths, not guess absolute paths
- Tool param descriptions: mention workspace-relative resolution
- Subagent prompt: add missing workspace section with path guidance
2026-03-13 13:51:37 +07:00
viettranx 7f4f4a238e feat(memory): inject KG hint into memory_search results and improve KG tool prompting
- Add hasKG flag to MemorySearchTool, inject hint in results when KG is enabled
- Wire SetHasKG(true) in gateway when KG store is available
- Improve knowledge_graph_search tool description with concrete use cases
- Update system prompt KG guidance to be more actionable
2026-03-13 13:33:18 +07:00
viettranx 4c7db6e09b feat(agent): add mid-run message injection for DM and WebSocket
Inject user follow-up messages into the running agent loop at turn
boundaries instead of queueing them for a new run. This preserves
context so the LLM sees both tool results and user follow-ups together.

- Add InjectedMessage type and drainInjectChannel helper
- Add InjectCh to ActiveRun with buffered channel (cap=5)
- Drain injection channel at two points in agent loop (after tool
  results and before no-tool-calls exit)
- Route steer/new_task intents to InjectMessage with scheduler fallback
- WebSocket: inject into running loop when session is busy
- Remove IntentClassify config toggle (always on)
- Web UI: show send + stop buttons side by side during agent run
- i18n: add injection acknowledgment messages (en/vi/zh)
2026-03-13 11:55:55 +07:00
viettranx 6eb33f9cea feat: decouple memory/KG sharing from workspace folder sharing
Add independent `share_memory` config flag to control memory and
knowledge graph sharing separately from workspace folder isolation.

- Add ShareMemory field to WorkspaceSharingConfig
- Decouple WithSharedMemory(ctx) from shouldShareWorkspace() in loop.go
- Add shouldShareMemory() helper independent of workspace sharing
- Fix KG Traverse CTE to scope user_id in recursive step (pre-existing bug)
- Add memory toggle UI with violet styling in workspace sharing section
- Add i18n translations (en/vi/zh) for new memory sharing controls
- Add unit tests for shouldShareMemory() independence
2026-03-12 18:26:40 +07:00
Goon 7a4a20b2e8 fix(discord): per-user memory scope in guild channels (#166)
* docs: add brainstorm report for discord guild-user memory

* docs: update brainstorm report with corrected root cause analysis

* feat(discord): per-user memory scope in guild channels

Fixes shared USER.md between guild members by scoping userID to
"guild:{guildID}:user:{senderID}" for Discord group messages.
Updates all group-context prefix checks (write permissions, writer
cache, cron peer kind, history filter) to include the new guild: prefix.

Closes #165
2026-03-12 16:45:30 +07:00
viettranx bece4525ba feat: share memory and KG across users when workspace sharing is enabled
Memory (MEMORY.md, memory/*) and knowledge graph are now shared when
workspace sharing is active, matching the filesystem sharing behavior.
Previously memory was always per-user isolated even with shared workspace,
causing inconsistencies when collaborating on the same files.

Adds MemoryUserID(ctx) helper that returns empty userID (global scope)
when shared memory flag is set, used by memory interceptor, memory tools,
and KG search. UI warning updated to note data is not migrated on toggle.
2026-03-12 12:09:38 +07:00
viettranx 25b24ebd50 feat: configurable workspace sharing with per-agent DM/group/user controls
Add workspace_sharing config in other_config JSONB to control per-user
workspace isolation. When enabled, users share the base workspace directory
instead of isolated subfolders — configurable separately for DMs and groups,
with a per-user allowlist override.

Backend: WorkspaceSharingConfig struct, ParseWorkspaceSharing(), conditional
isolation in loop.go/loop_history.go, 7 unit tests.
Frontend: prominent always-visible config section with contact search
combobox, sticky save bar layout fix, i18n (en/vi/zh).
2026-03-12 10:54:17 +07:00
Luan Vu b488ef44d6 fix: media tag enrichment, Gemini file polling, credential merge (#158)
1. Media tag enrichment (audio/video/document):
   - Add enrichVideoIDs() — video media_id was never injected into
     <media:video> tags, causing LLM to hallucinate UUIDs
   - Fix all enrich functions to replace the LAST bare tag instead of
     the first. When group history prepends older media tags, the first
     occurrence belongs to history — injecting the current turn's ID
     there causes the LLM to reference the wrong file

2. Gemini File API polling:
   - Upload response returns fileURI immediately but file may still be
     in PROCESSING state. Check state field; only skip polling when
     file is already ACTIVE. Fixes "not in an ACTIVE state" errors

3. Channel instance credential merge:
   - Partial credential updates (e.g. updating just token) now merge
     with existing credentials instead of wiping other fields
   - Loads, decrypts, merges, re-encrypts in a single Update() call

Co-authored-by: Luvu182 <208665161+Luvu182@users.noreply.github.com>
2026-03-12 09:35:04 +07:00