From de11f95b6596ade5054b5d0348cab4d5d53511f2 Mon Sep 17 00:00:00 2001 From: Cytown Date: Tue, 24 Mar 2026 13:38:13 +0800 Subject: [PATCH 01/23] update security migration documents --- README.md | 7 +- config/config.example.json | 73 --- docs/configuration.md | 136 +++++- docs/credential_encryption.md | 2 +- docs/security_configuration.md | 644 +++++++++++++++++++++++++++ pkg/config/SECURITY_CONFIG.md | 551 ----------------------- pkg/config/example_security_usage.go | 433 ++++++++++++------ 7 files changed, 1063 insertions(+), 783 deletions(-) create mode 100644 docs/security_configuration.md delete mode 100644 pkg/config/SECURITY_CONFIG.md diff --git a/README.md b/README.md index 72d38103c..3ddce3a3f 100644 --- a/README.md +++ b/README.md @@ -322,14 +322,17 @@ This creates `~/.picoclaw/config.json` and the workspace directory. "model_list": [ { "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_key": "sk-your-api-key" + "model": "openai/gpt-5.4" + // api_key is now loaded from .security.yml } ] } ``` > See `config/config.example.json` in the repo for a complete configuration template with all available options. +> +> Please note: config.example.json format is version 0, with sensitive codes in it, and will be auto migrated to version 1+, then, the config.json will only store insensitive data, the sensitive codes will be stored in .security.yml, if you need manually modify the codes, please see `docs/security_configuration.md` for more details. + **3. Chat** diff --git a/config/config.example.json b/config/config.example.json index 88578701a..82aee2904 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -264,79 +264,6 @@ "reasoning_channel_id": "" } }, - "providers": { - "_comment": "DEPRECATED: Use model_list instead. This will be removed in a future version", - "anthropic": { - "api_key": "", - "api_base": "" - }, - "openai": { - "api_key": "", - "api_base": "", - "web_search": true - }, - "openrouter": { - "api_key": "sk-or-v1-xxx", - "api_base": "" - }, - "groq": { - "api_key": "gsk_xxx", - "api_base": "" - }, - "zhipu": { - "api_key": "YOUR_ZHIPU_API_KEY", - "api_base": "" - }, - "gemini": { - "api_key": "", - "api_base": "" - }, - "vllm": { - "api_key": "", - "api_base": "" - }, - "nvidia": { - "api_key": "nvapi-xxx", - "api_base": "", - "proxy": "http://127.0.0.1:7890" - }, - "moonshot": { - "api_key": "sk-xxx", - "api_base": "" - }, - "qwen": { - "api_key": "sk-xxx", - "api_base": "" - }, - "ollama": { - "api_key": "", - "api_base": "http://localhost:11434/v1" - }, - "cerebras": { - "api_key": "", - "api_base": "" - }, - "volcengine": { - "api_key": "", - "api_base": "" - }, - "mistral": { - "api_key": "", - "api_base": "https://api.mistral.ai/v1" - }, - "avian": { - "api_key": "", - "api_base": "https://api.avian.io/v1" - }, - "longcat": { - "api_key": "", - "api_base": "https://api.longcat.chat/openai" - }, - "modelscope": { - "api_key": "", - "api_base": "https://api-inference.modelscope.cn/v1" - } - }, "tools": { "allow_read_paths": null, "allow_write_paths": null, diff --git a/docs/configuration.md b/docs/configuration.md index 4e77300cf..d39806887 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -454,6 +454,70 @@ This design also enables **multi-agent support** with flexible provider selectio - **Load balancing**: Distribute requests across multiple endpoints - **Centralized configuration**: Manage all providers in one place +#### 🔒 Security Configuration (Recommended) + +PicoClaw supports separating sensitive data (API keys, tokens, secrets) from your main configuration by storing them in a `.security.yml` file. + +**Key Benefits:** +- **Security**: Sensitive data is never in your main config file +- **Easy sharing**: Share config.json without exposing API keys +- **Version control**: Add `.security.yml` to `.gitignore` +- **Flexible deployment**: Different environments can use different security files + +**Quick Setup:** + +1. Create `~/.picoclaw/.security.yml` with your API keys: +```yaml +model_list: + gpt-5.4: + api_keys: + - "sk-proj-your-actual-openai-key" + claude-sonnet-4.6: + api_keys: + - "sk-ant-your-actual-anthropic-key" +channels: + telegram: + token: "your-telegram-bot-token" +web: + brave: + api_keys: + - "BSAyour-brave-api-key" + glm_search: + api_key: "your-glm-search-api-key" +``` + +2. Set proper permissions: +```bash +chmod 600 ~/.picoclaw/.security.yml +``` + +3. Remove sensitive fields from `config.json` (recommended): +```json +{ + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4" + // api_key loaded from .security.yml + } + ], + "channels": { + "telegram": { + "enabled": true" + // token loaded from .security.yml + } + } +} +``` + +**How it works:** +- Values from `.security.yml` are automatically mapped to config fields +- No special syntax needed — just omit sensitive fields from config.json +- If a field exists in both files, `.security.yml` value takes precedence +- You can mix direct values in config.json with security values + +For complete documentation, see [`security_configuration.md`](security_configuration.md). + #### All Supported Vendors | Vendor | `model` Prefix | Default API Base | Protocol | API Key | @@ -515,16 +579,20 @@ This design also enables **multi-agent support** with flexible provider selectio } ``` +> **Security Note**: You can remove `api_key` fields from your config and store them in `.security.yml` instead. See [Security Configuration](#-security-configuration-recommended) above for details. + #### Vendor-Specific Examples +> **Tip**: You can omit `api_key` fields and store them in `.security.yml` for better security. See [Security Configuration](#-security-configuration-recommended). +
OpenAI ```json { "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_key": "sk-..." + "model": "openai/gpt-5.4" + // api_key: set in .security.yml } ``` @@ -536,8 +604,8 @@ This design also enables **multi-agent support** with flexible provider selectio ```json { "model_name": "ark-code-latest", - "model": "volcengine/ark-code-latest", - "api_key": "sk-..." + "model": "volcengine/ark-code-latest" + // api_key: set in .security.yml } ``` @@ -549,8 +617,8 @@ This design also enables **multi-agent support** with flexible provider selectio ```json { "model_name": "glm-4.7", - "model": "zhipu/glm-4.7", - "api_key": "your-key" + "model": "zhipu/glm-4.7" + // api_key: set in .security.yml } ``` @@ -562,8 +630,8 @@ This design also enables **multi-agent support** with flexible provider selectio ```json { "model_name": "deepseek-chat", - "model": "deepseek/deepseek-chat", - "api_key": "sk-..." + "model": "deepseek/deepseek-chat" + // api_key: set in .security.yml } ``` @@ -575,8 +643,8 @@ This design also enables **multi-agent support** with flexible provider selectio ```json { "model_name": "claude-sonnet-4.6", - "model": "anthropic/claude-sonnet-4.6", - "api_key": "sk-ant-your-key" + "model": "anthropic/claude-sonnet-4.6" + // api_key: set in .security.yml } ``` @@ -616,8 +684,8 @@ For direct Anthropic API access or custom endpoints that only support Anthropic' { "model_name": "my-custom-model", "model": "openai/custom-model", - "api_base": "https://my-proxy.com/v1", - "api_key": "sk-..." + "api_base": "https://my-proxy.com/v1" + // api_key: set in .security.yml } ``` @@ -629,6 +697,33 @@ PicoClaw strips only the outer `litellm/` prefix before sending the request, so Configure multiple endpoints for the same model name — PicoClaw will automatically round-robin between them: +**Option 1: Multiple API Keys in .security.yml (Recommended)** + +```yaml +# .security.yml +model_list: + gpt-5.4: + api_keys: + - "sk-proj-key-1" + - "sk-proj-key-2" +``` + +```json +// config.json +{ + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4", + "api_base": "https://api.openai.com/v1" + // api_keys loaded from .security.yml + } + ] +} +``` + +**Option 2: Multiple Model Entries** + ```json { "model_list": [ @@ -685,6 +780,8 @@ This keeps the runtime lightweight while making new OpenAI-compatible backends m } ``` +> **Note**: The `providers` format is deprecated. Use the new `model_list` format with `.security.yml` for better security. +
@@ -701,18 +798,10 @@ This keeps the runtime lightweight while making new OpenAI-compatible backends m "dm_scope": "per-channel-peer", "backlog_limit": 20 }, - "providers": { - "openrouter": { - "api_key": "sk-or-v1-xxx" - }, - "groq": { - "api_key": "gsk_xxx" - } - }, "channels": { "telegram": { - "enabled": true, - "token": "123456:ABC...", + "enabled": true" + // token: set in .security.yml "allow_from": ["123456789"] } }, @@ -731,6 +820,8 @@ This keeps the runtime lightweight while making new OpenAI-compatible backends m } ``` +> **Note**: Sensitive fields (`api_key`, `token`, etc.) can be omitted and stored in `.security.yml` for better security. +
### Scheduled Tasks / Reminders @@ -754,6 +845,7 @@ Scheduled tasks persist across restarts and are stored in `~/.picoclaw/workspace | Topic | Description | | ----- | ----------- | +| [Security Configuration](security_configuration.md) | Store API keys and secrets in separate `.security.yml` file | | [Sensitive Data Filtering](sensitive_data_filtering.md) | Filter API keys and tokens from tool results before sending to LLM | | [Hook System](hooks/README.md) | Event-driven hooks: observers, interceptors, approval hooks | | [Steering](steering.md) | Inject messages into a running agent loop between tool calls | diff --git a/docs/credential_encryption.md b/docs/credential_encryption.md index dde8c782c..de3b70e09 100644 --- a/docs/credential_encryption.md +++ b/docs/credential_encryption.md @@ -31,7 +31,7 @@ enc://AAAA...base64... { "model_name": "gpt-4o", "model": "openai/gpt-4o", - "api_key": "enc://AAAA...base64...", + // "api_key": "enc://AAAA...base64..." move to .security.yml "api_base": "https://api.openai.com/v1" } ] diff --git a/docs/security_configuration.md b/docs/security_configuration.md new file mode 100644 index 000000000..f4fe0e304 --- /dev/null +++ b/docs/security_configuration.md @@ -0,0 +1,644 @@ +# Security Configuration + +## Overview + +PicoClaw supports separating sensitive data (API keys, tokens, secrets, passwords) from the main configuration by storing them in a `.security.yml` file. This improves security by: + +1. **Separation of concerns**: Configuration settings and secrets are in separate files +2. **Easier sharing**: The main config can be shared without exposing sensitive data +3. **Better version control**: `.security.yml` should be added to `.gitignore` +4. **Flexible deployment**: Different environments can use different security files + +## File Structure + +``` +~/.picoclaw/ +├── config.json # Main configuration (safe to share) +└── .security.yml # Security data (never share) +``` + +## How It Works + +The security configuration works through **direct field mapping**, NOT through `ref:` string references. The system automatically loads values from `.security.yml` and applies them to the corresponding fields in `config.json`. + +### Key Points: + +- Values in `.security.yml` are automatically mapped to corresponding fields in the config +- The mapping is based on field names and structure, not on reference strings +- If a value exists in `.security.yml`, it **overrides** the value in `config.json` +- You can omit sensitive fields from `config.json` entirely (recommended) + +## Security Configuration Structure + +### Complete Example: .security.yml + +```yaml +# Model API Keys +# All models MUST use `api_keys` (plural) array format +# Even a single key must be provided as an array with one element +model_list: + gpt-5.4: + api_keys: + - "sk-proj-your-actual-openai-key-1" + - "sk-proj-your-actual-openai-key-2" # Optional: Multiple keys for failover + claude-sonnet-4.6: + api_keys: + - "sk-ant-your-actual-anthropic-key" # Single key in array format + +# Channel Tokens +channels: + telegram: + token: "your-telegram-bot-token" + feishu: + app_secret: "your-feishu-app-secret" + encrypt_key: "your-feishu-encrypt-key" + verification_token: "your-feishu-verification-token" + discord: + token: "your-discord-bot-token" + weixin: + token: "your-weixin-token" + qq: + app_secret: "your-qq-app-secret" + dingtalk: + client_secret: "your-dingtalk-client-secret" + slack: + bot_token: "your-slack-bot-token" + app_token: "your-slack-app-token" + matrix: + access_token: "your-matrix-access-token" + line: + channel_secret: "your-line-channel-secret" + channel_access_token: "your-line-channel-access-token" + onebot: + access_token: "your-onebot-access-token" + wecom: + token: "your-wecom-token" + encoding_aes_key: "your-wecom-encoding-aes-key" + wecom_app: + corp_secret: "your-wecom-app-corp-secret" + token: "your-wecom-app-token" + encoding_aes_key: "your-wecom-app-encoding-aes-key" + wecom_aibot: + secret: "your-wecom-aibot-secret" + token: "your-wecom-aibot-token" + encoding_aes_key: "your-wecom-aibot-encoding-aes-key" + pico: + token: "your-pico-token" + irc: + password: "your-irc-password" + nickserv_password: "your-irc-nickserv-password" + sasl_password: "your-irc-sasl-password" + +# Web Tool API Keys +web: + brave: + api_keys: + - "BSAyour-brave-api-key-1" + - "BSAyour-brave-api-key-2" # Optional: Multiple keys for failover + tavily: + api_keys: + - "tvly-your-tavily-api-key" # Single key in array format + perplexity: + api_keys: + - "pplx-your-perplexity-api-key" # Single key in array format + glm_search: + api_key: "your-glm-search-api-key" # GLMSearch uses single key format (not array) + baidu_search: + api_key: "your-baidu-search-api-key" + +# Skills Registry Tokens +skills: + github: + token: "your-github-token" + clawhub: + auth_token: "your-clawhub-auth-token" +``` + +## Usage + +### Step 1: Create .security.yml + +Create or copy the security file: +```bash +cp security.example.yml ~/.picoclaw/.security.yml +``` + +### Step 2: Fill in your actual values + +Edit `~/.picoclaw/.security.yml` and replace placeholder values with your actual API keys and tokens. + +### Step 3: Set proper permissions + +```bash +chmod 600 ~/.picoclaw/.security.yml +``` + +### Step 4: Simplify config.json (Recommended) + +You can now remove sensitive fields from `config.json` since they're loaded from `.security.yml`: + +**Before:** +```json +{ + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4", + "api_base": "https://api.openai.com/v1", + "api_key": "sk-your-actual-api-key-here" + } + ], + "channels": { + "telegram": { + "enabled": true, + "token": "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" + } + } +} +``` + +**After:** +```json +{ + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4", + "api_base": "https://api.openai.com/v1" + // api_key is now loaded from .security.yml + } + ], + "channels": { + "telegram": { + "enabled": true" + // token is now loaded from .security.yml + } + } +} +``` + +### Step 5: Verify + +Restart PicoClaw and verify it loads correctly: +```bash +picoclaw --version +``` + +## Field Mapping Rules + +### Models + +**In .security.yml:** +```yaml +model_list: + : + api_keys: + - "key-1" + - "key-2" +``` + +**Mapping:** +- Field `api_keys` (array) maps to the model's API keys +- The `` must match the `model_name` field in `config.json` +- Supports indexed names (e.g., "gpt-5.4:0") - the system will also try the base name ("gpt-5.4") + +### Channels + +Each channel maps its fields directly: + +**In .security.yml:** +```yaml +channels: + telegram: + token: "value" + feishu: + app_secret: "value" + encrypt_key: "value" + verification_token: "value" + discord: + token: "value" +``` + +**Mapping:** +- `channels.telegram.token` → `config.channels.telegram.token` +- `channels.feishu.app_secret` → `config.channels.feishu.app_secret` +- etc. + +### Web Tools + +**Brave, Tavily, Perplexity:** +```yaml +web: + brave: + api_keys: + - "key-1" + - "key-2" +``` +- Use `api_keys` (plural) array format + +**GLMSearch:** +```yaml +web: + glm_search: + api_key: "single-key-here" +``` +- Use `api_key` (singular) single string format + +**BaiduSearch:** +```yaml +web: + baidu_search: + api_key: "your-key" +``` +- Use `api_key` (singular) single string format + +### Skills + +**In .security.yml:** +```yaml +skills: + github: + token: "value" + clawhub: + auth_token: "value" +``` + +## API Key Formats + +### Models - Single key + +Use array format with one element: +```yaml +model_list: + gpt-5.4: + api_keys: + - "sk-your-key" +``` + +### Models - Multiple keys (Load Balancing & Failover) + +Use array format with multiple elements: +```yaml +model_list: + gpt-5.4: + api_keys: + - "sk-your-key-1" + - "sk-your-key-2" + - "sk-your-key-3" +``` + +**Benefits:** +- **Load balancing**: Requests are distributed across multiple keys +- **Failover**: Automatic switching to another key if one fails +- **Rate limit management**: Distribute usage across multiple keys +- **High availability**: Reduce downtime during API provider issues + +### Web Tools (Brave/Tavily/Perplexity) - Single key + +```yaml +web: + brave: + api_keys: + - "BSA-your-key" +``` + +### Web Tools (Brave/Tavily/Perplexity) - Multiple keys + +```yaml +web: + brave: + api_keys: + - "BSA-key-1" + - "BSA-key-2" +``` + +### Web Tool (GLMSearch/BaiduSearch) - Single key only + +```yaml +web: + glm_search: + api_key: "your-glm-key" # Single string (NOT array) + baidu_search: + api_key: "your-baidu-key" # Single string (NOT array) +``` + +## Model Name Matching + +The system supports intelligent model name matching in `.security.yml`: + +### Example 1: Exact Match + +**config.json:** +```json +{ + "model_name": "gpt-5.4:0" +} +``` + +**.security.yml (exact match with index):** +```yaml +model_list: + gpt-5.4:0: + api_keys: ["key-1"] +``` + +### Example 2: Base Name Match + +**config.json:** +```json +{ + "model_name": "gpt-5.4:0" +} +``` + +**.security.yml (base name without index):** +```yaml +model_list: + gpt-5.4: + api_keys: ["key-1", "key-2"] +``` + +Both methods work. The base name match allows you to use simpler keys in `.security.yml` even when your config uses indexed model names for load balancing. + +## Backward Compatibility + +The system maintains full backward compatibility: + +1. **Direct values**: You can still use direct values in `config.json` (not recommended for production) +2. **Mixed usage**: You can have some fields in `.security.yml` and others in `config.json` +3. **Optional security file**: If `.security.yml` doesn't exist, the system will only use values from `config.json` +4. **Override behavior**: If a field exists in both files, `.security.yml` value takes precedence + +## Environment Variables + +You can override any security value using environment variables: + +**For models:** +```bash +export PICOCLAW_CHANNELS_TELEGRAM_TOKEN="token-from-env" +``` + +**For channels:** +```bash +export PICOCLAW_CHANNELS_TELEGRAM_TOKEN="token-from-env" +export PICOCLAW_CHANNELS_FEISHU_APP_SECRET="secret-from-env" +``` + +**For web tools:** +```bash +export PICOCLAW_TOOLS_WEB_BRAVE_API_KEY="key-from-env" +export PICOCLAW_TOOLS_WEB_BAIDU_API_KEY="baidu-key-from-env" +``` + +Environment variables have the highest priority and will override both `config.json` and `.security.yml` values. + +The pattern is: `PICOCLAW_
__` with underscores separating path segments and converted to uppercase. + +## Security Best Practices + +1. **Never commit `.security.yml`** to version control +2. **Add to .gitignore**: Ensure `.security.yml` is in your `.gitignore` file +3. **Set file permissions**: `chmod 600 ~/.picoclaw/.security.yml` +4. **Use different keys** for different environments (dev, staging, production) +5. **Rotate keys regularly** and update `.security.yml` +6. **Backup securely**: Encrypt backups containing `.security.yml` +7. **Review access**: Ensure only authorized users have read access to the file + +## API + +### loadSecurityConfig + +```go +func loadSecurityConfig(securityPath string) (*SecurityConfig, error) +``` + +Loads the security configuration from `.security.yml`. Returns an empty `SecurityConfig` if the file doesn't exist. + +### saveSecurityConfig + +```go +func saveSecurityConfig(securityPath string, sec *SecurityConfig) error +``` + +Saves the security configuration to `.security.yml` with `0o600` permissions. + +### applySecurityConfig + +```go +func applySecurityConfig(cfg *Config, sec *SecurityConfig) error +``` + +Applies security configuration to the main config by copying values from `.security.yml` to the corresponding fields in the config. + +### securityPath + +```go +func securityPath(configPath string) string +``` + +Returns the path to `.security.yml` relative to the config file. + +## Example: Complete Configuration + +### config.json + +```json +{ + "version": 1, + "agents": { + "defaults": { + "workspace": "~/picoclaw-workspace", + "model_name": "gpt-5.4" + } + }, + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4", + "api_base": "https://api.openai.com/v1" + }, + { + "model_name": "claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4.6", + "api_base": "https://api.anthropic.com/v1" + } + ], + "channels": { + "telegram": { + "enabled": true + } + }, + "tools": { + "web": { + "brave": { + "enabled": true + } + } + } +} +``` + +### .security.yml + +```yaml +model_list: + gpt-5.4: + api_keys: + - "sk-proj-actual-openai-key-1" + - "sk-proj-actual-openai-key-2" + claude-sonnet-4.6: + api_keys: + - "sk-ant-actual-anthropic-key" + +channels: + telegram: + token: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" + +web: + brave: + api_keys: + - "BSAactualbravekey-1" + - "BSAactualbravekey-2" + tavily: + api_keys: + - "tvly-your-tavily-key" + glm_search: + api_key: "your-glm-key" + baidu_search: + api_key: "your-baidu-key" +``` + +## Testing + +Run the security configuration tests: + +```bash +go test ./pkg/config -run TestSecurityConfig +``` + +## Troubleshooting + +### Error: "failed to load security config" + +- Verify `.security.yml` exists in the same directory as `config.json` +- Check the YAML syntax is valid (use a YAML validator) +- Ensure file permissions allow reading + +### Error: "model security entry not found" + +- Ensure the model name in `config.json` matches exactly in `.security.yml` +- Check that the `model_list` section exists in `.security.yml` +- For models with indexed names (e.g., "gpt-5.4:0"), ensure the exact name is used or check the base name without index +- Verify the YAML structure is correct (proper indentation) + +### Multiple API Keys Not Working + +- Ensure you're using `api_keys` (plural) in `.security.yml` for models and web tools (except GLMSearch/BaiduSearch) +- Check that the array format is correct in YAML (proper indentation with dashes) +- Remember: Models, Brave, Tavily, Perplexity MUST use `api_keys` (array format) +- GLMSearch and BaiduSearch MUST use `api_key` (single string format) + +### Load Balancing/Failover Issues + +- Verify all API keys in the `api_keys` array are valid +- Check that all keys have the same rate limits and permissions +- Monitor logs to see which keys are being used and failing +- Ensure the `api_keys` array is properly formatted in YAML + +### Keys Not Being Applied + +- Check that `.security.yml` is in the same directory as `config.json` +- Verify the file permissions allow reading (`chmod 600 ~/.picoclaw/.security.yml`) +- Ensure the YAML structure matches the expected format +- Check for typos in field names (case-sensitive) +- Verify the model/channel names match exactly (case-sensitive) + +## Migration Guide + +### Step 1: Backup your config + +```bash +cp ~/.picoclaw/config.json ~/.picoclaw/config.json.backup +``` + +### Step 2: Create .security.yml + +```bash +cp security.example.yml ~/.picoclaw/.security.yml +``` + +### Step 3: Fill in your API keys + +Edit `~/.picoclaw/.security.yml` and replace placeholder values with your actual keys. + +### Step 4: Remove sensitive fields from config.json + +Remove or comment out sensitive fields from `config.json`: +- `api_key` fields from `model_list` entries +- `token` fields from `channels` +- `api_key` fields from `tools.web` +- `token`/`auth_token` fields from `tools.skills` + +### Step 5: Set proper permissions + +```bash +chmod 600 ~/.picoclaw/.security.yml +``` + +### Step 6: Test + +```bash +picoclaw --version +``` + +### Step 7: Verify functionality + +Test your models and channels to ensure everything works correctly. + +### Step 8: Clean up (optional) + +If everything works, you can delete the backup: +```bash +rm ~/.picoclaw/config.json.backup +``` + +## Advanced: Encrypted API Keys + +PicoClaw supports encrypting API keys in the security file for additional protection. + +### Setup + +1. Set a passphrase via environment variable: +```bash +export PICOCLAW_CREDENTIAL_PASSPHRASE="your-secure-passphrase" +``` + +2. When saving config, API keys will be encrypted automatically: +```go +SaveConfig(path, config) +``` + +### Encrypted Format + +Encrypted keys are stored as: +```yaml +model_list: + gpt-5.4: + api_keys: + - "enc://encrypted-base64-string" +``` + +The system automatically decrypts keys at runtime when loading the configuration. + +### Benefits + +- Additional layer of security +- Keys are encrypted at rest +- Passphrase can be managed separately from the config file + +### Important Notes + +- Always backup your passphrase securely +- If you lose the passphrase, you'll lose access to encrypted keys +- Use a strong, unique passphrase +- Never commit the passphrase to version control diff --git a/pkg/config/SECURITY_CONFIG.md b/pkg/config/SECURITY_CONFIG.md deleted file mode 100644 index c5aed54ae..000000000 --- a/pkg/config/SECURITY_CONFIG.md +++ /dev/null @@ -1,551 +0,0 @@ -# Security Configuration Refactoring - -## Overview - -This refactoring introduces a `.security.yml` file to store all sensitive data (API keys, tokens, secrets, passwords) separately from the main configuration. This improves security by: - -1. **Separation of concerns**: Configuration settings and secrets are in separate files -2. **Easier sharing**: The main config can be shared without exposing sensitive data -3. **Better version control**: `.security.yml` can be added to `.gitignore` -4. **Flexible deployment**: Different environments can use different security files - -## File Structure - -``` -~/.picoclaw/ -├── config.json # Main configuration (safe to share) -└── .security.yml # Security data (never share) -``` - -## Usage - -### Basic Configuration - -In your `config.json`, use `ref:` references to point to values in `.security.yml`: - -```json -{ - "version": 1, - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_base": "https://api.openai.com/v1", - "api_key": "ref:model_list.gpt-5.4.api_key" - } - ], - "channels": { - "telegram": { - "enabled": true, - "token": "ref:channels.telegram.token" - } - } -} -``` - -### Security Configuration - -In your `.security.yml`, store the actual values: - -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-your-actual-api-key-1" - - "sk-your-actual-api-key-2" # Optional: Multiple keys for failover - claude-sonnet-4.6: - api_keys: - - "sk-your-actual-anthropic-key" # Single key in array format - -channels: - telegram: - token: "your-telegram-bot-token" - -web: - brave: - api_keys: - - "BSAyour-brave-api-key-1" - - "BSAyour-brave-api-key-2" # Optional: Multiple keys for failover - tavily: - api_keys: - - "tvly-your-tavily-api-key" # Single key in array format - glm_search: - api_key: "your-glm-search-api-key" # GLMSearch uses single key format -``` - -## Reference Format - -### Model API Keys - -Format: `ref:model_list..api_key` - -Example: `ref:model_list.gpt-5.4.api_key` - -### Channel Tokens/Secrets - -Format: `ref:channels..` - -Examples: -- `ref:channels.telegram.token` -- `ref:channels.feishu.app_secret` -- `ref:channels.feishu.encrypt_key` -- `ref:channels.feishu.verification_token` -- `ref:channels.discord.token` -- `ref:channels.qq.app_secret` -- `ref:channels.dingtalk.client_secret` -- `ref:channels.slack.bot_token` -- `ref:channels.slack.app_token` -- `ref:channels.matrix.access_token` -- `ref:channels.line.channel_secret` -- `ref:channels.line.channel_access_token` -- `ref:channels.onebot.access_token` -- `ref:channels.wecom.token` -- `ref:channels.wecom.encoding_aes_key` -- `ref:channels.wecom_app.corp_secret` -- `ref:channels.wecom_app.token` -- `ref:channels.wecom_app.encoding_aes_key` -- `ref:channels.wecom_aibot.token` -- `ref:channels.wecom_aibot.encoding_aes_key` -- `ref:channels.pico.token` -- `ref:channels.irc.password` -- `ref:channels.irc.nickserv_password` -- `ref:channels.irc.sasl_password` - -### Web Tool API Keys - -Format: `ref:web..` - -Examples: -- `ref:web.brave.api_key` -- `ref:web.tavily.api_key` -- `ref:web.perplexity.api_key` -- `ref:web.glm_search.api_key` - -### Skills Registry Tokens - -Format: `ref:skills..` - -Examples: -- `ref:skills.github.token` -- `ref:skills.clawhub.auth_token` - -## Backward Compatibility - -The refactoring maintains full backward compatibility: - -1. **Direct values**: You can still use direct values in `config.json` (not recommended for production) -2. **Mixed usage**: You can mix `ref:` references and direct values -3. **Optional security file**: If `.security.yml` doesn't exist, all references will fail (but direct values still work) - -### API Key Formats in .security.yml - -**Models (gpt-5.4, claude-sonnet-4.6, etc.):** -- Must use `api_keys` (array) format -- Both single and multiple keys use array format - -**Web Tools (Brave, Tavily, Perplexity):** -- Must use `api_keys` (array) format -- Both single and multiple keys use array format - -**Web Tools (GLMSearch):** -- Must use `api_key` (single string) format -- Does NOT support array format - -**Channels (Telegram, Discord, etc.):** -- Use single field names (e.g., `token`, `app_secret`) -- Each channel uses its specific field names - -### Single Key (Models) - -Use array format with one element: -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-your-key" -``` - -In `config.json`: -```json -{ - "api_key": "ref:model_list.gpt-5.4.api_key" -} -``` - -### Single Key (GLMSearch) - -Use single string format: -```yaml -web: - glm_search: - api_key: "your-glm-key" -``` - -In `config.json`: -```json -{ - "api_key": "ref:web.glm_search.api_key" -} -``` - -## Migration Guide - -### Step 1: Create .security.yml - -Copy the example template: -```bash -cp security.example.yml ~/.picoclaw/.security.yml -``` - -### Step 2: Fill in your actual values - -Edit `~/.picoclaw/.security.yml` and replace placeholder values with your actual API keys and tokens. - -### Step 3: Update config.json - -Replace sensitive values in `~/.picoclaw/config.json` with `ref:` references: - -**Before:** -```json -{ - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_key": "sk-your-actual-api-key-here" - } - ] -} -``` - -**After:** -```json -{ - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_key": "ref:model_list.gpt-5.4.api_key" - } - ] -} -``` - -### Step 4: Verify - -Restart PicoClaw and verify it loads correctly: -```bash -picoclaw --version -``` - -## Security Best Practices - -1. **Never commit `.security.yml`** to version control -2. **Set file permissions**: `chmod 600 ~/.picoclaw/.security.yml` -3. **Use different keys** for different environments (dev, staging, production) -4. **Rotate keys regularly** and update `.security.yml` -5. **Backup securely**: Encrypt backups containing `.security.yml` - -## API - -### LoadSecurityConfig - -```go -func LoadSecurityConfig(securityPath string) (*SecurityConfig, error) -``` - -Loads the security configuration from `.security.yml`. Returns an empty `SecurityConfig` if the file doesn't exist. - -### SaveSecurityConfig - -```go -func SaveSecurityConfig(securityPath string, sec *SecurityConfig) error -``` - -Saves the security configuration to `.security.yml` with `0o600` permissions. - -### ResolveReference - -```go -func (sec *SecurityConfig) ResolveReference(ref string) (string, error) -``` - -Resolves a reference string (e.g., `"ref:model_list.test.api_key"`) and returns the actual value. - -### SecurityPath - -```go -func SecurityPath(configPath string) string -``` - -Returns the path to `.security.yml` relative to the config file. - -## Example: Complete Configuration - -### config.json -```json -{ - "version": 1, - "agents": { - "defaults": { - "workspace": "~/picoclaw-workspace", - "model_name": "gpt-5.4" - } - }, - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_base": "https://api.openai.com/v1", - "api_key": "ref:model_list.gpt-5.4.api_key" - }, - { - "model_name": "claude-sonnet-4.6", - "model": "anthropic/claude-sonnet-4.6", - "api_base": "https://api.anthropic.com/v1", - "api_key": "ref:model_list.claude-sonnet-4.6.api_key" - } - ], - "channels": { - "telegram": { - "enabled": true, - "token": "ref:channels.telegram.token" - } - }, - "tools": { - "web": { - "brave": { - "enabled": true, - "api_key": "ref:web.brave.api_key" - } - } - } -} -``` - -### .security.yml -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-proj-actual-openai-key-1" - - "sk-proj-actual-openai-key-2" - claude-sonnet-4.6: - api_keys: - - "sk-ant-actual-anthropic-key" # Single key in array format - -channels: - telegram: - token: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" - -web: - brave: - api_keys: - - "BSAactualbravekey-1" - - "BSAactualbravekey-2" - tavily: - api_keys: - - "tvly-your-tavily-key" # Single key in array format - glm_search: - api_key: "your-glm-key" # GLMSearch uses single key format -``` - -## Testing - -The refactoring includes comprehensive tests: - -```bash -go test ./pkg/config -run TestSecurityConfig -``` - -## Troubleshooting - -### Error: "model security entry not found" - -- Ensure the model name in your reference matches exactly in `.security.yml` -- Check that the `model_list` section exists in `.security.yml` -- For models with indexed names (e.g., "gpt-5.4:0"), ensure the exact name is used or check the base name without index - -### Error: "failed to load security config" - -- Verify `.security.yml` exists in the same directory as `config.json` -- Check the YAML syntax is valid (use a YAML validator) -- Ensure file permissions allow reading - -### Error: "unknown reference path" - -- Verify the reference format is correct -- Check the path structure matches the examples above -- Ensure all required sections exist in `.security.yml` - -## Advanced Features - -### Multiple API Keys (Load Balancing & Failover) - -Both models and web tools support multiple API keys for improved reliability: - -**Benefits:** -- **Load balancing**: Requests are distributed across multiple keys -- **Failover**: Automatic switching to another key if one fails -- **Rate limit management**: Distribute usage across multiple keys -- **High availability**: Reduce downtime during API provider issues - -#### Example: Model with Multiple Keys - -**.security.yml:** -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-proj-key-1" - - "sk-proj-key-2" - - "sk-proj-key-3" -``` - -**config.json:** -```json -{ - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_key": "ref:model_list.gpt-5.4.api_key" - } - ] -} -``` - -#### Example: Web Tool with Multiple Keys - -**.security.yml:** -```yaml -web: - brave: - api_keys: - - "BSA-key-1" - - "BSA-key-2" - tavily: - api_keys: - - "tvly-your-key" # Single key in array format - glm_search: - api_key: "your-glm-key" # GLMSearch uses single key format -``` - -**config.json:** -```json -{ - "tools": { - "web": { - "brave": { - "enabled": true, - "api_key": "ref:web.brave.api_key" - }, - "tavily": { - "enabled": true, - "api_key": "ref:web.tavily.api_key" - } - } - } -} -``` - -#### Supported Formats - -**Models - Single key:** -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-your-key" # Array with one element -``` - -**Models - Multiple keys:** -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-your-key-1" - - "sk-your-key-2" - - "sk-your-key-3" -``` - -**Web Tools (Brave/Tavily/Perplexity) - Single key:** -```yaml -web: - brave: - api_keys: - - "BSA-your-key" # Array with one element -``` - -**Web Tools (Brave/Tavily/Perplexity) - Multiple keys:** -```yaml -web: - brave: - api_keys: - - "BSA-key-1" - - "BSA-key-2" -``` - -**Web Tool (GLMSearch) - Single key only:** -```yaml -web: - glm_search: - api_key: "your-glm-key" # Single string (NOT array) -``` - -All formats work identically in `config.json` - you always use the same reference format: -```json -{ - "api_key": "ref:model_list.gpt-5.4.api_key" -} -``` - -### Model Indexing for Load Balancing - -When you have multiple models with the same base name but different API keys, you can use indexed names: - -**.security.yml:** -```yaml -model_list: - gpt-5.4: - api_keys: - - "sk-proj-key-1" - - "sk-proj-key-2" -``` - -The system will automatically expand this into multiple model entries with fallback support. - -### Environment Variables - -You can override any security value using environment variables: - -**For models:** -```bash -export PICOCLAW_MODEL_LIST_GPT-5.4_API_KEY="sk-from-env" -``` - -**For channels:** -```bash -export PICOCLAW_CHANNELS_TELEGRAM_TOKEN="token-from-env" -``` - -**For web tools:** -```bash -export PICOCLAW_WEB_BRAVE_API_KEY="key-from-env" -``` - -Environment variables follow this pattern: `PICOCLAW_
___` with dots replaced by underscores and converted to uppercase. - -### Multiple API Keys Not Working - -- Ensure you're using `api_keys` (plural) in `.security.yml` for models and web tools (except GLMSearch) -- Check that the array format is correct in YAML (proper indentation) -- Remember: Models, Brave, Tavily, Perplexity MUST use `api_keys` (array format) -- GLMSearch MUST use `api_key` (single string format) -- The reference in `config.json` is the same regardless of single or multiple keys - -### Load Balancing/Failover Issues - -- Verify all API keys in the `api_keys` array are valid -- Check that all keys have the same rate limits and permissions -- Monitor logs to see which keys are being used and failing diff --git a/pkg/config/example_security_usage.go b/pkg/config/example_security_usage.go index cba76c6bc..0a6749537 100644 --- a/pkg/config/example_security_usage.go +++ b/pkg/config/example_security_usage.go @@ -11,20 +11,33 @@ Package config # Example: Using Security Configuration -## 1. Create security.yml +## Overview -File: ~/.picoclaw/security.yml +The security configuration feature allows you to separate sensitive data (API keys, +tokens, secrets, passwords) from your main configuration. The system automatically +loads values from `.security.yml` and applies them to the corresponding fields in +your config. + +**Key Points:** +- Values from `.security.yml` are automatically mapped to config fields +- No `ref:` syntax is needed - just omit sensitive fields from config.json +- If a field exists in both files, `.security.yml` value takes precedence +- You can mix direct values in config.json with security values + +## 1. Create .security.yml + +File: ~/.picoclaw/.security.yml ```yaml # Model API Keys -# Note: Use 'api_keys' array for multiple keys (load balancing/failover) -# Single key should be provided as an array with one element +# All models MUST use 'api_keys' (plural) array format +# Even a single key must be provided as an array with one element model_list: gpt-5.4: api_keys: - "sk-proj-your-actual-openai-key-1" - - "sk-proj-your-actual-openai-key-2" # Failover key + - "sk-proj-your-actual-openai-key-2" # Optional: Multiple keys for failover claude-sonnet-4.6: api_keys: - "sk-ant-your-actual-anthropic-key" # Single key in array format @@ -38,80 +51,95 @@ channels: token: "your-discord-bot-token" # Web Tool Keys -# Note: Use 'api_keys' array for multiple keys (load balancing/failover) -# For GLMSearch, use 'api_key' (single string) +# Brave, Tavily, Perplexity: Use 'api_keys' array +# GLMSearch, BaiduSearch: Use 'api_key' single string web: brave: api_keys: - "BSAyour-brave-api-key-1" - - "BSAyour-brave-api-key-2" # Failover key + - "BSAyour-brave-api-key-2" # Optional: Multiple keys for failover tavily: api_keys: - "tvly-your-tavily-api-key" # Single key in array format + perplexity: + api_keys: + - "pplx-your-perplexity-api-key" # Single key in array format glm_search: api_key: "your-glm-search-api-key" # Single key (not array) + baidu_search: + api_key: "your-baidu-search-api-key" # Single key (not array) ``` -## 2. Update config.json to use references +## 2. Simplify config.json File: ~/.picoclaw/config.json +Note: Sensitive fields are omitted because they're loaded from .security.yml + ```json - { - "version": 1, - "agents": { - "defaults": { - "workspace": "~/picoclaw-workspace", - "model_name": "gpt-5.4" - } - }, - "model_list": [ - { - "model_name": "gpt-5.4", - "model": "openai/gpt-5.4", - "api_base": "https://api.openai.com/v1", - "api_key": "ref:model_list.gpt-5.4.api_key" - }, - { - "model_name": "claude-sonnet-4.6", - "model": "anthropic/claude-sonnet-4.6", - "api_base": "https://api.anthropic.com/v1", - "api_key": "ref:model_list.claude-sonnet-4.6.api_key" - } - ], - "channels": { - "telegram": { - "enabled": true, - "token": "ref:channels.telegram.token" - }, - "discord": { - "enabled": true, - "token": "ref:channels.discord.token" - } - }, + { + "version": 1, + "agents": { + "defaults": { + "workspace": "~/picoclaw-workspace", + "model_name": "gpt-5.4" + } + }, + "model_list": [ + { + "model_name": "gpt-5.4", + "model": "openai/gpt-5.4", + "api_base": "https://api.openai.com/v1" + // api_key is automatically loaded from .security.yml + }, + { + "model_name": "claude-sonnet-4.6", + "model": "anthropic/claude-sonnet-4.6", + "api_base": "https://api.anthropic.com/v1" + // api_key is automatically loaded from .security.yml + } + ], + "channels": { + "telegram": { + "enabled": true" + // token is automatically loaded from .security.yml + }, + "discord": { + "enabled": true" + // token is automatically loaded from .security.yml + } + }, "tools": { "web": { "brave": { - "enabled": true, - "api_key": "ref:web.brave.api_key" + "enabled": true" + // api_key is automatically loaded from .security.yml }, "tavily": { - "enabled": true, - "api_key": "ref:web.tavily.api_key" + "enabled": true" + // api_key is automatically loaded from .security.yml + }, + "glm_search": { + "enabled": true" + // api_key is automatically loaded from .security.yml + }, + "baidu_search": { + "enabled": true" + // api_key is automatically loaded from .security.yml } } } - } + } ``` ## 3. Set proper permissions ```bash -chmod 600 ~/.picoclaw/security.yml +chmod 600 ~/.picoclaw/.security.yml ``` ## 4. Add to .gitignore @@ -127,57 +155,133 @@ chmod 600 ~/.picoclaw/security.yml picoclaw --version ``` -# Available Reference Paths +# Supported Fields in .security.yml ## Model API Keys -- ref:model_list..api_key + +All models MUST use the `api_keys` (plural) array format in .security.yml. + +```yaml +model_list: + + : + api_keys: + - "key-1" + - "key-2" # Optional: Multiple keys for failover + +``` Examples: -- ref:model_list.gpt-5.4.api_key -- ref:model_list.claude-sonnet-4.6.api_key +```yaml +model_list: -**Note:** In .security.yml, use `api_keys` (array) format for models. -Both single and multiple keys should use the array format. + gpt-5.4: + api_keys: + - "sk-proj-key-1" + - "sk-proj-key-2" + claude-sonnet-4.6: + api_keys: + - "sk-ant-key" + +``` + +**Important:** +- Always use `api_keys` (plural) for models +- Even a single key must be in an array format +- The model_name in .security.yml must match the model_name in config.json ## Channel Tokens/Secrets -- ref:channels.telegram.token -- ref:channels.feishu.app_secret -- ref:channels.feishu.encrypt_key -- ref:channels.feishu.verification_token -- ref:channels.discord.token -- ref:channels.qq.app_secret -- ref:channels.dingtalk.client_secret -- ref:channels.slack.bot_token -- ref:channels.slack.app_token -- ref:channels.matrix.access_token -- ref:channels.line.channel_secret -- ref:channels.line.channel_access_token -- ref:channels.onebot.access_token -- ref:channels.wecom.token -- ref:channels.wecom.encoding_aes_key -- ref:channels.wecom_app.corp_secret -- ref:channels.wecom_app.token -- ref:channels.wecom_app.encoding_aes_key -- ref:channels.wecom_aibot.token -- ref:channels.wecom_aibot.encoding_aes_key -- ref:channels.pico.token -- ref:channels.irc.password -- ref:channels.irc.nickserv_password -- ref:channels.irc.sasl_password + +```yaml +channels: + + telegram: + token: "value" + feishu: + app_secret: "value" + encrypt_key: "value" + verification_token: "value" + discord: + token: "value" + weixin: + token: "value" + qq: + app_secret: "value" + dingtalk: + client_secret: "value" + slack: + bot_token: "value" + app_token: "value" + matrix: + access_token: "value" + line: + channel_secret: "value" + channel_access_token: "value" + onebot: + access_token: "value" + wecom: + token: "value" + encoding_aes_key: "value" + wecom_app: + corp_secret: "value" + token: "value" + encoding_aes_key: "value" + wecom_aibot: + secret: "value" + token: "value" + encoding_aes_key: "value" + pico: + token: "value" + irc: + password: "value" + nickserv_password: "value" + sasl_password: "value" + +``` ## Web Tool API Keys -- ref:web.brave.api_key -- ref:web.tavily.api_key -- ref:web.perplexity.api_key -- ref:web.glm_search.api_key -**Note:** -- Brave, Tavily, Perplexity: Use `api_keys` (array) format in .security.yml -- GLMSearch: Use `api_key` (single string) format in .security.yml +**Brave, Tavily, Perplexity:** +```yaml +web: + + brave: + api_keys: + - "BSA-key-1" + - "BSA-key-2" + tavily: + api_keys: + - "tvly-key" + perplexity: + api_keys: + - "pplx-key" + +``` +Use `api_keys` (plural) array format. + +**GLMSearch, BaiduSearch:** +```yaml +web: + + glm_search: + api_key: "your-glm-key" + baidu_search: + api_key: "your-baidu-key" + +``` +Use `api_key` (singular) single string format. ## Skills Registry Tokens -- ref:skills.github.token -- ref:skills.clawhub.auth_token + +```yaml +skills: + + github: + token: "value" + clawhub: + auth_token: "value" + +``` # Backward Compatibility @@ -191,14 +295,14 @@ You can still use direct values in config.json if needed: "model_name": "local-model", "model": "ollama/llama3", "api_base": "http://localhost:11434/v1", - "api_key": "ollama" // Direct value (no reference) + "api_key": "ollama" // Direct value (works fine) } ] } ``` -You can also mix references and direct values: +You can also mix security values and direct values: ```json @@ -206,10 +310,12 @@ You can also mix references and direct values: "model_list": [ { "model_name": "cloud-model", - "api_key": "ref:model_list.cloud-model.api_key" // From .security.yml + // api_key loaded from .security.yml }, { "model_name": "local-model", + "model": "ollama/llama3", + "api_base": "http://localhost:11434/v1", "api_key": "ollama" // Direct value } ] @@ -217,6 +323,11 @@ You can also mix references and direct values: ``` +**Priority Order:** +1. Environment variables (highest priority) +2. .security.yml values +3. config.json direct values (lowest priority) + # Migration from Old Config ## Step 1: Backup your config @@ -224,7 +335,7 @@ You can also mix references and direct values: cp ~/.picoclaw/config.json ~/.picoclaw/config.json.backup ``` -## Step 2: Copy the example security file +## Step 2: Create .security.yml ```bash cp security.example.yml ~/.picoclaw/.security.yml ``` @@ -232,10 +343,19 @@ cp security.example.yml ~/.picoclaw/.security.yml ## Step 3: Fill in your API keys Edit ~/.picoclaw/.security.yml and replace placeholders with your actual keys. -## Step 4: Update config.json references -Replace sensitive values in ~/.picoclaw/config.json with ref: references. +## Step 4: Simplify config.json (Recommended) +Remove sensitive fields from ~/.picoclaw/config.json: +- `api_key` fields from model_list entries +- `token` fields from channels +- `api_key` fields from tools.web +- `token`/`auth_token` fields from tools.skills -## Step 5: Test +## Step 5: Set permissions +```bash +chmod 600 ~/.picoclaw/.security.yml +``` + +## Step 6: Test ```bash picoclaw --version ``` @@ -249,9 +369,11 @@ rm ~/.picoclaw/config.json.backup ## Multiple API Keys (Load Balancing & Failover) -You can configure multiple API keys for both models and web tools to enable: +You can configure multiple API keys for models and web tools to enable: - **Load balancing**: Requests are distributed across multiple keys - **Failover**: If a key fails, the system automatically switches to another key +- **Rate limit management**: Distribute usage across multiple keys +- **High availability**: Reduce downtime during API provider issues ### Example: Model with Multiple Keys @@ -275,7 +397,7 @@ model_list: { "model_name": "gpt-5.4", "model": "openai/gpt-5.4", - "api_key": "ref:model_list.gpt-5.4.api_key" + "api_base": "https://api.openai.com/v1" } ] } @@ -307,8 +429,13 @@ web: "tools": { "web": { "brave": { - "enabled": true, - "api_key": "ref:web.brave.api_key" + "enabled": true" + }, + "tavily": { + "enabled": true" + }, + "glm_search": { + "enabled": true" } } } @@ -316,9 +443,9 @@ web: ``` -### Single Key +## Single Key Format -Use array format with one element: +**Models, Brave, Tavily, Perplexity:** ```yaml model_list: @@ -328,36 +455,32 @@ model_list: ``` -### Multiple Keys (Load Balancing & Failover) - -Use array format with multiple elements: +**GLMSearch, BaiduSearch:** ```yaml -model_list: +web: - gpt-5.4: - api_keys: - - "sk-proj-key-1" - - "sk-proj-key-2" - - "sk-proj-key-3" + glm_search: + api_key: "your-glm-key" # Single key (not array) ``` -**Important:** All model keys in .security.yml must use the `api_keys` (plural) array format. -The single `api_key` (singular) format is NOT supported for models. - -### Model Index Matching +## Model Name Matching The system supports intelligent model name matching in .security.yml: -**Example 1: Exact Match** -```yaml -# config.json +### Example 1: Exact Match + +**config.json:** +```json { "model_name": "gpt-5.4:0" } -# .security.yml (exact match with index) +``` + +**.security.yml (exact match with index):** +```yaml model_list: gpt-5.4:0: @@ -365,26 +488,30 @@ model_list: ``` -**Example 2: Base Name Match** -```yaml -# config.json +### Example 2: Base Name Match + +**config.json:** +```json { "model_name": "gpt-5.4:0" } -# .security.yml (base name without index) +``` + +**.security.yml (base name without index):** +```yaml model_list: gpt-5.4: - api_keys: ["key-1"] + api_keys: ["key-1", "key-2"] ``` Both methods work. The base name match allows you to use simpler keys in .security.yml even when your config uses indexed model names for load balancing. -### Security File Permissions +## Security File Permissions The security file should have restricted permissions: @@ -397,26 +524,64 @@ This ensures only the owner can read and write the file. # Security Best Practices 1. Never commit .security.yml to version control -2. Set file permissions: chmod 600 ~/.picoclaw/.security.yml -3. Use different keys for different environments -4. Rotate keys regularly and update .security.yml -5. Encrypt backups containing .security.yml +2. Add .security.yml to your .gitignore file +3. Set file permissions: chmod 600 ~/.picoclaw/.security.yml +4. Use different keys for different environments (dev, staging, production) +5. Rotate keys regularly and update .security.yml +6. Encrypt backups containing .security.yml +7. Review access regularly + +# Environment Variables + +You can override any security value using environment variables: + +```bash +# Channels +export PICOCLAW_CHANNELS_TELEGRAM_TOKEN="token-from-env" +export PICOCLAW_CHANNELS_DISCORD_TOKEN="discord-token-from-env" + +# Web Tools +export PICOCLAW_TOOLS_WEB_BRAVE_API_KEY="brave-key-from-env" +export PICOCLAW_TOOLS_WEB_BAIDU_API_KEY="baidu-key-from-env" + +# Skills +export PICOCLAW_TOOLS_SKILLS_GITHUB_TOKEN="github-token-from-env" +``` + +Environment variables have the highest priority and will override both config.json +and .security.yml values. # Troubleshooting +## Error: "failed to load security config" +- Ensure .security.yml exists in the same directory as config.json +- Check YAML syntax is valid (use a YAML validator) +- Verify file permissions allow reading + ## Error: "model security entry not found" - Check that the model name in config.json matches exactly in .security.yml - Verify the model_list section exists in .security.yml +- For indexed names (e.g., "gpt-5.4:0"), check both exact match and base name match +- Ensure the YAML structure is correct (proper indentation) -## Error: "failed to load security config" -- Ensure .security.yml exists in the same directory as config.json -- Check YAML syntax is valid -- Verify file permissions allow reading +## Multiple API Keys Not Working +- Ensure you're using `api_keys` (plural) in .security.yml for models and web tools (except GLMSearch/BaiduSearch) +- Check that the array format is correct in YAML (proper indentation with dashes) +- Remember: Models, Brave, Tavily, Perplexity MUST use `api_keys` (array format) +- GLMSearch and BaiduSearch MUST use `api_key` (single string format) -## Error: "unknown reference path" -- Verify the reference format is correct -- Check the path structure matches the examples above -- Ensure all required sections exist in .security.yml +## Keys Not Being Applied +- Check that .security.yml is in the same directory as config.json +- Verify the file permissions allow reading (chmod 600 ~/.picoclaw/.security.yml) +- Ensure the YAML structure matches the expected format +- Check for typos in field names (case-sensitive) +- Verify the model/channel names match exactly (case-sensitive) + +## Load Balancing/Failover Issues +- Verify all API keys in the api_keys array are valid +- Check that all keys have the same rate limits and permissions +- Monitor logs to see which keys are being used and failing +- Ensure the api_keys array is properly formatted in YAML */ package config From a10036a7f1400b2ef29e4fa9a110b533580e56f8 Mon Sep 17 00:00:00 2001 From: wenjie Date: Wed, 25 Mar 2026 11:44:57 +0800 Subject: [PATCH 02/23] refactor(web): clean up systray platform build files Separate embedded tray icons into platform-specific files, rename the no-cgo systray stub for consistency, and add the app version to the launcher startup log. --- web/backend/main.go | 2 +- web/backend/systray.go | 6 ------ web/backend/systray_icon_nonwindows.go | 12 ++++++++++++ .../{systray_windows.go => systray_icon_windows.go} | 6 +++++- .../{tray_stub_nocgo.go => systray_stub_nocgo.go} | 1 + web/backend/systray_unix.go | 8 -------- 6 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 web/backend/systray_icon_nonwindows.go rename web/backend/{systray_windows.go => systray_icon_windows.go} (53%) rename web/backend/{tray_stub_nocgo.go => systray_stub_nocgo.go} (88%) delete mode 100644 web/backend/systray_unix.go diff --git a/web/backend/main.go b/web/backend/main.go index 2f181603e..6987a4515 100644 --- a/web/backend/main.go +++ b/web/backend/main.go @@ -98,7 +98,7 @@ func main() { defer logger.DisableFileLogging() } - logger.InfoC("web", "PicoClaw Launcher starting...") + logger.InfoC("web", fmt.Sprintf("%s Launcher %s starting...", appName, appVersion)) logger.InfoC("web", fmt.Sprintf("PicoClaw Home: %s", picoHome)) // Set language from command line or auto-detect diff --git a/web/backend/systray.go b/web/backend/systray.go index fde2e115e..9dcc025df 100644 --- a/web/backend/systray.go +++ b/web/backend/systray.go @@ -3,7 +3,6 @@ package main import ( - _ "embed" "fmt" "fyne.io/systray" @@ -93,8 +92,3 @@ func onReady() { func onExit() { logger.Info(T(Exiting)) } - -// getIcon returns the system tray icon -func getIcon() []byte { - return iconData -} diff --git a/web/backend/systray_icon_nonwindows.go b/web/backend/systray_icon_nonwindows.go new file mode 100644 index 000000000..0117a9ae8 --- /dev/null +++ b/web/backend/systray_icon_nonwindows.go @@ -0,0 +1,12 @@ +//go:build !windows && ((!darwin && !freebsd) || cgo) + +package main + +import _ "embed" + +//go:embed icon.png +var iconPNG []byte + +func getIcon() []byte { + return iconPNG +} diff --git a/web/backend/systray_windows.go b/web/backend/systray_icon_windows.go similarity index 53% rename from web/backend/systray_windows.go rename to web/backend/systray_icon_windows.go index cc1885155..c265e2f9c 100644 --- a/web/backend/systray_windows.go +++ b/web/backend/systray_icon_windows.go @@ -5,4 +5,8 @@ package main import _ "embed" //go:embed icon.ico -var iconData []byte +var iconICO []byte + +func getIcon() []byte { + return iconICO +} diff --git a/web/backend/tray_stub_nocgo.go b/web/backend/systray_stub_nocgo.go similarity index 88% rename from web/backend/tray_stub_nocgo.go rename to web/backend/systray_stub_nocgo.go index 13ecfd2cb..9e75e112a 100644 --- a/web/backend/tray_stub_nocgo.go +++ b/web/backend/systray_stub_nocgo.go @@ -13,6 +13,7 @@ import ( "github.com/sipeed/picoclaw/pkg/logger" ) +// runTray falls back to a headless mode on platforms where systray requires cgo. func runTray() { logger.Infof("System tray is unavailable in %s builds without cgo; running without tray", runtime.GOOS) diff --git a/web/backend/systray_unix.go b/web/backend/systray_unix.go deleted file mode 100644 index 0f9d2bb51..000000000 --- a/web/backend/systray_unix.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build !windows - -package main - -import _ "embed" - -//go:embed icon.png -var iconData []byte From 85dfb341a8aac4bea9dd851ec979554680001684 Mon Sep 17 00:00:00 2001 From: xiwuqi <64734786+xiwuqi@users.noreply.github.com> Date: Wed, 25 Mar 2026 01:22:41 -0500 Subject: [PATCH 03/23] fix(agent): suppress heartbeat tool feedback (#1937) --- pkg/agent/loop.go | 22 ++++--- pkg/agent/loop_test.go | 140 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 9 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 995c5720b..c9efb318b 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -85,6 +85,7 @@ type processOptions struct { DefaultResponse string // Response when LLM returns empty EnableSummary bool // Whether to trigger summarization SendResponse bool // Whether to send response via bus + SuppressToolFeedback bool // Whether to suppress inline tool feedback messages NoHistory bool // If true, don't load session history (for heartbeat) SkipInitialSteeringPoll bool // If true, skip the steering poll at loop start (used by Continue) } @@ -1242,14 +1243,15 @@ func (al *AgentLoop) ProcessHeartbeat( return "", fmt.Errorf("no default agent for heartbeat") } return al.runAgentLoop(ctx, agent, processOptions{ - SessionKey: "heartbeat", - Channel: channel, - ChatID: chatID, - UserMessage: content, - DefaultResponse: defaultResponse, - EnableSummary: false, - SendResponse: false, - NoHistory: true, // Don't load session history for heartbeat + SessionKey: "heartbeat", + Channel: channel, + ChatID: chatID, + UserMessage: content, + DefaultResponse: defaultResponse, + EnableSummary: false, + SendResponse: false, + SuppressToolFeedback: true, + NoHistory: true, // Don't load session history for heartbeat }) } @@ -2305,7 +2307,9 @@ turnLoop: ) // Send tool feedback to chat channel if enabled (from HEAD) - if al.cfg.Agents.Defaults.IsToolFeedbackEnabled() && ts.channel != "" { + if al.cfg.Agents.Defaults.IsToolFeedbackEnabled() && + ts.channel != "" && + !ts.opts.SuppressToolFeedback { feedbackPreview := utils.Truncate( string(argsJSON), al.cfg.Agents.Defaults.GetToolFeedbackMaxArgsLength(), diff --git a/pkg/agent/loop_test.go b/pkg/agent/loop_test.go index e0a5dffb3..341d15a2f 100644 --- a/pkg/agent/loop_test.go +++ b/pkg/agent/loop_test.go @@ -1018,6 +1018,40 @@ func (m *artifactThenSendProvider) GetDefaultModel() string { return "artifact-then-send-model" } +type toolFeedbackProvider struct { + filePath string + calls int +} + +func (m *toolFeedbackProvider) Chat( + ctx context.Context, + messages []providers.Message, + tools []providers.ToolDefinition, + model string, + opts map[string]any, +) (*providers.LLMResponse, error) { + m.calls++ + if m.calls == 1 { + return &providers.LLMResponse{ + ToolCalls: []providers.ToolCall{{ + ID: "call_heartbeat_read_file", + Type: "function", + Name: "read_file", + Arguments: map[string]any{"path": m.filePath}, + }}, + }, nil + } + + return &providers.LLMResponse{ + Content: "HEARTBEAT_OK", + ToolCalls: []providers.ToolCall{}, + }, nil +} + +func (m *toolFeedbackProvider) GetDefaultModel() string { + return "heartbeat-tool-feedback-model" +} + type toolLimitOnlyProvider struct{} func (m *toolLimitOnlyProvider) Chat( @@ -2313,6 +2347,112 @@ func TestProcessMessage_PublishesReasoningContentToReasoningChannel(t *testing.T } } +func TestProcessHeartbeat_DoesNotPublishToolFeedback(t *testing.T) { + tmpDir := t.TempDir() + heartbeatFile := filepath.Join(tmpDir, "heartbeat-task.txt") + if err := os.WriteFile(heartbeatFile, []byte("heartbeat task"), 0o644); err != nil { + t.Fatalf("WriteFile() error = %v", err) + } + + cfg := &config.Config{ + Agents: config.AgentsConfig{ + Defaults: config.AgentDefaults{ + Workspace: tmpDir, + ModelName: "test-model", + MaxTokens: 4096, + MaxToolIterations: 10, + ToolFeedback: config.ToolFeedbackConfig{ + Enabled: true, + MaxArgsLength: 300, + }, + }, + }, + Tools: config.ToolsConfig{ + ReadFile: config.ReadFileToolConfig{ + Enabled: true, + }, + }, + } + + msgBus := bus.NewMessageBus() + provider := &toolFeedbackProvider{filePath: heartbeatFile} + al := NewAgentLoop(cfg, msgBus, provider) + + response, err := al.ProcessHeartbeat(context.Background(), "check heartbeat tasks", "telegram", "chat-1") + if err != nil { + t.Fatalf("ProcessHeartbeat() error = %v", err) + } + if response != "HEARTBEAT_OK" { + t.Fatalf("ProcessHeartbeat() response = %q, want %q", response, "HEARTBEAT_OK") + } + + select { + case outbound := <-msgBus.OutboundChan(): + t.Fatalf("expected no outbound tool feedback during heartbeat, got %+v", outbound) + case <-time.After(200 * time.Millisecond): + } +} + +func TestProcessMessage_PublishesToolFeedbackWhenEnabled(t *testing.T) { + tmpDir := t.TempDir() + heartbeatFile := filepath.Join(tmpDir, "tool-feedback.txt") + if err := os.WriteFile(heartbeatFile, []byte("tool feedback task"), 0o644); err != nil { + t.Fatalf("WriteFile() error = %v", err) + } + + cfg := &config.Config{ + Agents: config.AgentsConfig{ + Defaults: config.AgentDefaults{ + Workspace: tmpDir, + ModelName: "test-model", + MaxTokens: 4096, + MaxToolIterations: 10, + ToolFeedback: config.ToolFeedbackConfig{ + Enabled: true, + MaxArgsLength: 300, + }, + }, + }, + Tools: config.ToolsConfig{ + ReadFile: config.ReadFileToolConfig{ + Enabled: true, + }, + }, + } + + msgBus := bus.NewMessageBus() + provider := &toolFeedbackProvider{filePath: heartbeatFile} + al := NewAgentLoop(cfg, msgBus, provider) + + response, err := al.processMessage(context.Background(), bus.InboundMessage{ + Channel: "telegram", + SenderID: "user-1", + ChatID: "chat-1", + Content: "check tool feedback", + }) + if err != nil { + t.Fatalf("processMessage() error = %v", err) + } + if response != "HEARTBEAT_OK" { + t.Fatalf("processMessage() response = %q, want %q", response, "HEARTBEAT_OK") + } + + select { + case outbound := <-msgBus.OutboundChan(): + if outbound.Channel != "telegram" { + t.Fatalf("tool feedback channel = %q, want %q", outbound.Channel, "telegram") + } + if outbound.ChatID != "chat-1" { + t.Fatalf("tool feedback chatID = %q, want %q", outbound.ChatID, "chat-1") + } + if !strings.Contains(outbound.Content, "`read_file`") { + t.Fatalf("tool feedback content = %q, want read_file preview", outbound.Content) + } + case <-time.After(2 * time.Second): + t.Fatal("expected outbound tool feedback for regular messages") + } +} + func TestResolveMediaRefs_ResolvesToBase64(t *testing.T) { store := media.NewFileMediaStore() dir := t.TempDir() From 95204dbf17451fbaf52551b87cc06530fc7d243a Mon Sep 17 00:00:00 2001 From: Luo Peng Date: Wed, 25 Mar 2026 14:42:29 +0800 Subject: [PATCH 04/23] fix(lint): remove CGO_ENABLED=0 for lint and fix (#1989) * fix(lint): remove CGO_ENABLED=0 for lint and fix * fix makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8ffadb4ef..0b09cf7f7 100644 --- a/Makefile +++ b/Makefile @@ -242,11 +242,11 @@ fmt: ## lint: Run linters lint: - @CGO_ENABLED=0 $(GOLANGCI_LINT) run --build-tags $(GO_BUILD_TAGS) + @$(GOLANGCI_LINT) run --build-tags $(GO_BUILD_TAGS) ## fix: Fix linting issues fix: - @CGO_ENABLED=0 $(GOLANGCI_LINT) run --fix --build-tags $(GO_BUILD_TAGS) + @$(GOLANGCI_LINT) run --fix --build-tags $(GO_BUILD_TAGS) ## deps: Download dependencies deps: From 77d4716a82c9ae9dea8d07ecf83661db0c246b9c Mon Sep 17 00:00:00 2001 From: BeaconCat <111232138+BeaconCat@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:11:02 +0800 Subject: [PATCH 05/23] config: add baidu_search example to config.example.json (#1990) Add Baidu Qianfan AI Search configuration block after glm_search, matching the BaiduSearchConfig struct defaults (enabled: false, max_results: 10). Co-authored-by: BeaconCat Co-authored-by: Claude Opus 4.6 --- config/config.example.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/config.example.json b/config/config.example.json index 90b603d72..5826ea25a 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -286,6 +286,12 @@ "search_engine": "search_std", "max_results": 5 }, + "baidu_search": { + "enabled": false, + "api_key": "", + "base_url": "https://qianfan.baidubce.com/v2/ai_search/web_search", + "max_results": 10 + }, "fetch_limit_bytes": 10485760, "private_host_whitelist": [] }, From 6bd8fec87a39ee8710d0d05c39b2fce64da1ebbf Mon Sep 17 00:00:00 2001 From: lxowalle <83055338+lxowalle@users.noreply.github.com> Date: Wed, 25 Mar 2026 15:29:43 +0800 Subject: [PATCH 06/23] Fix security config precedence during migration (#1984) * Fix security config precedence during migration * add doc * fix ci * add baidu search --- pkg/config/config.go | 48 +++++++++++++++++++++---- pkg/config/config_old.go | 34 +++++++++++++++--- pkg/config/security_integration_test.go | 40 +++++++++++---------- 3 files changed, 92 insertions(+), 30 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 47bb7e8f1..c61219d9b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1314,17 +1314,29 @@ func LoadConfig(path string) (*Config, error) { if err != nil { return nil, err } - // Load security configuration - securityPath := securityPath(path) - sec, err := loadSecurityConfig(securityPath) + + // Legacy config (no version field) + tmpCfg, e := loadConfigV0(data) + if e != nil { + return nil, e + } + + tmpCfgMigrated, e := tmpCfg.Migrate() + if e != nil { + logger.ErrorF("config migrate fail", map[string]any{"from": versionInfo.Version, "to": CurrentVersion}) + return nil, e + } + + // Load security configuration from .security.yml + secPath := securityPath(path) + sec, err := loadSecurityConfig(secPath) if err != nil { return nil, fmt.Errorf("failed to load security config: %w", err) } - // Apply security references from .security.yml BEFORE resolveAPIKeys - // This resolves ref: references to actual values - if err := applySecurityConfig(cfg, sec); err != nil { - return nil, fmt.Errorf("failed to apply security config: %w", err) + // Merge security configs: config.json takes precedence over .security.yml + if err := applySecurityConfigWithPrecedence(cfg, tmpCfgMigrated, sec); err != nil { + return nil, fmt.Errorf("failed to merge security config: %w", err) } default: return nil, fmt.Errorf("unsupported config version: %d", versionInfo.Version) @@ -1557,6 +1569,28 @@ func applySecurityConfig(cfg *Config, sec *SecurityConfig) error { return nil } +// applySecurityConfigWithPrecedence merges security config from tmpCfg (migrated from configV0) and sec (SecurityConfig), +// with tmpCfg taking precedence. It then applies the merged security config to cfg. +func applySecurityConfigWithPrecedence(cfg *Config, tmpCfg *Config, sec *SecurityConfig) error { + // Get security config from tmpCfg (already extracted during migration) + var tmpSec *SecurityConfig + if tmpCfg != nil { + tmpSec = tmpCfg.security + } + + // If tmpCfg has no security config, just apply sec directly + if tmpSec == nil { + return applySecurityConfig(cfg, sec) + } + + // Merge sec and tmpSec, with tmpSec (from config.json) taking precedence + // mergeSecurityConfig(existing, newer) - newer takes precedence + mergedSec := mergeSecurityConfig(sec, tmpSec) + + // Apply the merged security config to cfg + return applySecurityConfig(cfg, mergedSec) +} + func toNameIndex(list []*ModelConfig) []string { nameList := make([]string, 0, len(list)) countMap := make(map[string]int) diff --git a/pkg/config/config_old.go b/pkg/config/config_old.go index 44c9435d1..ad31833a3 100644 --- a/pkg/config/config_old.go +++ b/pkg/config/config_old.go @@ -833,6 +833,7 @@ type webToolsConfigV0 struct { Perplexity perplexityConfigV0 ` json:"perplexity"` SearXNG SearXNGConfig ` json:"searxng"` GLMSearch glmSearchConfigV0 ` json:"glm_search"` + BaiduSearch baiduSearchConfigV0 ` json:"baidu_search"` PreferNative bool ` json:"prefer_native" env:"PICOCLAW_TOOLS_WEB_PREFER_NATIVE"` Proxy string ` json:"proxy,omitempty" env:"PICOCLAW_TOOLS_WEB_PROXY"` FetchLimitBytes int64 ` json:"fetch_limit_bytes,omitempty" env:"PICOCLAW_TOOLS_WEB_FETCH_LIMIT_BYTES"` @@ -924,11 +925,34 @@ func (v *glmSearchConfigV0) ToGLMSearchConfig() (GLMSearchConfig, *GLMSearchSecu }, sec } +type baiduSearchConfigV0 struct { + Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_BAIDU_ENABLED"` + APIKey string `json:"api_key" env:"PICOCLAW_TOOLS_WEB_BAIDU_API_KEY"` + BaseURL string `json:"base_url" env:"PICOCLAW_TOOLS_WEB_BAIDU_BASE_URL"` + MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_BAIDU_MAX_RESULTS"` +} + +func (v *baiduSearchConfigV0) ToBaiduSearchConfig() (BaiduSearchConfig, *BaiduSearchSecurity) { + var sec *BaiduSearchSecurity + if v.APIKey != "" { + sec = &BaiduSearchSecurity{ + APIKey: v.APIKey, + } + } + return BaiduSearchConfig{ + Enabled: v.Enabled, + apiKey: v.APIKey, + BaseURL: v.BaseURL, + MaxResults: v.MaxResults, + }, sec +} + func (v *webToolsConfigV0) ToWebToolsConfig() (WebToolsConfig, WebToolsSecurity) { brave, braveSecurity := v.Brave.ToBraveConfig() tavily, tavilySecurity := v.Tavily.ToTavilyConfig() perplexity, perplexitySecurity := v.Perplexity.ToPerplexityConfig() glmSearch, glmSearchSecurity := v.GLMSearch.ToGLMSearchConfig() + baiduSearch, baiduSearchSecurity := v.BaiduSearch.ToBaiduSearchConfig() return WebToolsConfig{ ToolConfig: v.ToolConfig, @@ -938,16 +962,18 @@ func (v *webToolsConfigV0) ToWebToolsConfig() (WebToolsConfig, WebToolsSecurity) Perplexity: perplexity, SearXNG: v.SearXNG, GLMSearch: glmSearch, + BaiduSearch: baiduSearch, PreferNative: v.PreferNative, Proxy: v.Proxy, FetchLimitBytes: v.FetchLimitBytes, Format: v.Format, PrivateHostWhitelist: v.PrivateHostWhitelist, }, WebToolsSecurity{ - Brave: braveSecurity, - Tavily: tavilySecurity, - Perplexity: perplexitySecurity, - GLMSearch: glmSearchSecurity, + Brave: braveSecurity, + Tavily: tavilySecurity, + Perplexity: perplexitySecurity, + GLMSearch: glmSearchSecurity, + BaiduSearch: baiduSearchSecurity, } } diff --git a/pkg/config/security_integration_test.go b/pkg/config/security_integration_test.go index 03990ce5b..002988f2f 100644 --- a/pkg/config/security_integration_test.go +++ b/pkg/config/security_integration_test.go @@ -43,7 +43,8 @@ func TestSecurityConfigIntegration(t *testing.T) { t.Run("Full workflow with security references", func(t *testing.T) { tmpDir := t.TempDir() - // Create config.json with references + // Create config.json with direct security values (not ref: references) + // These values should take precedence over .security.yml configPath := filepath.Join(tmpDir, "config.json") configContent := `{ "version": 1, @@ -52,25 +53,25 @@ func TestSecurityConfigIntegration(t *testing.T) { "model_name": "test-model", "model": "openai/test-model", "api_base": "https://api.openai.com/v1", - "api_key": "ref:model_list.test-model.api_key" + "api_key": "sk-from-config-json-direct" } ], "channels": { "telegram": { "enabled": true, - "token": "ref:channels.telegram.token" + "token": "token-from-config-json-direct" } }, "tools": { "web": { "brave": { "enabled": true, - "api_key": "ref:web.brave.api_key" + "api_key": "BSA-from-config-json-direct" } }, "skills": { "github": { - "token": "ref:skills.github.token" + "token": "ghp-from-config-json-direct" } } } @@ -78,46 +79,47 @@ func TestSecurityConfigIntegration(t *testing.T) { err := os.WriteFile(configPath, []byte(configContent), 0o644) require.NoError(t, err) - // Create .security.yml with actual values + // Create .security.yml with different values + // These should be overridden by config.json values securityPath := filepath.Join(tmpDir, SecurityConfigFile) securityContent := `model_list: test-model: api_keys: - - "sk-test-api-key-12345" + - "sk-from-security-yml" channels: telegram: - token: "123456789:ABCdefGHIjklMNOpqrsTUVwxyz" + token: "token-from-security-yml" web: brave: api_keys: - - "BSAbrave-api-key-67890" + - "BSA-from-security-yml" skills: github: - token: "ghp_github-token-abc123"` + token: "ghp-from-security-yml"` err = os.WriteFile(securityPath, []byte(securityContent), 0o600) require.NoError(t, err) - // Load config and verify references are resolved + // Load config and verify config.json values take precedence cfg, err := LoadConfig(configPath) require.NoError(t, err) require.NotNil(t, cfg) - // Verify model API key is resolved + // Verify model API key from config.json takes precedence assert.Equal(t, 1, len(cfg.ModelList)) assert.Equal(t, "test-model", cfg.ModelList[0].ModelName) - assert.Equal(t, "sk-test-api-key-12345", cfg.ModelList[0].apiKeys[0]) + assert.Equal(t, "sk-from-config-json-direct", cfg.ModelList[0].apiKeys[0]) - // Verify channel token is resolved - assert.Equal(t, "123456789:ABCdefGHIjklMNOpqrsTUVwxyz", cfg.Channels.Telegram.token) + // Verify channel token from config.json takes precedence + assert.Equal(t, "token-from-config-json-direct", cfg.Channels.Telegram.token) - // Verify web tool API key is resolved - assert.Equal(t, "BSAbrave-api-key-67890", cfg.Tools.Web.Brave.APIKey()) + // Verify web tool API key from config.json takes precedence + assert.Equal(t, "BSA-from-config-json-direct", cfg.Tools.Web.Brave.APIKey()) - // Verify skills token is resolved - assert.Equal(t, "ghp_github-token-abc123", cfg.Tools.Skills.Github.token) + // Verify skills token from config.json takes precedence + assert.Equal(t, "ghp-from-config-json-direct", cfg.Tools.Skills.Github.token) }) } From eb307e942b828ed49176e0555178367b963c87b4 Mon Sep 17 00:00:00 2001 From: wenjie Date: Wed, 25 Mar 2026 16:15:04 +0800 Subject: [PATCH 07/23] feat(web): add WeCom QR binding flow to channel settings (#1994) - add backend WeCom QR flow endpoints and in-memory flow state management - add frontend WeCom binding UI with QR polling and channel enable toggle - update channel config behavior and i18n strings for WeCom and WeChat - apply minor formatting cleanup in model-related components --- web/backend/api/router.go | 6 + web/backend/api/wecom.go | 424 ++++++++++++++++++ web/frontend/src/api/channels.ts | 20 + .../channels/channel-config-page.tsx | 91 +++- .../channels/channel-forms/generic-form.tsx | 4 +- .../channels/channel-forms/wecom-form.tsx | 367 +++++++++++++++ .../src/components/models/add-model-sheet.tsx | 5 +- .../components/models/edit-model-sheet.tsx | 5 +- .../src/components/models/model-card.tsx | 3 +- web/frontend/src/i18n/locales/en.json | 18 +- web/frontend/src/i18n/locales/zh.json | 18 +- 11 files changed, 945 insertions(+), 16 deletions(-) create mode 100644 web/backend/api/wecom.go create mode 100644 web/frontend/src/components/channels/channel-forms/wecom-form.tsx diff --git a/web/backend/api/router.go b/web/backend/api/router.go index d09f68eac..ce652d4c4 100644 --- a/web/backend/api/router.go +++ b/web/backend/api/router.go @@ -19,6 +19,8 @@ type Handler struct { oauthState map[string]string weixinMu sync.Mutex weixinFlows map[string]*weixinFlow + wecomMu sync.Mutex + wecomFlows map[string]*wecomFlow } // NewHandler creates an instance of the API handler. @@ -29,6 +31,7 @@ func NewHandler(configPath string) *Handler { oauthFlows: make(map[string]*oauthFlow), oauthState: make(map[string]string), weixinFlows: make(map[string]*weixinFlow), + wecomFlows: make(map[string]*wecomFlow), } } @@ -75,6 +78,9 @@ func (h *Handler) RegisterRoutes(mux *http.ServeMux) { // WeChat QR login flow h.registerWeixinRoutes(mux) + + // WeCom QR login flow + h.registerWecomRoutes(mux) } // Shutdown gracefully shuts down the handler, stopping the gateway if it was started by this handler. diff --git a/web/backend/api/wecom.go b/web/backend/api/wecom.go new file mode 100644 index 000000000..7dcec9f49 --- /dev/null +++ b/web/backend/api/wecom.go @@ -0,0 +1,424 @@ +package api + +import ( + "context" + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "runtime" + "strconv" + "strings" + "time" + + "github.com/sipeed/picoclaw/pkg/config" + "github.com/sipeed/picoclaw/pkg/logger" +) + +const ( + wecomFlowTTL = 5 * time.Minute + wecomFlowGCAge = 30 * time.Minute + wecomQRSourceID = "picoclaw" + wecomQRGenerateEndpoint = "https://work.weixin.qq.com/ai/qc/generate" + wecomQRQueryEndpoint = "https://work.weixin.qq.com/ai/qc/query_result" + wecomQRHTTPTimeout = 15 * time.Second + wecomDefaultWebSocketURL = "wss://openws.work.weixin.qq.com" + wecomPollStartTimeout = 15 * time.Second + wecomPollStatusTimeout = 10 * time.Second +) + +const ( + wecomStatusWait = "wait" + wecomStatusScanned = "scaned" + wecomStatusConfirmed = "confirmed" + wecomStatusExpired = "expired" + wecomStatusError = "error" +) + +type wecomFlow struct { + ID string + SCode string + QRDataURI string + BotID string + Status string + Error string + CreatedAt time.Time + UpdatedAt time.Time + ExpiresAt time.Time +} + +type wecomFlowResponse struct { + FlowID string `json:"flow_id"` + Status string `json:"status"` + QRDataURI string `json:"qr_data_uri,omitempty"` + BotID string `json:"bot_id,omitempty"` + Error string `json:"error,omitempty"` +} + +type wecomQRGenerateResponse struct { + ErrCode int `json:"errcode,omitempty"` + ErrMsg string `json:"errmsg,omitempty"` + Data struct { + SCode string `json:"scode"` + AuthURL string `json:"auth_url"` + } `json:"data"` +} + +type wecomQRQueryResponse struct { + ErrCode int `json:"errcode,omitempty"` + ErrMsg string `json:"errmsg,omitempty"` + Data struct { + Status string `json:"status"` + BotInfo struct { + BotID string `json:"botid"` + Secret string `json:"secret"` + } `json:"bot_info"` + } `json:"data"` +} + +// registerWecomRoutes binds WeCom QR login endpoints to the ServeMux. +func (h *Handler) registerWecomRoutes(mux *http.ServeMux) { + mux.HandleFunc("POST /api/wecom/flows", h.handleStartWecomFlow) + mux.HandleFunc("GET /api/wecom/flows/{id}", h.handlePollWecomFlow) +} + +// handleStartWecomFlow starts a new WeCom QR login flow. +// +// POST /api/wecom/flows +func (h *Handler) handleStartWecomFlow(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(r.Context(), wecomPollStartTimeout) + defer cancel() + + session, err := fetchWecomQRCode(ctx) + if err != nil { + http.Error(w, fmt.Sprintf("failed to get QR code: %v", err), http.StatusInternalServerError) + return + } + + dataURI, err := generateQRDataURI(session.Data.AuthURL) + if err != nil { + http.Error(w, fmt.Sprintf("failed to generate QR image: %v", err), http.StatusInternalServerError) + return + } + + now := time.Now() + flow := &wecomFlow{ + ID: newWecomFlowID(), + SCode: session.Data.SCode, + QRDataURI: dataURI, + Status: wecomStatusWait, + CreatedAt: now, + UpdatedAt: now, + ExpiresAt: now.Add(wecomFlowTTL), + } + h.storeWecomFlow(flow) + + logger.InfoCF("wecom", "QR flow started", map[string]any{"flow_id": flow.ID}) + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(wecomFlowResponse{ + FlowID: flow.ID, + Status: flow.Status, + QRDataURI: flow.QRDataURI, + }) +} + +// handlePollWecomFlow polls the WeCom API for QR code status and updates the flow. +// +// GET /api/wecom/flows/{id} +func (h *Handler) handlePollWecomFlow(w http.ResponseWriter, r *http.Request) { + flowID := strings.TrimSpace(r.PathValue("id")) + if flowID == "" { + http.Error(w, "missing flow id", http.StatusBadRequest) + return + } + + flow, ok := h.getWecomFlow(flowID) + if !ok { + http.Error(w, "flow not found", http.StatusNotFound) + return + } + + if flow.Status == wecomStatusConfirmed || + flow.Status == wecomStatusExpired || + flow.Status == wecomStatusError { + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(wecomFlowResponse{ + FlowID: flow.ID, + Status: flow.Status, + BotID: flow.BotID, + Error: flow.Error, + }) + return + } + + ctx, cancel := context.WithTimeout(r.Context(), wecomPollStatusTimeout) + defer cancel() + + statusResp, err := queryWecomQRCodeStatus(ctx, flow.SCode) + if err != nil { + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(wecomFlowResponse{ + FlowID: flow.ID, + Status: flow.Status, + QRDataURI: flow.QRDataURI, + }) + return + } + + switch strings.ToLower(statusResp.Data.Status) { + case wecomStatusWait: + // no-op + case wecomStatusScanned, "scanned": + h.updateWecomFlowStatus(flowID, wecomStatusScanned) + case "success": + if statusResp.Data.BotInfo.BotID == "" || statusResp.Data.BotInfo.Secret == "" { + h.setWecomFlowError(flowID, "login confirmed but missing bot credentials") + break + } + if saveErr := h.saveWecomBinding( + statusResp.Data.BotInfo.BotID, + statusResp.Data.BotInfo.Secret, + ); saveErr != nil { + h.setWecomFlowError(flowID, fmt.Sprintf("failed to save credentials: %v", saveErr)) + logger.ErrorCF("wecom", "failed to save credentials", map[string]any{"error": saveErr.Error()}) + break + } + h.setWecomFlowConfirmed(flowID, statusResp.Data.BotInfo.BotID) + logger.InfoCF("wecom", "QR login confirmed, credentials saved", map[string]any{ + "flow_id": flowID, + "bot_id": statusResp.Data.BotInfo.BotID, + }) + case wecomStatusExpired: + h.updateWecomFlowStatus(flowID, wecomStatusExpired) + } + + flow, _ = h.getWecomFlow(flowID) + w.Header().Set("Content-Type", "application/json") + resp := wecomFlowResponse{ + FlowID: flow.ID, + Status: flow.Status, + BotID: flow.BotID, + Error: flow.Error, + } + if flow.Status == wecomStatusWait || flow.Status == wecomStatusScanned { + resp.QRDataURI = flow.QRDataURI + } + _ = json.NewEncoder(w).Encode(resp) +} + +func (h *Handler) saveWecomBinding(botID, secret string) error { + cfg, err := config.LoadConfig(h.configPath) + if err != nil { + return fmt.Errorf("load config: %w", err) + } + + cfg.Channels.WeCom.Enabled = true + cfg.Channels.WeCom.BotID = botID + cfg.Channels.WeCom.SetSecret(secret) + if strings.TrimSpace(cfg.Channels.WeCom.WebSocketURL) == "" { + cfg.Channels.WeCom.WebSocketURL = wecomDefaultWebSocketURL + } + if err := config.SaveConfig(h.configPath, cfg); err != nil { + return err + } + + status := h.gatewayStatusData() + gatewayStatus, _ := status["gateway_status"].(string) + if gatewayStatus != "running" { + return nil + } + + if _, err := h.RestartGateway(); err != nil { + logger.ErrorCF("wecom", "failed to restart gateway after saving binding", map[string]any{ + "error": err.Error(), + }) + } + return nil +} + +func fetchWecomQRCode(ctx context.Context) (wecomQRGenerateResponse, error) { + targetURL, err := buildWecomQRGenerateURL(wecomQRGenerateEndpoint, wecomQRSourceID, wecomPlatformCode()) + if err != nil { + return wecomQRGenerateResponse{}, err + } + + var resp wecomQRGenerateResponse + if err := doWecomJSONGet(ctx, targetURL, &resp); err != nil { + return wecomQRGenerateResponse{}, err + } + if resp.ErrCode != 0 { + return wecomQRGenerateResponse{}, fmt.Errorf( + "errcode=%d errmsg=%s", + resp.ErrCode, + resp.ErrMsg, + ) + } + if resp.Data.SCode == "" || resp.Data.AuthURL == "" { + return wecomQRGenerateResponse{}, fmt.Errorf("response missing scode or auth_url") + } + return resp, nil +} + +func queryWecomQRCodeStatus(ctx context.Context, scode string) (wecomQRQueryResponse, error) { + targetURL, err := buildWecomQRQueryURL(wecomQRQueryEndpoint, scode) + if err != nil { + return wecomQRQueryResponse{}, err + } + + var resp wecomQRQueryResponse + if err := doWecomJSONGet(ctx, targetURL, &resp); err != nil { + return wecomQRQueryResponse{}, err + } + if resp.ErrCode != 0 { + return wecomQRQueryResponse{}, fmt.Errorf( + "errcode=%d errmsg=%s", + resp.ErrCode, + resp.ErrMsg, + ) + } + return resp, nil +} + +func buildWecomQRGenerateURL(baseURL, sourceID string, platformCode int) (string, error) { + u, err := url.Parse(baseURL) + if err != nil { + return "", fmt.Errorf("invalid WeCom QR generate URL: %w", err) + } + + query := u.Query() + query.Set("source", sourceID) + query.Set("sourceID", sourceID) + query.Set("plat", strconv.Itoa(platformCode)) + u.RawQuery = query.Encode() + + return u.String(), nil +} + +func buildWecomQRQueryURL(baseURL, scode string) (string, error) { + u, err := url.Parse(baseURL) + if err != nil { + return "", fmt.Errorf("invalid WeCom QR query URL: %w", err) + } + + query := u.Query() + query.Set("scode", scode) + u.RawQuery = query.Encode() + + return u.String(), nil +} + +func doWecomJSONGet(ctx context.Context, targetURL string, out any) error { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, targetURL, nil) + if err != nil { + return err + } + + client := &http.Client{Timeout: wecomQRHTTPTimeout} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, readErr := io.ReadAll(io.LimitReader(resp.Body, 8192)) + if readErr != nil { + return fmt.Errorf("unexpected status %s", resp.Status) + } + return fmt.Errorf("unexpected status %s: %s", resp.Status, strings.TrimSpace(string(body))) + } + + if err := json.NewDecoder(resp.Body).Decode(out); err != nil { + return fmt.Errorf("decode JSON response: %w", err) + } + return nil +} + +func wecomPlatformCode() int { + switch runtime.GOOS { + case "darwin": + return 1 + case "windows": + return 2 + case "linux": + return 3 + default: + return 0 + } +} + +func newWecomFlowID() string { + buf := make([]byte, 12) + if _, err := rand.Read(buf); err != nil { + return fmt.Sprintf("wc_%d", time.Now().UnixNano()) + } + return "wc_" + hex.EncodeToString(buf) +} + +func (h *Handler) storeWecomFlow(flow *wecomFlow) { + h.wecomMu.Lock() + defer h.wecomMu.Unlock() + h.gcWecomFlowsLocked(time.Now()) + h.wecomFlows[flow.ID] = flow +} + +func (h *Handler) getWecomFlow(flowID string) (*wecomFlow, bool) { + h.wecomMu.Lock() + defer h.wecomMu.Unlock() + h.gcWecomFlowsLocked(time.Now()) + flow, ok := h.wecomFlows[flowID] + if !ok { + return nil, false + } + cp := *flow + return &cp, true +} + +func (h *Handler) updateWecomFlowStatus(flowID, status string) { + h.wecomMu.Lock() + defer h.wecomMu.Unlock() + if flow, ok := h.wecomFlows[flowID]; ok { + flow.Status = status + flow.UpdatedAt = time.Now() + } +} + +func (h *Handler) setWecomFlowConfirmed(flowID, botID string) { + h.wecomMu.Lock() + defer h.wecomMu.Unlock() + if flow, ok := h.wecomFlows[flowID]; ok { + flow.Status = wecomStatusConfirmed + flow.BotID = botID + flow.UpdatedAt = time.Now() + } +} + +func (h *Handler) setWecomFlowError(flowID, errMsg string) { + h.wecomMu.Lock() + defer h.wecomMu.Unlock() + if flow, ok := h.wecomFlows[flowID]; ok { + flow.Status = wecomStatusError + flow.Error = errMsg + flow.UpdatedAt = time.Now() + } +} + +func (h *Handler) gcWecomFlowsLocked(now time.Time) { + for id, flow := range h.wecomFlows { + if flow.Status == wecomStatusWait || flow.Status == wecomStatusScanned { + if !flow.ExpiresAt.IsZero() && now.After(flow.ExpiresAt) { + flow.Status = wecomStatusExpired + flow.UpdatedAt = now + } + } + if flow.Status != wecomStatusWait && + flow.Status != wecomStatusScanned && + now.Sub(flow.UpdatedAt) > wecomFlowGCAge { + delete(h.wecomFlows, id) + } + } +} diff --git a/web/frontend/src/api/channels.ts b/web/frontend/src/api/channels.ts index d4c3ac74b..85550ca81 100644 --- a/web/frontend/src/api/channels.ts +++ b/web/frontend/src/api/channels.ts @@ -72,6 +72,14 @@ export interface WeixinFlowResponse { error?: string } +export interface WecomFlowResponse { + flow_id: string + status: "wait" | "scaned" | "confirmed" | "expired" | "error" + qr_data_uri?: string + bot_id?: string + error?: string +} + export async function startWeixinFlow(): Promise { return request("/api/weixin/flows", { method: "POST" }) } @@ -84,4 +92,16 @@ export async function pollWeixinFlow( ) } +export async function startWecomFlow(): Promise { + return request("/api/wecom/flows", { method: "POST" }) +} + +export async function pollWecomFlow( + flowID: string, +): Promise { + return request( + `/api/wecom/flows/${encodeURIComponent(flowID)}`, + ) +} + export type { ChannelsCatalogResponse, ConfigActionResponse } diff --git a/web/frontend/src/components/channels/channel-config-page.tsx b/web/frontend/src/components/channels/channel-config-page.tsx index 7f1f695bc..6af821ac9 100644 --- a/web/frontend/src/components/channels/channel-config-page.tsx +++ b/web/frontend/src/components/channels/channel-config-page.tsx @@ -1,4 +1,4 @@ -import { IconLoader2 } from "@tabler/icons-react" +import { IconAlertTriangle, IconLoader2 } from "@tabler/icons-react" import { useCallback, useEffect, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" @@ -15,6 +15,7 @@ import { FeishuForm } from "@/components/channels/channel-forms/feishu-form" import { GenericForm } from "@/components/channels/channel-forms/generic-form" import { SlackForm } from "@/components/channels/channel-forms/slack-form" import { TelegramForm } from "@/components/channels/channel-forms/telegram-form" +import { WecomForm } from "@/components/channels/channel-forms/wecom-form" import { WeixinForm } from "@/components/channels/channel-forms/weixin-form" import { PageHeader } from "@/components/page-header" import { Button } from "@/components/ui/button" @@ -186,7 +187,7 @@ function getRequiredFieldKeys(channelName: string): string[] { case "onebot": return ["ws_url"] case "wecom": - return ["bot_id", "secret"] + return [] case "whatsapp": return ["bridge_url"] case "pico": @@ -326,6 +327,8 @@ export function ChannelConfigPage({ channelName }: ChannelConfigPageProps) { return getChannelDisplayName(channel, t) }, [channel, channelName, t]) + const hidesPageLevelEnableToggle = channel?.name === "wecom" + const hiddenKeys = useMemo(() => { if (!channel) return [] if (channel.name === "whatsapp") { @@ -410,6 +413,36 @@ export function ChannelConfigPage({ channelName }: ChannelConfigPageProps) { } }, [loadData, t]) + const handleWecomBindSuccess = useCallback(async () => { + try { + setEnabled(true) + await Promise.all([loadData(true), refreshGatewayState({ force: true })]) + } catch (e) { + const message = + e instanceof Error ? e.message : t("channels.page.saveError") + setServerError(message) + await loadData(true) + } + }, [loadData, t]) + + const handleWecomEnabledChange = useCallback( + async (nextEnabled: boolean) => { + try { + setEnabled(nextEnabled) + await Promise.all([ + loadData(true), + refreshGatewayState({ force: true }), + ]) + } catch (e) { + const message = + e instanceof Error ? e.message : t("channels.page.saveError") + setServerError(message) + await loadData(true) + } + }, + [loadData, t], + ) + const renderForm = () => { if (!channel) return null const isEdit = configured @@ -460,6 +493,27 @@ export function ChannelConfigPage({ channelName }: ChannelConfigPageProps) { onBindSuccess={() => void handleWeixinBindSuccess()} /> ) + case "wecom": + return ( + <> + void handleWecomBindSuccess()} + onEnabledChange={(nextEnabled) => + void handleWecomEnabledChange(nextEnabled) + } + /> + + + ) default: return ( -
-

- {t("channels.page.enableLabel")} -

- -
+ {channel?.name === "weixin" && ( +
+
+ +
+

+ {t("channels.weixin.warningTitle")} +

+

+ {t("channels.weixin.warningDesc")} +

+
+
+
+ )} + + {!hidesPageLevelEnableToggle && ( +
+

+ {t("channels.page.enableLabel")} +

+ +
+ )} {renderForm()} diff --git a/web/frontend/src/components/channels/channel-forms/generic-form.tsx b/web/frontend/src/components/channels/channel-forms/generic-form.tsx index 1a872542b..936802944 100644 --- a/web/frontend/src/components/channels/channel-forms/generic-form.tsx +++ b/web/frontend/src/components/channels/channel-forms/generic-form.tsx @@ -123,7 +123,9 @@ export function GenericForm({ bot_id: t("channels.form.desc.appId"), websocket_url: t("channels.form.desc.wsUrl"), dm_policy: t("channels.form.desc.genericField", { field: "DM policy" }), - group_policy: t("channels.form.desc.genericField", { field: "group policy" }), + group_policy: t("channels.form.desc.genericField", { + field: "group policy", + }), group_allow_from: t("channels.form.desc.allowFrom"), send_thinking_message: t("channels.form.desc.genericField", { field: "thinking message behavior", diff --git a/web/frontend/src/components/channels/channel-forms/wecom-form.tsx b/web/frontend/src/components/channels/channel-forms/wecom-form.tsx new file mode 100644 index 000000000..744c87ba2 --- /dev/null +++ b/web/frontend/src/components/channels/channel-forms/wecom-form.tsx @@ -0,0 +1,367 @@ +import { + IconCheck, + IconLoader2, + IconQrcode, + IconRefresh, + IconX, +} from "@tabler/icons-react" +import { useCallback, useEffect, useRef, useState } from "react" +import { useTranslation } from "react-i18next" + +import type { ChannelConfig } from "@/api/channels" +import { patchAppConfig, pollWecomFlow, startWecomFlow } from "@/api/channels" +import { Button } from "@/components/ui/button" +import { Switch } from "@/components/ui/switch" + +type BindingState = + | "idle" + | "loading" + | "waiting" + | "scaned" + | "confirmed" + | "expired" + | "error" + +interface WecomFormProps { + config: ChannelConfig + isEdit: boolean + onBindSuccess?: () => void + onEnabledChange?: (enabled: boolean) => void +} + +function asString(value: unknown): string { + return typeof value === "string" ? value : "" +} + +export function WecomForm({ + config, + isEdit, + onBindSuccess, + onEnabledChange, +}: WecomFormProps) { + const { t } = useTranslation() + + const [bindState, setBindState] = useState("idle") + const [qrDataURI, setQrDataURI] = useState(null) + const [botID, setBotID] = useState(null) + const [errorMsg, setErrorMsg] = useState("") + const [enabled, setEnabled] = useState(config.enabled === true) + const [toggleSaving, setToggleSaving] = useState(false) + const [toggleError, setToggleError] = useState("") + + const pollTimerRef = useRef | null>(null) + const pollGenerationRef = useRef(0) + const existingBotID = asString(config.bot_id) + const isBound = isEdit && existingBotID !== "" + + const stopPolling = useCallback(() => { + pollGenerationRef.current += 1 + if (pollTimerRef.current !== null) { + clearInterval(pollTimerRef.current) + pollTimerRef.current = null + } + }, []) + + useEffect(() => () => stopPolling(), [stopPolling]) + + useEffect(() => { + setEnabled(config.enabled === true) + }, [config.enabled]) + + useEffect(() => { + if (!existingBotID) return + stopPolling() + setBotID(existingBotID) + setBindState("confirmed") + setErrorMsg("") + }, [existingBotID, stopPolling]) + + const startPolling = useCallback( + (id: string) => { + stopPolling() + const generation = pollGenerationRef.current + let inFlight = false + pollTimerRef.current = setInterval(async () => { + if (inFlight) return + inFlight = true + try { + const resp = await pollWecomFlow(id) + if (generation !== pollGenerationRef.current) { + return + } + if (resp.status === "scaned") { + setBindState("scaned") + } else if (resp.status === "confirmed") { + stopPolling() + setBotID(resp.bot_id ?? existingBotID ?? null) + setBindState("confirmed") + onBindSuccess?.() + } else if (resp.status === "expired") { + stopPolling() + setBindState("expired") + } else if (resp.status === "error") { + stopPolling() + setBindState("error") + setErrorMsg(resp.error ?? t("channels.wecom.errorGeneric")) + } + } catch { + // transient network error — keep polling + } finally { + inFlight = false + } + }, 2000) + }, + [existingBotID, onBindSuccess, stopPolling, t], + ) + + const handleEnabledChange = useCallback( + async (checked: boolean) => { + if (!existingBotID || toggleSaving) { + return + } + setToggleSaving(true) + setToggleError("") + try { + await patchAppConfig({ + channels: { + wecom: { + enabled: checked, + }, + }, + }) + setEnabled(checked) + onEnabledChange?.(checked) + } catch (e) { + setToggleError( + e instanceof Error ? e.message : t("channels.wecom.errorGeneric"), + ) + } finally { + setToggleSaving(false) + } + }, + [existingBotID, onEnabledChange, t, toggleSaving], + ) + + const handleBind = async () => { + setBindState("loading") + setErrorMsg("") + setToggleError("") + setQrDataURI(null) + stopPolling() + try { + const resp = await startWecomFlow() + setQrDataURI(resp.qr_data_uri ?? null) + setBindState("waiting") + startPolling(resp.flow_id) + } catch (e) { + setBindState("error") + setErrorMsg( + e instanceof Error ? e.message : t("channels.wecom.errorGeneric"), + ) + } + } + + const handleRebind = () => { + stopPolling() + setBindState("idle") + setQrDataURI(null) + setBotID(null) + setErrorMsg("") + void handleBind() + } + + const renderBindSection = () => { + if (bindState === "idle") { + if (isBound) { + return ( +
+
+ + {t("channels.wecom.bound")} +
+ {existingBotID && ( +

+ {existingBotID} +

+ )} + +
+ ) + } + return ( +
+

+ {t("channels.wecom.notBound")} +

+ +
+ ) + } + + if (bindState === "loading") { + return ( +
+ +

+ {t("channels.wecom.generating")} +

+
+ ) + } + + if (bindState === "waiting" || bindState === "scaned") { + return ( +
+ {qrDataURI ? ( + WeCom QR Code + ) : ( +
+ +
+ )} + {bindState === "scaned" ? ( +
+ + {t("channels.wecom.scanned")} +
+ ) : ( +

+ {t("channels.wecom.scanHint")} +

+ )} + +
+ ) + } + + if (bindState === "confirmed") { + return ( +
+
+ +
+

+ {t("channels.wecom.bound")} +

+ {botID && ( +

{botID}

+ )} + +
+ ) + } + + if (bindState === "expired") { + return ( +
+
+ +
+

+ {t("channels.wecom.expired")} +

+ +
+ ) + } + + if (bindState === "error") { + return ( +
+
+ +
+

+ {errorMsg || t("channels.wecom.errorGeneric")} +

+ +
+ ) + } + + return null + } + + return ( +
+
+
+
+

+ {t("channels.page.enableLabel")} +

+

+ {isBound + ? t("channels.wecom.enableDesc") + : t("channels.wecom.enableBindFirst")} +

+
+ void handleEnabledChange(checked)} + /> +
+ {toggleError && ( +

{toggleError}

+ )} +
+ +
+
+

{t("channels.wecom.bindTitle")}

+

+ {t("channels.wecom.bindDesc")} +

+
+ {renderBindSection()} +
+
+ ) +} diff --git a/web/frontend/src/components/models/add-model-sheet.tsx b/web/frontend/src/components/models/add-model-sheet.tsx index c0c48994f..de9481391 100644 --- a/web/frontend/src/components/models/add-model-sheet.tsx +++ b/web/frontend/src/components/models/add-model-sheet.tsx @@ -12,7 +12,6 @@ import { } from "@/components/shared-form" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import { Textarea } from "@/components/ui/textarea" import { Sheet, SheetContent, @@ -21,6 +20,7 @@ import { SheetHeader, SheetTitle, } from "@/components/ui/sheet" +import { Textarea } from "@/components/ui/textarea" interface AddForm { modelName: string @@ -103,7 +103,8 @@ export function AddModelSheet({ } const setField = - (key: keyof AddForm) => (e: React.ChangeEvent) => { + (key: keyof AddForm) => + (e: React.ChangeEvent) => { setForm((f) => ({ ...f, [key]: e.target.value })) if (fieldErrors[key]) { setFieldErrors((prev) => ({ ...prev, [key]: undefined })) diff --git a/web/frontend/src/components/models/edit-model-sheet.tsx b/web/frontend/src/components/models/edit-model-sheet.tsx index 13678f03d..d1cba6719 100644 --- a/web/frontend/src/components/models/edit-model-sheet.tsx +++ b/web/frontend/src/components/models/edit-model-sheet.tsx @@ -12,7 +12,6 @@ import { } from "@/components/shared-form" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" -import { Textarea } from "@/components/ui/textarea" import { Sheet, SheetContent, @@ -21,6 +20,7 @@ import { SheetHeader, SheetTitle, } from "@/components/ui/sheet" +import { Textarea } from "@/components/ui/textarea" interface EditForm { apiKey: string @@ -92,7 +92,8 @@ export function EditModelSheet({ }, [model]) const setField = - (key: keyof EditForm) => (e: React.ChangeEvent) => + (key: keyof EditForm) => + (e: React.ChangeEvent) => setForm((f) => ({ ...f, [key]: e.target.value })) const handleSave = async () => { diff --git a/web/frontend/src/components/models/model-card.tsx b/web/frontend/src/components/models/model-card.tsx index 319cb11a3..c554410a8 100644 --- a/web/frontend/src/components/models/model-card.tsx +++ b/web/frontend/src/components/models/model-card.tsx @@ -28,7 +28,8 @@ export function ModelCard({ }: ModelCardProps) { const { t } = useTranslation() const isOAuth = model.auth_method === "oauth" - const canSetDefault = model.configured && !model.is_default && !model.is_virtual + const canSetDefault = + model.configured && !model.is_default && !model.is_virtual return (
Date: Wed, 25 Mar 2026 16:17:26 +0800 Subject: [PATCH 08/23] chore(tui): add build target for picoclaw-launcher TUI and create README for TUI launcher (#1995) --- Makefile | 8 ++++ cmd/picoclaw-launcher-tui/README.md | 69 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 cmd/picoclaw-launcher-tui/README.md diff --git a/Makefile b/Makefile index 0b09cf7f7..77af92d4a 100644 --- a/Makefile +++ b/Makefile @@ -131,6 +131,14 @@ build-launcher: @ln -sf picoclaw-launcher-$(PLATFORM)-$(ARCH) $(BUILD_DIR)/picoclaw-launcher @echo "Build complete: $(BUILD_DIR)/picoclaw-launcher" +## build-launcher-tui: Build the picoclaw-launcher TUI binary +build-launcher-tui: + @echo "Building picoclaw-launcher-tui for $(PLATFORM)/$(ARCH)..." + @mkdir -p $(BUILD_DIR) + @$(GO) build $(GOFLAGS) -o $(BUILD_DIR)/picoclaw-launcher-tui-$(PLATFORM)-$(ARCH) ./cmd/picoclaw-launcher-tui + @ln -sf picoclaw-launcher-tui-$(PLATFORM)-$(ARCH) $(BUILD_DIR)/picoclaw-launcher-tui + @echo "Build complete: $(BUILD_DIR)/picoclaw-launcher-tui" + ## build-whatsapp-native: Build with WhatsApp native (whatsmeow) support; larger binary build-whatsapp-native: generate ## @echo "Building $(BINARY_NAME) with WhatsApp native for $(PLATFORM)/$(ARCH)..." diff --git a/cmd/picoclaw-launcher-tui/README.md b/cmd/picoclaw-launcher-tui/README.md new file mode 100644 index 000000000..a942045a5 --- /dev/null +++ b/cmd/picoclaw-launcher-tui/README.md @@ -0,0 +1,69 @@ +# Picoclaw Launcher TUI + +This directory contains the terminal-based TUI launcher for `picoclaw`. +It provides a lightweight, terminal-native user interface for managing, configuring, and interacting with the core `picoclaw` engine, without requiring a web browser or graphical environment. + +## Architecture + +The TUI launcher is implemented purely in Go with no external runtime dependencies: +* **`main.go`**: Application entry point, handles initialization and main event loop +* **`ui/`**: TUI interface components built on tview + tcell framework: + - `home.go`: Main dashboard with navigation menu + - `schemes.go`: AI model scheme management + - `users.go`: User and API key management for model providers + - `channels.go`: Communication channel (Telegram/Discord/WeChat etc.) configuration editor + - `gateway.go`: PicoClaw gateway daemon lifecycle management (start/stop/status) + - `app.go`: Core TUI application framework and navigation logic + - `models.go`: Data structures and state management +* **`config/`**: Configuration management layer, integrates with the core picoclaw configuration system + +## Getting Started + +### Prerequisites + +* Go 1.25+ +* Terminal with 256-color support (most modern terminals are compatible) + +### Development + +Run the TUI launcher directly in development mode: + +```bash +# From project root +go run ./cmd/picoclaw-launcher-tui + +# Or from this directory +go run . +``` + +### Build + +Build the standalone TUI launcher binary: + +```bash +# From project root (recommended) +make build-launcher-tui + +# Output will be at: +# build/picoclaw-launcher-tui-- +# with symlink build/picoclaw-launcher-tui + +# Or build directly from this directory +go build -o picoclaw-launcher-tui . +``` + +### Key Features + +* 🖥️ Terminal-native interface - works over SSH, on headless servers, and in low-resource environments +* ⚙️ AI model scheme and API key management +* 📱 Communication channel configuration editor (Telegram/Discord/WeChat etc.) +* 🔄 PicoClaw gateway daemon management (start/stop/status monitoring) +* 💬 One-click launch of interactive AI chat session +* 🎯 Keyboard-first design with intuitive shortcuts + +### Other Commands + +```bash +# Run with custom config file path +go run . /path/to/custom/config.json +``` From 51f8285f93fbc96aaa81b1fd9fc39ba0bcbc4820 Mon Sep 17 00:00:00 2001 From: wenjie Date: Wed, 25 Mar 2026 16:59:11 +0800 Subject: [PATCH 09/23] fix(build): disable Matrix gateway import on freebsd/arm Exclude the Matrix gateway shim from freebsd/arm builds because modernc.org/libc currently fails to compile on that target. Document the upstream 32-bit FreeBSD codegen mismatch as well. --- pkg/gateway/channel_matrix.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/gateway/channel_matrix.go b/pkg/gateway/channel_matrix.go index f753c60e2..a46addae1 100644 --- a/pkg/gateway/channel_matrix.go +++ b/pkg/gateway/channel_matrix.go @@ -1,4 +1,4 @@ -//go:build !mipsle && !netbsd +//go:build !mipsle && !netbsd && !(freebsd && arm) package gateway @@ -12,6 +12,9 @@ import ( // - netbsd/*: modernc.org/sqlite v1.46.1 fails to compile due to broken // generated mutex code on NetBSD (for example sqlite_netbsd_amd64.go calls // mu.enter/mu.leave, but the generated mutex type does not define them). + // - freebsd/arm: modernc.org/libc v1.67.6 fails to compile due to broken + // generated 32-bit FreeBSD code (size_t/uint64 and int32/int64 mismatches + // in libc_freebsd.go). // // This means Matrix is currently unavailable on those targets. The proper // long-term fix is to split Matrix basic support from its E2EE/sqlite-backed From dc956f2feb81412d184fd84ad3bc34858972d602 Mon Sep 17 00:00:00 2001 From: hezixu Date: Wed, 25 Mar 2026 17:41:50 +0800 Subject: [PATCH 10/23] feat(config): allow placeholder text to be string or list Allow PlaceholderConfig.Text to accept either a single string or an array of strings, from which one is randomly selected at runtime. This maintains backward compatibility with existing single-string configs while enabling random placeholder selection. Changes: - Modify PlaceholderConfig.Text type from string to FlexibleStringSlice - Add GetRandomText() helper method for random selection - Update SendPlaceholder in all channels to use GetRandomText() - Update config.example.json with array placeholder examples - Update Matrix channel documentation --- config/config.example.json | 6 +++++- docs/channels/matrix/README.md | 11 +++++++++-- docs/channels/matrix/README.zh.md | 9 ++++++++- pkg/channels/discord/discord.go | 5 +---- pkg/channels/feishu/feishu_64.go | 5 +---- pkg/channels/matrix/matrix.go | 5 +---- pkg/channels/pico/pico.go | 5 +---- pkg/channels/telegram/telegram.go | 5 +---- pkg/config/config.go | 17 +++++++++++++++-- pkg/config/defaults.go | 4 ++-- 10 files changed, 44 insertions(+), 28 deletions(-) diff --git a/config/config.example.json b/config/config.example.json index 5826ea25a..11e270cb9 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -129,6 +129,10 @@ "encrypt_key": "", "verification_token": "", "allow_from": [], + "placeholder": { + "enabled": true, + "text": ["Thinking...", "Processing...", "Typing..."] + }, "reasoning_channel_id": "", "random_reaction_emoji": [], "is_lark": false @@ -160,7 +164,7 @@ }, "placeholder": { "enabled": true, - "text": "Thinking... 💭" + "text": ["Thinking...", "Processing...", "Typing..."] }, "reasoning_channel_id": "", "crypto_database_path": "", diff --git a/docs/channels/matrix/README.md b/docs/channels/matrix/README.md index dd4b45eba..baded984e 100644 --- a/docs/channels/matrix/README.md +++ b/docs/channels/matrix/README.md @@ -22,7 +22,7 @@ Add this to `config.json`: }, "placeholder": { "enabled": true, - "text": "Thinking..." + "text": ["Thinking...", "Processing...", "Typing..."] }, "reasoning_channel_id": "", "message_format": "richtext", @@ -45,12 +45,19 @@ Add this to `config.json`: | join_on_invite | bool | No | Auto-join invited rooms | | allow_from | []string | No | User whitelist (Matrix user IDs) | | group_trigger | object | No | Group trigger strategy (`mention_only` / `prefixes`) | -| placeholder | object | No | Placeholder message config | +| placeholder | object | No | Placeholder message config (see below) | | reasoning_channel_id | string | No | Target channel for reasoning output | | message_format | string | No | Output format: `"richtext"` (default) renders markdown as HTML; `"plain"` sends plain text only | | crypto_database_path | string | No | Path to store the crypto database (uses workspace path `~/.picoclaw/workspace` if empty) | | crypto_passphrase | string | No | Serialization key for encrypting session keys in the database; must remain unchanged once set | +### Placeholder Config + +| Field | Type | Required | Description | +|---------|----------------|----------|-------------| +| enabled | bool | No | Enable placeholder messages (default: false) | +| text | string/[]string | No | Placeholder text(s). Can be a single string or array of strings. If multiple texts are provided, one is randomly selected at runtime. Default: "Thinking..." | + ## 3. Currently Supported - Text message send/receive with markdown rendering (bold, italic, headers, code blocks, etc.) diff --git a/docs/channels/matrix/README.zh.md b/docs/channels/matrix/README.zh.md index cd68a057e..81afa550b 100644 --- a/docs/channels/matrix/README.zh.md +++ b/docs/channels/matrix/README.zh.md @@ -22,7 +22,7 @@ }, "placeholder": { "enabled": true, - "text": "Thinking... 💭" + "text": ["Thinking...", "Processing...", "Typing..."] }, "reasoning_channel_id": "", "message_format": "richtext", @@ -51,6 +51,13 @@ | crypto_database_path | string | 否 | 加密数据库存储路径(为空时使用工作空间路径 `~/.picoclaw/workspace`) | | crypto_passphrase | string | 否 | 加密数据库中 session key 的序列化密钥;设置后不能更改 | +### 占位消息配置 (Placeholder) + +| 字段 | 类型 | 必填 | 说明 | +|---------|-----------------|------|------| +| enabled | bool | 否 | 是否启用占位消息(默认:false) | +| text | string/[]string | 否 | 占位文本。可以是单个字符串或字符串数组。如果提供多个文本,运行时会随机选择一个。默认:"Thinking..." | + ## 3. 当前支持 - 文本消息收发 diff --git a/pkg/channels/discord/discord.go b/pkg/channels/discord/discord.go index 3b5b4f8bb..2385544a6 100644 --- a/pkg/channels/discord/discord.go +++ b/pkg/channels/discord/discord.go @@ -254,10 +254,7 @@ func (c *DiscordChannel) SendPlaceholder(ctx context.Context, chatID string) (st return "", nil } - text := c.config.Placeholder.Text - if text == "" { - text = "Thinking... 💭" - } + text := c.config.Placeholder.GetRandomText() msg, err := c.session.ChannelMessageSend(chatID, text) if err != nil { diff --git a/pkg/channels/feishu/feishu_64.go b/pkg/channels/feishu/feishu_64.go index 0ab70649f..76df988ad 100644 --- a/pkg/channels/feishu/feishu_64.go +++ b/pkg/channels/feishu/feishu_64.go @@ -211,10 +211,7 @@ func (c *FeishuChannel) SendPlaceholder(ctx context.Context, chatID string) (str return "", nil } - text := c.config.Placeholder.Text - if text == "" { - text = "Thinking..." - } + text := c.config.Placeholder.GetRandomText() cardContent, err := buildMarkdownCard(text) if err != nil { diff --git a/pkg/channels/matrix/matrix.go b/pkg/channels/matrix/matrix.go index 50b86158d..f6370fa20 100644 --- a/pkg/channels/matrix/matrix.go +++ b/pkg/channels/matrix/matrix.go @@ -573,10 +573,7 @@ func (c *MatrixChannel) SendPlaceholder(ctx context.Context, chatID string) (str return "", fmt.Errorf("matrix room ID is empty") } - text := strings.TrimSpace(c.config.Placeholder.Text) - if text == "" { - text = "Thinking... 💭" - } + text := c.config.Placeholder.GetRandomText() resp, err := c.client.SendMessageEvent(ctx, roomID, event.EventMessage, &event.MessageEventContent{ MsgType: event.MsgNotice, diff --git a/pkg/channels/pico/pico.go b/pkg/channels/pico/pico.go index f3ba55a92..1aa1941cf 100644 --- a/pkg/channels/pico/pico.go +++ b/pkg/channels/pico/pico.go @@ -275,10 +275,7 @@ func (c *PicoChannel) SendPlaceholder(ctx context.Context, chatID string) (strin return "", nil } - text := c.config.Placeholder.Text - if text == "" { - text = "Thinking... 💭" - } + text := c.config.Placeholder.GetRandomText() msgID := uuid.New().String() outMsg := newMessage(TypeMessageCreate, map[string]any{ diff --git a/pkg/channels/telegram/telegram.go b/pkg/channels/telegram/telegram.go index e7da1d615..5adb40a7e 100644 --- a/pkg/channels/telegram/telegram.go +++ b/pkg/channels/telegram/telegram.go @@ -402,10 +402,7 @@ func (c *TelegramChannel) SendPlaceholder(ctx context.Context, chatID string) (s return "", nil } - text := phCfg.Text - if text == "" { - text = "Thinking... 💭" - } + text := phCfg.GetRandomText() cid, threadID, err := parseTelegramChatID(chatID) if err != nil { diff --git a/pkg/config/config.go b/pkg/config/config.go index c61219d9b..fec30a374 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -3,6 +3,7 @@ package config import ( "encoding/json" "fmt" + "math/rand" "os" "path/filepath" "strings" @@ -381,8 +382,20 @@ type TypingConfig struct { // PlaceholderConfig controls placeholder message behavior (Phase 10). type PlaceholderConfig struct { - Enabled bool `json:"enabled"` - Text string `json:"text,omitempty"` + Enabled bool `json:"enabled"` + Text FlexibleStringSlice `json:"text,omitempty"` +} + +// GetRandomText returns a random placeholder text, or default if none set. +func (p *PlaceholderConfig) GetRandomText() string { + if len(p.Text) == 0 { + return "Thinking..." + } + if len(p.Text) == 1 { + return p.Text[0] + } + idx := rand.Intn(len(p.Text)) + return p.Text[idx] } type StreamingConfig struct { diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index ba1a5a0cf..5afa7ba11 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -62,7 +62,7 @@ func DefaultConfig() *Config { Typing: TypingConfig{Enabled: true}, Placeholder: PlaceholderConfig{ Enabled: true, - Text: "Thinking... 💭", + Text: FlexibleStringSlice{"Thinking... 💭"}, }, Streaming: StreamingConfig{Enabled: true, ThrottleSeconds: 3, MinGrowthChars: 200}, UseMarkdownV2: false, @@ -111,7 +111,7 @@ func DefaultConfig() *Config { }, Placeholder: PlaceholderConfig{ Enabled: true, - Text: "Thinking... 💭", + Text: FlexibleStringSlice{"Thinking... 💭"}, }, CryptoDatabasePath: "", CryptoPassphrase: "", From 123b9db6a9ca4e5df7a7d9aa36635ef81ed2d1ad Mon Sep 17 00:00:00 2001 From: hezixu Date: Wed, 25 Mar 2026 18:03:27 +0800 Subject: [PATCH 11/23] fix: correct struct field alignment for gci --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index fec30a374..d0e424c2c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -382,7 +382,7 @@ type TypingConfig struct { // PlaceholderConfig controls placeholder message behavior (Phase 10). type PlaceholderConfig struct { - Enabled bool `json:"enabled"` + Enabled bool `json:"enabled"` Text FlexibleStringSlice `json:"text,omitempty"` } From e4f4afcd4da880383f04ec50fcba6147ed365ef5 Mon Sep 17 00:00:00 2001 From: Guoguo <16666742+imguoguo@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:49:44 +0800 Subject: [PATCH 12/23] fix(release): ignore nightly tags in goreleaser changelog (#1999) GoReleaser was picking nightly tags as the "previous tag" when generating changelogs, causing release changelogs to be incomplete. Add git.ignore_tags to skip nightly tags. --- .goreleaser.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index ea93d0377..9c26de34f 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -2,6 +2,11 @@ # vim: set ts=2 sw=2 tw=0 fo=cnqoj version: 2 +git: + ignore_tags: + - nightly + - ".*-nightly.*" + before: hooks: - go mod tidy From 3f1ac297d43750d408376290dd90444bded92fb1 Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Sat, 21 Mar 2026 22:38:03 +0800 Subject: [PATCH 13/23] 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 --- Makefile | 8 + go.mod | 1 + go.sum | 1 + pkg/agent/instance_test.go | 5 +- pkg/tools/session.go | 252 +++++++ pkg/tools/session_process_unix.go | 14 + pkg/tools/session_process_windows.go | 13 + pkg/tools/session_test.go | 99 +++ pkg/tools/shell.go | 667 ++++++++++++++++++- pkg/tools/shell_test.go | 962 ++++++++++++++++++++++++++- pkg/tools/shell_timeout_unix_test.go | 1 + pkg/tools/sysproc_unix.go | 12 + pkg/tools/sysproc_windows.go | 10 + pkg/tools/types.go | 21 + 14 files changed, 2041 insertions(+), 25 deletions(-) create mode 100644 pkg/tools/session.go create mode 100644 pkg/tools/session_process_unix.go create mode 100644 pkg/tools/session_process_windows.go create mode 100644 pkg/tools/session_test.go create mode 100644 pkg/tools/sysproc_unix.go create mode 100644 pkg/tools/sysproc_windows.go diff --git a/Makefile b/Makefile index 77af92d4a..9581fa633 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,13 @@ define PATCH_MIPS_FLAGS fi endef +# Patch creack/pty for loong64 support (upstream doesn't have ztypes_loong64.go) +PTY_PATCH_LOONG64=pty_dir=$$(go env GOMODCACHE)/github.com/creack/pty@v1.1.9; \ + if [ -d "$$pty_dir" ] && [ ! -f "$$pty_dir/ztypes_loong64.go" ]; then \ + chmod +w "$$pty_dir" 2>/dev/null || true; \ + printf '//go:build linux && loong64\npackage pty\ntype (_C_int int32; _C_uint uint32)\n' > "$$pty_dir/ztypes_loong64.go"; \ + fi + # Golangci-lint GOLANGCI_LINT?=golangci-lint @@ -190,6 +197,7 @@ build-all: generate GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(CMD_DIR) GOOS=linux GOARCH=arm GOARM=7 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm ./$(CMD_DIR) GOOS=linux GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 ./$(CMD_DIR) + @$(PTY_PATCH_LOONG64) GOOS=linux GOARCH=loong64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-loong64 ./$(CMD_DIR) GOOS=linux GOARCH=riscv64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-riscv64 ./$(CMD_DIR) GOOS=linux GOARCH=mipsle GOMIPS=softfloat $(GO) build $(GOFLAGS_NO_GOOLM) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-mipsle ./$(CMD_DIR) diff --git a/go.mod b/go.mod index e9ef37e98..e8f00d7a5 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.50.2 github.com/bwmarrin/discordgo v0.29.0 github.com/caarlos0/env/v11 v11.4.0 + github.com/creack/pty v1.1.9 github.com/ergochat/irc-go v0.6.0 github.com/ergochat/readline v0.1.3 github.com/gdamore/tcell/v2 v2.13.8 diff --git a/go.sum b/go.sum index 87117bc98..7cebd1744 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,7 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9 github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/pkg/agent/instance_test.go b/pkg/agent/instance_test.go index e073cb929..e296a18cb 100644 --- a/pkg/agent/instance_test.go +++ b/pkg/agent/instance_test.go @@ -236,8 +236,9 @@ func TestNewAgentInstance_AllowsMediaTempDirForReadListAndExec(t *testing.T) { t.Fatal("exec tool not registered") } execResult := execTool.Execute(context.Background(), map[string]any{ - "command": "cat " + filepath.Base(mediaPath), - "working_dir": mediaDir, + "action": "run", + "command": "cat " + filepath.Base(mediaPath), + "cwd": mediaDir, }) if execResult.IsError { t.Fatalf("exec should allow media temp dir, got: %s", execResult.ForLLM) diff --git a/pkg/tools/session.go b/pkg/tools/session.go new file mode 100644 index 000000000..141dd4b5e --- /dev/null +++ b/pkg/tools/session.go @@ -0,0 +1,252 @@ +package tools + +import ( + "bytes" + "errors" + "io" + "os" + "sync" + "time" + + "github.com/google/uuid" +) + +const maxOutputBufferSize = 1 * 1024 * 1024 // 1MB + +const outputTruncateMarker = "\n... [output truncated, exceeded 1MB]\n" + +// PtyKeyMode represents arrow key encoding mode for PTY sessions. +// Programs send smkx/rmkx sequences to switch between CSI and SS3 modes. +type PtyKeyMode uint8 + +const ( + PtyKeyModeCSI PtyKeyMode = iota // triggered by rmkx (\x1b[?1l) + PtyKeyModeSS3 // triggered by smkx (\x1b[?1h) +) + +const PtyKeyModeNotFound PtyKeyMode = 255 + +var ( + ErrSessionNotFound = errors.New("session not found") + ErrSessionDone = errors.New("session already completed") + ErrPTYNotSupported = errors.New("PTY is not supported on this platform") + ErrNoStdin = errors.New("no stdin available") +) + +type ProcessSession struct { + mu sync.Mutex + ID string + PID int + Command string + PTY bool + Background bool + StartTime int64 + ExitCode int + Status string + stdinWriter io.Writer + stdoutPipe io.Reader + outputBuffer *bytes.Buffer + outputTruncated bool + ptyMaster *os.File + + // ptyKeyMode tracks arrow key encoding mode (CSI vs SS3) + ptyKeyMode PtyKeyMode +} + +func (s *ProcessSession) IsDone() bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.Status == "done" || s.Status == "exited" +} + +func (s *ProcessSession) GetPtyKeyMode() PtyKeyMode { + s.mu.Lock() + defer s.mu.Unlock() + return s.ptyKeyMode +} + +func (s *ProcessSession) SetPtyKeyMode(mode PtyKeyMode) { + s.mu.Lock() + defer s.mu.Unlock() + s.ptyKeyMode = mode +} + +func (s *ProcessSession) GetStatus() string { + s.mu.Lock() + defer s.mu.Unlock() + return s.Status +} + +func (s *ProcessSession) SetStatus(status string) { + s.mu.Lock() + defer s.mu.Unlock() + s.Status = status +} + +func (s *ProcessSession) GetExitCode() int { + s.mu.Lock() + defer s.mu.Unlock() + return s.ExitCode +} + +func (s *ProcessSession) SetExitCode(code int) { + s.mu.Lock() + defer s.mu.Unlock() + s.ExitCode = code +} + +func (s *ProcessSession) killProcess() error { + s.mu.Lock() + defer s.mu.Unlock() + + if s.Status != "running" { + return ErrSessionDone + } + + pid := s.PID + if pid <= 0 { + return ErrSessionNotFound + } + + if err := killProcessGroup(pid); err != nil { + return err + } + + s.Status = "done" + s.ExitCode = -1 + return nil +} + +func (s *ProcessSession) Kill() error { + return s.killProcess() +} + +func (s *ProcessSession) Write(data string) error { + s.mu.Lock() + defer s.mu.Unlock() + + if s.Status != "running" { + return ErrSessionDone + } + + var writer io.Writer + if s.PTY && s.ptyMaster != nil { + writer = s.ptyMaster + } else if s.stdinWriter != nil { + writer = s.stdinWriter + } else { + return ErrNoStdin + } + + _, err := writer.Write([]byte(data)) + return err +} + +func (s *ProcessSession) Read() string { + s.mu.Lock() + defer s.mu.Unlock() + + if s.outputBuffer.Len() == 0 { + return "" + } + + data := s.outputBuffer.String() + s.outputBuffer.Reset() + return data +} + +func (s *ProcessSession) ToSessionInfo() SessionInfo { + s.mu.Lock() + defer s.mu.Unlock() + + return SessionInfo{ + ID: s.ID, + Command: s.Command, + Status: s.Status, + PID: s.PID, + StartedAt: s.StartTime, + } +} + +type SessionManager struct { + mu sync.RWMutex + sessions map[string]*ProcessSession +} + +func NewSessionManager() *SessionManager { + sm := &SessionManager{ + sessions: make(map[string]*ProcessSession), + } + + // Start cleaner goroutine - runs every 5 minutes, cleans up sessions done for >30 minutes + go func() { + ticker := time.NewTicker(5 * time.Minute) + defer ticker.Stop() + for range ticker.C { + sm.cleanupOldSessions() + } + }() + + return sm +} + +// cleanupOldSessions removes sessions that are done and older than 30 minutes +func (sm *SessionManager) cleanupOldSessions() { + sm.mu.Lock() + defer sm.mu.Unlock() + + cutoff := time.Now().Add(-30 * time.Minute) + for id, session := range sm.sessions { + if session.IsDone() && session.StartTime < cutoff.Unix() { + delete(sm.sessions, id) + } + } +} + +func (sm *SessionManager) Add(session *ProcessSession) { + sm.mu.Lock() + defer sm.mu.Unlock() + sm.sessions[session.ID] = session +} + +func (sm *SessionManager) Get(sessionID string) (*ProcessSession, error) { + sm.mu.RLock() + defer sm.mu.RUnlock() + + session, ok := sm.sessions[sessionID] + if !ok { + return nil, ErrSessionNotFound + } + + return session, nil +} + +func (sm *SessionManager) Remove(sessionID string) { + sm.mu.Lock() + defer sm.mu.Unlock() + delete(sm.sessions, sessionID) +} + +func (sm *SessionManager) List() []SessionInfo { + sm.mu.RLock() + defer sm.mu.RUnlock() + + result := make([]SessionInfo, 0, len(sm.sessions)) + for _, session := range sm.sessions { + result = append(result, session.ToSessionInfo()) + } + + return result +} + +func generateSessionID() string { + return uuid.New().String()[:8] +} + +type SessionInfo struct { + ID string `json:"id"` + Command string `json:"command"` + Status string `json:"status"` + PID int `json:"pid"` + StartedAt int64 `json:"startedAt"` +} diff --git a/pkg/tools/session_process_unix.go b/pkg/tools/session_process_unix.go new file mode 100644 index 000000000..2fe30166e --- /dev/null +++ b/pkg/tools/session_process_unix.go @@ -0,0 +1,14 @@ +//go:build !windows + +package tools + +import ( + "syscall" +) + +func killProcessGroup(pid int) error { + if err := syscall.Kill(-pid, syscall.SIGKILL); err != nil { + _ = syscall.Kill(pid, syscall.SIGKILL) + } + return nil +} diff --git a/pkg/tools/session_process_windows.go b/pkg/tools/session_process_windows.go new file mode 100644 index 000000000..7cf558954 --- /dev/null +++ b/pkg/tools/session_process_windows.go @@ -0,0 +1,13 @@ +//go:build windows + +package tools + +import ( + "os/exec" + "strconv" +) + +func killProcessGroup(pid int) error { + _ = exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(pid)).Run() + return nil +} diff --git a/pkg/tools/session_test.go b/pkg/tools/session_test.go new file mode 100644 index 000000000..6cfe72a10 --- /dev/null +++ b/pkg/tools/session_test.go @@ -0,0 +1,99 @@ +package tools + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSessionManager_AddGet(t *testing.T) { + sm := NewSessionManager() + session := &ProcessSession{ + ID: "test-1", + Command: "echo hello", + Status: "running", + StartTime: 1000, + } + + sm.Add(session) + + got, err := sm.Get("test-1") + require.NoError(t, err) + require.Equal(t, "test-1", got.ID) +} + +func TestSessionManager_Remove(t *testing.T) { + sm := NewSessionManager() + session := &ProcessSession{ + ID: "test-1", + Command: "echo hello", + Status: "running", + StartTime: 1000, + } + sm.Add(session) + sm.Remove("test-1") + + _, err := sm.Get("test-1") + require.ErrorIs(t, err, ErrSessionNotFound) +} + +func TestSessionManager_List(t *testing.T) { + sm := NewSessionManager() + sm.Add(&ProcessSession{ + ID: "test-1", + Command: "echo hello", + Status: "running", + StartTime: 1000, + }) + sm.Add(&ProcessSession{ + ID: "test-2", + Command: "echo world", + Status: "running", + StartTime: 1001, + }) + sm.Add(&ProcessSession{ + ID: "test-3", + Command: "echo done", + Status: "done", + StartTime: 1002, + }) + + sessions := sm.List() + require.Len(t, sessions, 3) + + ids := make(map[string]bool) + for _, s := range sessions { + ids[s.ID] = true + } + require.True(t, ids["test-1"]) + require.True(t, ids["test-2"]) + require.True(t, ids["test-3"]) +} + +func TestProcessSession_IsDone(t *testing.T) { + session := &ProcessSession{Status: "running"} + require.False(t, session.IsDone()) + + session.Status = "done" + require.True(t, session.IsDone()) + + session.Status = "exited" + require.True(t, session.IsDone()) +} + +func TestProcessSession_ToSessionInfo(t *testing.T) { + session := &ProcessSession{ + ID: "test-1", + PID: 12345, + Command: "echo hello", + Status: "running", + StartTime: 1000, + } + + info := session.ToSessionInfo() + require.Equal(t, "test-1", info.ID) + require.Equal(t, "echo hello", info.Command) + require.Equal(t, "running", info.Status) + require.Equal(t, 12345, info.PID) + require.Equal(t, int64(1000), info.StartedAt) +} diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index 78ad2b26d..6ee1cb993 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -3,20 +3,36 @@ package tools import ( "bytes" "context" + "encoding/json" "errors" "fmt" + "io" "os" "os/exec" "path/filepath" "regexp" "runtime" "strings" + "sync" "time" + "github.com/creack/pty" + "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/constants" ) +var ( + globalSessionManager = NewSessionManager() + sessionManagerMu sync.RWMutex +) + +func getSessionManager() *SessionManager { + sessionManagerMu.RLock() + defer sessionManagerMu.RUnlock() + return globalSessionManager +} + type ExecTool struct { workingDir string timeout time.Duration @@ -26,6 +42,7 @@ type ExecTool struct { allowedPathPatterns []*regexp.Regexp restrictToWorkspace bool allowRemote bool + sessionManager *SessionManager } var ( @@ -145,7 +162,7 @@ func NewExecToolWithConfig( denyPatterns = append(denyPatterns, defaultDenyPatterns...) } - timeout := 60 * time.Second + var timeout time.Duration if config != nil && config.Tools.Exec.TimeoutSeconds > 0 { timeout = time.Duration(config.Tools.Exec.TimeoutSeconds) * time.Second } @@ -159,6 +176,7 @@ func NewExecToolWithConfig( allowedPathPatterns: allowedPathPatterns, restrictToWorkspace: restrict, allowRemote: allowRemote, + sessionManager: getSessionManager(), }, nil } @@ -167,27 +185,82 @@ func (t *ExecTool) Name() string { } func (t *ExecTool) Description() string { - return "Execute a shell command and return its output. Use with caution." + return `Execute shell commands. Use background=true for long-running commands (returns sessionId). Use pty=true for interactive commands (can combine with background=true). Use poll/read/write/send-keys/kill with sessionId to manage background sessions. Sessions auto-cleanup 30 minutes after process exits; use kill to terminate early. Output buffer limit: 1MB.` } func (t *ExecTool) Parameters() map[string]any { return map[string]any{ "type": "object", "properties": map[string]any{ + "action": map[string]any{ + "type": "string", + "enum": []string{"run", "list", "poll", "read", "write", "kill", "send-keys"}, + "description": "Action: run (execute command), list (show sessions), poll (check status), read (get output), write (send input), kill (terminate), send-keys (send keys to PTY)", + }, "command": map[string]any{ "type": "string", - "description": "The shell command to execute", + "description": "Shell command to execute (required for run)", }, - "working_dir": map[string]any{ + "sessionId": map[string]any{ "type": "string", - "description": "Optional working directory for the command", + "description": "Session ID (required for poll/read/write/kill/send-keys)", + }, + "keys": map[string]any{ + "type": "string", + "description": "Key names for send-keys: up, down, left, right, enter, tab, escape, backspace, ctrl-c, ctrl-d, home, end, pageup, pagedown, f1-f12", + }, + "data": map[string]any{ + "type": "string", + "description": "Data to write to stdin (required for write)", + }, + "background": map[string]any{ + "type": "string", + "description": "Run in background immediately", + }, + "pty": map[string]any{ + "type": "string", + "description": "Run in a pseudo-terminal (PTY) when available", + }, + "cwd": map[string]any{ + "type": "string", + "description": "Working directory for the command", + }, + "timeout": map[string]any{ + "type": "integer", + "description": "Timeout in seconds (0 = no timeout)", }, }, - "required": []string{"command"}, + "required": []string{"action"}, } } func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult { + action, _ := args["action"].(string) + if action == "" { + return ErrorResult("action is required") + } + + switch action { + case "run": + return t.executeRun(ctx, args) + case "list": + return t.executeList() + case "poll": + return t.executePoll(args) + case "read": + return t.executeRead(args) + case "write": + return t.executeWrite(args) + case "kill": + return t.executeKill(args) + case "send-keys": + return t.executeSendKeys(args) + default: + return ErrorResult(fmt.Sprintf("unknown action: %s", action)) + } +} + +func (t *ExecTool) executeRun(ctx context.Context, args map[string]any) *ToolResult { command, ok := args["command"].(string) if !ok { return ErrorResult("command is required") @@ -206,8 +279,26 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult } } + getBoolArg := func(key string) bool { + switch v := args[key].(type) { + case bool: + return v + case string: + return v == "true" + } + return false + } + isPty := getBoolArg("pty") + isBackground := getBoolArg("background") + + if isPty { + if runtime.GOOS == "windows" { + return ErrorResult("PTY is not supported on Windows. Use background=true without pty.") + } + } + cwd := t.workingDir - if wd, ok := args["working_dir"].(string); ok && wd != "" { + if wd, ok := args["cwd"].(string); ok && wd != "" { if t.restrictToWorkspace && t.workingDir != "" { resolvedWD, err := validatePathWithAllowPaths(wd, t.workingDir, true, t.allowedPathPatterns) if err != nil { @@ -253,6 +344,14 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult } } + if isBackground { + return t.runBackground(ctx, command, cwd, isPty) + } + + return t.runSync(ctx, command, cwd) +} + +func (t *ExecTool) runSync(ctx context.Context, command, cwd string) *ToolResult { // timeout == 0 means no timeout var cmdCtx context.Context var cancel context.CancelFunc @@ -361,6 +460,560 @@ func (t *ExecTool) Execute(ctx context.Context, args map[string]any) *ToolResult } } +func (t *ExecTool) runBackground(ctx context.Context, command, cwd string, ptyEnabled bool) *ToolResult { + sessionID := generateSessionID() + session := &ProcessSession{ + ID: sessionID, + Command: command, + PTY: ptyEnabled, + Background: true, + StartTime: time.Now().Unix(), + Status: "running", + ptyKeyMode: PtyKeyModeCSI, + } + + var cmd *exec.Cmd + if runtime.GOOS == "windows" { + cmd = exec.Command("powershell", "-NoProfile", "-NonInteractive", "-Command", command) + } else { + cmd = exec.Command("sh", "-c", command) + } + if cwd != "" { + cmd.Dir = cwd + } + + prepareCommandForTermination(cmd) + + var stdoutReader io.ReadCloser + var stderrReader io.ReadCloser + var stdinWriter io.WriteCloser + + if ptyEnabled { + ptmx, tty, err := pty.Open() + if err != nil { + return ErrorResult(fmt.Sprintf("failed to create PTY: %v", err)) + } + + cmd.Stdin = tty + cmd.Stdout = tty + cmd.Stderr = tty + + // For PTY, we need Setsid to create a new session. + // Note: Setsid and Setpgid conflict, so we must replace SysProcAttr entirely. + setSysProcAttrForPty(cmd) + + session.ptyMaster = ptmx + } else { + var err error + stdoutReader, err = cmd.StdoutPipe() + if err != nil { + return ErrorResult(fmt.Sprintf("failed to create stdout pipe: %v", err)) + } + stderrReader, err = cmd.StderrPipe() + if err != nil { + return ErrorResult(fmt.Sprintf("failed to create stderr pipe: %v", err)) + } + stdinWriter, err = cmd.StdinPipe() + if err != nil { + return ErrorResult(fmt.Sprintf("failed to create stdin pipe: %v", err)) + } + session.stdoutPipe = io.MultiReader(stdoutReader, stderrReader) + session.stdinWriter = stdinWriter + } + + if err := cmd.Start(); err != nil { + if session.ptyMaster != nil { + session.ptyMaster.Close() + } + return ErrorResult(fmt.Sprintf("failed to start command: %v", err)) + } + + session.PID = cmd.Process.Pid + t.sessionManager.Add(session) + + session.outputBuffer = &bytes.Buffer{} + + // PTY mode: read from ptyMaster and wait for process + // Note: On Linux, closing ptyMaster doesn't interrupt blocking Read() calls, + // so we need cmd.Wait() in a separate goroutine to detect process exit. + if session.PTY && session.ptyMaster != nil { + go func() { + cmd.Wait() // Wait for process to exit + session.mu.Lock() + if cmd.ProcessState != nil { + session.ExitCode = cmd.ProcessState.ExitCode() + } + session.Status = "done" + session.mu.Unlock() + }() + + go func() { + buf := make([]byte, 4096) + for { + n, err := session.ptyMaster.Read(buf) + if n > 0 { + raw := string(buf[:n]) + if mode := detectPtyKeyMode(raw); mode != PtyKeyModeNotFound && mode != session.GetPtyKeyMode() { + session.SetPtyKeyMode(mode) + } + + session.mu.Lock() + if session.outputBuffer.Len() >= maxOutputBufferSize { + if !session.outputTruncated { + session.outputBuffer.WriteString(outputTruncateMarker) + session.outputTruncated = true + } + } else { + session.outputBuffer.Write(buf[:n]) + } + session.mu.Unlock() + } + if err != nil { + break + } + } + }() + } else { + // Non-PTY mode: single goroutine reads pipes. + // When Read() returns EOF (pipe closed), we break. + // When process exits, OS closes pipe write end → Read() returns EOF → we exit. + go func() { + buf := make([]byte, 4096) + + // Read stdout + for { + n, err := stdoutReader.Read(buf) + if n > 0 { + session.mu.Lock() + if session.outputBuffer.Len() >= maxOutputBufferSize { + if !session.outputTruncated { + session.outputBuffer.WriteString(outputTruncateMarker) + session.outputTruncated = true + } + } else { + session.outputBuffer.Write(buf[:n]) + } + session.mu.Unlock() + } + if err != nil { + break + } + } + + // Read stderr + for { + n, err := stderrReader.Read(buf) + if n > 0 { + session.mu.Lock() + if session.outputBuffer.Len() >= maxOutputBufferSize { + if !session.outputTruncated { + session.outputBuffer.WriteString(outputTruncateMarker) + session.outputTruncated = true + } + } else { + session.outputBuffer.Write(buf[:n]) + } + session.mu.Unlock() + } + if err != nil { + break + } + } + + // All pipes closed, get exit status + if stdinWriter != nil { + stdinWriter.Close() + } + cmd.Wait() + + session.mu.Lock() + if cmd.ProcessState != nil { + session.ExitCode = cmd.ProcessState.ExitCode() + } + session.Status = "done" + session.mu.Unlock() + }() + } + + resp := ExecResponse{ + SessionID: sessionID, + Status: "running", + } + data, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(data), + ForUser: fmt.Sprintf("Session %s started", sessionID), + IsError: false, + } +} + +func (t *ExecTool) executeList() *ToolResult { + sessions := t.sessionManager.List() + resp := ExecResponse{ + Sessions: sessions, + } + data, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(data), + ForUser: fmt.Sprintf("%d active sessions", len(sessions)), + IsError: false, + } +} + +func (t *ExecTool) executePoll(args map[string]any) *ToolResult { + sessionID, ok := args["sessionId"].(string) + if !ok { + return ErrorResult("sessionId is required") + } + + session, err := t.sessionManager.Get(sessionID) + if err != nil { + if errors.Is(err, ErrSessionNotFound) { + return ErrorResult(fmt.Sprintf("session not found: %s", sessionID)) + } + return ErrorResult(err.Error()) + } + + resp := ExecResponse{ + SessionID: sessionID, + Status: session.GetStatus(), + ExitCode: session.GetExitCode(), + } + data, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(data), + IsError: false, + } +} + +func (t *ExecTool) executeRead(args map[string]any) *ToolResult { + sessionID, ok := args["sessionId"].(string) + if !ok { + return ErrorResult("sessionId is required") + } + + session, err := t.sessionManager.Get(sessionID) + if err != nil { + if errors.Is(err, ErrSessionNotFound) { + return ErrorResult(fmt.Sprintf("session not found: %s", sessionID)) + } + return ErrorResult(err.Error()) + } + + output := session.Read() + + resp := ExecResponse{ + SessionID: sessionID, + Output: output, + Status: session.GetStatus(), + } + data, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(data), + IsError: false, + } +} + +func (t *ExecTool) executeWrite(args map[string]any) *ToolResult { + sessionID, ok := args["sessionId"].(string) + if !ok { + return ErrorResult("sessionId is required") + } + + data, ok := args["data"].(string) + if !ok { + return ErrorResult("data is required") + } + + session, err := t.sessionManager.Get(sessionID) + if err != nil { + if errors.Is(err, ErrSessionNotFound) { + return ErrorResult(fmt.Sprintf("session not found: %s", sessionID)) + } + return ErrorResult(err.Error()) + } + + if session.IsDone() { + return ErrorResult(fmt.Sprintf("process already exited with code %d", session.GetExitCode())) + } + + if err := session.Write(data); err != nil { + if errors.Is(err, ErrSessionDone) { + return ErrorResult(fmt.Sprintf("process already exited with code %d", session.GetExitCode())) + } + return ErrorResult(fmt.Sprintf("failed to write to session: %v", err)) + } + + resp := ExecResponse{ + SessionID: sessionID, + Status: session.GetStatus(), + } + respData, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(respData), + IsError: false, + } +} + +func (t *ExecTool) executeKill(args map[string]any) *ToolResult { + sessionID, ok := args["sessionId"].(string) + if !ok { + return ErrorResult("sessionId is required") + } + + session, err := t.sessionManager.Get(sessionID) + if err != nil { + if errors.Is(err, ErrSessionNotFound) { + return ErrorResult(fmt.Sprintf("session not found: %s", sessionID)) + } + return ErrorResult(err.Error()) + } + + if session.IsDone() { + return ErrorResult(fmt.Sprintf("process already exited with code %d", session.GetExitCode())) + } + + if err := session.Kill(); err != nil { + return ErrorResult(fmt.Sprintf("failed to kill session: %v", err)) + } + + t.sessionManager.Remove(sessionID) + + resp := ExecResponse{ + SessionID: sessionID, + Status: "done", + } + data, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(data), + ForUser: fmt.Sprintf("Session %s killed", sessionID), + IsError: false, + } +} + +// keyMap maps key names to their escape sequences. +var keyMap = map[string]string{ + "enter": "\r", + "return": "\r", + "tab": "\t", + "escape": "\x1b", + "esc": "\x1b", + "space": " ", + "backspace": "\x7f", + "bspace": "\x7f", + "up": "\x1b[A", + "down": "\x1b[B", + "right": "\x1b[C", + "left": "\x1b[D", + "home": "\x1b[1~", + "end": "\x1b[4~", + "pageup": "\x1b[5~", + "pagedown": "\x1b[6~", + "pgup": "\x1b[5~", + "pgdn": "\x1b[6~", + "insert": "\x1b[2~", + "ic": "\x1b[2~", + "delete": "\x1b[3~", + "del": "\x1b[3~", + "dc": "\x1b[3~", + "btab": "\x1b[Z", + "f1": "\x1bOP", + "f2": "\x1bOQ", + "f3": "\x1bOR", + "f4": "\x1bOS", + "f5": "\x1b[15~", + "f6": "\x1b[17~", + "f7": "\x1b[18~", + "f8": "\x1b[19~", + "f9": "\x1b[20~", + "f10": "\x1b[21~", + "f11": "\x1b[23~", + "f12": "\x1b[24~", +} + +// ss3KeysMap maps key names to SS3 escape sequences +var ss3KeysMap = map[string]string{ + "up": "\x1bOA", + "down": "\x1bOB", + "right": "\x1bOC", + "left": "\x1bOD", + "home": "\x1bOH", + "end": "\x1bOF", +} + +func detectPtyKeyMode(raw string) PtyKeyMode { + const SMKX = "\x1b[?1h" + const RMKX = "\x1b[?1l" + + lastSmkx := strings.LastIndex(raw, SMKX) + lastRmkx := strings.LastIndex(raw, RMKX) + + if lastSmkx == -1 && lastRmkx == -1 { + return PtyKeyModeNotFound + } + + if lastSmkx > lastRmkx { + return PtyKeyModeSS3 + } + return PtyKeyModeCSI +} + +// encodeKeyToken encodes a single key token into its escape sequence. +// Supports: +// - Named keys: "enter", "tab", "up", "ctrl-c", "alt-x", etc. +// - Ctrl modifier: "ctrl-c" or "c-c" (sends Ctrl+char) +// - Alt modifier: "alt-x" or "m-x" (sends ESC+char) +func encodeKeyToken(token string, ptyKeyMode PtyKeyMode) (string, error) { + token = strings.ToLower(strings.TrimSpace(token)) + if token == "" { + return "", nil + } + + // Handle ctrl-X format (c-x) + if strings.HasPrefix(token, "c-") { + char := token[2] + if char >= 'a' && char <= 'z' { + return string(rune(char) & 0x1f), nil // ctrl-a through ctrl-z + } + return "", fmt.Errorf("invalid ctrl key: %s", token) + } + + // Handle ctrl-X format (ctrl-x) + if strings.HasPrefix(token, "ctrl-") { + char := token[5] + if char >= 'a' && char <= 'z' { + return string(rune(char) & 0x1f), nil + } + return "", fmt.Errorf("invalid ctrl key: %s", token) + } + + // Handle alt-X format (m-x or alt-x) + if strings.HasPrefix(token, "m-") || strings.HasPrefix(token, "alt-") { + var char string + if strings.HasPrefix(token, "m-") { + char = token[2:] + } else { + char = token[4:] + } + if len(char) == 1 { + return "\x1b" + char, nil + } + return "", fmt.Errorf("invalid alt key: %s", token) + } + + // Handle shift modifier for special keys (shift-up, shift-down, etc.) + if strings.HasPrefix(token, "s-") || strings.HasPrefix(token, "shift-") { + var key string + if strings.HasPrefix(token, "s-") { + key = token[2:] + } else { + key = token[6:] + } + // Apply shift modifier: for single-char keys, return uppercase + if seq, ok := keyMap[key]; ok { + // For escape sequences, we can't easily add shift + // For single-char keys (letters), return uppercase + if len(seq) == 1 { + return strings.ToUpper(seq), nil + } + return seq, nil + } + return "", fmt.Errorf("unknown key with shift: %s", key) + } + + if ptyKeyMode == PtyKeyModeSS3 { + if seq, ok := ss3KeysMap[token]; ok { + return seq, nil + } + } + + if seq, ok := keyMap[token]; ok { + return seq, nil + } + + return "", fmt.Errorf("unknown key: %s (use write action for text input)", token) +} + +// encodeKeySequence encodes a slice of key tokens into a single string. +func encodeKeySequence(tokens []string, ptyKeyMode PtyKeyMode) (string, error) { + var result string + for _, token := range tokens { + seq, err := encodeKeyToken(token, ptyKeyMode) + if err != nil { + return "", err + } + result += seq + } + return result, nil +} + +func (t *ExecTool) executeSendKeys(args map[string]any) *ToolResult { + sessionID, ok := args["sessionId"].(string) + if !ok { + return ErrorResult("sessionId is required") + } + + keysStr, ok := args["keys"].(string) + if !ok { + return ErrorResult("keys must be a string") + } + + if keysStr == "" { + return ErrorResult("keys cannot be empty") + } + + // Parse comma-separated key names + keyNames := strings.Split(keysStr, ",") + var keys []string + for _, k := range keyNames { + k = strings.TrimSpace(k) + if k != "" { + keys = append(keys, k) + } + } + + if len(keys) == 0 { + return ErrorResult("keys cannot be empty") + } + + session, err := t.sessionManager.Get(sessionID) + if err != nil { + if errors.Is(err, ErrSessionNotFound) { + return ErrorResult(fmt.Sprintf("session not found: %s", sessionID)) + } + return ErrorResult(err.Error()) + } + + ptyKeyMode := session.GetPtyKeyMode() + + data, err := encodeKeySequence(keys, ptyKeyMode) + if err != nil { + return ErrorResult(fmt.Sprintf("invalid key: %v", err)) + } + + if session.IsDone() { + return ErrorResult(fmt.Sprintf("process already exited with code %d", session.GetExitCode())) + } + + if err := session.Write(data); err != nil { + if errors.Is(err, ErrSessionDone) { + return ErrorResult(fmt.Sprintf("process already exited with code %d", session.GetExitCode())) + } + return ErrorResult(fmt.Sprintf("failed to send keys: %v", err)) + } + + resp := ExecResponse{ + SessionID: sessionID, + Status: "running", + Output: fmt.Sprintf("Sent keys: %v", keys), + } + respData, _ := json.Marshal(resp) + return &ToolResult{ + ForLLM: string(respData), + IsError: false, + } +} + func (t *ExecTool) guardCommand(command, cwd string) string { cmd := strings.TrimSpace(command) lower := strings.ToLower(cmd) diff --git a/pkg/tools/shell_test.go b/pkg/tools/shell_test.go index f8f83ea74..a8de2f4c9 100644 --- a/pkg/tools/shell_test.go +++ b/pkg/tools/shell_test.go @@ -2,12 +2,16 @@ package tools import ( "context" + "encoding/json" "os" "path/filepath" + "runtime" "strings" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/sipeed/picoclaw/pkg/config" ) @@ -20,6 +24,7 @@ func TestShellTool_Success(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "echo 'hello world'", } @@ -50,6 +55,7 @@ func TestShellTool_Failure(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "ls /nonexistent_directory_12345", } @@ -82,6 +88,7 @@ func TestShellTool_Timeout(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "sleep 10", } @@ -112,8 +119,9 @@ func TestShellTool_WorkingDir(t *testing.T) { ctx := context.Background() args := map[string]any{ - "command": "cat test.txt", - "working_dir": tmpDir, + "action": "run", + "command": "cat test.txt", + "cwd": tmpDir, } result := tool.Execute(ctx, args) @@ -136,6 +144,7 @@ func TestShellTool_DangerousCommand(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "rm -rf /", } @@ -159,6 +168,7 @@ func TestShellTool_DangerousCommand_KillBlocked(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "kill 12345", } @@ -198,6 +208,7 @@ func TestShellTool_StderrCapture(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "sh -c 'echo stdout; echo stderr >&2'", } @@ -222,6 +233,7 @@ func TestShellTool_OutputTruncation(t *testing.T) { ctx := context.Background() // Generate long output (>10000 chars) args := map[string]any{ + "action": "run", "command": "python3 -c \"print('x' * 20000)\" || echo " + strings.Repeat("x", 20000), } @@ -251,8 +263,9 @@ func TestShellTool_WorkingDir_OutsideWorkspace(t *testing.T) { } result := tool.Execute(context.Background(), map[string]any{ - "command": "pwd", - "working_dir": outsideDir, + "action": "run", + "command": "pwd", + "cwd": outsideDir, }) if !result.IsError { @@ -289,8 +302,9 @@ func TestShellTool_WorkingDir_SymlinkEscape(t *testing.T) { } result := tool.Execute(context.Background(), map[string]any{ - "command": "cat secret.txt", - "working_dir": link, + "action": "run", + "command": "cat secret.txt", + "cwd": link, }) if !result.IsError { @@ -312,7 +326,7 @@ func TestShellTool_RemoteChannelBlockedByDefault(t *testing.T) { t.Fatalf("NewExecToolWithConfig() error: %v", err) } ctx := WithToolContext(context.Background(), "telegram", "chat-1") - result := tool.Execute(ctx, map[string]any{"command": "echo hi"}) + result := tool.Execute(ctx, map[string]any{"action": "run", "command": "echo hi"}) if !result.IsError { t.Fatal("expected remote-channel exec to be blocked") @@ -333,7 +347,7 @@ func TestShellTool_InternalChannelAllowed(t *testing.T) { t.Fatalf("NewExecToolWithConfig() error: %v", err) } ctx := WithToolContext(context.Background(), "cli", "direct") - result := tool.Execute(ctx, map[string]any{"command": "echo hi"}) + result := tool.Execute(ctx, map[string]any{"action": "run", "command": "echo hi"}) if result.IsError { t.Fatalf("expected internal channel exec to succeed, got: %s", result.ForLLM) @@ -373,7 +387,7 @@ func TestShellTool_AllowRemoteBypassesChannelCheck(t *testing.T) { t.Fatalf("NewExecToolWithConfig() error: %v", err) } ctx := WithToolContext(context.Background(), "telegram", "chat-1") - result := tool.Execute(ctx, map[string]any{"command": "echo hi"}) + result := tool.Execute(ctx, map[string]any{"action": "run", "command": "echo hi"}) if result.IsError { t.Fatalf("expected allowRemote=true to permit remote channel, got: %s", result.ForLLM) @@ -392,6 +406,7 @@ func TestShellTool_RestrictToWorkspace(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "cat ../../etc/passwd", } @@ -429,7 +444,7 @@ func TestShellTool_DevNullAllowed(t *testing.T) { } for _, cmd := range commands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if result.IsError && strings.Contains(result.ForLLM, "blocked") { t.Errorf("command should not be blocked: %s\n error: %s", cmd, result.ForLLM) } @@ -458,7 +473,7 @@ func TestShellTool_BlockDevices(t *testing.T) { } for _, cmd := range blocked { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if !result.IsError { t.Errorf("expected block device write to be blocked: %s", cmd) } @@ -482,7 +497,7 @@ func TestShellTool_SafePathsInWorkspaceRestriction(t *testing.T) { } for _, cmd := range commands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if result.IsError && strings.Contains(result.ForLLM, "path outside working dir") { t.Errorf("safe path should not be blocked by workspace check: %s\n error: %s", cmd, result.ForLLM) } @@ -498,6 +513,7 @@ func TestShellTool_ExitCodeDetails(t *testing.T) { ctx := context.Background() args := map[string]any{ + "action": "run", "command": "sh -c 'exit 42'", } @@ -534,6 +550,7 @@ func TestShellTool_TimeoutWithPartialOutput(t *testing.T) { ctx := context.Background() // Use a command that outputs immediately then sleeps args := map[string]any{ + "action": "run", "command": "echo 'partial output before timeout' && sleep 30", } @@ -608,7 +625,9 @@ func TestShellTool_URLsNotBlocked(t *testing.T) { } for _, cmd := range commands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + result := tool.Execute(ctx, map[string]any{"action": "run", "command": cmd}) + cancel() if result.IsError && strings.Contains(result.ForLLM, "path outside working dir") { t.Errorf("command with URL should not be blocked by workspace check: %s\n error: %s", cmd, result.ForLLM) } @@ -633,7 +652,7 @@ func TestShellTool_FileURISandboxing(t *testing.T) { } for _, cmd := range blockedCommands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if !result.IsError || !strings.Contains(result.ForLLM, "path outside working dir") { t.Errorf("file:// URI outside workspace should be blocked: %s", cmd) } @@ -651,7 +670,7 @@ func TestShellTool_FileURISandboxing(t *testing.T) { } for _, cmd := range allowedCommands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if result.IsError && strings.Contains(result.ForLLM, "path outside working dir") { t.Errorf("file:// URI inside workspace should be allowed: %s\n error: %s", cmd, result.ForLLM) } @@ -677,9 +696,920 @@ func TestShellTool_URLBypassPrevented(t *testing.T) { } for _, cmd := range blockedCommands { - result := tool.Execute(context.Background(), map[string]any{"command": cmd}) + result := tool.Execute(context.Background(), map[string]any{"action": "run", "command": cmd}) if !result.IsError || !strings.Contains(result.ForLLM, "path outside working dir") { t.Errorf("bypass attempt should be blocked: %q\n got: %s", cmd, result.ForLLM) } } } + +func TestShellTool_Background_ReturnsImmediately(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + ctx := context.Background() + args := map[string]any{ + "action": "run", + "command": "sleep 5", + "background": "true", + } + + start := time.Now() + result := tool.Execute(ctx, args) + elapsed := time.Since(start) + + require.False(t, result.IsError, "background run should not error: %s", result.ForLLM) + require.Less(t, elapsed, time.Second, "background run should return immediately") + require.Contains(t, result.ForLLM, "sessionId") +} + +func TestShellTool_List_Empty(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := context.Background() + args := map[string]any{"action": "list"} + + result := tool.Execute(ctx, args) + require.False(t, result.IsError) + require.Contains(t, result.ForUser, "0 active sessions") +} + +func TestShellTool_RunBackground_List(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 10", + "background": "true", + }) + require.False(t, runResult.IsError, "run should succeed: %s", runResult.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &resp) + require.NoError(t, err) + require.NotEmpty(t, resp.SessionID) + + time.Sleep(100 * time.Millisecond) + + listResult := tool.Execute(ctx, map[string]any{"action": "list"}) + require.False(t, listResult.IsError) + + var listResp ExecResponse + err = json.Unmarshal([]byte(listResult.ForLLM), &listResp) + require.NoError(t, err) + require.Len(t, listResp.Sessions, 1) + require.Equal(t, resp.SessionID, listResp.Sessions[0].ID) + + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) +} + +func TestShellTool_Read_Output(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "echo hello", + "background": "true", + }) + require.False(t, runResult.IsError) + + var resp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &resp) + require.NoError(t, err) + + time.Sleep(200 * time.Millisecond) + + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": resp.SessionID, + }) + + if !readResult.IsError { + var readResp ExecResponse + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + } +} + +func TestShellTool_Kill(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 100", + "background": "true", + }) + require.False(t, runResult.IsError) + + var resp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &resp) + require.NoError(t, err) + + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) + + time.Sleep(100 * time.Millisecond) + + listResult := tool.Execute(ctx, map[string]any{"action": "list"}) + var listResp ExecResponse + err = json.Unmarshal([]byte(listResult.ForLLM), &listResp) + require.NoError(t, err) + require.Len(t, listResp.Sessions, 0) +} + +func TestShellTool_PTY_AllowedCommands(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Test that PTY is allowed for non-interpreter commands + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "cat", + "pty": "true", + "background": "true", + }) + require.False(t, result.IsError, "PTY with cat should succeed: %s", result.ForLLM) + require.Contains(t, result.ForLLM, "sessionId") + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + require.NotEmpty(t, resp.SessionID) + + // Clean up + tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) +} + +func TestShellTool_PTY_WriteRead(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a PTY session with a command that waits for input + // Using 'cat' which will wait for stdin + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "cat", + "pty": "true", + "background": "true", + }) + require.False(t, result.IsError, "PTY run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Write some input to cat + writeResult := tool.Execute(ctx, map[string]any{ + "action": "write", + "sessionId": resp.SessionID, + "data": "hello\n", + }) + require.False(t, writeResult.IsError, "write should succeed: %s", writeResult.ForLLM) + + // Give cat time to process and output + time.Sleep(200 * time.Millisecond) + + // Read the output + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": resp.SessionID, + }) + + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + + var readResp ExecResponse + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + // PTY output should contain "hello" + require.Contains(t, readResp.Output, "hello") + + // Clean up + tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) +} + +func TestShellTool_PTY_Poll(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a PTY session with a long-running command + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 2", + "pty": "true", + "background": "true", + }) + require.False(t, result.IsError, "PTY run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Poll should show running + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.False(t, pollResult.IsError, "poll should succeed: %s", pollResult.ForLLM) + + var pollResp ExecResponse + err = json.Unmarshal([]byte(pollResult.ForLLM), &pollResp) + require.NoError(t, err) + require.Equal(t, "running", pollResp.Status) + + // Wait for sleep to complete + time.Sleep(2500 * time.Millisecond) + + // Poll should show done + pollResult = tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.False(t, pollResult.IsError) + + err = json.Unmarshal([]byte(pollResult.ForLLM), &pollResp) + require.NoError(t, err) + require.Equal(t, "done", pollResp.Status) +} + +func TestShellTool_PTY_Kill(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a PTY session with a long-running command + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 10", + "pty": "true", + "background": "true", + }) + require.False(t, result.IsError, "PTY run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Kill the session + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) + + // Verify kill response shows done status + var killResp ExecResponse + err = json.Unmarshal([]byte(killResult.ForLLM), &killResp) + require.NoError(t, err) + require.Equal(t, "done", killResp.Status) + + // Poll should return error since session is removed after kill + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + // Session is removed after kill, so poll returns error with "session not found" + require.True(t, pollResult.IsError, "poll should error after kill (session removed)") + require.Contains(t, pollResult.ForLLM, "session not found") +} + +func TestShellTool_Write_Read_NonPTY(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a background process that reads from stdin and outputs it + // Using 'cat' which echoes stdin to stdout + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "cat", + "pty": false, + "background": "true", + }) + require.False(t, result.IsError, "run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Write some input to cat + writeResult := tool.Execute(ctx, map[string]any{ + "action": "write", + "sessionId": resp.SessionID, + "data": "hello world\n", + }) + require.False(t, writeResult.IsError, "write should succeed: %s", writeResult.ForLLM) + + // Give cat time to process and output + time.Sleep(200 * time.Millisecond) + + // Read the output + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": resp.SessionID, + }) + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + + var readResp ExecResponse + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + require.Contains(t, readResp.Output, "hello world") + + // Clean up + tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) +} + +func TestShellTool_Read_NonPTY_Running(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a long-running process that produces output over time + // Using sh -c with sleep at the end so process doesn't exit immediately + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sh -c 'echo line1; sleep 0.5; echo line2; sleep 0.5; echo line3; sleep 10'", + "pty": false, + "background": "true", + }) + require.False(t, result.IsError, "run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Give time for first outputs to be produced + time.Sleep(300 * time.Millisecond) + + // Read output while process is running + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": resp.SessionID, + }) + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + + var readResp ExecResponse + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + // Should have at least line1 + require.Contains(t, readResp.Output, "line1") + + // Wait for line3 to be produced (line1=0s, line2=0.5s, line3=1s, then sleep 10) + time.Sleep(1200 * time.Millisecond) + + // Read again - should have line3 as well + readResult = tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": resp.SessionID, + }) + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + require.Contains(t, readResp.Output, "line3") + + // Clean up + tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) +} + +func TestShellTool_ProcessGroupKill(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Process group kill not supported on Windows") + } + + // Note: Testing process group kill with PTY is tricky because the command + // must be run through an interpreter (sh, bash) which is blocked for PTY. + // Instead, we test with non-PTY mode which also uses Setsid for background processes. + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a shell that spawns child processes (non-PTY mode) + // The sh -c command creates child sleep processes + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sh -c 'sleep 30 & sleep 30 & wait'", + "pty": false, + "background": "true", + }) + require.False(t, result.IsError, "run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Give time for child processes to spawn + time.Sleep(500 * time.Millisecond) + + // Kill the session - should kill the entire process group + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) + + // Verify kill response shows done status + var killResp ExecResponse + err = json.Unmarshal([]byte(killResult.ForLLM), &killResp) + require.NoError(t, err) + require.Equal(t, "done", killResp.Status) + + // Poll should return error since session is removed after kill + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.True(t, pollResult.IsError, "poll should error after kill (session removed)") + require.Contains(t, pollResult.ForLLM, "session not found") +} + +func TestShellTool_PTY_ProcessGroupKill(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY process group kill not supported on Windows") + } + + // This test binary creates 4 child sleep processes and waits for signals. + // It's not an interpreter, so it's allowed with PTY mode. + // The binary is created in /tmp/test_pgroup.c and compiled as part of test setup. + testBinary := "/tmp/test_pgroup" + if _, err := os.Stat(testBinary); os.IsNotExist(err) { + t.Skip("Test binary /tmp/test_pgroup not found - run: gcc -o /tmp/test_pgroup /tmp/test_pgroup.c") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start the test binary with PTY mode + // It forks 4 child sleep processes and waits for signals + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": testBinary, + "pty": "true", + "background": "true", + }) + require.False(t, result.IsError, "run should succeed: %s", result.ForLLM) + + var resp ExecResponse + err = json.Unmarshal([]byte(result.ForLLM), &resp) + require.NoError(t, err) + + // Give time for child processes to spawn + time.Sleep(500 * time.Millisecond) + + // Kill the session - should kill the entire process group + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": resp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) + + // Verify kill response shows done status + var killResp ExecResponse + err = json.Unmarshal([]byte(killResult.ForLLM), &killResp) + require.NoError(t, err) + require.Equal(t, "done", killResp.Status) + + // Poll should return error since session is removed after kill + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.True(t, pollResult.IsError, "poll should error after kill (session removed)") + require.Contains(t, pollResult.ForLLM, "session not found") +} + +func TestShellTool_PTY_Background_Read(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a fast command with PTY + background mode + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "echo hello", + "pty": "true", + "background": "true", + }) + require.False(t, runResult.IsError, "run should succeed: %s", runResult.ForLLM) + + var runResp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &runResp) + require.NoError(t, err) + require.NotEmpty(t, runResp.SessionID) + require.Equal(t, "running", runResp.Status) + + // Wait for command to complete + time.Sleep(500 * time.Millisecond) + + // Read output - this is the key test: PTY + background mode should preserve output + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": runResp.SessionID, + }) + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + require.Contains(t, readResult.ForLLM, "hello", "output should contain 'hello'") +} + +func TestShellTool_PTY_Background_ReadNoBlock(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("PTY not supported on Windows") + } + + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + // Start a long-running command with PTY + background mode + // This command produces no output, just sleeps + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 10", + "pty": "true", + "background": "true", + }) + require.False(t, runResult.IsError, "run should succeed: %s", runResult.ForLLM) + + var runResp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &runResp) + require.NoError(t, err) + require.NotEmpty(t, runResp.SessionID) + + // Read immediately - should NOT block even though process is running and has no output + // This tests that Read() returns quickly (within 1 second) instead of blocking for 10 seconds + start := time.Now() + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": runResp.SessionID, + }) + elapsed := time.Since(start) + + require.False(t, readResult.IsError, "read should succeed: %s", readResult.ForLLM) + require.Less(t, elapsed.Seconds(), 1.0, "read should not block, should return within 1 second") + + // Kill the session to clean up + killResult := tool.Execute(ctx, map[string]any{ + "action": "kill", + "sessionId": runResp.SessionID, + }) + require.False(t, killResult.IsError, "kill should succeed: %s", killResult.ForLLM) +} + +func TestShellTool_Poll_Status(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + sm := NewSessionManager() + tool.sessionManager = sm + + ctx := WithToolContext(context.Background(), "cli", "test") + + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "sleep 1", + "background": "true", + }) + require.False(t, runResult.IsError) + + var resp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &resp) + require.NoError(t, err) + + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.False(t, pollResult.IsError) + + var pollResp ExecResponse + err = json.Unmarshal([]byte(pollResult.ForLLM), &pollResp) + require.NoError(t, err) + require.Equal(t, "running", pollResp.Status) + + time.Sleep(1200 * time.Millisecond) + + pollResult = tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": resp.SessionID, + }) + require.False(t, pollResult.IsError) + + err = json.Unmarshal([]byte(pollResult.ForLLM), &pollResp) + require.NoError(t, err) + require.Equal(t, "done", pollResp.Status) +} + +func TestShellTool_Action_Run_Sync(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + ctx := context.Background() + + result := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "echo hello", + }) + + require.False(t, result.IsError) + require.Contains(t, result.ForLLM, "hello") +} + +// TestShellTool_Background_ReadAfterExit verifies that we can read +// buffered output even after the background process has exited. +func TestShellTool_Background_ReadAfterExit(t *testing.T) { + tool, err := NewExecTool("", false) + require.NoError(t, err) + + ctx := context.Background() + + // Start a background command that produces output and exits quickly + runResult := tool.Execute(ctx, map[string]any{ + "action": "run", + "command": "echo hello && sleep 1 && echo world", + "background": "true", + }) + require.False(t, runResult.IsError, "run should succeed: %s", runResult.ForUser) + + // Parse session ID from response + var resp ExecResponse + err = json.Unmarshal([]byte(runResult.ForLLM), &resp) + require.NoError(t, err) + require.NotEmpty(t, resp.SessionID) + sessionID := resp.SessionID + + // Wait for process to exit (sleep 1 + some buffer) + time.Sleep(1500 * time.Millisecond) + + // Poll to verify process is done + pollResult := tool.Execute(ctx, map[string]any{ + "action": "poll", + "sessionId": sessionID, + }) + require.False(t, pollResult.IsError, "poll should succeed: %s", pollResult.ForLLM) + var pollResp ExecResponse + err = json.Unmarshal([]byte(pollResult.ForLLM), &pollResp) + require.NoError(t, err) + require.Equal(t, "done", pollResp.Status, "process should be done") + + // Try to read output AFTER process has exited + readResult := tool.Execute(ctx, map[string]any{ + "action": "read", + "sessionId": sessionID, + }) + require.False(t, readResult.IsError, "read should succeed after exit: %s", readResult.ForLLM) + + var readResp ExecResponse + err = json.Unmarshal([]byte(readResult.ForLLM), &readResp) + require.NoError(t, err) + + // Output should contain both "hello" and "world" + require.Contains(t, readResp.Output, "hello", "should contain hello") + require.Contains(t, readResp.Output, "world", "should contain world after sleep") +} + +func TestSendKeys_CtrlC(t *testing.T) { + // Note: Ctrl-C as a signal requires sending SIGINT to the process group, + // which requires elevated privileges. Writing "\x03" to PTY passes the byte + // to the process but doesn't generate SIGINT for processes that don't read stdin. + // For interrupting processes, use the kill action instead. + t.Skip("Ctrl-C as signal not supported - use kill action for interruption") +} + +func TestEncodeKeyToken(t *testing.T) { + tests := []struct { + token string + expected string + hasError bool + }{ + // Named keys + {"enter", "\r", false}, + {"return", "\r", false}, + {"tab", "\t", false}, + {"escape", "\x1b", false}, + {"esc", "\x1b", false}, + {"backspace", "\x7f", false}, + {"up", "\x1b[A", false}, + {"down", "\x1b[B", false}, + {"left", "\x1b[D", false}, + {"right", "\x1b[C", false}, + {"home", "\x1b[1~", false}, + {"end", "\x1b[4~", false}, + {"pageup", "\x1b[5~", false}, + {"pagedown", "\x1b[6~", false}, + {"delete", "\x1b[3~", false}, + {"f1", "\x1bOP", false}, + {"f12", "\x1b[24~", false}, + + // Ctrl keys + {"ctrl-c", "\x03", false}, + {"ctrl-d", "\x04", false}, + {"ctrl-a", "\x01", false}, + {"ctrl-z", "\x1a", false}, + {"c-c", "\x03", false}, + {"c-d", "\x04", false}, + + // Alt keys + {"alt-x", "\x1bx", false}, + {"m-x", "\x1bx", false}, + + // Case insensitive tests + {"ENTER", "\r", false}, + {"TAB", "\t", false}, + {"CTRL-C", "\x03", false}, + {"Ctrl-D", "\x04", false}, + {"ALT-X", "\x1bx", false}, + {"M-X", "\x1bx", false}, + {"UP", "\x1b[A", false}, + {"DOWN", "\x1b[B", false}, + + // Unknown keys should return error (use write action for text input) + {"unknown-key", "", true}, + } + + for _, tt := range tests { + t.Run(tt.token, func(t *testing.T) { + result, err := encodeKeyToken(tt.token, PtyKeyModeCSI) + if tt.hasError { + require.Error(t, err, "expected error for %s", tt.token) + } else { + require.NoError(t, err, "unexpected error for %s", tt.token) + require.Equal(t, tt.expected, result, "wrong encoding for %s", tt.token) + } + }) + } +} + +// TestDetectPtyKeyMode tests smkx/rmkx detection in PTY output +func TestDetectPtyKeyMode(t *testing.T) { + tests := []struct { + name string + raw string + expected PtyKeyMode + }{ + {"no toggle", "hello world", PtyKeyModeNotFound}, + {"smkx only", "\x1b[?1h\x1b=", PtyKeyModeSS3}, + {"rmkx only", "\x1b[?1l\x1b>", PtyKeyModeCSI}, + {"both smkx first", "\x1b[?1h\x1b=...\x1b[?1l\x1b>", PtyKeyModeCSI}, + {"both rmkx first", "\x1b[?1l\x1b>...\x1b[?1h\x1b=", PtyKeyModeSS3}, + {"multiple toggles smkx last", "\x1b[?1h\x1b=...\x1b[?1l\x1b>...\x1b[?1h\x1b=", PtyKeyModeSS3}, + {"multiple toggles rmkx last", "\x1b[?1l\x1b>...\x1b[?1h\x1b=...\x1b[?1l\x1b>", PtyKeyModeCSI}, + {"partial smkx", "\x1b[?1h", PtyKeyModeSS3}, + {"partial rmkx", "\x1b[?1l", PtyKeyModeCSI}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := detectPtyKeyMode(tt.raw) + require.Equal(t, tt.expected, result, "wrong mode for %s", tt.name) + }) + } +} + +func TestEncodeKeyTokenWithPtyKeyMode(t *testing.T) { + tests := []struct { + name string + token string + mode PtyKeyMode + expected string + hasError bool + }{ + // CSI mode + {"up csi", "up", PtyKeyModeCSI, "\x1b[A", false}, + {"down csi", "down", PtyKeyModeCSI, "\x1b[B", false}, + {"left csi", "left", PtyKeyModeCSI, "\x1b[D", false}, + {"right csi", "right", PtyKeyModeCSI, "\x1b[C", false}, + + // SS3 mode + {"up ss3", "up", PtyKeyModeSS3, "\x1bOA", false}, + {"down ss3", "down", PtyKeyModeSS3, "\x1bOB", false}, + {"left ss3", "left", PtyKeyModeSS3, "\x1bOD", false}, + {"right ss3", "right", PtyKeyModeSS3, "\x1bOC", false}, + {"home ss3", "home", PtyKeyModeSS3, "\x1bOH", false}, + {"end ss3", "end", PtyKeyModeSS3, "\x1bOF", false}, + + // Other keys unaffected by mode + {"enter ss3", "enter", PtyKeyModeSS3, "\r", false}, + {"tab ss3", "tab", PtyKeyModeSS3, "\t", false}, + {"ctrl-c ss3", "ctrl-c", PtyKeyModeSS3, "\x03", false}, + + // NotFound behaves like CSI + {"up notfound", "up", PtyKeyModeNotFound, "\x1b[A", false}, + {"down notfound", "down", PtyKeyModeNotFound, "\x1b[B", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := encodeKeyToken(tt.token, tt.mode) + if tt.hasError { + require.Error(t, err, "expected error for %s", tt.name) + } else { + require.NoError(t, err, "unexpected error for %s", tt.name) + require.Equal(t, tt.expected, result, "wrong encoding for %s", tt.name) + } + }) + } +} diff --git a/pkg/tools/shell_timeout_unix_test.go b/pkg/tools/shell_timeout_unix_test.go index 357e1276e..dfd28454c 100644 --- a/pkg/tools/shell_timeout_unix_test.go +++ b/pkg/tools/shell_timeout_unix_test.go @@ -30,6 +30,7 @@ func TestShellTool_TimeoutKillsChildProcess(t *testing.T) { tool.SetTimeout(500 * time.Millisecond) args := map[string]any{ + "action": "run", // Spawn a child process that would outlive the shell unless process-group kill is used. "command": "sleep 60 & echo $! > child.pid; wait", } diff --git a/pkg/tools/sysproc_unix.go b/pkg/tools/sysproc_unix.go new file mode 100644 index 000000000..0fb03d43a --- /dev/null +++ b/pkg/tools/sysproc_unix.go @@ -0,0 +1,12 @@ +//go:build !windows + +package tools + +import ( + "os/exec" + "syscall" +) + +func setSysProcAttrForPty(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} +} diff --git a/pkg/tools/sysproc_windows.go b/pkg/tools/sysproc_windows.go new file mode 100644 index 000000000..150f166fb --- /dev/null +++ b/pkg/tools/sysproc_windows.go @@ -0,0 +1,10 @@ +//go:build windows + +package tools + +import "os/exec" + +func setSysProcAttrForPty(cmd *exec.Cmd) { + // Windows doesn't support Setsid, and PTY is not available on Windows anyway. + // This function is a no-op for Windows builds. +} diff --git a/pkg/tools/types.go b/pkg/tools/types.go index a6015cde3..4d1a18d5a 100644 --- a/pkg/tools/types.go +++ b/pkg/tools/types.go @@ -56,3 +56,24 @@ type ToolFunctionDefinition struct { Description string `json:"description"` Parameters map[string]any `json:"parameters"` } + +type ExecRequest struct { + Action string `json:"action"` + Command string `json:"command,omitempty"` + PTY bool `json:"pty,omitempty"` + Background bool `json:"background,omitempty"` + Timeout int `json:"timeout,omitempty"` + Env map[string]string `json:"env,omitempty"` + Cwd string `json:"cwd,omitempty"` + SessionID string `json:"sessionId,omitempty"` + Data string `json:"data,omitempty"` +} + +type ExecResponse struct { + SessionID string `json:"sessionId,omitempty"` + Status string `json:"status,omitempty"` + ExitCode int `json:"exitCode,omitempty"` + Output string `json:"output,omitempty"` + Error string `json:"error,omitempty"` + Sessions []SessionInfo `json:"sessions,omitempty"` +} From a97d43390281f93d1a495eab9c9fdc1de910b0ee Mon Sep 17 00:00:00 2001 From: BeaconCat <111232138+BeaconCat@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:27:54 +0800 Subject: [PATCH 14/23] docs: update WeChat community QR code (#2003) Co-authored-by: BeaconCat Co-authored-by: Claude Opus 4.6 --- assets/wechat.png | Bin 62722 -> 365540 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/wechat.png b/assets/wechat.png index effb4dab959a68bde6aa6c24d509cac80a1a1ae1..ecce856af070a8e8d4343ad4dd04ab127fa17298 100644 GIT binary patch literal 365540 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 RXsdw z*%do}RX=1vRKeObC~FmrV=6n)l4EA@=g%L@AP_CZzFJ0o*}*9vp`z7Ml^3D$(Ey;C zv$K3>V{9|R3Z4~s46@l? zg}Xg)cqG#y$HihD4G(xI$7v2;nvZ z7_?C<5-Q=XVUxT4>Ti>_1MO5w*3`#e6ecR}Uw+^kQR+GEZ9u`I?~dzPV|GrQmPN(6 zPM}YG_LxSYW$N(6;x})FVg;{?hoYz3Y%|M;{3Gqdfg`k9f5H8mn?NonE~JHE8}b&4 zU^KGGF9W*1A4nSqW#RS(7p==E*Rre%TP8~~aDm=SRR&+q?rH(jV?n78q=(`$E^KC- zs0Ic=D*f^p7;gXi`5O<5<+CXR;py zr=n2UdgtqjuL<2Twhtjxsus4i{i38*RmM#=T7i=$8_=Oh(q1CH^m}E+-wGbB*ZqVz z;Zvj)R5Ut`K~VRS7)bc3ydvrW1CUyv>kRDZXYXijzfgXjv^CRev)0W%4Zglv;b$u^ z9fZ5ItTuPr^Cfdk;*-3tj(`TxyxbV&5hoYVS;n_G+TkOQfI$uCL;#tqW4%^8g4Qyj zbxUP9M-9H7diD6}izbu;l;Ny?otNYpIeWjv0_%SH*QlbDq*Dj`_3`qC5_bIqm}~EL zdO=6n`oTY_`1<_mQzeH{ymD3@#tDqIO_=(eVx6J_e(mi+aax8rHRu|sw?%uZ*mwD` zNjt&8rD}!qPC;}x?Q&}AL|atTmg*!wreS*i&4GnJeub8fC+HUMq!R~cYIG;0{l*9G zICeSpwELHO^KmQ^o;b;gAZo%OizmF8#`EI43jAtcSSGCa$-XXrGCEoJYef;j;k{`u zbR^G(w(Li@O0@j2!L<&R4A-08@@c-{~z(%=#CM;) zW)T{$|AKIT)%q!&_*9F6$EJ{NB<`To{fG#yr(bxNu7-UW{@K5;4}=`)7F zlJ*lW-C!_>u*QI`j!dEu)ImV9?J-0;p_vgJE=AgG6}&KA)moCFqf;J!9t=SbnV)@? zs`DA{qR4f%PG64BRbcUjTUWeq0617-1i*$4mJuMYA|LR@KYE#Q`xEm6W})flKaRkG zo?M4#d;zNbyT@;ji+Nrs`9R8X3(?r>36zRIIAx5g3%@mjE@!*Cx-vaOJnlmACVILy zA;Z5#2wXs}dsK3kG(8)Txu#(3(|UAQ-bhvC7)sb7DhdOHgapkxVX+{+1! z3$GF8N^nmz5=FvzO_5RNSt2SRlo0e*+sW*Vu^qsOd4~G(oP`aG^YeSa1Ag}Vcl|>! z5h^kgMGx9d=)cqNK2EK1la$9=K^f0B?PRfYakf$GOQ~@)UTgZFdTbRh`=s=|u6`}y zjk4u2&+zHl8DMNPzY#Y10f!UZMx|sF!#&$ss78gi%7yrM59~e>RvIPfJE`$wn7GJV z7*$fX#<;dJoa4)C$I_&JuO4wWd$g!u8i3L?n5lIBkZK7#U0anYJx^D)%E2aB73M$? zpvgATz~giRcH;ARwR;*0EEydme`S}{sNAr9eu<}kaVzAKf5zmhV~QMlMptD-NASP! z0dUzMp3nwLLF=rW=qgMqVUF&_|yMCcRA0j zjS6KYcT!Kzc>B*^v3O1oQ&Ur0H3=>6MzU#7It7NZJl5<+@-zEW z{leHnUrC=48M?fqA4Ax^2IKh1{B5k7Z&kHc?S?fZsaIl(0#vQ+J0tZv(fZctxgJd} zwdVhZ>eopTkUy`gYbUiO_=KH}b8PhzGAxV9?--V@7*ciaD2VORv|SMC31y zlHPBl%TJDu(~4+co%aK+88~Jvf5i#WGtE*8EE{?8GLqJBF0nM;iQ3n5l7={XJ!7rr z{D9}@LaDi&%mtHgLCB934RetIo!L=dRNrduzr^xH~NTOfS!R_lp!u(iz9m65+Un)eB$z8(r5xV)Y$i zVSme$WzROC4vTah#TvV`%7>pH#CZ1Zp5ROgmsmhiLO)C}e{f;%<&hkcNyy%p5esp6 zn~Ptfqjm2a8L?rPQbLw4afUI5e$CD;60B2W&0o`fD&{@p!@FsgIT=CopQL~b`o-cE zMkCL+hoDagDCO(2lE|iIW}%2Mwb6I4$H(>2_G6O2s|Vt+Cx6j6`7bgpY=M$I)<{9F zX}-+PsZRB-*uc1<%CDs9^o#=TR#M;GhlHH!295r6F<~3u`Ukc>X~1FaB`|sC!AmVe zS8F%T&?siE-YkOdM0bLLkJ>7v_q5Cs_rSfDMn+g!ahC#4BUz zJ$%0DBCa{h6VI>uF2D(-CFWvwH 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 Pz^{8sT8i)F%|rhmTKk2_ literal 62722 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 Js$|SQ{x4a%qip~H From 155af28841d2ca66da9db37ca926071a7fab153e Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Wed, 25 Mar 2026 21:31:07 +0800 Subject: [PATCH 15/23] feat(logger): add PICOCLAW_LOG_FILE env var for file-only logging --- cmd/picoclaw/internal/agent/helpers.go | 2 ++ pkg/logger/logger.go | 23 +++++++++++++++ pkg/logger/logger_test.go | 41 ++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/cmd/picoclaw/internal/agent/helpers.go b/cmd/picoclaw/internal/agent/helpers.go index 0af743bb5..23227d56a 100644 --- a/cmd/picoclaw/internal/agent/helpers.go +++ b/cmd/picoclaw/internal/agent/helpers.go @@ -28,6 +28,8 @@ func agentCmd(message, sessionKey, model string, debug bool) error { return fmt.Errorf("error loading config: %w", err) } + logger.ConfigureFromEnv() + if debug { logger.SetLevel(logger.DEBUG) fmt.Println("🔍 Debug mode enabled") diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index eeb1436de..1bcc1cec9 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -2,6 +2,7 @@ package logger import ( "fmt" + "io" "os" "path/filepath" "runtime" @@ -100,6 +101,12 @@ func SetConsoleLevel(level LogLevel) { logger = logger.Level(level) } +func DisableConsole() { + mu.Lock() + defer mu.Unlock() + logger = zerolog.New(io.Discard).With().Timestamp().Caller().Logger() +} + func GetLevel() LogLevel { mu.RLock() defer mu.RUnlock() @@ -170,6 +177,22 @@ func DisableFileLogging() { fileLogger = zerolog.Logger{} } +func ConfigureFromEnv() { + if logFile := os.Getenv("PICOCLAW_LOG_FILE"); logFile != "" { + if strings.HasPrefix(logFile, "~/") { + if home := os.Getenv("HOME"); home != "" { + logFile = filepath.Join(home, logFile[2:]) + } + } + + if err := EnableFileLogging(logFile); err != nil { + fmt.Fprintf(os.Stderr, "failed to enable file logging: %v\n", err) + } else { + DisableConsole() + } + } +} + func getCallerSkip() int { for i := 2; i < 15; i++ { pc, file, _, ok := runtime.Caller(i) diff --git a/pkg/logger/logger_test.go b/pkg/logger/logger_test.go index 6ad3a8dd6..1eca72607 100644 --- a/pkg/logger/logger_test.go +++ b/pkg/logger/logger_test.go @@ -4,7 +4,11 @@ import ( "bytes" "encoding/json" "errors" + "fmt" + "os" + "path/filepath" "testing" + "time" "github.com/rs/zerolog" ) @@ -365,3 +369,40 @@ func TestAppendFields_ErrorUsesErrorString(t *testing.T) { t.Fatalf("error field = %#v, want %q", got["error"], "transcription request failed") } } + +func TestDisableConsole(t *testing.T) { + DisableConsole() + Info("this should go to nowhere") +} + +func TestConfigureFromEnv(t *testing.T) { + home := os.Getenv("HOME") + if home == "" { + t.Skip("HOME not set") + } + + tmpFile := "/tmp/picoclaw_test_log_" + fmt.Sprintf("%d", time.Now().UnixNano()) + defer os.Remove(tmpFile) + + os.Setenv("PICOCLAW_LOG_FILE", tmpFile) + defer os.Unsetenv("PICOCLAW_LOG_FILE") + + ConfigureFromEnv() + + if logFile == nil { + t.Error("expected log file to be set") + } + + Info("test message") + + os.Setenv("PICOCLAW_LOG_FILE", "~/test_log") + ConfigureFromEnv() + + expanded := filepath.Join(home, "test_log") + defer os.Remove(expanded) +} + +func TestConfigureFromEnvNoEnv(t *testing.T) { + os.Unsetenv("PICOCLAW_LOG_FILE") + ConfigureFromEnv() +} From bb2eddc79dfc92e41a3687abe4a3d78374e4ca22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=82=86=E6=9C=88?= <2835601846@qq.com> Date: Wed, 25 Mar 2026 23:29:44 +0800 Subject: [PATCH 16/23] Feature/add mimo provider (#1987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add Xiaomi MiMo provider support - Add 'mimo' protocol prefix support in factory_provider.go - Add default API base URL for MiMo: https://api.xiaomimimo.com/v1 - Update provider-label.ts to include Xiaomi MiMo label - Add MiMo to provider tables in both English and Chinese documentation - Add comprehensive unit tests for MiMo provider MiMo API is compatible with OpenAI API format, making it easy to integrate with the existing HTTPProvider infrastructure. Users can now use MiMo by configuring: { "model_name": "mimo", "model": "mimo/mimo-v2-pro", "api_key": "your-mimo-api-key" } * hassas dosyaları kaldırma * Add .security.yml and onboard to .gitignore --- .gitignore | 3 ++ docs/providers.md | 2 ++ docs/zh/providers.md | 2 ++ pkg/providers/factory_provider.go | 4 ++- pkg/providers/factory_provider_test.go | 30 +++++++++++++++++++ .../src/components/models/models-page.tsx | 1 + .../src/components/models/provider-icon.tsx | 1 + .../src/components/models/provider-label.ts | 1 + 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 72f3b1761..b869ecc33 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,9 @@ build/ # Secrets & Config (keep templates, ignore actual secrets) .env config/config.json +.security.yml +onboard + # Test coverage.txt diff --git a/docs/providers.md b/docs/providers.md index 3a740d3b8..42d46189a 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -27,6 +27,7 @@ | `mistral` | LLM (Mistral direct) | [console.mistral.ai](https://console.mistral.ai) | | `longcat` | LLM (Longcat direct) | [longcat.ai](https://longcat.ai) | | `modelscope` | LLM (ModelScope direct) | [modelscope.cn](https://modelscope.cn) | +| `mimo` | LLM (Xiaomi MiMo direct) | [platform.xiaomimimo.com](https://platform.xiaomimimo.com) | ### Model Configuration (model_list) @@ -63,6 +64,7 @@ This design also enables **multi-agent support** with flexible provider selectio | **Vivgrid** | `vivgrid/` | `https://api.vivgrid.com/v1` | OpenAI | [Get Key](https://vivgrid.com) | | **LongCat** | `longcat/` | `https://api.longcat.chat/openai` | OpenAI | [Get Key](https://longcat.chat/platform) | | **ModelScope (魔搭)**| `modelscope/` | `https://api-inference.modelscope.cn/v1` | OpenAI | [Get Token](https://modelscope.cn/my/tokens) | +| **Xiaomi MiMo** | `mimo/` | `https://api.xiaomimimo.com/v1` | OpenAI | [Get Key](https://platform.xiaomimimo.com) | | **Azure OpenAI** | `azure/` | `https://{resource}.openai.azure.com` | Azure | [Get Key](https://portal.azure.com) | | **Antigravity** | `antigravity/` | Google Cloud | Custom | OAuth only | | **GitHub Copilot** | `github-copilot/` | `localhost:4321` | gRPC | - | diff --git a/docs/zh/providers.md b/docs/zh/providers.md index e7b323ebf..057e7d3d5 100644 --- a/docs/zh/providers.md +++ b/docs/zh/providers.md @@ -26,6 +26,7 @@ | `mistral` | LLM (Mistral 直连) | [console.mistral.ai](https://console.mistral.ai) | | `longcat` | LLM (Longcat 直连) | [longcat.ai](https://longcat.ai) | | `modelscope` | LLM (ModelScope 直连) | [modelscope.cn](https://modelscope.cn) | +| `mimo` | LLM (小米 MiMo 直连) | [platform.xiaomimimo.com](https://platform.xiaomimimo.com) | ### 模型配置 (model_list) @@ -62,6 +63,7 @@ | **Vivgrid** | `vivgrid/` | `https://api.vivgrid.com/v1` | OpenAI | [获取密钥](https://vivgrid.com) | | **LongCat** | `longcat/` | `https://api.longcat.chat/openai` | OpenAI | [获取密钥](https://longcat.chat/platform) | | **ModelScope (魔搭)**| `modelscope/` | `https://api-inference.modelscope.cn/v1` | OpenAI | [获取 Token](https://modelscope.cn/my/tokens) | +| **小米 MiMo** | `mimo/` | `https://api.xiaomimimo.com/v1` | OpenAI | [获取密钥](https://platform.xiaomimimo.com) | | **Antigravity** | `antigravity/` | Google Cloud | 自定义 | 仅 OAuth | | **GitHub Copilot** | `github-copilot/` | `localhost:4321` | gRPC | - | diff --git a/pkg/providers/factory_provider.go b/pkg/providers/factory_provider.go index 1128fc042..962e6ae19 100644 --- a/pkg/providers/factory_provider.go +++ b/pkg/providers/factory_provider.go @@ -158,7 +158,7 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err "ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras", "vivgrid", "volcengine", "vllm", "qwen", "qwen-intl", "qwen-international", "dashscope-intl", "qwen-us", "dashscope-us", "mistral", "avian", "longcat", "modelscope", "novita", - "coding-plan", "alibaba-coding", "qwen-coding": + "coding-plan", "alibaba-coding", "qwen-coding", "mimo": // All other OpenAI-compatible HTTP providers if cfg.APIKey() == "" && cfg.APIBase == "" { return nil, "", fmt.Errorf("api_key or api_base is required for HTTP-based protocol %q", protocol) @@ -349,6 +349,8 @@ func getDefaultAPIBase(protocol string) string { return "https://api.longcat.chat/openai" case "modelscope": return "https://api-inference.modelscope.cn/v1" + case "mimo": + return "https://api.xiaomimimo.com/v1" default: return "" } diff --git a/pkg/providers/factory_provider_test.go b/pkg/providers/factory_provider_test.go index 2fed18c35..f1fe02cc2 100644 --- a/pkg/providers/factory_provider_test.go +++ b/pkg/providers/factory_provider_test.go @@ -123,6 +123,7 @@ func TestCreateProviderFromConfig_DefaultAPIBase(t *testing.T) { {"ollama", "ollama"}, {"longcat", "longcat"}, {"modelscope", "modelscope"}, + {"mimo", "mimo"}, } for _, tt := range tests { @@ -252,6 +253,35 @@ func TestGetDefaultAPIBase_Novita(t *testing.T) { } } +func TestCreateProviderFromConfig_Mimo(t *testing.T) { + cfg := &config.ModelConfig{ + ModelName: "test-mimo", + Model: "mimo/mimo-v2-pro", + APIBase: "https://api.xiaomimimo.com/v1", + } + cfg.SetAPIKey("test-key") + + provider, modelID, err := CreateProviderFromConfig(cfg) + if err != nil { + t.Fatalf("CreateProviderFromConfig() error = %v", err) + } + if provider == nil { + t.Fatal("CreateProviderFromConfig() returned nil provider") + } + if modelID != "mimo-v2-pro" { + t.Errorf("modelID = %q, want %q", modelID, "mimo-v2-pro") + } + if _, ok := provider.(*HTTPProvider); !ok { + t.Fatalf("expected *HTTPProvider, got %T", provider) + } +} + +func TestGetDefaultAPIBase_Mimo(t *testing.T) { + if got := getDefaultAPIBase("mimo"); got != "https://api.xiaomimimo.com/v1" { + t.Fatalf("getDefaultAPIBase(%q) = %q, want %q", "mimo", got, "https://api.xiaomimimo.com/v1") + } +} + func TestCreateProviderFromConfig_Anthropic(t *testing.T) { cfg := &config.ModelConfig{ ModelName: "test-anthropic", diff --git a/web/frontend/src/components/models/models-page.tsx b/web/frontend/src/components/models/models-page.tsx index 6776e5ca8..a6747c5e0 100644 --- a/web/frontend/src/components/models/models-page.tsx +++ b/web/frontend/src/components/models/models-page.tsx @@ -32,6 +32,7 @@ const PROVIDER_PRIORITY: Record = { vllm: 16, mistral: 17, avian: 18, + mimo: 19, } interface ProviderGroup { diff --git a/web/frontend/src/components/models/provider-icon.tsx b/web/frontend/src/components/models/provider-icon.tsx index 5e2151e2d..814a59834 100644 --- a/web/frontend/src/components/models/provider-icon.tsx +++ b/web/frontend/src/components/models/provider-icon.tsx @@ -37,6 +37,7 @@ const PROVIDER_DOMAINS: Record = { avian: "avian.io", vllm: "vllm.ai", zhipu: "zhipuai.cn", + mimo: "xiaomi.com", } interface ProviderIconProps { diff --git a/web/frontend/src/components/models/provider-label.ts b/web/frontend/src/components/models/provider-label.ts index 923cd9506..82600a96f 100644 --- a/web/frontend/src/components/models/provider-label.ts +++ b/web/frontend/src/components/models/provider-label.ts @@ -18,6 +18,7 @@ const PROVIDER_LABELS: Record = { avian: "Avian", vllm: "VLLM (local)", zhipu: "Zhipu AI (智谱)", + mimo: "Xiaomi MiMo", } export function getProviderKey(model: string): string { From 82c78e853b0d0ac106ead11bf4ae8205740c805b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?daming=E5=A4=A7=E9=93=AD?= Date: Thu, 26 Mar 2026 00:35:56 +0800 Subject: [PATCH 17/23] build(deps): upgrade pty and reorganize sqlite dependencies (#2012) - Upgrade github.com/creack/pty from v1.1.9 to v1.1.24 - Move github.com/mattn/go-sqlite3 to indirect dependency - Move rsc.io/qr from indirect to direct dependency --- go.mod | 6 +++--- go.sum | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index e8f00d7a5..54c275102 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/bedrockruntime v1.50.2 github.com/bwmarrin/discordgo v0.29.0 github.com/caarlos0/env/v11 v11.4.0 - github.com/creack/pty v1.1.9 + github.com/creack/pty v1.1.24 github.com/ergochat/irc-go v0.6.0 github.com/ergochat/readline v0.1.3 github.com/gdamore/tcell/v2 v2.13.8 @@ -21,7 +21,6 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/h2non/filetype v1.1.3 github.com/larksuite/oapi-sdk-go/v3 v3.5.3 - github.com/mattn/go-sqlite3 v1.14.34 github.com/mdp/qrterminal/v3 v3.2.1 github.com/modelcontextprotocol/go-sdk v1.4.1 github.com/mymmrac/telego v1.7.0 @@ -42,6 +41,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 maunium.net/go/mautrix v0.26.4 modernc.org/sqlite v1.46.1 + rsc.io/qr v0.2.0 ) require ( @@ -70,6 +70,7 @@ require ( github.com/lucasb-eyer/go-colorful v1.3.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.34 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -85,7 +86,6 @@ require ( modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - rsc.io/qr v0.2.0 // indirect ) require ( diff --git a/go.sum b/go.sum index 7cebd1744..ae12473f3 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,9 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9 github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From ed618e14aa50d2a045381406460b284ab92b051f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=9A=E5=AD=90?= <40852301+uiYzzi@users.noreply.github.com> Date: Thu, 26 Mar 2026 01:33:49 +0800 Subject: [PATCH 18/23] feat(channels): support multi-message sending via split marker (#2008) * Add multi-message sending via split marker * Add marker and length split integration tests Tests that SplitByMarker and SplitMessage work together correctly, and that code block boundaries are preserved during marker splitting. * Simplify message chunking logic in channel worker Extract splitByLength helper function and remove goto-based control flow. The logic now flows more naturally - try marker splitting first, then fall back to length-based splitting. * Update multi-message output instructions in agent context * Add split_on_marker to config defaults * Add split_on_marker config option * Rename 'Multi-Message Sending' setting to 'Chatty Mode' * Add SplitOnMarker config option --- config/config.example.json | 39 ++--- pkg/agent/context.go | 14 ++ pkg/agent/instance.go | 10 +- pkg/channels/manager.go | 44 ++++-- pkg/channels/marker.go | 37 +++++ pkg/channels/marker_test.go | 141 ++++++++++++++++++ pkg/config/config.go | 1 + pkg/config/defaults.go | 1 + .../src/components/config/config-page.tsx | 1 + .../src/components/config/config-sections.tsx | 10 ++ .../src/components/config/form-model.ts | 6 + web/frontend/src/i18n/locales/en.json | 2 + web/frontend/src/i18n/locales/zh.json | 2 + 13 files changed, 264 insertions(+), 44 deletions(-) create mode 100644 pkg/channels/marker.go create mode 100644 pkg/channels/marker_test.go diff --git a/config/config.example.json b/config/config.example.json index 5826ea25a..a8400ad5f 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -10,6 +10,7 @@ "max_tool_iterations": 20, "summarize_message_threshold": 20, "summarize_token_percent": 75, + "split_on_marker": false, "tool_feedback": { "enabled": false, "max_args_length": 300 @@ -223,13 +224,8 @@ "nickserv_password": "", "sasl_user": "", "sasl_password": "", - "channels": [ - "#mychannel" - ], - "request_caps": [ - "server-time", - "message-tags" - ], + "channels": ["#mychannel"], + "request_caps": ["server-time", "message-tags"], "allow_from": [], "group_trigger": { "mention_only": true @@ -251,9 +247,7 @@ "brave": { "enabled": false, "api_key": "YOUR_BRAVE_API_KEY", - "api_keys": [ - "YOUR_BRAVE_API_KEY" - ], + "api_keys": ["YOUR_BRAVE_API_KEY"], "max_results": 5 }, "tavily": { @@ -269,9 +263,7 @@ "perplexity": { "enabled": false, "api_key": "pplx-xxx", - "api_keys": [ - "pplx-xxx" - ], + "api_keys": ["pplx-xxx"], "max_results": 5 }, "searxng": { @@ -320,19 +312,12 @@ "filesystem": { "enabled": false, "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-filesystem", - "/tmp" - ] + "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] }, "github": { "enabled": false, "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-github" - ], + "args": ["-y", "@modelcontextprotocol/server-github"], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN" } @@ -340,10 +325,7 @@ "brave-search": { "enabled": false, "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-brave-search" - ], + "args": ["-y", "@modelcontextprotocol/server-brave-search"], "env": { "BRAVE_API_KEY": "YOUR_BRAVE_API_KEY" } @@ -360,10 +342,7 @@ "slack": { "enabled": false, "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-slack" - ], + "args": ["-y", "@modelcontextprotocol/server-slack"], "env": { "SLACK_BOT_TOKEN": "YOUR_SLACK_BOT_TOKEN", "SLACK_TEAM_ID": "YOUR_SLACK_TEAM_ID" diff --git a/pkg/agent/context.go b/pkg/agent/context.go index 12e3cdd4d..c3fcc9fff 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -26,6 +26,7 @@ type ContextBuilder struct { memory *MemoryStore toolDiscoveryBM25 bool toolDiscoveryRegex bool + splitOnMarker bool // Cache for system prompt to avoid rebuilding on every call. // This fixes issue #607: repeated reprocessing of the entire context. @@ -52,6 +53,11 @@ func (cb *ContextBuilder) WithToolDiscovery(useBM25, useRegex bool) *ContextBuil return cb } +func (cb *ContextBuilder) WithSplitOnMarker(enabled bool) *ContextBuilder { + cb.splitOnMarker = enabled + return cb +} + func getGlobalConfigDir() string { if home := os.Getenv(config.EnvHome); home != "" { return home @@ -157,6 +163,14 @@ The following skills extend your capabilities. To use a skill, read its SKILL.md parts = append(parts, "# Memory\n\n"+memoryContext) } + // Multi-Message Sending (if enabled) + if cb.splitOnMarker { + parts = append(parts, `# MULTI-MESSAGE OUTPUT +You MUST frequently use <|[SPLIT]|> to break your responses into multiple short messages. NEVER output a single long wall of text. Actively split distinct concepts or parts. Example: Message part 1<|[SPLIT]|>Message part 2<|[SPLIT]|>Message part 3 + +Each part separated by the marker will be sent as an independent message.`) + } + // Join with "---" separator return strings.Join(parts, "\n\n---\n\n") } diff --git a/pkg/agent/instance.go b/pkg/agent/instance.go index 34d401186..cef736981 100644 --- a/pkg/agent/instance.go +++ b/pkg/agent/instance.go @@ -103,10 +103,12 @@ func NewAgentInstance( sessions := initSessionStore(sessionsDir) mcpDiscoveryActive := cfg.Tools.MCP.Enabled && cfg.Tools.MCP.Discovery.Enabled - contextBuilder := NewContextBuilder(workspace).WithToolDiscovery( - mcpDiscoveryActive && cfg.Tools.MCP.Discovery.UseBM25, - mcpDiscoveryActive && cfg.Tools.MCP.Discovery.UseRegex, - ) + contextBuilder := NewContextBuilder(workspace). + WithToolDiscovery( + mcpDiscoveryActive && cfg.Tools.MCP.Discovery.UseBM25, + mcpDiscoveryActive && cfg.Tools.MCP.Discovery.UseRegex, + ). + WithSplitOnMarker(cfg.Agents.Defaults.SplitOnMarker) agentID := routing.DefaultAgentID agentName := "" diff --git a/pkg/channels/manager.go b/pkg/channels/manager.go index c8269dc77..7bcb933ce 100644 --- a/pkg/channels/manager.go +++ b/pkg/channels/manager.go @@ -608,8 +608,10 @@ func newChannelWorker(name string, ch Channel) *channelWorker { } } -// runWorker processes outbound messages for a single channel, splitting -// messages that exceed the channel's maximum message length. +// runWorker processes outbound messages for a single channel. +// Message processing follows this order: +// 1. SplitByMarker (if enabled in config) - LLM semantic marker-based splitting +// 2. SplitMessage - channel-specific length-based splitting (MaxMessageLength) func (m *Manager) runWorker(ctx context.Context, name string, w *channelWorker) { defer close(w.done) for { @@ -622,15 +624,29 @@ func (m *Manager) runWorker(ctx context.Context, name string, w *channelWorker) if mlp, ok := w.ch.(MessageLengthProvider); ok { maxLen = mlp.MaxMessageLength() } - if maxLen > 0 && len([]rune(msg.Content)) > maxLen { - chunks := SplitMessage(msg.Content, maxLen) - for _, chunk := range chunks { - chunkMsg := msg - chunkMsg.Content = chunk - m.sendWithRetry(ctx, name, w, chunkMsg) + + // Collect all message chunks to send + var chunks []string + + // Step 1: Try marker-based splitting if enabled + if m.config != nil && m.config.Agents.Defaults.SplitOnMarker { + if markerChunks := SplitByMarker(msg.Content); len(markerChunks) > 1 { + for _, chunk := range markerChunks { + chunks = append(chunks, splitByLength(chunk, maxLen)...) + } } - } else { - m.sendWithRetry(ctx, name, w, msg) + } + + // Step 2: Fallback to length-based splitting if no chunks from marker + if len(chunks) == 0 { + chunks = splitByLength(msg.Content, maxLen) + } + + // Step 3: Send all chunks + for _, chunk := range chunks { + chunkMsg := msg + chunkMsg.Content = chunk + m.sendWithRetry(ctx, name, w, chunkMsg) } case <-ctx.Done(): return @@ -638,6 +654,14 @@ func (m *Manager) runWorker(ctx context.Context, name string, w *channelWorker) } } +// splitByLength splits content by maxLen if needed, otherwise returns single chunk. +func splitByLength(content string, maxLen int) []string { + if maxLen > 0 && len([]rune(content)) > maxLen { + return SplitMessage(content, maxLen) + } + return []string{content} +} + // sendWithRetry sends a message through the channel with rate limiting and // retry logic. It classifies errors to determine the retry strategy: // - ErrNotRunning / ErrSendFailed: permanent, no retry diff --git a/pkg/channels/marker.go b/pkg/channels/marker.go new file mode 100644 index 000000000..4801e3d27 --- /dev/null +++ b/pkg/channels/marker.go @@ -0,0 +1,37 @@ +// PicoClaw - Ultra-lightweight personal AI agent +// Inspired by and based on nanobot: https://github.com/HKUDS/nanobot +// License: MIT +// +// Copyright (c) 2026 PicoClaw contributors + +package channels + +import ( + "strings" +) + +// MessageSplitMarker is the delimiter used to split a message into multiple outbound messages. +// When SplitOnMarker is enabled in config, the Manager will split messages on this marker +// and send each part as a separate message. +const MessageSplitMarker = "<|[SPLIT]|>" + +// SplitByMarker splits a message by the MessageSplitMarker and returns the parts. +// Empty parts (including from consecutive markers) are filtered out. +// If no marker is found, returns a single-element slice containing the original content. +func SplitByMarker(content string) []string { + if content == "" { + return nil + } + parts := strings.Split(content, MessageSplitMarker) + result := make([]string, 0, len(parts)) + for _, part := range parts { + trimmed := strings.TrimSpace(part) + if trimmed != "" { + result = append(result, trimmed) + } + } + if len(result) == 0 { + return []string{content} + } + return result +} diff --git a/pkg/channels/marker_test.go b/pkg/channels/marker_test.go new file mode 100644 index 000000000..b7b4ca99e --- /dev/null +++ b/pkg/channels/marker_test.go @@ -0,0 +1,141 @@ +// PicoClaw - Ultra-lightweight personal AI agent +// License: MIT +// +// Copyright (c) 2026 PicoClaw contributors + +package channels + +import ( + "testing" +) + +func TestSplitByMarker_Basic(t *testing.T) { + content := "Hello <|[SPLIT]|>World" + chunks := SplitByMarker(content) + + if len(chunks) != 2 { + t.Fatalf("Expected 2 chunks, got %d: %q", len(chunks), chunks) + } + if chunks[0] != "Hello" { + t.Errorf("Expected first chunk 'Hello', got %q", chunks[0]) + } + if chunks[1] != "World" { + t.Errorf("Expected second chunk 'World', got %q", chunks[1]) + } +} + +func TestSplitByMarker_NoMarker(t *testing.T) { + content := "Hello World" + chunks := SplitByMarker(content) + + if len(chunks) != 1 { + t.Fatalf("Expected 1 chunk, got %d: %q", len(chunks), chunks) + } + if chunks[0] != "Hello World" { + t.Errorf("Expected chunk 'Hello World', got %q", chunks[0]) + } +} + +func TestSplitByMarker_MultipleMarkers(t *testing.T) { + content := "Part1 <|[SPLIT]|> Part2 <|[SPLIT]|> Part3" + chunks := SplitByMarker(content) + + if len(chunks) != 3 { + t.Fatalf("Expected 3 chunks, got %d: %q", len(chunks), chunks) + } + if chunks[0] != "Part1" || chunks[1] != "Part2" || chunks[2] != "Part3" { + t.Errorf("Unexpected chunks: %q", chunks) + } +} + +func TestSplitByMarker_EmptyParts(t *testing.T) { + // Test consecutive markers and leading/trailing markers + content := "<|[SPLIT]|>Hello <|[SPLIT]|><|[SPLIT]|>World<|[SPLIT]|>" + chunks := SplitByMarker(content) + + if len(chunks) != 2 { + t.Fatalf("Expected 2 chunks, got %d: %q", len(chunks), chunks) + } + if chunks[0] != "Hello" || chunks[1] != "World" { + t.Errorf("Unexpected chunks: %q", chunks) + } +} + +func TestSplitByMarker_WhitespaceTrimmed(t *testing.T) { + content := " Hello <|[SPLIT]|> World " + chunks := SplitByMarker(content) + + if len(chunks) != 2 { + t.Fatalf("Expected 2 chunks, got %d: %q", len(chunks), chunks) + } + if chunks[0] != "Hello" || chunks[1] != "World" { + t.Errorf("Whitespace should be trimmed: %q", chunks) + } +} + +func TestSplitByMarker_EmptyInput(t *testing.T) { + chunks := SplitByMarker("") + if len(chunks) != 0 { + t.Errorf("Expected empty slice for empty input, got %d chunks", len(chunks)) + } +} + +// TestMarkerAndLengthSplitIntegration tests that SplitByMarker and SplitMessage work together correctly. +// Marker splitting happens first (per-agent config), then length splitting happens (per-channel config). +func TestMarkerAndLengthSplitIntegration(t *testing.T) { + maxLen := 10 + + // Original content: "Short <|[SPLIT]|> ThisIsAVeryLongString" + content := "Short <|[SPLIT]|> ThisIsAVeryLongString" + markerChunks := SplitByMarker(content) + + // Step 1: Marker split should give us 2 chunks + if len(markerChunks) != 2 { + t.Fatalf("Expected 2 marker chunks, got %d: %q", len(markerChunks), markerChunks) + } + + // Step 2: Length split should be applied to each marker chunk + var finalChunks []string + for _, chunk := range markerChunks { + if len([]rune(chunk)) > maxLen { + lengthChunks := SplitMessage(chunk, maxLen) + finalChunks = append(finalChunks, lengthChunks...) + } else { + finalChunks = append(finalChunks, chunk) + } + } + + // "Short" is 6 chars, within limit + // "ThisIsAVeryLongString" is 22 chars, should be split into multiple chunks + // SplitMessage with maxLen=10 splits: "ThisIsAVeryLongString" -> ["ThisI", "sAVer", "yLong", "String"] (5 chunks) + if len(finalChunks) != 5 { + t.Errorf("Expected 5 final chunks, got %d: %q", len(finalChunks), finalChunks) + } + + // Verify first chunk is unchanged + if finalChunks[0] != "Short" { + t.Errorf("First chunk should be 'Short', got %q", finalChunks[0]) + } + + // Verify all length-split chunks are within limit + for i, chunk := range finalChunks[1:] { + if len([]rune(chunk)) > maxLen { + t.Errorf("Chunk %d exceeds maxLen: %q (%d chars)", i+1, chunk, len([]rune(chunk))) + } + } +} + +// TestMarkerSplitPreservesCodeBlockIntegrity tests that marker split preserves code block boundaries +func TestMarkerSplitPreservesCodeBlockIntegrity(t *testing.T) { + content := "Hello <|[SPLIT]|>```go\npackage main\n```<|[SPLIT]|>World" + chunks := SplitByMarker(content) + + if len(chunks) != 3 { + t.Fatalf("Expected 3 chunks, got %d: %q", len(chunks), chunks) + } + + // Verify code block is intact in middle chunk + if chunks[1] != "```go\npackage main\n```" { + t.Errorf("Code block not preserved correctly: %q", chunks[1]) + } +} diff --git a/pkg/config/config.go b/pkg/config/config.go index c61219d9b..fd7c48964 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -319,6 +319,7 @@ type AgentDefaults struct { SteeringMode string `json:"steering_mode,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_STEERING_MODE"` // "one-at-a-time" (default) or "all" SubTurn SubTurnConfig `json:"subturn" envPrefix:"PICOCLAW_AGENTS_DEFAULTS_SUBTURN_"` ToolFeedback ToolFeedbackConfig `json:"tool_feedback,omitempty"` + SplitOnMarker bool `json:"split_on_marker" env:"PICOCLAW_AGENTS_DEFAULTS_SPLIT_ON_MARKER"` // split messages on <|[SPLIT]|> marker } const DefaultMaxMediaSize = 20 * 1024 * 1024 // 20 MB diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index ba1a5a0cf..c56cd8596 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -42,6 +42,7 @@ func DefaultConfig() *Config { Enabled: true, MaxArgsLength: 300, }, + SplitOnMarker: false, }, }, Bindings: []AgentBinding{}, diff --git a/web/frontend/src/components/config/config-page.tsx b/web/frontend/src/components/config/config-page.tsx index 24a719d86..46f62f426 100644 --- a/web/frontend/src/components/config/config-page.tsx +++ b/web/frontend/src/components/config/config-page.tsx @@ -208,6 +208,7 @@ export function ConfigPage() { defaults: { workspace, restrict_to_workspace: form.restrictToWorkspace, + split_on_marker: form.splitOnMarker, tool_feedback: { enabled: form.toolFeedbackEnabled, max_args_length: toolFeedbackMaxArgsLength, diff --git a/web/frontend/src/components/config/config-sections.tsx b/web/frontend/src/components/config/config-sections.tsx index 1f7426d22..b5bec8acd 100644 --- a/web/frontend/src/components/config/config-sections.tsx +++ b/web/frontend/src/components/config/config-sections.tsx @@ -95,6 +95,16 @@ export function AgentDefaultsSection({ } /> + + onFieldChange("splitOnMarker", checked) + } + /> + export interface CoreConfigForm { workspace: string restrictToWorkspace: boolean + splitOnMarker: boolean toolFeedbackEnabled: boolean toolFeedbackMaxArgsLength: string execEnabled: boolean @@ -65,6 +66,7 @@ export const DM_SCOPE_OPTIONS = [ export const EMPTY_FORM: CoreConfigForm = { workspace: "", restrictToWorkspace: true, + splitOnMarker: false, toolFeedbackEnabled: true, toolFeedbackMaxArgsLength: "300", execEnabled: true, @@ -136,6 +138,10 @@ export function buildFormFromConfig(config: unknown): CoreConfigForm { defaults.restrict_to_workspace === undefined ? EMPTY_FORM.restrictToWorkspace : asBool(defaults.restrict_to_workspace), + splitOnMarker: + defaults.split_on_marker === undefined + ? EMPTY_FORM.splitOnMarker + : asBool(defaults.split_on_marker), toolFeedbackEnabled: toolFeedback.enabled === undefined ? EMPTY_FORM.toolFeedbackEnabled diff --git a/web/frontend/src/i18n/locales/en.json b/web/frontend/src/i18n/locales/en.json index 8e051f42e..a7c60f893 100644 --- a/web/frontend/src/i18n/locales/en.json +++ b/web/frontend/src/i18n/locales/en.json @@ -434,6 +434,8 @@ "workspace_hint": "Base directory for agent file operations.", "restrict_workspace": "Restrict to Workspace", "restrict_workspace_hint": "Only allow file operations inside workspace.", + "split_on_marker": "Chatty Mode", + "split_on_marker_hint": "Split long messages into short ones like real human chatting.", "tool_feedback_enabled": "Tool Feedback", "tool_feedback_enabled_hint": "Send a short tool-call preview into the current chat before each tool execution.", "tool_feedback_max_args_length": "Tool Feedback Args Preview Length", diff --git a/web/frontend/src/i18n/locales/zh.json b/web/frontend/src/i18n/locales/zh.json index a6c588807..9dde090f8 100644 --- a/web/frontend/src/i18n/locales/zh.json +++ b/web/frontend/src/i18n/locales/zh.json @@ -434,6 +434,8 @@ "workspace_hint": "智能体执行文件读写操作时使用的基础目录。", "restrict_workspace": "限制工作目录访问", "restrict_workspace_hint": "仅允许在工作目录内执行文件操作。", + "split_on_marker": "连续短消息", + "split_on_marker_hint": "像真人聊天一样,把长难句拆成多条短消息快速发出", "tool_feedback_enabled": "工具反馈", "tool_feedback_enabled_hint": "在每次执行工具前,先向当前会话发送一条简短的工具调用预览。", "tool_feedback_max_args_length": "工具反馈参数预览长度", From 97dec16769b72df590c7533533f78d0f6a2d0e3d Mon Sep 17 00:00:00 2001 From: Badgerbees Date: Thu, 26 Mar 2026 00:55:48 +0700 Subject: [PATCH 19/23] fix(providers): improve context overflow detection and classification --- pkg/agent/loop.go | 1 + pkg/providers/error_classifier.go | 12 ++++++++++++ pkg/providers/types.go | 17 +++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index c9efb318b..81b979490 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1949,6 +1949,7 @@ turnLoop: isContextError := !isTimeoutError && (strings.Contains(errMsg, "context_length_exceeded") || strings.Contains(errMsg, "context window") || + strings.Contains(errMsg, "context_window") || strings.Contains(errMsg, "maximum context length") || strings.Contains(errMsg, "token limit") || strings.Contains(errMsg, "too many tokens") || diff --git a/pkg/providers/error_classifier.go b/pkg/providers/error_classifier.go index fd9bf1e81..e7691aa93 100644 --- a/pkg/providers/error_classifier.go +++ b/pkg/providers/error_classifier.go @@ -84,6 +84,15 @@ var ( substr("messages.1.content.1.tool_use.id"), substr("invalid request format"), } + contextOverflowPatterns = []errorPattern{ + rxp(`context[_ ]?length[_ ]?exceeded`), + rxp(`context[_ ]?window[_ ]?exceeded`), + substr("maximum context length"), + substr("token limit"), + substr("too many tokens"), + substr("prompt is too long"), + substr("request too large"), + } imageDimensionPatterns = []errorPattern{ rxp(`image dimensions exceed max`), @@ -201,6 +210,9 @@ func classifyByMessage(msg string) FailoverReason { if matchesAny(msg, formatPatterns) { return FailoverFormat } + if matchesAny(msg, contextOverflowPatterns) { + return FailoverContextOverflow + } return "" } diff --git a/pkg/providers/types.go b/pkg/providers/types.go index 9a4d126a7..f98ae9243 100644 --- a/pkg/providers/types.go +++ b/pkg/providers/types.go @@ -71,13 +71,14 @@ type NativeSearchCapable interface { type FailoverReason string const ( - FailoverAuth FailoverReason = "auth" - FailoverRateLimit FailoverReason = "rate_limit" - FailoverBilling FailoverReason = "billing" - FailoverTimeout FailoverReason = "timeout" - FailoverFormat FailoverReason = "format" - FailoverOverloaded FailoverReason = "overloaded" - FailoverUnknown FailoverReason = "unknown" + FailoverAuth FailoverReason = "auth" + FailoverRateLimit FailoverReason = "rate_limit" + FailoverBilling FailoverReason = "billing" + FailoverTimeout FailoverReason = "timeout" + FailoverFormat FailoverReason = "format" + FailoverContextOverflow FailoverReason = "context_overflow" + FailoverOverloaded FailoverReason = "overloaded" + FailoverUnknown FailoverReason = "unknown" ) // FailoverError wraps an LLM provider error with classification metadata. @@ -101,7 +102,7 @@ func (e *FailoverError) Unwrap() error { // IsRetriable returns true if this error should trigger fallback to next candidate. // Non-retriable: Format errors (bad request structure, image dimension/size). func (e *FailoverError) IsRetriable() bool { - return e.Reason != FailoverFormat + return e.Reason != FailoverFormat && e.Reason != FailoverContextOverflow } // ModelConfig holds primary model and fallback list. From ae9489360578810711171809592f731bc4087f2e Mon Sep 17 00:00:00 2001 From: Badgerbees Date: Thu, 26 Mar 2026 03:03:19 +0700 Subject: [PATCH 20/23] adding test units --- pkg/agent/loop_test.go | 109 +++++++++++++++++++++++++ pkg/providers/error_classifier_test.go | 25 ++++++ 2 files changed, 134 insertions(+) diff --git a/pkg/agent/loop_test.go b/pkg/agent/loop_test.go index 341d15a2f..2366b1277 100644 --- a/pkg/agent/loop_test.go +++ b/pkg/agent/loop_test.go @@ -3,6 +3,7 @@ package agent import ( "context" "encoding/json" + "errors" "fmt" "net/http" "net/http/httptest" @@ -2817,3 +2818,111 @@ func TestFilterClientWebSearch_EmptyInput(t *testing.T) { t.Fatalf("len(result) = %d, want 0", len(result)) } } + +type overflowProvider struct { + calls int + lastMessages []providers.Message + chatFunc func(ctx context.Context, messages []providers.Message, tools []providers.ToolDefinition, model string, opts map[string]any) (*providers.LLMResponse, error) +} + +func (p *overflowProvider) Chat( + ctx context.Context, + messages []providers.Message, + tools []providers.ToolDefinition, + model string, + opts map[string]any, +) (*providers.LLMResponse, error) { + p.calls++ + p.lastMessages = append([]providers.Message(nil), messages...) + + if p.chatFunc != nil { + return p.chatFunc(ctx, messages, tools, model, opts) + } + + if p.calls == 1 { + return nil, errors.New("context_window_exceeded") + } + + return &providers.LLMResponse{ + Content: "Recovered from overflow", + }, nil +} + +func (p *overflowProvider) GetDefaultModel() string { + return "test-model" +} + +func TestProcessMessage_ContextOverflowRecovery(t *testing.T) { + al, cfg, _, _, cleanup := newTestAgentLoop(t) + defer cleanup() + _ = cfg + + provider := &overflowProvider{} + al.registry = NewAgentRegistry(al.cfg, provider) + + sessionKey := "agent:main:test-session" + agent := al.GetRegistry().GetDefaultAgent() + + for i := 0; i < 5; i++ { + agent.Sessions.AddFullMessage(sessionKey, providers.Message{Role: "user", Content: "heavy message"}) + agent.Sessions.AddFullMessage(sessionKey, providers.Message{Role: "assistant", Content: "response"}) + } + + response, err := al.processMessage(context.Background(), bus.InboundMessage{ + Channel: "test", + ChatID: "chat1", + SenderID: "user1", + SessionKey: "test-session", + Content: "trigger recovery", + }) + if err != nil { + t.Fatalf("processMessage() error = %v", err) + } + if response != "Recovered from overflow" { + t.Fatalf("response = %q, want %q", response, "Recovered from overflow") + } + + if provider.calls != 2 { + t.Fatalf("expected 2 calls, got %d", provider.calls) + } +} + +func TestProcessMessage_ContextOverflow_AnthropicStyle(t *testing.T) { + al, cfg, _, _, cleanup := newTestAgentLoop(t) + defer cleanup() + _ = cfg + + provider := &overflowProvider{} + al.registry = NewAgentRegistry(al.cfg, provider) + + recoveryMsg := "error: status 400: context_window_exceeded" + + provider.chatFunc = func( + ctx context.Context, + messages []providers.Message, + tools []providers.ToolDefinition, + model string, + opts map[string]any, + ) (*providers.LLMResponse, error) { + if provider.calls == 1 { + return nil, errors.New(recoveryMsg) + } + return &providers.LLMResponse{Content: "Anthropic recovery success"}, nil + } + + response, err := al.processMessage(context.Background(), bus.InboundMessage{ + Channel: "test", + ChatID: "chat1", + SenderID: "user1", + Content: "hello", + }) + if err != nil { + t.Fatalf("processMessage() error = %v", err) + } + if !strings.Contains(response, "Anthropic recovery success") { + t.Fatalf("response = %q, want success message", response) + } + if provider.calls != 2 { + t.Fatalf("expected 2 calls for retry, got %d", provider.calls) + } +} diff --git a/pkg/providers/error_classifier_test.go b/pkg/providers/error_classifier_test.go index 67d9af62b..46b180835 100644 --- a/pkg/providers/error_classifier_test.go +++ b/pkg/providers/error_classifier_test.go @@ -221,6 +221,30 @@ func TestClassifyError_ImageDimensionError(t *testing.T) { } } +func TestClassifyError_ContextOverflowPatterns(t *testing.T) { + patterns := []string{ + "context_length_exceeded", + "context_window_exceeded", + "maximum context length", + "token limit", + "too many tokens", + "prompt is too long", + "request too large", + } + + for _, msg := range patterns { + err := errors.New(msg) + result := ClassifyError(err, "openai", "gpt-4") + if result == nil { + t.Errorf("pattern %q: expected non-nil", msg) + continue + } + if result.Reason != FailoverContextOverflow { + t.Errorf("pattern %q: reason = %q, want context_overflow", msg, result.Reason) + } + } +} + func TestClassifyError_ImageSizeError(t *testing.T) { err := errors.New("image exceeds 20 mb limit") result := ClassifyError(err, "openai", "gpt-4o") @@ -265,6 +289,7 @@ func TestFailoverError_IsRetriable(t *testing.T) { {FailoverTimeout, true}, {FailoverOverloaded, true}, {FailoverFormat, false}, + {FailoverContextOverflow, false}, {FailoverUnknown, true}, } From 9503f38ace5c73521536d1c5ec182ffd00e967a5 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Thu, 26 Mar 2026 09:27:34 +0800 Subject: [PATCH 21/23] docs: clarify gateway vs launcher chat endpoints (#2025) Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com> --- docs/docker.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/docker.md b/docs/docker.md index f868d4a42..a00dfbe9f 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -26,6 +26,9 @@ docker compose -f docker/docker-compose.yml --profile gateway up -d > [!TIP] > **Docker Users**: By default, the Gateway listens on `127.0.0.1` which is not accessible from the host. If you need to access the health endpoints or expose ports, set `PICOCLAW_GATEWAY_HOST=0.0.0.0` in your environment or update `config.json`. +> [!NOTE] +> The `gateway` profile only serves the webhook handlers (including Pico when enabled) and health endpoints on the gateway port, so it does not expose generic REST chat endpoints such as `/chat` or `/a2a`. Launcher mode adds the browser UI plus `/api/pico/token` and a `/pico/ws` proxy on the launcher port, but `/pico/ws` is also available directly on the gateway whenever the Pico channel is enabled. + ```bash # 5. Check logs docker compose -f docker/docker-compose.yml logs -f picoclaw-gateway From 5c210e6f15d61351f503ce496c4f8a84b5542014 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Thu, 26 Mar 2026 09:31:42 +0800 Subject: [PATCH 22/23] fix(config): disable tool feedback by default (#2026) Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com> --- pkg/config/config_test.go | 27 +++++++++++++++++++ pkg/config/defaults.go | 2 +- .../src/components/config/form-model.ts | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index bedd46f6e..6718de91e 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -487,6 +487,33 @@ func TestDefaultConfig_WebPreferNativeEnabled(t *testing.T) { } } +func TestDefaultConfig_ToolFeedbackDisabled(t *testing.T) { + cfg := DefaultConfig() + if cfg.Agents.Defaults.ToolFeedback.Enabled { + t.Fatal("DefaultConfig().Agents.Defaults.ToolFeedback.Enabled should be false") + } +} + +func TestLoadConfig_ToolFeedbackDefaultsFalseWhenUnset(t *testing.T) { + dir := t.TempDir() + configPath := filepath.Join(dir, "config.json") + if err := os.WriteFile( + configPath, + []byte(`{"version":1,"agents":{"defaults":{"workspace":"./workspace"}}}`), + 0o600, + ); err != nil { + t.Fatalf("WriteFile() error: %v", err) + } + + cfg, err := LoadConfig(configPath) + if err != nil { + t.Fatalf("LoadConfig() error: %v", err) + } + if cfg.Agents.Defaults.ToolFeedback.Enabled { + t.Fatal("agents.defaults.tool_feedback.enabled should remain false when unset in config file") + } +} + func TestLoadConfig_WebPreferNativeDefaultsTrueWhenUnset(t *testing.T) { dir := t.TempDir() configPath := filepath.Join(dir, "config.json") diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 44fc1f049..b2148bbde 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -39,7 +39,7 @@ func DefaultConfig() *Config { SummarizeTokenPercent: 75, SteeringMode: "one-at-a-time", ToolFeedback: ToolFeedbackConfig{ - Enabled: true, + Enabled: false, MaxArgsLength: 300, }, SplitOnMarker: false, diff --git a/web/frontend/src/components/config/form-model.ts b/web/frontend/src/components/config/form-model.ts index 3437195c3..c5542a3b2 100644 --- a/web/frontend/src/components/config/form-model.ts +++ b/web/frontend/src/components/config/form-model.ts @@ -67,7 +67,7 @@ export const EMPTY_FORM: CoreConfigForm = { workspace: "", restrictToWorkspace: true, splitOnMarker: false, - toolFeedbackEnabled: true, + toolFeedbackEnabled: false, toolFeedbackMaxArgsLength: "300", execEnabled: true, allowRemote: true, From 9d6a445bb175bb3881265c2d68e0685f72ba2786 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Thu, 26 Mar 2026 09:32:56 +0800 Subject: [PATCH 23/23] docs: clarify gateway.log_level default and options (#2013) (#2015) Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com> --- docs/configuration.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index d39806887..9360d3897 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -31,6 +31,22 @@ PICOCLAW_HOME=/opt/picoclaw picoclaw agent PICOCLAW_HOME=/srv/picoclaw PICOCLAW_CONFIG=/srv/picoclaw/main.json picoclaw gateway ``` +### Gateway Log Level + +`gateway.log_level` controls Gateway log verbosity and is configurable in `config.json`. + +```json +{ + "gateway": { + "log_level": "fatal" + } +} +``` + +When omitted, the default is `fatal`. Supported values: `debug`, `info`, `warn`, `error`, `fatal`. + +You can also override this with the environment variable `PICOCLAW_LOG_LEVEL`. + ### Workspace Layout PicoClaw stores data in your configured workspace (default: `~/.picoclaw/workspace`):