- Deny regex: expand left boundary to match shell separators (;, &&, ||)
to prevent bypass via chained commands like ";format c:"
- Path regex: add "." to initial char class to catch hidden dirs (/.ssh),
add "=" to left boundary to catch flag-attached paths (--file=/etc/passwd)
- Add test: ModelName must match user model for GetModelConfig lookup
- Add test: stripSystemParts preserves reasoning_content in wire format
- Add test: forceCompression avoids orphaning tool result messages
- Add test: deny pattern blocks disk-wiping commands with shell separators
while allowing legitimate --format flags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. migration.go: Set ModelName to userModel when provider matches so
GetModelConfig(userModel) can find the entry. Previously the migration
created entries with the provider name as ModelName (e.g. "moonshot")
but lookup used the model name (e.g. "k2p5"), causing "model not found".
2. openai_compat/provider.go: Preserve reasoning_content in conversation
history. Thinking models (e.g. Kimi K2, DeepSeek-R1) return
reasoning_content which must be echoed back. Without it, APIs return
400: "thinking is enabled but reasoning_content is missing".
3. shell.go: Fix deny pattern regex for format/mkfs/diskpart to use
(?:^|\s) instead of \b to avoid matching --format flags.
Fix path extraction regex to use submatch to avoid matching flags
like -rf as paths.
4. loop.go: Adjust forceCompression mid-point to avoid splitting
tool-call/result message pairs, which causes API errors.
Replace unconditional WithTimeout usage with conditional context creation
based on timeout configuration. Zero values now bypass timeout enforcement,
using WithCancel for graceful cancellation while preserving existing timeout
behavior for positive values. Simplifies CronTool initialization by removing
unnecessary conditional timeout assignment.
Resolved conflicts:
- pkg/heartbeat/service.go: merged both 'started' field and 'onHeartbeatWithTools'
- pkg/tools/edit.go: use validatePath() with ToolResult return
- pkg/tools/filesystem.go: fixed return values to use ToolResult
- cmd/picoclaw/main.go: kept active setupCronTool, fixed toolsPkg import
- pkg/tools/cron.go: fixed Execute return value handling
Fixed tests for new function signatures (NewEditFileTool, NewAppendFileTool, NewExecTool)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update all Tool implementations to return *ToolResult instead of (string, error)
- ShellTool: returns UserResult for command output, ErrorResult for failures
- SpawnTool: returns NewToolResult on success, ErrorResult on failure
- WebTool: returns ToolResult with ForUser=content, ForLLM=summary
- EditTool: returns SilentResult for silent edits, ErrorResult on failure
- FilesystemTool: returns SilentResult/NewToolResult for operations, ErrorResult on failure
- Temporarily disable cronTool in main.go (will be re-enabled in US-016)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implemented a unified path validation helper to ensure filesystem operations stay within the designated workspace. This now supports a 'restrict_to_workspace' option in config.json (enabled by default) to allow flexibility for specific environments while maintaining a secure default posture. I've updated read_file, write_file, list_dir, append_file, edit_file, and exec tools to respect this setting and included tests for both restricted and unrestricted modes.
- Add MemoryStore for persistent long-term and daily notes
- Add dynamic tool summary generation in system prompt
- Fix YAML frontmatter parsing for nanobot skill format
- Add GetSummaries() method to ToolRegistry
- Fix DebugCF logging to use structured metadata
- Improve web_search and shell tool descriptions