Commit graph

368 commits

Author SHA1 Message Date
Hoshina
a1f95f02bc refactor(wecom): rebuild ai bot channel 2026-03-24 20:23:29 +08:00
美電球
f2f6987f00
test(agent): allow mock custom tool args (#1965) 2026-03-24 19:27:29 +08:00
Orkun Manap
dd9adf8a04
feat: add ElevenLabs Scribe STT transcriber and Telegram SendVoice support (#1905)
* feat: add ElevenLabs Scribe STT transcriber and Telegram SendVoice support

Add ElevenLabsTranscriber as an alternative speech-to-text provider using
the ElevenLabs Scribe API (scribe_v1). This enables voice message
transcription for users who already have an ElevenLabs API key, without
requiring a separate Groq account.

Changes:
- Add ElevenLabsTranscriber implementing the Transcriber interface
- Update DetectTranscriber to check providers.elevenlabs.api_key first,
  falling back to Groq for backward compatibility
- Add ElevenLabs to ProvidersConfig
- Add "voice" media type for OGG files with "voice" in filename
- Add SendVoice support in Telegram channel for voice bubble messages
- Add comprehensive tests for ElevenLabs transcriber

Configuration:
  "providers": {
    "elevenlabs": {
      "api_key": "sk_your_key_here"
    }
  }

Closes #1503 (partial)

* fix: move voice-bubble detection into Telegram channel to avoid regression in other channels

Address review feedback: keep inferMediaType returning "audio" for all
OGG files. Voice-bubble detection (SendVoice vs SendAudio) is now done
inside the Telegram channel based on filename, so other channels that
map "audio" explicitly are unaffected.

* fix: align VoiceConfig struct tags to pass golines formatter

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

* fix(agent): use ModelName in loop test added by upstream

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 22:11:10 +01:00
daming大铭
2c48cd3461
Merge pull request #1907 from xiwuqi/wuxi/fix-reasoning-channel-content
fix(agent): route reasoning_content to reasoning channel
2026-03-24 01:24:14 +08:00
afjcjsbx
5d5536a1a6 fix delivery and steering 2026-03-23 14:09:52 +01:00
uiyzzi
16d23d8cdc feat(security): add sensitive data filtering for tool results sent to
LLM

Prevent LLM from seeing its own credentials (API keys, tokens, secrets)
by filtering sensitive values from tool call results before sending to
the
model. Values are collected from .security.yml and replaced with
[FILTERED] using an efficient strings.Replacer (O(n+m)).

- Add FilterSensitiveData and FilterMinLength to ToolsConfig
- Implement SensitiveDataReplacer() with sync.Once caching in
  SecurityConfig
- Use reflection to collect all sensitive values (Model API keys,
  channel
  tokens, web tool API keys, skills tokens)
- Apply filtering in agent loop at 4 tool result locations
- Add comprehensive tests covering all token types
2026-03-23 20:55:41 +08:00
afjcjsbx
8ed171dbe6 resolved conflicts 2026-03-23 13:43:02 +01:00
afjcjsbx
fddfd56b50 Merge branch 'main' into fix/binary-tool-output-handling
# Conflicts:
#	pkg/agent/loop.go
#	pkg/agent/loop_test.go
#	pkg/commands/builtin_test.go
#	pkg/tools/send_file_test.go
2026-03-23 13:16:23 +01:00
Liqiang Liu
f81b44bf19
fix(provider): deduplicate tool results and merge consecutive tool_result blocks for Anthropic API (#1793)
Anthropic API returns 400 when multiple tool_result blocks share the same
tool_use_id, or when consecutive tool results are sent as separate user
messages. This fix:

1. Adds ToolCallID deduplication in sanitizeHistoryForProvider (context.go)
   to drop duplicate tool results before sending to any provider.
2. Merges consecutive tool result messages into a single user message with
   multiple tool_result content blocks in Anthropic's buildRequestBody,
   for both "user" (with ToolCallID) and "tool" role messages.
3. Adds tests for both behaviors.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:24:46 +08:00
uiyzzi
d1d2155edb Use ModelName instead of Model in test config structs 2026-03-23 16:47:13 +08:00
Mauro
054b55fdfc
Merge pull request #1893 from afjcjsbx/feat/skill-channel-commands
feat(skills): add channel commands to list and force installed skills
2026-03-23 09:04:06 +01:00
Cytown
5a8aab8143 Merge branch 'main' into version 2026-03-23 11:41:36 +08:00
Cytown
7bf4831059 Merge branch 'main' into version 2026-03-23 10:54:08 +08:00
xiwuqi
336d5d4c07 fix(agent): route reasoning_content to reasoning channel 2026-03-22 19:57:47 -05:00
afjcjsbx
1e98f86fa9 fix Ooutboundmedia 2026-03-23 00:08:43 +01:00
afjcjsbx
f735b0551c fix 2026-03-22 23:46:10 +01:00
afjcjsbx
388505d7e0 fix lint 2026-03-22 23:39:33 +01:00
afjcjsbx
b90c5007f6 resolve conflicts 2026-03-22 23:36:25 +01:00
afjcjsbx
14a4983af3 Merge branch 'main' into fix/binary-tool-output-handling
# Conflicts:
#	pkg/agent/loop.go
#	pkg/tools/result.go
2026-03-22 23:08:27 +01:00
afjcjsbx
be59133ce9 resolve conflicts 2026-03-22 20:58:46 +01:00
afjcjsbx
d3ba40090b Merge branch 'main' into feat/skill-channel-commands
# Conflicts:
#	pkg/agent/loop.go
2026-03-22 20:51:16 +01:00
BeaconCat
60a7098fd3 feat(search): add Baidu Qianfan AI Search provider with i18n docs
- Add BaiduSearchConfig struct and register in WebToolsConfig/defaults
- Insert Baidu Search in priority chain: DuckDuckGo > Baidu > GLM Search
- Use perplexityTimeout (30s) — Qianfan is LLM-based
- Fix response parsing: use references[] field per API spec
- Add baidu_search block to config.example.json

docs: sync configuration.md and README Documentation table across all languages

- Complete truncated configuration.md for fr/ja/pt-br/vi/zh: add Spawn
  async flow diagram, Providers table, Model Configuration (all vendors,
  examples, load balancing, migration), Provider Architecture, Scheduled
  Tasks, and Advanced Topics links
- Add Hooks/Steering/SubTurn entries to Documentation table in all 8
  READMEs (en/zh/fr/id/it/ja/pt-br/vi), ordered before Troubleshooting
- Add Baidu Search row to web search table in all 8 READMEs and
  tools_configuration.md (en + 5 i18n); zh README reorders search
  engines with China-friendly options first
- Add Matrix channel docs translations (fr/ja/pt-br/vi)
- Add Weixin channel to chat-apps.md and all README Channels tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 00:51:27 +08:00
afjcjsbx
d7d2bf69bf feat(skills): add channel commands to list and force installed skills 2026-03-22 15:33:25 +01:00
Administrator
7868c5811a fix(agent): fix subturn panic result, hard abort rollback, and drain bus exit
- spawnSubTurn: set result=nil on panic instead of constructing a non-nil ToolResult
- HardAbort: roll back session history to initialHistoryLength after Finish()
- drainBusToSteering: switch to non-blocking reads after first message so function
  returns promptly when the inbound channel is empty
- remove obsolete documentation files
2026-03-22 20:35:14 +08:00
Administrator
7ba8682ac5 Merge branch 'refactor/agent' into feat/subturn-poc 2026-03-22 19:51:43 +08:00
Administrator
f7f27e237a merge: resolve conflicts between refactor/agent and main 2026-03-22 19:21:58 +08:00
afjcjsbx
df4f322f09 fix(tool): route binary outputs through the media pipeline. 2026-03-22 12:05:28 +01:00
daming大铭
0432facffc
Merge pull request #1863 from alexhoshina/feat/hook-manager
Feat/hook manager
2026-03-22 14:36:07 +08:00
Administrator
88d754b172 merge main 2026-03-22 13:47:14 +08:00
Cytown
7c854fe6d7 Merge branch 'main' into version 2026-03-22 02:53:55 +08:00
Cytown
e455eb5e67 refactor: seperate security.yml for store keys 2026-03-22 01:55:00 +08:00
daming大铭
ebcd5645f1
Revert "feat(tools): add exec tool enhancement with background execution and …"
This reverts commit f901af8cbc.
2026-03-22 00:39:47 +08:00
Administrator
24d6cb5272 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-21 23:42:25 +08:00
Liu Yuan
f901af8cbc
feat(tools): add exec tool enhancement with background execution and PTY support (#1752)
- Unified exec tool with actions: run/list/poll/read/write/send-keys/kill
- PTY support using creack/pty library
- Process session management with background execution
- Process group kill for cleaning up child processes
- Session cleanup: 30-minute TTL for old sessions
- Output buffer: 100MB limit with truncation

Actions:
- run: execute command (sync or background)
- list: list all sessions
- poll: check session status
- read: read session output
- write: send input to session stdin
- send-keys: send special keys (up, down, ctrl-c, enter, etc.)
- kill: terminate session

Tests:
- PTY: allowed commands, write/read, poll, kill, process group kill
- Non-PTY: background execution, list, read, write, poll, kill, process group kill
- Session management: add/get/remove/list/cleanup
2026-03-21 22:38:03 +08:00
Hoshina
337e43e5a5 feat(agent): add configurable hook mounting 2026-03-21 19:46:16 +08:00
Hoshina
cf68c91eca feat(agent): add hook manager foundation 2026-03-21 19:15:10 +08:00
Administrator
670b433f1a refactor: replace interface{} with any for improved type clarity 2026-03-21 18:24:56 +08:00
Administrator
1bd144ac13 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-21 17:13:26 +08:00
Administrator
087e8519c5 refactor: improve code readability and consistency across multiple files 2026-03-21 17:12:45 +08:00
Mauro
100720bb74
Merge pull request #1818 from Alix-007/fix/issue-1815-empty-response-message
fix(agent): separate empty-response and tool-limit fallbacks
2026-03-20 23:23:48 +01:00
afjcjsbx
9e344594a2 fix logic 2026-03-20 21:07:07 +01:00
afjcjsbx
827449aff3 fix lint 2026-03-20 20:12:55 +01:00
afjcjsbx
1c6586681d fix(agent) scope steering 2026-03-20 19:44:00 +01:00
Amir Mamaghani
71134babb9
feat(telegram): stream LLM responses via sendMessageDraft (#1101)
* feat(telegram): stream LLM responses in real-time via sendMessageDraft

Implements real-time token streaming to Telegram using the sendMessageDraft
API (telego v1.6.0). Instead of showing only a "Thinking..." placeholder
until the full response arrives, users now see partial LLM output appear
in the chat as it's generated.

The streaming pipeline threads through all layers:

- StreamingProvider interface (providers/types.go): opt-in ChatStream()
  method that receives an onChunk callback with accumulated text
- OpenAI-compatible SSE streaming (openai_compat/provider.go): parses
  SSE events with stream:true, handles text deltas and tool call assembly
- Anthropic native streaming (anthropic/provider.go): uses SDK's
  NewStreaming() for direct Anthropic API connections
- HTTPProvider delegation (http_provider.go): delegates ChatStream to
  the underlying openai_compat provider
- StreamingCapable + Streamer interfaces (channels/interfaces.go):
  opt-in channel capability like TypingCapable/PlaceholderCapable
- Telegram streamer (telegram/telegram.go): BeginStream returns a
  telegramStreamer that throttles sendMessageDraft calls (3s/200 chars)
  with graceful degradation on API errors
- StreamDelegate bridge (bus/bus.go): decouples agent loop from channel
  manager without tight imports
- Manager integration (manager.go): implements StreamDelegate, tracks
  streamActive state, coordinates with placeholder editing
- Agent loop (loop.go): uses ChatStream when both provider and channel
  support streaming, cancels stream on tool calls, skips PublishOutbound
  when Finalize already delivered the message

Graceful degradation:
- Bots without forum/topics mode: first sendMessageDraft error sets
  failed=true, subsequent Updates become no-ops, Finalize still delivers
  via SendMessage. User sees normal non-streaming behavior.
- Non-streaming providers: type assertion fails, falls back to Chat()
- Config opt-out: streaming.enabled (default true) in telegram config

Closes #1098

* fix(telegram): delete placeholder message when streaming delivers response

When streaming was active, the "Thinking..." placeholder message stayed
in the chat because preSend only deleted the tracking entry without
removing the actual Telegram message. Now preSend deletes the placeholder
via the new MessageDeleter interface when streamActive is set.

* refactor(streaming): remove dead code and simplify streaming wiring

- Delete unused Anthropic ChatStream/parseStream (-131 lines) — factory
  creates HTTPProvider for all OpenAI-compat providers including OpenRouter
- Simplify runLLMIteration from 4 to 3 return values (remove unused
  streamed bool)
- Replace managerStreamer struct with finalizeHookStreamer using embedding
  (Update/Cancel promoted, only Finalize overridden)

* fix(streaming): skip streamer acquisition when SendResponse is false

Heartbeat messages set SendResponse=false but the streaming path
was unconditionally acquiring a streamer, causing HEARTBEAT_OK to
leak to Telegram via streamer.Finalize().

* fix(streaming): guard streamer for non-sendable messages, add streaming config

Skip streamer acquisition for heartbeat (NoHistory=true), preventing
HEARTBEAT_OK from leaking to Telegram via streamer.Finalize().

Add streaming.enabled to Telegram defaults and example config.

* feat(telegram): stream LLM responses in real-time via sendMessageDraft

Implements real-time token streaming to Telegram using the sendMessageDraft
API (telego v1.6.0). Instead of showing only a "Thinking..." placeholder
until the full response arrives, users now see partial LLM output appear
in the chat as it's generated.

The streaming pipeline threads through all layers:

- StreamingProvider interface (providers/types.go): opt-in ChatStream()
  method that receives an onChunk callback with accumulated text
- OpenAI-compatible SSE streaming (openai_compat/provider.go): parses
  SSE events with stream:true, handles text deltas and tool call assembly
- Anthropic native streaming (anthropic/provider.go): uses SDK's
  NewStreaming() for direct Anthropic API connections
- HTTPProvider delegation (http_provider.go): delegates ChatStream to
  the underlying openai_compat provider
- StreamingCapable + Streamer interfaces (channels/interfaces.go):
  opt-in channel capability like TypingCapable/PlaceholderCapable
- Telegram streamer (telegram/telegram.go): BeginStream returns a
  telegramStreamer that throttles sendMessageDraft calls (3s/200 chars)
  with graceful degradation on API errors
- StreamDelegate bridge (bus/bus.go): decouples agent loop from channel
  manager without tight imports
- Manager integration (manager.go): implements StreamDelegate, tracks
  streamActive state, coordinates with placeholder editing
- Agent loop (loop.go): uses ChatStream when both provider and channel
  support streaming, cancels stream on tool calls, skips PublishOutbound
  when Finalize already delivered the message

Graceful degradation:
- Bots without forum/topics mode: first sendMessageDraft error sets
  failed=true, subsequent Updates become no-ops, Finalize still delivers
  via SendMessage. User sees normal non-streaming behavior.
- Non-streaming providers: type assertion fails, falls back to Chat()
- Config opt-out: streaming.enabled (default true) in telegram config

Closes #1098

* fix(telegram): delete placeholder message when streaming delivers response

When streaming was active, the "Thinking..." placeholder message stayed
in the chat because preSend only deleted the tracking entry without
removing the actual Telegram message. Now preSend deletes the placeholder
via the new MessageDeleter interface when streamActive is set.

* refactor(streaming): remove dead code and simplify streaming wiring

- Delete unused Anthropic ChatStream/parseStream (-131 lines) — factory
  creates HTTPProvider for all OpenAI-compat providers including OpenRouter
- Simplify runLLMIteration from 4 to 3 return values (remove unused
  streamed bool)
- Replace managerStreamer struct with finalizeHookStreamer using embedding
  (Update/Cancel promoted, only Finalize overridden)

* fix(streaming): skip streamer acquisition when SendResponse is false

Heartbeat messages set SendResponse=false but the streaming path
was unconditionally acquiring a streamer, causing HEARTBEAT_OK to
leak to Telegram via streamer.Finalize().

* fix(streaming): guard streamer for non-sendable messages, add streaming config

Skip streamer acquisition for heartbeat (NoHistory=true), preventing
HEARTBEAT_OK from leaking to Telegram via streamer.Finalize().

Add streaming.enabled to Telegram defaults and example config.

* fix(picoclaw): add missing closing brace for StreamingProvider interface

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

* fix: resolve golangci-lint formatting issues

Fix gci import ordering in telegram and anthropic provider, and break
long function signature in openai_compat provider to satisfy golines.

* fix: address code review feedback on streaming PR

- Deduplicate Streamer interface: alias channels.Streamer to bus.Streamer
  to prevent type drift across packages
- Increase SSE scanner buffer to 10MB max to handle large single-line
  responses that exceed bufio.Scanner's 64KB default
- Switch draftID generation from math/rand to crypto/rand for
  collision-resistant random IDs
- Add context cancellation check in SSE parsing loop so cancelled
  streams stop processing immediately
- Log Finalize failures with chat_id and content length for debugging
  silent message delivery failures

* feat: make streaming throttle interval and min growth configurable

Move hardcoded streamThrottleInterval (3s) and streamMinGrowth (200)
into StreamingConfig so they can be tuned per deployment via config
or environment variables.

* fix(telegram): use parseTelegramChatID in DeleteMessage and BeginStream

These two functions called undefined parseChatID. Use
parseTelegramChatID with _ for the unused threadID instead of adding
a wrapper function. Fixes all three CI checks.

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

* fix(streaming): set streamActive only after successful Finalize

Move onFinalize hook to run after Streamer.Finalize succeeds, so that
if Finalize fails the streamActive flag stays false and the regular
placeholder fallback path remains available.

Addresses review feedback from @alexhoshina.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:04:14 +08:00
Hoshina
2b3c95b1f1 fix: lint err 2026-03-20 17:46:31 +08:00
Hoshina
0e075f7300 feat(agent): centralize turn lifecycle and continue queued steering
Refactor agent loop execution around runTurn, add explicit turn state and interrupt semantics, and automatically continue queued steering that misses the current turn boundary.
2026-03-20 17:28:12 +08:00
Hoshina
a65e0e95d6 fix: lint err 2026-03-20 15:45:27 +08:00
Hoshina
57cde73b36 feat(agent): expand event bus coverage 2026-03-20 15:29:52 +08:00
Hoshina
50cc7100ce feat(agent): make event logs show event kind clearly 2026-03-20 15:06:43 +08:00
Hoshina
af61d0bca7 feat(agent): add event bus foundation 2026-03-20 14:53:22 +08:00
Alix-007
82d574eb7b fix(agent): separate empty-response and tool-limit fallbacks 2026-03-20 14:37:47 +08:00
Administrator
4f646ef2b8 Merge branch 'main' into feat/subturn-poc 2026-03-20 11:51:25 +08:00
Administrator
e71ef3764d fix(test): reduce blank identifiers to comply with dogsled linter
Changed newTestAgentLoop calls from using 3 blank identifiers to 2 by
assigning the unused provider parameter and explicitly marking it as
unused with `_ = provider`. This fixes the dogsled linter violations
that were causing CI failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 11:12:47 +08:00
Mauro
bd4317f1f4
Merge pull request #1390 from kiannidev/fix/1323-telegram-endless-typing
fix(telegram): stop typing indicator when LLM fails or hangs
2026-03-19 21:52:10 +01:00
Administrator
c18d8a2ecc Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 22:12:51 +08:00
Alix-007
276a0cb92c
fix(agent): rebind provider after /switch model to (#1769)
* fix(agent): rebind provider after model switch

* test(agent): deduplicate switch model mock servers

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-19 21:44:01 +08:00
SakoroYou
844a4eefc7
fix(agent): avoid process exit on exec init failure and add regression test (#1784)
* fix(agent): make exec tool init failure non-fatal

* test(agent): add regression test for invalid exec config fallback
2026-03-19 21:11:36 +08:00
Administrator
583c586db6 Merge branch 'main' into feat/subturn-poc 2026-03-19 20:20:31 +08:00
Cytown
94fcb25039 Merge branch 'main' into version 2026-03-19 18:16:15 +08:00
Mauro
7673b626b3
feat(tool): debug tool usage via channels (#1332)
* feat(tool): debug usage via channel

* set defaults

* fix conflicts
2026-03-19 18:08:50 +08:00
Cytown
cfd3a1b441 Merge branch 'main' into version 2026-03-19 18:04:58 +08:00
Administrator
54889f21a7 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 17:05:09 +08:00
Mauro
a4b5a9eec1
feat(mcp): per server deferred mode (#1654)
* feat(mcp): per server deferred mode

* fix deferred behavior
2026-03-19 17:03:17 +08:00
kiannidev
310358d3da Merge upstream/main into fix/1323-telegram-endless-typing
Made-with: Cursor
2026-03-19 10:53:50 +02:00
Administrator
24a382bc0a merge main 2026-03-19 13:53:31 +08:00
Administrator
29a161e757 fix(tools): prevent nil pointer dereference in spawn tools
Add nil checks in NewSpawnTool and NewSubagentTool constructors to
handle nil manager gracefully. Fix spelling errors (cancelled->canceled)
and remove unused test code. Update tests to use mock spawner.
2026-03-19 13:51:11 +08:00
Cytown
2a6ade0fe4
feat: add /reload to gateway api and command (#1725)
* feat: add /reload to gateway api and command

* prevent duplicate reload request in same time
2026-03-19 13:42:36 +08:00
Administrator
ce311be70b feat(subturn): add configurable runtime parameters under agents.defaults
Replace hardcoded constants with config-driven parameters in agents.defaults:
- MaxDepth, MaxConcurrent, DefaultTimeout, DefaultTokenBudget, ConcurrencyTimeout
- Support JSON config and env vars (PICOCLAW_AGENTS_DEFAULTS_SUBTURN_*)
- Add getSubTurnConfig() for runtime config resolution with defaults
- Apply defaultTokenBudget when no explicit budget is provided

Rationale: SubTurn is agent execution infrastructure, not a tool, so it belongs
in agents.defaults rather than tools config.

Example:
{
  "agents": {
    "defaults": {
      "subturn": {
        "max_depth": 5,
        "max_concurrent": 10,
        "default_timeout_minutes": 10
      }
    }
  }
}
2026-03-19 13:08:46 +08:00
Administrator
99b189d3fb feat(subturn): implement token budget tracking for SubTurns 2026-03-19 12:38:18 +08:00
Administrator
01c2f8d608 refactor(subturn): remove redundant system prompt handling in runTurn function 2026-03-19 11:10:44 +08:00
Administrator
53404f18ca feat(subturn): support stateful iteration for evaluator-optimizer pattern
Add ActualSystemPrompt and InitialMessages fields to SubTurnConfig to enable
stateful worker context passing across multiple evaluation iterations.

Changes:
- Add ActualSystemPrompt field to separate system role from user task description
- Add InitialMessages field to preload ephemeral session history before agent loop starts
- Add Messages field to ToolResult for carrying session history (internal use, not serialized)
- Update runTurn to inject system prompt and preload history from InitialMessages
- Update AgentLoopSpawner to map new fields from tools.SubTurnConfig to agent.SubTurnConfig

This enables the evaluator-optimizer execution strategy in team tool to maintain
worker context across iterations while keeping SubTurn isolation intact.
2026-03-19 10:15:00 +08:00
Administrator
c732e63650 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-19 09:16:38 +08:00
Paolo Anzani
eb86e10e5c
fix(tools): propagate tool registry to subagents (#1711)
* fix(tools): propagate tool registry to subagents via Clone

SubagentManager was created with an empty ToolRegistry and SetTools()
was never called, causing all subagent tool invocations to fail with
"tool not found". This was a regression from the multi-agent refactor.

Fix: clone the parent agent's tool registry into the subagent manager
after creation but before spawn/spawn_status registration — giving
subagents access to file, exec, web, and other tools while preventing
recursive subagent spawning.

- Add ToolRegistry.Clone() for independent shallow copies
- Call subagentManager.SetTools(agent.Tools.Clone()) in registerSharedTools
- Add tests for Clone isolation, empty clone, and hidden tool state

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

* fix(tools): fix cron_test build error and add TTL clone test

- Fix cron_test.go:229 — replace non-existent SubscribeOutbound(ctx)
  with select on OutboundChan(), matching the MessageBus channel API
- Add TestToolRegistry_Clone_PreservesTTLValue per reviewer feedback
- Add version reset note to Clone() doc comment

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:17:16 +08:00
Administrator
431a53cbb1 Merge branch 'upstream-main' into feat/subturn-poc 2026-03-18 22:57:01 +08:00
美電球
899558bbfa
Feat/issue 1218 agent md context structure (#1705)
* feat(agent): add structured agent definition loader

Parse AGENT.md frontmatter into a runtime definition and pair it with SOUL.md while keeping a legacy AGENTS.md fallback for transition.

Refs #1218

* refactor(agent): build context from structured agent files

Use AGENT.md and SOUL.md as the structured bootstrap source, ignore IDENTITY.md for structured agents, remove USER.md from the new context flow, and update pkg/agent tests accordingly.

Refs #1218

* refactor(onboard): switch workspace templates to AGENT.md

Replace the legacy AGENTS.md, IDENTITY.md, and USER.md templates with a structured AGENT.md plus SOUL.md, and update the onboard template test to assert the new generated files.

Refs #1218

* docs(readme): update workspace layout for AGENT.md

Refresh the documented workspace tree across the README translations so onboarding now points to AGENT.md and SOUL.md instead of the retired AGENTS.md, IDENTITY.md, and USER.md files.

Refs #1218

* feat(agent): restore workspace USER.md context

* docs(readme): document workspace USER.md layout

* fix: sort agent definition imports for gci
2026-03-18 22:42:57 +08:00
Administrator
3611034795 fix(agent): implement Critical flag, complete tools.SubTurnConfig, remove redundant subTurnResults
- Critical flag was declared but never acted on; non-critical SubTurns
  now break out of the iteration loop when IsParentEnded() returns true
- tools.SubTurnConfig was missing Critical/Timeout/MaxContextRunes,
  making those fields unreachable from the tools layer; added fields and
  wired them through AgentLoopSpawner.SpawnSubTurn
- Removed subTurnResults sync.Map from AgentLoop — it was a redundant
  alias for the same channel already stored in turnState.pendingResults;
  dequeuePendingSubTurnResults now reads directly via activeTurnStates
- Replace hardcoded concurrencySem size 5 with maxConcurrentSubTurns constant
- Update affected tests to match new dequeuePendingSubTurnResults API
2026-03-18 18:22:06 +08:00
dev-miro26
c07f5c948f
refactor: centralize environment variable key constants (#1730)
* refactor: centralize environment variable key constants

* refactor: update environment variable constants and usage in gateway
2026-03-18 18:03:24 +08:00
Administrator
777230dcd1 feat(agent): implement /subagents command and fix sub-turn observability
- Added `/subagents` platform command to visualize the active task tree.
- Implemented GetAllActiveTurns and FormatTree in AgentLoop to support cross-session observability.
- Fixed a bug where sub-turns spawned via tools were not registered in the global `activeTurnStates` map, making them invisible to system queries.
- Enhanced tree rendering logic to identify and display "orphaned" subagents (children that outlive their parent turns).
- Registered the new command in `builtin.go` and injected the turn state provider into the commands runtime.

Modified Files:
- pkg/agent/turn_state.go: Added TurnInfo snapshotting and recursive tree formatting.
- pkg/agent/loop.go: Injected GetActiveTurn hook and implemented multi-root forest rendering.
- pkg/agent/subturn.go: Added child turn registration into activeTurnStates.
- pkg/commands/cmd_subagents.go: New command implementation.
- pkg/commands/builtin.go: Command registration.
2026-03-18 14:46:20 +08:00
Administrator
e20ff43f8b fix(agent): resolve subturn deadlocks, panics and context retry state
This commit addresses several critical concurrency and state management bugs within the SubTurn execution and delivery logic.

1. Fix Goroutine Leak & Deadlock in deliverSubTurnResult:
   - Replaced non-blocking select with a safe blocking select that listens to `resultChan` and a new `<-parentTS.Finished()` channel.
   - This ensures results are not arbitrarily dropped when the channel is full (preventing orphaned valid results), while also guaranteeing the child goroutine safely unblocks and exits if the parent finishes execution early.

2. Prevent "Send on Closed Channel" Fatal Panics:
   - Removed `close(pendingResults)` and `drainPendingResults` from `turnState.Finish()`.
   - The pendingResults channel is now naturally garbage collected, completely eliminating the race condition panic when a child attempts delivery at the exact moment the parent finishes.
   - Added a `defer recover()` failsafe inside deliverSubTurnResult to gracefully emit Orphan events in extreme edge cases.

3. Fix Truncation Recovery Prompt Drop:
   - Fixed the runTurn truncation retry logic by introducing an explicit `promptAlreadyAdded` boolean.
   - Ensures that the dynamically generated `recoveryPrompt` is correctly injected into the LLM history sequence on subsequent iterations, adhering to API roles without duplicating arrays.

4. Test Suite Stabilization:
   - Fixed TestDeliverSubTurnResultNoDeadlock to accurately wait for deterministic deliveries instead of racing timeouts.
   - Replaced defunct closed-channel tests with TestFinishedChannelClosedState matching the new Finished() mechanism.
   - Fixed the Finish(true) parameter in TestGrandchildAbort_CascadingCancellation to correctly validate Context cascade behavior.
   - All tests now pass cleanly without hanging or emitting false positives.
2026-03-18 13:10:36 +08:00
Administrator
c7ea018a73 fix(agent): prevent duplicate history during subturn context recoveries
Problem:
During subturn context limit or truncation recoveries, the recovery loops repeatedly
called `runAgentLoop` with the same or modified `UserMessage`. Because `runAgentLoop`
unconditionally adds the `UserMessage` to the session history, this resulted in:
1. Duplicate User Messages polluting the history upon `context_length_exceeded` retries.
2. The possibility of injecting empty User Messages if `opts.UserMessage` was artificially blanked out to work around the duplication.
3. Messy or duplicate entries during `finish_reason="truncated"` recovery injections.

Solution:
- Introduce `SkipAddUserMessage` boolean to `processOptions` to explicitly control whether the agent loop should write the user prompt to history.
- Add an explicit `opts.UserMessage != ""` check in `runAgentLoop` to prevent polluting history with empty message content.
- In `subturn.go`'s recovery loop, set `SkipAddUserMessage: contextRetryCount > 0` to skip writing the user message on context
2026-03-18 12:18:32 +08:00
dataCenter430
f79469c19d
Add model-native search (prefer_native) for OpenAI/Codex (#1618)
* config: add prefer_native and NativeSearchCapable for model-native search

* providers: implement native web search for OpenAI and Codex

* agent: use provider-native search when prefer_native and supported

* tests: add coverage for model-native search

* fix: Golang lint errors

* fix: update the code based on the review

* fix: update codex_provider_test
2026-03-18 11:55:30 +08:00
afjcjsbx
13d4801601 Merge branch 'main' into feat/markdown-output-format-web-fetch 2026-03-17 17:21:14 +01:00
afjcjsbx
8f460726cc fix lint + error check 2026-03-17 17:14:23 +01:00
juju
9c31b0ca95
fix: Fixed the bug where the bus was closed and consumers had unfinished messages. (#1179)
* fix: Fixed the bug where the bus was closed and consumers had unfinished messages.

* fix: remove unnecessary blank line in Close method

* fix: refactor message bus and channel handling for improved performance and reliability

* fix: improve message handling and bus closure logic for better reliability

* fix: reduce sleep duration in agent loop for improved responsiveness

* fix the test case
2026-03-18 00:12:12 +08:00
Mauro
3791f06faf
Merge branch 'main' into feat/markdown-output-format-web-fetch 2026-03-17 16:37:22 +01:00
Alix-007
c639e2c216
feat(agent): include current sender in dynamic context (#1696)
* feat(agent): include current sender in dynamic context

* test(agent): keep current-sender regression ASCII-only

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 23:31:56 +08:00
Alix-007
b4468313e4
feat(web): whitelist private fetch targets (#1688)
* feat(web): whitelist private fetch targets

* test(web): avoid accept error shadowing

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 23:22:05 +08:00
Administrator
f8defe3ae1 feat(agent): implement graceful finish vs hard abort for SubTurn lifecycle
Problem:
When parent turn finishes early, all child SubTurns receive "context canceled"
error,because child context was derived from parent context.

Solution:
Implement a lifecycle management system that distinguishes between:
- Graceful finish (Finish(false)): signals parentEnded, children continue
- Hard abort (Finish(true)): immediately cancels all children

Changes:
- turn_state.go:
  - Add parentEnded atomic.Bool to signal parent completion
  - Add parentTurnState reference for IsParentEnded() checks
  - Modify Finish(isHardAbort bool) to distinguish abort types

- subturn.go:
  - Add Critical bool to SubTurnConfig (Critical SubTurns continue after parent ends)
  - Add Timeout time.Duration for SubTurn self-protection
  - Use independent context (context.Background()) instead of derived context
  - SubTurns check IsParentEnded() to decide whether to continue or exit

- loop.go:
  - Call Finish(false) for normal completion (graceful)
  - Add IsParentEnded() check in LLM iteration loop

- steering.go:
  - HardAbort calls Finish(true) to immediately cancel children

Behavior:
- Normal finish: parentEnded=true, children continue, orphan results delivered
- Hard abort: all children cancelled immediately via context
- Critical SubTurns: continue running after parent finishes gracefully
- Non-Critical SubTurns: can exit gracefully when IsParentEnded() returns true
2026-03-17 23:06:16 +08:00
Administrator
e05d2620e1 Added tests to verify SubTurn context cancellation behavior when parent
finishes early - identified need for Critical+heartbeat+timeout mechanism.
2026-03-17 22:31:56 +08:00
Administrator
e00a3d9017 Merge upstream/main into feat/subturn-poc
Includes JSONL session persistence (#1170), spawn_status tool, Azure provider,
credential encryption, and various fixes. SubTurn features preserved and
integrated with new spawn_status functionality.
2026-03-17 21:55:20 +08:00
Administrator
2fec249be1 refactor(agent): improve SubTurn error handling and logging
- Fix context cancellation check order in concurrency timeout
  - Add structured logging for panic recovery
  - Replace println with proper logger for channel full warning
  - Simplify tool registry initialization logic
  - Remove unused ErrConcurrencyLimitExceeded error
2026-03-17 20:02:56 +08:00
Desmond Foo
b402888bfa
feat(tools): add SpawnStatusTool for reporting subagent statuses (#1540)
* feat(tools): add SpawnStatusTool for reporting subagent statuses

* feat(tools): enhance SpawnStatusTool to restrict task visibility by conversation context

* feat(tests): add Unicode result truncation and channel filtering tests for SpawnStatusTool

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* feat(tools): enhance SpawnStatusTool with task ID validation and sorting by creation timestamp

* feat(tools): update SpawnStatusTool description and parameter documentation for clarity

* refactor(tests): improve comments for clarity in ChannelFiltering test case

* fix(tools): update no subagents message for clarity and remove unnecessary locking in runTask

* fix(tools): improve description clarity for SpawnStatusTool regarding task context

* feat(tools): add spawn_status tool configuration and registration

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(agent): improve subagent management for spawn and spawn_status tools

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(tests): update ResultTruncation_Unicode test to use valid CJK character

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: lxowalle <83055338+lxowalle@users.noreply.github.com>
2026-03-17 14:41:43 +08:00
Cytown
e41423483e
add systray ui for all platform (#1649)
* add systray ui for all platform

* update from getlantern/systray to fyne.io/systray for fix test
2026-03-17 14:12:32 +08:00
Administrator
a26a7db7d2 moved turnState and related code from subturn.go to a new turn_state.go file
Created /pkg/agent/turn_state.go (246 lines) containing:
  - turnStateKeyType and context key management
  - turnState struct definition
  - TurnInfo struct and GetActiveTurn() method
  - newTurnState(), Finish(), and drainPendingResults() methods
  - ephemeralSessionStore implementation
  - All context helper functions (withTurnState, TurnStateFromContext, etc.)

  Updated /pkg/agent/subturn.go (428 lines) by:
  - Removing the moved turnState struct and methods
  - Removing unused imports (sync, session)
  - Keeping SubTurn spawning logic, config, events, and result delivery

  All tests pass and the code compiles successfully.
2026-03-17 14:11:38 +08:00
Administrator
12a8590ada fix(agent): enhance SubTurn robustness and fix race conditions
Major improvements to SubTurn implementation:

**Fixes:**
- Channel close race condition (sync.Once)
- Semaphore blocking timeout (30s)
- Redundant context wrapping
- Memory accumulation (auto-truncate at 50 msgs)
- Channel draining on Finish()
- Missing depth limit logging
- Model validation

**Enhancements:**
- Comprehensive documentation (150+ lines)
- 11 new tests covering edge cases
- Improved error messages

All tests pass. Production-ready.

Related: #1316
2026-03-17 12:50:32 +08:00
xiaoen
c63c6449b4 fix(agent): forceCompression recovers from single oversized Turn
When the entire session history is a single Turn (e.g. one user message
followed by a massive tool response), findSafeBoundary returns 0 and
forceCompression previously did nothing — leaving the agent stuck in
a context-exceeded retry loop.

Now falls back to keeping only the most recent user message when no
safe Turn boundary exists. This breaks Turn atomicity as a last resort
but guarantees the agent can recover.

Also updates docs/agent-refactor/context.md to document this behavior.

Ref #1490
2026-03-17 10:23:16 +08:00
Mauro
79b0568d75
Merge pull request #1536 from alexhoshina/fix/allow-picoclaw-media-tempdir
Fix: allow picoclaw media tempdir
2026-03-16 21:30:42 +01:00
Administrator
672d11c7d4 fix(agent): prevent double result delivery and panic bypass in SubTurn
- Fix synchronous SubTurn calls placing results in pendingResults channel,
  causing double delivery. Now only async calls (Async=true) use the channel.
- Move deliverSubTurnResult into defer to ensure result delivery even when
  runTurn panics. Add TestSpawnSubTurn_PanicRecovery to verify.
- Fix ContextWindow incorrectly set to MaxTokens; now inherits from
  parentAgent.ContextWindow.
- Add TestSpawnSubTurn_ResultDeliverySync to verify sync behavior.
2026-03-16 23:48:51 +08:00
Administrator
3c2d373a5c fix(agent): resolve race conditions and resource leaks in SubTurn
Critical fixes (5):
- Fix turnState hierarchy corruption in nested SubTurns by checking context
  before creating new root turnState in runAgentLoop
- Fix deadlock risk in deliverSubTurnResult by separating lock and channel ops
- Fix session rollback race in HardAbort by calling Finish() before rollback
- Fix resource leak by closing pendingResults channel in Finish() with recovery
- Add thread-safety docs for childTurnIDs and isFinished fields

Medium priority fixes (5):
- Move globalTurnCounter to AgentLoop.subTurnCounter to prevent ID conflicts
- Improve semaphore acquisition to ensure release even on early validation failures
- Document design choice: ephemeral sessions start empty for complete isolation
- Add final poll before Finish() to capture late-arriving SubTurn results
- Remove duplicate channel registration in spawnSubTurn to fix timing issues

Testing:
- Add 6 new tests covering hierarchy, deadlock, ordering, channel lifecycle,
  final poll, and semaphore behavior
- All 12 SubTurn tests passing with race detector

This resolves 10 critical and medium issues (5 race conditions, 2 resource leaks,
3 timing issues) identified in code review, bringing SubTurn to production-ready state.
2026-03-16 22:54:01 +08:00
Administrator
6b5d7e3fd7 fix(agent): resolve critical race conditions and resource leaks in SubTurn
- Fix turnState hierarchy corruption when SubTurns recursively call runAgentLoop
  by checking context for existing turnState before creating new root
- Fix deadlock risk in deliverSubTurnResult by separating lock and channel operations
- Fix session rollback race in HardAbort by calling Finish() before rollback
- Fix resource leak by closing pendingResults channel in Finish() with panic recovery
- Add thread-safety documentation for childTurnIDs and isFinished fields
- Move globalTurnCounter to AgentLoop.subTurnCounter to prevent ID conflicts
- Improve semaphore acquisition to ensure release even on early validation failures
- Document design choice: ephemeral sessions start empty for complete isolation
- Add 5 new tests: hierarchy, deadlock, order, channel close, and semaphore
2026-03-16 22:37:21 +08:00