Commit Graph

202 Commits

Author SHA1 Message Date
Alix-007
b1d20d38f9 feat(skills): add read_skill for compact mode 2026-03-19 17:53:40 +08:00
Argenis
02688eb124
feat(skills): autonomous skill creation from multi-step tasks (#3916)
Add SkillCreator module that persists successful multi-step task
executions as reusable SKILL.toml definitions under the workspace
skills directory.

- SkillCreationConfig in [skills.skill_creation] (disabled by default)
- Slug validation, TOML generation, embedding-based deduplication
- LRU eviction when max_skills limit is reached
- Agent loop integration post-success
- Gated behind `skill-creation` compile-time feature flag

Closes #3825.
2026-03-18 17:15:02 -04:00
Argenis
1f7c3c99e4
feat(i18n): externalize tool descriptions for translation (#3912)
Add a locale-aware tool description system that loads translations from
TOML files in tool_descriptions/. This enables non-English users to see
tool descriptions in their language.

- Add src/i18n.rs module with ToolDescriptions loader, locale detection
  (ZEROCLAW_LOCALE, LANG, LC_ALL env vars), and English fallback chain
- Add locale config field to Config struct for explicit locale override
- Create tool_descriptions/en.toml with all 47 tool descriptions
- Create tool_descriptions/zh-CN.toml with Chinese translations
- Integrate with ToolsSection::build() and build_tool_instructions()
  to resolve descriptions from locale files before hardcoded fallback
- Add PromptContext.tool_descriptions field for prompt-time resolution
- Add AgentBuilder.tool_descriptions() setter for Agent construction
- Include tool_descriptions/ in Cargo.toml package include list
- Add 8 unit tests covering locale loading, fallback chains, env
  detection, and config override

Closes #3901
2026-03-18 17:01:39 -04:00
Argenis
d77c616905
fix: reset tool call dedup cache each iteration to prevent loops (#3910)
The seen_tool_signatures HashSet was initialized outside the iteration loop, causing cross-iteration deduplication of legitimate tool calls. This triggered a self-correction spiral where the agent repeatedly attempted skipped calls until hitting max_iterations.

Moving the HashSet inside the loop ensures deduplication only applies within a single iteration, as originally intended.

Fixes #3798
2026-03-18 15:45:10 -04:00
Vasanth
58b98c59a8
feat(agent): add runtime model switching via model_switch tool (#3853)
Add support for switching AI models at runtime during a conversation.
The model_switch tool allows users to:
- Get current model state
- List available providers
- List models for a provider
- Switch to a different model

The switch takes effect immediately for the current conversation by
recreating the provider with the new model after tool execution.

Risk: Medium - internal state changes and provider recreation
2026-03-18 14:17:52 -04:00
Argenis
fc2aac7c94
feat(gateway): persist WS chat sessions across restarts (#3813)
Gateway WebSocket chat sessions were in-memory only — conversation
history was lost on gateway restart, macOS sleep/wake, or client
reconnect. This wires up the existing SessionBackend (SQLite) to
the gateway WS handler so sessions survive restarts and reconnections.

Changes:
- Add delete_session() to SessionBackend trait + SQLite implementation
- Add session_persistence and session_ttl_hours to GatewayConfig
- Add Agent::seed_history() to hydrate agent from persisted messages
- Initialize SqliteSessionBackend in run_gateway() when enabled
- Send session_start message on WS connect with session_id + resumed
- Persist user/assistant messages after each turn
- Add GET /api/sessions and DELETE /api/sessions/{id} REST endpoints
- Bump version to 0.5.0

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:26:39 -04:00
Argenis
f3fbd1b094
fix(web): preserve provider runtime options in ws agent (#3807)
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 14:06:22 -04:00
Alix-007
1f1123d071
fix(channels): allow low-risk shell in non-interactive mode (#3771)
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 13:39:37 -04:00
Alix-007
5f8d7d7347
fix(daemon): preserve deferred MCP tools in /api/chat (#3790)
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 13:39:12 -04:00
Alix-007
7b3bea8d01
fix(agent): resolve deferred MCP tools by suffix (#3793)
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 13:39:03 -04:00
Argenis
025724913d
feat(runtime): add configurable reasoning effort (#3785)
* feat(runtime): add configurable reasoning effort

* fix(test): add missing reasoning_effort field in live test

Add reasoning_effort: None to ProviderRuntimeOptions construction in
openai_codex_vision_e2e.rs to fix E0063 compile error.

---------

Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
2026-03-17 09:21:53 -04:00
Ricardo Madriz
9a073fae1a
fix(tools) Wire activated toolset into dispatch (#3747)
* fix(tools): wire ActivatedToolSet into tool dispatch and spec advertisement

When deferred MCP tools are activated via tool_search, they are stored
in ActivatedToolSet but never consulted by the tool call loop.
tool_specs is built once before the iteration loop and never refreshed,
so the provider API tools[] parameter never includes activated tools.
find_tool only searches the static registry, so execution dispatch also
fails silently.

Thread Arc<Mutex<ActivatedToolSet>> from creation sites through to
run_tool_call_loop. Rebuild tool_specs each iteration to merge base
registry specs with activated specs. Add fallback in execute_one_tool
to check the activated set when the static registry lookup misses.

Change ActivatedToolSet internal storage from Box<dyn Tool> to
Arc<dyn Tool> so we can clone the Arc out of the mutex guard before
awaiting tool.execute() (std::sync::MutexGuard is not Send).

* fix(tools): add activated_tools field to new ChannelRuntimeContext test site
2026-03-16 21:34:08 -04:00
Argenis
c3a3cfc9a6
fix(agent): prevent duplicate tool schema injection in XML dispatcher (#3744)
Remove duplicate tool listing from XmlToolDispatcher::prompt_instructions()
since tool listing is already handled by ToolsSection in prompt.rs. The
method now only emits the XML protocol envelope.

Also fix UTF-8 char boundary panics in memory consolidation truncation by
using char_indices() instead of manual byte-boundary scanning.

Fixes #3643
Supersedes #3678

Co-authored-by: TJUEZ <TJUEZ@users.noreply.github.com>
2026-03-16 18:38:44 -04:00
Ericsunsk
83803cef5b
fix(memory): filter autosave noise and scope recall/store by session (#3695)
* fix(memory): filter autosave noise and scope memory by session

* style: format rebase-resolved gateway and memory loader

* fix(tests): update memory loader mock for session-aware context

* fix(openai-codex): decode utf-8 safely across stream chunks
2026-03-16 16:36:35 -04:00
Vast-stars
dcb182cdd5
fix(agent): remove bare URL → curl fallback in GLM-style tool call parser (#3694)
* fix(agent): remove bare URL → curl fallback in GLM-style tool call parser

The `parse_glm_style_tool_calls` function had a "Plain URL" fallback
that converted any bare URL line (e.g. `https://example.com`) into a
`shell` tool call running `curl -s '<url>'`. This caused:

- False positives: normal URLs in LLM replies misinterpreted as tool calls
- Swallowed replies: text with URLs not forwarded to the channel
- Unintended shell commands: `curl` executed without user intent

Explicit GLM-format tool calls like `browser_open/url>https://...` and
`shell/command>...` are unaffected — only the bare URL catch-all is
removed.

* style: cargo fmt

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-03-16 16:36:27 -04:00
argenis de la rosa
98688c61ff feat(cache): wire two-tier response cache, multi-provider token tracking, and cache analytics
- Two-tier response cache: in-memory LRU (hot) + SQLite (warm) with TTL-aware eviction
- Wire response cache into agent turn loop (temp==0.0, text-only responses only)
- Parse Anthropic cache_creation_input_tokens/cache_read_input_tokens
- Parse OpenAI prompt_tokens_details.cached_tokens
- Add cached_input_tokens to TokenUsage, prompt_caching to ProviderCapabilities
- Add CacheHit/CacheMiss observer events with Prometheus counters
- Add response_cache_hot_entries config field (default: 256)
2026-03-16 12:44:48 -04:00
argenis de la rosa
fabd35c4ea feat(security): add capability-based tool access control
Add an optional `allowed_tools` parameter that restricts which tools are
available to the agent. When `Some(list)`, only tools whose name appears
in the list are retained; when `None`, all tools remain available
(backward compatible). This enables fine-grained capability control for
cron jobs, heartbeat tasks, and CLI invocations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 19:34:34 -04:00
SimianAstronaut7
314e1d3ae8
Merge pull request #3638 from zeroclaw-labs/work-issues/3487-channel-approval-manager
fix(security): enforce approval policy for channel-driven runs
2026-03-15 16:11:14 -04:00
simianastronaut
a1af84d992 fix(security): enforce approval policy for channel-driven runs
Channel-driven runs (Telegram, Matrix, Discord, etc.) previously bypassed
the ApprovalManager entirely — `None` was passed into the tool-call loop,
so `auto_approve`, `always_ask`, and supervised approval checks were
silently skipped for all non-CLI execution paths.

Add a non-interactive mode to ApprovalManager that enforces the same
autonomy config policies but auto-denies tools requiring interactive
approval (since no operator is present on channel runs). Specifically:

- Add `ApprovalManager::for_non_interactive()` constructor that creates
  a manager which auto-denies tools needing approval instead of prompting
- Add `is_non_interactive()` method so the tool-call loop can distinguish
  interactive (CLI prompt) from non-interactive (auto-deny) managers
- Update tool-call loop: non-interactive managers auto-deny instead of
  the previous auto-approve behavior for non-CLI channels
- Wire the non-interactive approval manager into ChannelRuntimeContext
  so channel runs enforce the full approval policy
- Add 8 tests covering non-interactive approval behavior

Security implications:
- `always_ask` tools are now denied on channels (previously bypassed)
- Supervised-mode unknown tools are now denied on channels (previously
  bypassed)
- `auto_approve` tools continue to work on channels unchanged
- `full` autonomy mode is unaffected (no approval needed regardless)
- `read_only` mode is unaffected (blocks execution elsewhere)

Closes #3487

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 15:56:57 -04:00
simianastronaut
0ad1965081 feat(agent): surface tool call failure reasons in chat progress messages
When a tool call fails (security policy block, hook cancellation, user
denial, or execution error), the failure reason is now included in the
progress message sent to the chat channel via on_delta. Previously only
a  icon was shown; now users see the actual reason (e.g. "Command not
allowed by security policy") without needing to check `zeroclaw doctor
traces`.

Closes #3628

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 15:49:27 -04:00
Argenis
93b5a0b824
feat(context): token-based compaction, persistent sessions, and LLM consolidation (#3574)
Comprehensive long-running context upgrades:

- Token-based compaction: replace message-count trigger with token
  estimation (~4 chars/token). Compaction fires when estimated tokens
  exceed max_context_tokens (default 32K) OR message count exceeds
  max_history_messages. Cuts at user-turn boundaries only.

- Persistent sessions: JSONL append-only session files per channel
  sender in {workspace}/sessions/. Sessions survive daemon restarts.
  Hydrates in-memory history from disk on startup.

- LLM-driven memory consolidation: two-phase extraction after each
  conversation turn. Phase 1 writes a timestamped history entry (Daily).
  Phase 2 extracts new facts/preferences to Core memory (if any).
  Replaces raw message auto-save with semantic extraction.

- New config fields: agent.max_context_tokens (32000),
  channels_config.session_persistence (true).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 09:25:23 -04:00
Jacobinwwey
8fcbb6eb2d
fix(channels): harden slack threading and utf8 truncation (#3461)
* fix(channels): harden slack threading and utf8 truncation

* refactor(channel): collapse interrupt flags to satisfy clippy

---------

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-14 07:31:10 -04:00
guitaripod
c5fcda06ad
fix(agent): add channel media markers to system prompt (#3459)
The system prompt has no documentation of channel media markers
([Voice], [IMAGE:], [Document:]), causing the LLM to misinterpret
transcribed voice messages as unprocessable audio attachments instead
of responding to the transcribed text content.

Re-applies fix from merged dev PR #1697 which was lost during the
master branch migration.

Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-14 06:58:40 -04:00
Ericsunsk
51a52dcadb
fix(memory): pass embedding_routes in gateway and agent loop (#3462)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-14 06:56:55 -04:00
Asuta
348c0c37b7
feat(agent): 支持交互会话状态持久化与恢复 (#3421)
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-13 18:55:42 -04:00
Argenis
c384c34c31
feat(provider): support custom API path suffix for custom: endpoints (#3447)
* feat(provider): support custom API path suffix for custom: endpoints

Allow users to configure a custom API path for custom/compatible
providers instead of hardcoding /v1/chat/completions. Some self-hosted
LLM servers use different API paths.

Adds an optional `api_path` field to:
- Config (top-level and model_providers profile)
- ProviderRuntimeOptions
- OpenAiCompatibleProvider

When set, the custom path is appended to base_url instead of the
default /chat/completions suffix.

Closes #3125

* fix: add missing api_path field to test ModelProviderConfig initializers
2026-03-13 17:54:21 -04:00
Argenis
ef770f15b9
feat(tool): on-demand MCP tool loading via tool_search (#3446)
Add deferred MCP tool activation to reduce context window waste.
When mcp.deferred_loading is true (the default), MCP tool schemas
are not eagerly included in the LLM context. Instead, only tool
names appear in an <available-deferred-tools> system prompt section,
and the LLM calls the built-in tool_search tool to fetch full schemas
on demand. Setting deferred_loading to false preserves the existing
eager behavior.

Closes #3095
2026-03-13 17:25:19 -04:00
Argenis
939edf5e86
fix: expose MCP tools to delegate subagents (#3436)
MCP tools were not visible to delegate subagents because parent_tools
was a static snapshot taken before MCP tool wiring. Switch to interior
mutability (parking_lot::RwLock) so MCP wrappers pushed after
DelegateTool construction are visible at sub-agent execution time.

Closes #3069
2026-03-13 16:26:01 -04:00
Vernon Stinebaker
a52446c637
feat(agent): add tool_filter_groups for per-turn MCP tool schema filtering (#3395)
* feat(agent): add tool_filter_groups for per-turn MCP tool schema filtering

Introduces per-turn MCP tool schema filtering to reduce token overhead when
many MCP tools are registered. Filtering is driven by a new config field
`agent.tool_filter_groups`, which is a list of named groups that each
specify tool glob patterns and an activation mode (`always` or `dynamic`).

Built-in (non-MCP) tools always pass through unchanged; the feature is fully
backward-compatible — an empty `tool_filter_groups` list (the default) leaves
all existing behaviour untouched.

Changes:
- src/config/schema.rs: add `ToolFilterGroupMode`, `ToolFilterGroup` types
  and `tool_filter_groups` field on `AgentConfig`
- src/config/mod.rs: re-export `ToolFilterGroup`, `ToolFilterGroupMode`
- src/agent/loop_.rs: add `glob_match()`, `filter_tool_specs_for_turn()`,
  `compute_excluded_mcp_tools()` helpers; wire call sites in both single-shot
  and interactive REPL modes; add unit tests for all three functions
- docs/reference/api/config-reference.md: document `tool_filter_groups`
  field and sub-table schema with example
- docs/i18n/el/config-reference.md: add Greek locale config-reference with
  `tool_filter_groups` section (2026-03-12 update)

* Remove accidentally committed worktree directories

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-03-13 14:23:57 -04:00
Vernon Stinebaker
292952e563
feat(tools/mcp): add MCP subsystem tools layer with multi-transport client (#3394)
* feat(tools/mcp): add MCP subsystem tools layer with multi-transport client

Introduces a new MCP (Model Context Protocol) subsystem to the tools layer,
providing a multi-transport client implementation (stdio, HTTP, SSE) that
allows ZeroClaw agents to connect to external MCP servers and register their
exposed tools into the runtime tool registry.

New files:
- src/tools/mcp_client.rs: McpRegistry — lifecycle manager for MCP server connections
- src/tools/mcp_protocol.rs: protocol types (request/response/notifications)
- src/tools/mcp_tool.rs: McpToolWrapper — bridges MCP tools to ZeroClaw Tool trait
- src/tools/mcp_transport.rs: transport abstraction (Stdio, Http, Sse)

Wiring changes:
- src/tools/mod.rs: pub mod + pub use for new MCP modules
- src/config/schema.rs: McpTransport, McpServerConfig, McpConfig types; mcp field
  on Config; validate_mcp_config; mcp unit tests
- src/config/mod.rs: re-exports McpConfig, McpServerConfig, McpTransport
- src/channels/mod.rs: MCP server init block in start_channels()
- src/agent/loop_.rs: MCP registry init in run() and process_message()
- src/onboard/wizard.rs: mcp: McpConfig::default() in both wizard constructors

* fix(tools/mcp): inject MCP tools after built-in tool filter, not before

MCP servers are user-declared external integrations. The built-in
agent.allowed_tools / agent.denied_tools filter (filter_primary_agent_tools_or_fail)
governs built-in tool governance only. Injecting MCP tools before that
filter would silently drop all MCP tools when a restrictive allowlist is
configured.

Add ordering comments at both call sites (run() CLI path and
process_message() path) to make this contract explicit for reviewers
and future merges.

Identified via: shady831213/zeroclaw-agent-mcp@3f90b78

* fix(tools/mcp): strip approved field from MCP tool args before forwarding

ZeroClaw's security model injects `approved: bool` into built-in tool
args for supervised-mode confirmation. MCP servers have no knowledge of
this field and reject calls that include it as an unexpected parameter.

Strip `approved` from object-typed args in McpToolWrapper::execute()
before forwarding to the MCP server. Non-object args pass through
unchanged (no silent conversion or rejection).

Add two unit tests:
- execute_strips_approved_field_from_object_args: verifies removal
- execute_handles_non_object_args_without_panic: verifies non-object
  shapes are not broken by the stripping logic

Identified via: shady831213/zeroclaw-agent-mcp@c68be01

---------

Co-authored-by: argenis de la rosa <theonlyhennygod@gmail.com>
2026-03-13 14:23:48 -04:00
SimianAstronaut7
e3e711073a
feat(providers): support custom HTTP headers for LLM API requests (#3423)
Add `extra_headers` config field and `ZEROCLAW_EXTRA_HEADERS` env var
support so users can specify custom HTTP headers for provider API
requests. This enables connecting to providers that require specific
headers (e.g., User-Agent, HTTP-Referer, X-Title) without a reverse
proxy.

Config file headers serve as the base; env var headers override them.
Format: `Key:Value,Key2:Value2`

Closes #3189

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-13 14:15:42 -04:00
Argenis
6a4ccaeb73
fix: strip stale tool_result from conversation history and memory context (#3418)
Prevent orphan `<tool_result>` blocks from leaking into LLM sessions:

- Strip `<tool_result>` blocks from cached prior turns in
  `process_channel_message` so the LLM never sees a tool result
  without a preceding tool call (Case A — in-memory accumulation).
- Skip memory entries containing `<tool_result` in both
  `should_skip_memory_context_entry` (channel path) and
  `build_context` (agent path) so SQLite-recalled tool output
  is never injected as memory context (Case B — post-restart).

Closes #3402
2026-03-13 09:55:57 -04:00
SimianAstronaut7
d2b923ae07
Merge pull request #3322 from zeroclaw-labs/work-issues/2984-fix-cli-chinese-input-crash
fix(agent): use byte-level stdin reads to prevent CJK input crash
2026-03-12 16:58:46 +00:00
SimianAstronaut7
d02fbf2d76
Merge pull request #3326 from zeroclaw-labs/work-issues/2978-tool-call-dedup-exempt
feat(agent): add tool_call_dedup_exempt config to bypass within-turn dedup
2026-03-12 16:58:41 +00:00
simianastronaut
ea6abc9f42 feat(provider): make HTTP request timeout configurable (#2926)
The provider HTTP request timeout was hardcoded at 120 seconds in
`OpenAiCompatibleProvider::http_client()`. This makes it configurable
via the `provider_timeout_secs` config key and the
`ZEROCLAW_PROVIDER_TIMEOUT_SECS` environment variable, defaulting
to 120s for backward compatibility.

Changes:
- Add `provider_timeout_secs` field to Config with serde default
- Add `ZEROCLAW_PROVIDER_TIMEOUT_SECS` env var override
- Add `timeout_secs` field and `with_timeout_secs()` builder on
  `OpenAiCompatibleProvider`
- Add `provider_timeout_secs` to `ProviderRuntimeOptions`
- Thread config value through agent loop, channels, gateway, and tools
- Use `compat()` closure in provider factory to apply timeout to all
  compatible providers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:40:18 -04:00
simianastronaut
e2f6f20bfb feat(agent): add tool_call_dedup_exempt config to bypass within-turn dedup (#2978)
Add `agent.tool_call_dedup_exempt` config key (list of tool names) to
allow specific tools to bypass the within-turn identical-signature
deduplication check in run_tool_call_loop. This fixes the browser
snapshot polling use case where repeated calls with identical arguments
are legitimate and should not be suppressed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:28:42 -04:00
simianastronaut
0dba55959d fix(agent): use byte-level stdin reads to prevent CJK input crash
When running through a PTY chain (kubectl exec, SSH, remote terminals),
the transport layer may split data frames at space (0x20) boundaries,
interrupting multi-byte UTF-8 characters mid-sequence. Rust's
BufRead::read_line requires valid UTF-8 and returns InvalidData
immediately, crashing the interactive agent loop.

Replace stdin().read_line() with byte-level read_until(b'\n') followed
by String::from_utf8_lossy() in both the main input loop and the
/clear confirmation prompt. This reads raw bytes without UTF-8
validation during transport, then does lossy conversion (replacing any
truly invalid bytes with U+FFFD instead of crashing).

Also set ENV LANG=C.UTF-8 in both Dockerfile stages as defense-in-depth
to ensure the container locale defaults to UTF-8.

Closes #2984

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 10:08:49 -04:00
SimianAstronaut7
cca3cf8f84
fix(agent): use char-boundary-safe slicing in scrub_credentials (#3024) (#3319)
Replace byte-level `&val[..4]` slice with `char_indices().nth(4)` to
prevent a panic when the captured credential value contains multi-byte
UTF-8 characters (e.g. Chinese text).  Adds a regression test with
CJK input.

Closes #3024

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 13:53:32 +00:00
Argenis
5cf1c77531
style: fix cargo fmt violations blocking CI lint (#3244)
* style: fix cargo fmt in ollama.rs test

* style: cargo fmt dispatcher.rs

* style: cargo fmt loop_.rs

* style: cargo fmt schema.rs

* style: cargo fmt mod.rs

* style: cargo fmt ws.rs

* style: cargo fmt ollama.rs
2026-03-11 21:53:25 -04:00
Argenis
483d3c0853
fix(ollama): strip <think> tags from Qwen responses and validate tool calls (#3079) (#3241)
- Strip `<think>...</think>` blocks in parse_tool_calls(), XmlToolDispatcher,
  and OllamaProvider before processing tool-call XML
- Add effective_content() fallback: when content is empty after stripping
  think tags, check the thinking field for tool-call XML
- Add strip_think_tags() to ollama.rs, loop_.rs, and dispatcher.rs
- Add comprehensive tests for think-tag stripping and tool-call parsing

Fixes #3079

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 20:35:33 -04:00
Argenis
195c7ba919
fix(agent): resolve display text for tool-only turns (#3054) 2026-03-11 20:08:16 -04:00
James Cowan
bb66df5276
fix(config): encrypt and decrypt all channel secrets on save/load (#3217)
Adds symmetric encrypt/decrypt calls for all channel secret fields in
Config::save() and Config::load_or_init(). Previously only nostr.private_key
was handled, leaving all other channel secrets (bot_token, app_token,
access_token, api_token, password, etc.) and gateway.paired_tokens stored
as plaintext when secrets.encrypt = true.

Closes #3175, closes #3173.

Co-authored-by: jameslcowan
2026-03-11 20:02:20 -04:00
Abdullah Imad
bd70c0f45b
feat(observer): live tool call notifications (#3221)
Add ChannelNotifyObserver that wraps the observer to forward tool-call
events as real-time threaded messages on messaging channels. Include
tool arguments (truncated) in ToolCallStart events for better
visibility into what tools are doing. Auto-thread final replies when
tools were used.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Argenis <theonlyhennygod@gmail.com>
2026-03-11 19:07:34 -04:00
smallwhite
1c2a49459e fix(agent): strip prompt-guided tool artifacts from visible replies 2026-03-11 23:50:39 +08:00
Simian Astronaut 7
7ef9d8a7b5 Addressed clippy lint issues 2026-03-10 01:48:19 -04:00
Chummy
7305f6df59
fix(ci): address strict-delta clippy blockers 2026-02-24 16:03:01 +08:00
Chummy
bfd56f2ba9
chore(fmt): fix loop_ test formatting after #1505 2026-02-24 16:03:01 +08:00
Chummy
921132575d
test: add regression coverage for provider parser cron and telegram 2026-02-24 16:03:01 +08:00
Chummy
05e88f81ea
fix: improve tool-call parsing and shell expansion checks 2026-02-24 16:03:01 +08:00
Chummy
0fc812f7db
fix: align codex provider runtime options with current interfaces 2026-02-24 16:03:01 +08:00