Commit Graph
94 Commits
Author SHA1 Message Date
viettranx ae89239dd5 feat: Refine tool policies with updated groups and aliases, and enhance credential scrubbing by dynamically detecting and redacting server IPs. 2026-03-02 20:34:25 +07:00
viettranxandClaude Opus 4.6 74d85c8dd5 feat(security): enforce group file writer restrictions + harden exec against env/config leaks
Group writer enforcement (managed mode):
- GroupWriterCache with 5min TTL wrapping AgentStore.ListGroupFileWriters
- Tool-level blocking: write_file, edit, read_file (SOUL.md/AGENTS.md), cron mutations
- System prompt injection: non-writers get refusal instructions + filtered context files
- Cache invalidation via bus events on add/remove writer
- Wired through resolver, loop, gateway_managed, gateway_callbacks

Exec security hardening:
- Block /proc/PID/environ and /proc/self/environ reads (env var exfiltration)
- Block strings on /proc files (binary env dump)
- DenyPaths() on ExecTool: block data dir, .goclaw/, config file from exec commands
- Scrub VIRTUAL_* env vars from tool output

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:22:21 +07:00
Thieu Nguyen 846c217cf9 fix(store): handle NULL JSONB columns in MCP server scan (#40)
* fix(store): handle NULL JSONB columns in MCP server scan

Scan JSONB nullable columns (args, headers, env, settings) into *[]byte
instead of directly into json.RawMessage to prevent silent scan failures
when database values are SQL NULL. Also initialize result slices with
make() to return empty JSON arrays instead of null.

* fix(store): keep settings scanning direct since column is NOT NULL
2026-03-02 16:45:02 +07:00
viettranx 53db5165a3 feat: add a hint to bot reply bodies indicating full content is in session history for LLM context. 2026-03-02 16:41:20 +07:00
viettranx e9ab15bb09 feat: Propagate local key for subagent, delegation, and team messages to enable topic/thread-specific routing and context. 2026-03-02 15:28:15 +07:00
viettranxandClaude Opus 4.6 5bd486882d feat(telegram): port forum topic features from TS — per-topic config, DM threads, thread fallback, createForumTopic tool, Web UI
Port 4 missing Telegram forum/topic features from TypeScript OpenClaw:

1. Thread-not-found fallback: retry sends without message_thread_id when
   a topic is deleted (sendHTML, sendPhoto, sendVideo, sendAudio,
   sendDocument, stream flush).

2. Per-topic config: hierarchical config resolution (global → wildcard
   group "*" → specific group → specific topic) for groupPolicy,
   requireMention, allowFrom, enabled, skills, systemPrompt.
   New TelegramGroupConfig/TelegramTopicConfig structs, resolveTopicConfig()
   with 10 unit tests.

3. DM topic support: preserve message_thread_id in private chats for
   session isolation. New BuildDMThreadSessionKey, parseRawChatID handles
   🧵 suffix.

4. createForumTopic agent tool: ForumTopicCreator interface decoupled
   from telego, lazy bot resolution via channel manager.

5. Web UI: structured group/topic config form with tri-state booleans
   (Inherit/Yes/No), nested collapsible group and topic entries.

Also fix: forum group pairing reply and approval notification now
correctly set MessageThreadID so messages land in the right topic.
Send() extracts threadID from localKey suffix as fallback for cases
where metadata is absent (e.g. pairing approval via SendToChannel).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:45:21 +07:00
viettranxandClaude Opus 4.6 6ed62b8506 feat: channel-isolated workspace, resolvePath fix, create_image workspace, summoner Expertise section, bus Topic constants
- Fix resolvePath for nested non-existent dirs (use resolveThroughExistingAncestors)
- Channel-isolated workspace: user_agent_profiles.workspace stores channel prefix,
  used as source of truth with backward compat for existing users
- Loop caches workspace per-user with CacheKindUserWorkspace invalidation via pubsub
- ContractHome/ExpandHome for portable ~-based paths in DB
- create_image saves to workspace/generated/YYYY-MM-DD/ instead of OS temp dir
- SOUL.md template: add ## Expertise section for domain knowledge
- Summoner buildEditPrompt: section guide, complete file output, frontmatter update
- Bus: Topic* constants for Subscribe/Broadcast keys, CacheKind* for payload kinds
- Teams, delegates, sessions, agent links: various enhancements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:52:32 +07:00
Thieu Nguyen 363838c309 fix(sandbox): rename from openclaw to goclaw for project name consistency (#35)
Update sandbox image name, container prefix, Docker labels, and MCP client info
from 'openclaw' to 'goclaw' to match the repository project name.

Changes:
- internal/sandbox/sandbox.go: image and container prefix
- internal/sandbox/docker.go: Docker label and fallback prefix
- docker-compose.sandbox.yml: image reference in comments and env
- internal/mcp/manager_connect.go: MCP client info name
2026-03-02 07:38:23 +07:00
viettranx df02ab77f2 test: add GetDefault method to stubAgentStore. 2026-03-01 21:56:02 +07:00
therichardngai-code 8d513763f2 fix: invalidate ContextFileInterceptor cache on agents.files.set (#29)
* fix: invalidate ContextFileInterceptor cache on agents.files.set

When agents.files.set (or agents.update) wrote context files to
agent_context_files in Postgres, only the agent router cache was
invalidated via agents.InvalidateAgent(). The ContextFileInterceptor
maintains its own separate in-memory cache with a 5-minute TTL which
was never cleared, causing the agent to serve stale file content
(e.g. wizard-written SOUL.md/IDENTITY.md) for up to 5 minutes.

Fix: inject *tools.ContextFileInterceptor into AgentsMethods and call
intc.InvalidateAgent(ag.ID) immediately after each successful DB write
in handleFilesSet and handleUpdate.

Wire path: wireManagedExtras now returns the interceptor it creates;
gateway.go captures it and passes it through registerAllMethods →
NewAgentsMethods. The interceptor is nil in standalone mode so all
nil guards are in place.

* test: add unit tests for ContextFileInterceptor cache invalidation

Covers:
- Cache hit: second read does not call store again
- InvalidateAgent clears agent cache → fresh content served from store
- InvalidateAgent clears user cache for that agent
- InvalidateAgent does not affect other agents' cache entries
- TTL expiry causes re-fetch from store
2026-03-01 21:44:29 +07:00
viettranxandClaude Opus 4.6 82ce20a029 refactor: add AgentStore.GetDefault() to replace full List scan in heartbeat setup
Replaces List(ctx, "") + loop with a single-row query
(ORDER BY is_default DESC, created_at ASC LIMIT 1).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:34:09 +07:00
Michael e8607f9686 fix(heartbeat): resolve default agent from DB in managed mode (#31)
In managed mode, agents live in the database, not in config files.
ResolveDefaultAgentID() always returns "default" which doesn't exist
as a real agent, causing heartbeat to silently fail.

Add resolveDefaultAgentManaged() helper that checks the managed DB
for the agent marked is_default=true, falling back to the first
available agent. Apply it in setupHeartbeat().
2026-03-01 21:31:21 +07:00
therichardngai-code ad82c09720 fix(bootstrap): SeedUserFiles should use agent-level USER.md as seed for predefined agents (#30)
* fix: SeedUserFiles uses agent-level USER.md as seed for predefined agents

For predefined agents, the wizard writes a populated USER.md (owner
name, language, notes) via agents.files.set into agent_context_files
(agent-level). On the first chat message, SeedUserFiles was seeding a
blank embedded template into user_context_files (per-user level).

LoadContextFiles for predefined agents lets per-user content override
agent-level content, so the blank per-user USER.md shadowed the
wizard-written content. The owner profile was stored in the DB but
never served to the agent, triggering unnecessary onboarding.

Fix: before falling back to the embedded template, check whether
agent_context_files already has a non-empty USER.md for the agent.
If it does, use that content as the per-user seed. The check is
conditional (predefined agent + USER.md not yet seeded per-user) so
it adds at most one extra DB read per new user.

The existing "don't overwrite" guard (hasFile check) is unchanged —
personalized per-user content written through conversation is still
never overwritten.

* test: add unit tests for SeedUserFiles agent-level USER.md seeding

Covers:
- Predefined agent: wizard-written USER.md at agent level is used as
  per-user seed (primary regression test for the bug fix)
- Predefined agent: falls back to blank embedded template when no
  agent-level USER.md exists
- Predefined agent: existing per-user content is never overwritten
- Open agent: embedded template path is unaffected
- Predefined agent: BOOTSTRAP.md uses BOOTSTRAP_PREDEFINED.md template
- Idempotency: second SeedUserFiles call seeds nothing

* fix(bootstrap): SeedUserFiles uses agent-level USER.md as seed for predefined agents

Use map[string]string for agent-level files (more general, extensible)
and clean continue-based loop flow, matching the investigation spec
in plans/goclaw-pr/goclaw-pr-seed-user-files.md exactly.

Previous implementation used a single string and if/else structure —
functionally correct but diverged from the spec in variable type,
load condition, and loop exit pattern.
2026-03-01 21:23:38 +07:00
therichardngai-code 3cbdd8d778 fix(agents): predefined agents visible in web UI for channel members (#34)
* fix: SeedUserFiles uses agent-level USER.md as seed for predefined agents

For predefined agents, the wizard writes a populated USER.md (owner
name, language, notes) via agents.files.set into agent_context_files
(agent-level). On the first chat message, SeedUserFiles was seeding a
blank embedded template into user_context_files (per-user level).

LoadContextFiles for predefined agents lets per-user content override
agent-level content, so the blank per-user USER.md shadowed the
wizard-written content. The owner profile was stored in the DB but
never served to the agent, triggering unnecessary onboarding.

Fix: before falling back to the embedded template, check whether
agent_context_files already has a non-empty USER.md for the agent.
If it does, use that content as the per-user seed. The check is
conditional (predefined agent + USER.md not yet seeded per-user) so
it adds at most one extra DB read per new user.

The existing "don't overwrite" guard (hasFile check) is unchanged —
personalized per-user content written through conversation is still
never overwritten.

* test: add unit tests for SeedUserFiles agent-level USER.md seeding

Covers:
- Predefined agent: wizard-written USER.md at agent level is used as
  per-user seed (primary regression test for the bug fix)
- Predefined agent: falls back to blank embedded template when no
  agent-level USER.md exists
- Predefined agent: existing per-user content is never overwritten
- Open agent: embedded template path is unaffected
- Predefined agent: BOOTSTRAP.md uses BOOTSTRAP_PREDEFINED.md template
- Idempotency: second SeedUserFiles call seeds nothing

* fix(bootstrap): SeedUserFiles uses agent-level USER.md as seed for predefined agents

Use map[string]string for agent-level files (more general, extensible)
and clean continue-based loop flow, matching the investigation spec
in plans/goclaw-pr/goclaw-pr-seed-user-files.md exactly.

Previous implementation used a single string and if/else structure —
functionally correct but diverged from the spec in variable type,
load condition, and loop exit pattern.

* fix(agents): predefined agents visible in web UI for channel members

Two bugs combined to make wizard-installed predefined agents invisible
in the web UI for all real users.

Bug 1 — agents.create WS hardcoded owner_id = "system":
- Add `owner_ids []string` to WS params struct (omitempty, backward compat)
- Resolve ownerID: use first entry if provided, fall back to "system"
- Allows external provisioning tools to set a real user as owner

Bug 2 — ListAccessible SQL excluded system-owned predefined agents:
- Extend WHERE clause with 4th OR: predefined agents are visible when
  the requesting user appears in any enabled channel's allow_from list
- Uses EXISTS + jsonb_array_elements_text(ci.config->'allow_from')
- No schema migration needed — allow_from already populated by wizard

Also adds 4 unit tests for Bug 1 (agents_create_owner_test.go):
- UsesProvidedOwnerID, FallsBackToSystem_WhenAbsent,
  FallsBackToSystem_WhenEmpty, MultipleOwnerIDs_UsesFirst
2026-03-01 21:17:32 +07:00
419935b9f9 fix: validate provider API keys during bootstrap using auth-required endpoints (#22)
* fix(channels): start outbound dispatcher before channel check

StartAll() returned early when no channels existed at boot,
skipping the dispatchOutbound goroutine. Channels loaded later
via Reload() assumed the dispatcher was running, causing outbound
messages (agent responses) to never reach Telegram.

Move dispatcher startup before the empty-channel early return so
dynamically loaded channels always have a running consumer.

* feat(ui): add LLM provider warning on overview page and ignore plans dir

Show alert when no providers configured or all disabled, linking to provider settings. Add plans/ to .gitignore.

* feat(onboard): add provider connectivity verification and placeholder seeding

- Add onboard_verify.go: verify API keys via POST to chat/completions
  endpoint (401/403 = fatal, 400/422 = key valid, 5xx = warn)
- Verify all configured providers before seeding in auto-onboard
- Seed disabled placeholder providers (OpenRouter, Synthetic, AliCloud
  API/Sub) for UI discoverability after managed data seeding

* refactor: reuse provider layer for bootstrap key verification

- Replace raw HTTP requests with provider.Chat() calls, matching the
  existing verify pattern in internal/http/provider_verify.go
- Respect config base URL overrides (GOCLAW_ANTHROPIC_BASE_URL, etc.)
- Only block bootstrap if the primary provider key is invalid;
  secondary provider failures are logged as warnings
- Add friendlyProviderError for human-readable error extraction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
Co-authored-by: viettranx <viettranx@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:36:13 +07:00
51f8b895a3 feat: Publish pre-built Docker images to GHCR (#23)
* feat: add GitHub Actions workflow to publish Docker images to GHCR

Build and push all 4 variants (latest, otel, tsnet, full) on version
tags with multi-platform support (linux/amd64, linux/arm64).

Closes #19

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add web UI image build to GHCR publish workflow

Adds a separate job to build and push the ui/web Dockerfile as
ghcr.io/<repo>-web with the same multi-platform and tagging strategy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Bruno Clermont <bruno.clermont@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:06:53 +07:00
Duc Nguyenandntduc 1afe721542 feat(ui): add LLM provider warning and fix outbound dispatcher startup (#20)
* fix(channels): start outbound dispatcher before channel check

StartAll() returned early when no channels existed at boot,
skipping the dispatchOutbound goroutine. Channels loaded later
via Reload() assumed the dispatcher was running, causing outbound
messages (agent responses) to never reach Telegram.

Move dispatcher startup before the empty-channel early return so
dynamically loaded channels always have a running consumer.

* feat(ui): add LLM provider warning on overview page and ignore plans dir

Show alert when no providers configured or all disabled, linking to provider settings. Add plans/ to .gitignore.

---------

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
2026-03-01 15:05:02 +07:00
Thieu Nguyen b07159894d fix(mcp): use json.RawMessage for JSONB fields to prevent base64 serialization (#25)
[]byte fields were base64-encoded during JSON serialization, causing
frontend TypeError when calling .join() on non-array values. Added
Array.isArray() guards in UI as defensive fallback.
2026-03-01 15:03:57 +07:00
Duc Nguyenandntduc 27f73cde6a Fix/model name display (#26)
* fix(channels): start outbound dispatcher before channel check

StartAll() returned early when no channels existed at boot,
skipping the dispatchOutbound goroutine. Channels loaded later
via Reload() assumed the dispatcher was running, causing outbound
messages (agent responses) to never reach Telegram.

Move dispatcher startup before the empty-channel early return so
dynamically loaded channels always have a running consumer.

* feat(ui): add LLM provider warning on overview page and ignore plans dir

Show alert when no providers configured or all disabled, linking to provider settings. Add plans/ to .gitignore.

* fix: use model ID as display name in OpenAI-compatible provider list

The `owned_by` field (e.g. "system") was incorrectly used as the model
display name, causing all models to show as "system" in the UI dropdown
for providers like AliCloud DashScope.

---------

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
2026-03-01 14:38:28 +07:00
viettranxandClaude Opus 4.6 0e75c21e55 feat: overhaul team delegation, Telegram resilience, and artifact forwarding
Team delegation:
- Unify spawn/subagent/delegate into single spawn tool
- Sibling-aware announce suppression with artifact accumulation
- Fix auto-complete race (isLastDelegation guard)
- Add team tasks list limit (20) with search guidance
- Multi-round orchestration patterns in TEAM.md
- Communication guidance for initial vs follow-up delegations

Telegram resilience:
- Add retrySend wrapper (3 attempts, escalating delay) for network errors
- Fix HTML fallback: strip tags + unescape entities instead of showing raw HTML
- Pre-process HTML tags in LLM output to markdown before conversion pipeline
- Skip caption truncation entirely when > 1024 bytes, send text separately
- Auto-send large images (>5MB) as documents to avoid compression

Artifact forwarding:
- Fix missing ContentType on forwarded media (mimeFromExt for result.Media/ForwardMedia)
- Add deliver parameter to write_file for file attachment delivery
- Extend mimeFromExt with document MIME types

UI: fix regenerate dialog overflow, improve task list layout, delegation detail view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:34:36 +07:00
viettranx 7613e07e4f docs: expand Docker Compose upgrade instructions to detail both simple and explicit upgrade paths. 2026-02-28 23:39:52 +07:00
viettranx 857262c641 feat: Add copy-to-clipboard functionality for trace IDs and refine task list layouts. 2026-02-28 23:37:13 +07:00
viettranxandClaude Opus 4.6 56827aee11 feat: add team member management (add/remove) and fix UI issues
- Add teams.members.add and teams.members.remove RPC methods with
  bidirectional link management and cache invalidation
- Add DeleteTeamLinksForAgent to AgentLinkStore for link cleanup
- Add member add/remove UI in team detail Members tab
- Widen agent create dialog (sm:max-w-4xl) to fix cramped layout
- Fix combobox dropdown truncation (min-w-full instead of w-full)
- Fix traces refresh button animation using isFetching instead of isLoading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:23:48 +07:00
viettranx 2623c65321 fix: Improve text wrapping in trace and span previews by changing break-words to break-all. 2026-02-28 19:01:47 +07:00
viettranx 26067d2432 feat: enhance agent tool loop detection sensitivity, add Markdown to HTML conversion for Telegram media captions, and refine trace detail dialog UI styling. 2026-02-28 18:58:55 +07:00
viettranx 45ea0ee9a4 feat: Add native Gemini image generation support and refine media path stripping in agent output. 2026-02-28 18:44:51 +07:00
viettranxandClaude Opus 4.6 50a90aa8c6 refactor: split large Go files (>350 lines) into smaller same-package files
Pure file reorganization — no logic changes, no renames, no refactoring.
Functions moved to new files in the same package for maintainability.

Split 13 files across 6 packages into 25 new files:
- store/pg: teams.go → teams_tasks/delegation/messaging.go; mcp_servers.go → mcp_servers_access.go
- tools: delegate.go → delegate_state/policy/events.go; subagent.go → subagent_exec/config.go;
  web_search.go → web_search_brave/ddg.go; web_fetch.go → web_fetch_convert.go;
  sessions.go → sessions_history/send.go
- providers: anthropic.go → anthropic_stream/request.go
- mcp: manager.go → manager_connect/tools/util.go
- channels/feishu: bot.go → bot_parse/policy.go; larkclient.go → larkclient_messaging.go
- cmd: gateway_consumer.go → gateway_cron.go; agent_chat.go → agent_chat_client/standalone.go

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:27:28 +07:00
viettranxandClaude Opus 4.6 0655849d3d fix(cron): route jobs through scheduler for concurrency control and parallel execution
- Simplify cron session key to `agent:{agentId}:cron:{jobID}` (remove redundant `:run:{runID}`)
- Route cron jobs through scheduler's cron lane instead of calling loop.Run() directly
- Scheduler enforces per-session maxConcurrent=1, preventing same job from running concurrently
- Parallelize due job execution with goroutines + WaitGroup (PG and file store)
- Move scheduler creation before cron setup in gateway.go initialization order

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:53:15 +07:00
viettranxandClaude Opus 4.6 73b46c3634 feat(security): apply upstream TS OpenClaw security and core engine fixes
Port 8 fixes from upstream TypeScript OpenClaw (4 CRITICAL + 4 HIGH):

CRITICAL:
1. Tool call name trimming — add strings.TrimSpace() to all provider
   response parsers (Anthropic 2 locations, OpenAI 3 locations) to
   prevent registry lookup failures from LLM whitespace-padded names
2. Shell env injection deny patterns — block GIT_EXTERNAL_DIFF,
   GIT_DIFF_OPTS, BASH_ENV, and ENV=.*sh to prevent code execution
   via environment variable injection during git/shell operations
3. Broken symlink escape — recursive target resolution via
   resolveThroughExistingAncestors() to catch chained symlinks
   that escape workspace (e.g. link1→link2→/etc/passwd)
4. Mutable parent-symlink TOCTOU check — hasMutableSymlinkParent()
   detects symlinks in writable parent dirs that could be rebound
   between path validation and file operation

HIGH:
5. Model fallback thinking preservation — add ThinkingCapable interface
   to providers/types.go, implement on Anthropic/OpenAI/DashScope,
   check before injecting thinking_level in agent loop, warn on
   fallback when thinking is configured
6. Cron session-key double-prefix guard — prevent agent:X:cron:agent:X
   duplication in BuildCronSessionKey()
7. Webhook rate limiter — bounded WebhookRateLimiter (4096 keys max,
   60s window, 30 hits/window) to prevent memory exhaustion DoS
8. DM policy allowlist validation — warn at startup when
   dmPolicy=allowlist with empty allowFrom (silent message drop)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:52:37 +07:00
viettranx d3323352a1 build: Add *.tsbuildinfo to gitignore to prevent tracking generated TypeScript build info files. 2026-02-28 16:27:21 +07:00
viettranxandClaude Opus 4.6 813c602bca feat(ui): migrate to TanStack Query, add server-side pagination, and improve error handling
- Add @tanstack/react-query with shared cache and centralized query keys
- Migrate all 14 CRUD hooks from manual useState/useCallback to useQuery/useMutation
- Add WS event-driven query invalidation (sessions, traces auto-refresh on run completion)
- Consolidate LlmConfigSection to delegate provider/model UI to ProviderModelSelect
- Add server-side pagination for custom-tools and channel-instances (Go store + HTTP handler)
- Extract shared types into dedicated files (provider, custom-tool, mcp, channel, skill, trace)
- Add network error handling in HTTP client and connectivity check on login
- Add disconnect banner in app layout when gateway connection is lost

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:25:59 +07:00
viettranxandClaude Opus 4.6 552ddc059e feat(thinking): add per-agent extended thinking with Anthropic, OpenAI, and DashScope support
Implement full thinking mode system: per-agent thinking_level config (off/low/medium/high)
stored in other_config JSONB, per-provider param injection (Anthropic budget_tokens, OpenAI
reasoning_effort, DashScope enable_thinking+thinking_budget), Anthropic extended thinking with
streaming parse and tool use block preservation via RawAssistantContent, thinking token tracking
in trace spans, and Web UI with agent config selector, chat thinking block rendering, and trace
thinking token display. No DB migration needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:45:34 +07:00
viettranxandClaude Opus 4.6 d913f29c69 feat(providers): add DashScope and Bailian Coding providers with reasoning_content support
- Add DashScope (Qwen) native provider with tools+streaming fallback
- Add Bailian Coding provider with hardcoded model list (no /v1/models API)
- Parse reasoning_content in OpenAI-compat streaming/non-streaming responses
- Emit ChatEventThinking events in agent loop for thinking models
- Add vision support for DashScope (qwen3-vl)
- Fix provider form dialog not updating API base URL when switching types
- Update README provider count from 11+ to 13+

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 14:56:14 +07:00
viettranx 2041b7037b feat: Implement timezone support for cron schedules, improve cron job patching, and enhance trace visibility for cron-triggered agent runs. 2026-02-28 14:17:30 +07:00
Michael e76aabb3a4 fix(browser): return MEDIA: path from screenshot instead of truncated base64 (#8)
handleScreenshot returned a truncated base64 string (first 100 chars only),
which meant the screenshot data was effectively lost and never delivered
to channels (Telegram, Discord, etc.) via the media pipeline.

The media pipeline in loop.go looks for "MEDIA:" prefix in tool results
to collect files for channel delivery (e.g. sendPhoto on Telegram).
Without this prefix, screenshots were silently discarded.

Fix: save screenshot bytes to a temp file and return MEDIA:/path,
matching the pattern used by create_image and tts tools.
2026-02-28 13:09:03 +07:00
Michael 370c290642 fix(tools): use /images/generations endpoint for Gemini and OpenAI image gen (#9)
create_image exclusively used /chat/completions with modalities:["image","text"]
which only works on OpenRouter. Gemini returns HTTP 400:
  "Image generation is not yet supported on the chat.completions endpoint"
OpenAI's DALL-E models also require /images/generations, not /chat/completions.

Fix: route OpenRouter through /chat/completions (supports modalities),
route all other providers (Gemini, OpenAI, etc.) through the standard
/images/generations endpoint with response_format:"b64_json".

Also update default Gemini model from deprecated gemini-2.0-flash-exp
to gemini-2.5-flash-image.
2026-02-28 13:08:32 +07:00
viettranx 4104420d5e feat: ignore commands explicitly addressed to other bots in Telegram group chats. 2026-02-28 13:07:32 +07:00
maemreyo eacc481998 feat(telegram): add speech-to-text transcription for voice/audio messages with audio-aware routing (#14)
* feat(telegram): add speech-to-text transcription for voice/audio messages with audio-aware routing

Implement an STT pipeline for inbound voice and audio messages in the Telegram channel:

- Add new STT configuration options (stt_proxy_url, stt_api_key, stt_tenant_id, stt_timeout_seconds)
- Add VoiceAgentID config to route voice messages to a dedicated speaking agent
- New stt.go module handles transcription via configurable STT proxy service
- MediaInfo struct now includes Transcript field for storing transcription results
- buildMediaTags embeds transcript in media tags when available for downstream processing

This enables the pipeline to process voice messages with full transcription rather than falling back to text-only handling.

* test(telegram): add tests for buildMediaTags and transcribeAudio functions
2026-02-28 11:54:33 +07:00
Duc Nguyen 4c67dff24d feat(providers): support custom base URL for Anthropic provider (#16)
Allow overriding the Anthropic API base URL via GOCLAW_ANTHROPIC_BASE_URL
env var, config JSON, or DB provider record. Enables use of Anthropic-
compatible proxies and custom endpoints.

Also adds Makefile shortcuts for docker compose (up/down/logs).
2026-02-28 11:50:00 +07:00
viettranxandClaude Opus 4.6 7450e7014a fix: Correct provider type seeding and add missing env vars for all channels
- Fix seedManagedData() hardcoding openai_compat for all non-Anthropic providers;
  now uses resolveProviderType() mapping to correct store constants (gemini_native,
  minimax_native, etc.) — fixes model listing in web UI for Gemini
- Rename GOCLAW_FEISHU_* env vars to GOCLAW_LARK_* (Lark is the global brand)
- Add WhatsApp env override (GOCLAW_WHATSAPP_BRIDGE_URL) and auto-enable
- Add missing env vars to docker-compose.yml (Cohere, Perplexity, Lark, Zalo, WhatsApp)
- Update .env.example with all providers/channels, remove unnecessary GOCLAW_PROVIDER
- Add Cohere and Perplexity to prepare-env.sh provider detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 11:46:59 +07:00
Duc Nguyenandntduc fcaf3531ba fix(channels): start outbound dispatcher before channel check (#15)
StartAll() returned early when no channels existed at boot,
skipping the dispatchOutbound goroutine. Channels loaded later
via Reload() assumed the dispatcher was running, causing outbound
messages (agent responses) to never reach Telegram.

Move dispatcher startup before the empty-channel early return so
dynamically loaded channels always have a running consumer.

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
2026-02-28 11:10:18 +07:00
miken90 4db5259581 fix(memory): update Gemini embedding to gemini-embedding-001 with dimension support (#10)
- Replace deprecated text-embedding-004 with gemini-embedding-001
- Add WithDimensions() to OpenAIEmbeddingProvider for dimension truncation
- Pass dimensions=1536 for Gemini to match pgvector column size
- Allow config override of Gemini embedding model via embedding_model
2026-02-28 09:16:00 +07:00
hiandClaude Opus 4.6 1b1ca2214a feat(discord): support GOCLAW_DISCORD_TOKEN env var for channel config (#6)
Add env var overlay and auto-enable for Discord channel, matching the
existing Telegram pattern. Update .env.example and docker-compose.yml.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 09:14:36 +07:00
viettranxandClaude Opus 4.6 2f44e86ef2 fix: Strip bot self-mention in Discord responses and remove AGENTS.md from summoning modal
Discord: include sender's mention format in [From:] annotation so models
use the correct user ID, and strip the bot's own @mention from message
content to prevent the model from echoing it back.

Summoning modal: remove AGENTS.md from progress list since backend only
generates SOUL.md and IDENTITY.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:12:15 +07:00
viettranxandClaude Opus 4.6 42263e5cc5 feat: Add tool loop detection, negative context injection, and fix Docker workspace permissions
- Add tool loop detection (toolloop.go): tracks repeated no-progress tool calls
  using SHA256 hashing of args+results. Warning at 5 identical calls, force stop
  at 10. Prevents Gemini models from burning tokens in infinite loops.
- Inject AVAILABILITY.md negative context when agent has no team/delegation
  targets, so models don't waste iterations probing unavailable capabilities.
- Fix Dockerfile: create /app/.goclaw directory so Docker volume initializes
  with correct goclaw:goclaw ownership instead of root:root.
- Update collapseToolCallsWithoutSig comments for clarity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:00:50 +07:00
viettranxandClaude Opus 4.6 40425d3ad2 fix: Fold tool results as user messages instead of imitable text pattern
Gemini 2.5 flash doesn't return thought_signature, causing
collapseToolCallsWithoutSig to convert tool_calls to "(Used tool ...)"
text that Gemini imitates instead of making real tool calls.

Now strips tool_calls and folds results into plain user messages
so the model retains context without an imitable pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 21:03:44 +07:00
viettranxandClaude Opus 4.6 ef3c35a8b5 fix: Drop tool_calls without thought_signature instead of converting to text, fix trace detail word-wrap
Gemini 2.5 flash doesn't return thought_signature in OpenAI-compat responses,
causing collapseToolCallsWithoutSig to convert ALL tool_calls to "(Used tool ...)"
text. Gemini then imitates this pattern instead of making actual tool calls.
Now drops tool_call cycles entirely, preserving only the assistant's text content.

Also fixes word-wrap in trace detail dialog (break-words instead of break-all)
and uses <pre> with whitespace-pre-wrap for trace-level input/output previews.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:53:53 +07:00
viettranx 2e5cf4a9c9 fix: Implement Lark bot identity probe and group history for mention detection, fix Discord placeholder chunking.
- Implement `probeBotInfo()` to fetch bot's `open_id` via `/open-apis/bot/v3/info`, fixing group mention detection that was always false due to empty `botOpenID`.
- Add group pending history support to Feishu channel (record/build context/clear) matching Discord pattern.
- Fix Discord placeholder edit to chunk long responses instead of truncating at 2000 chars.
2026-02-27 20:22:08 +07:00
viettranx 2ee39c8483 feat: Add pairing enforcement, group history, and display name resolution for Discord & WhatsApp channels.
- Implement DM pairing flow for Discord and WhatsApp (checkDMPolicy, sendPairingReply with debounce)
- Add "pairing" case to BaseChannel.CheckPolicy() to reject instead of falling through to "open"
- Add group pending history tracking to Discord (record when not mentioned, prepend context when mentioned)
- Resolve Discord display names with priority: server nickname > global name > username
- Fix Gemini collapse format to prevent model from imitating tool call patterns
- Fix formatTokens crash on null/undefined input
2026-02-27 19:59:51 +07:00
viettranx 0844969819 feat: Add thought_signature support for Gemini tool calls, including a compatibility function for old sessions and refactoring OpenAI types. 2026-02-27 18:46:01 +07:00