picoclaw/pkg/config/defaults.go
Hoshina f2e3945b46 feat(channels): enhance QQ channel with group support, typing, media, and URL sanitization
Add group message routing alongside existing C2C (direct) support using
chatType sync.Map to track whether a chatID is group or direct. Implement
passive reply with msg_id/msg_seq tracking for multi-part responses.

Add StartTyping (InputNotify msg_type=6 with periodic resend), SendMedia
(RichMediaMessage for HTTP/HTTPS URLs), and configurable Markdown message
support. Replace unbounded dedup map with TTL-based expiry and janitor
goroutine.

Sanitize URLs in group messages by replacing dots in domains with fullwidth
period to avoid QQ's URL blacklist rejection (error 40054010). Add rate
limit config (5 msg/s) and MaxMessageLength/SendMarkdown config fields.
2026-03-07 17:47:46 +08:00

466 lines
11 KiB
Go

// PicoClaw - Ultra-lightweight personal AI agent
// License: MIT
//
// Copyright (c) 2026 PicoClaw contributors
package config
import (
"os"
"path/filepath"
)
// DefaultConfig returns the default configuration for PicoClaw.
func DefaultConfig() *Config {
// Determine the base path for the workspace.
// Priority: $PICOCLAW_HOME > ~/.picoclaw
var homePath string
if picoclawHome := os.Getenv("PICOCLAW_HOME"); picoclawHome != "" {
homePath = picoclawHome
} else {
userHome, _ := os.UserHomeDir()
homePath = filepath.Join(userHome, ".picoclaw")
}
workspacePath := filepath.Join(homePath, "workspace")
return &Config{
Agents: AgentsConfig{
Defaults: AgentDefaults{
Workspace: workspacePath,
RestrictToWorkspace: true,
Provider: "",
Model: "",
MaxTokens: 32768,
Temperature: nil, // nil means use provider default
MaxToolIterations: 50,
SummarizeMessageThreshold: 20,
SummarizeTokenPercent: 75,
},
},
Bindings: []AgentBinding{},
Session: SessionConfig{
DMScope: "per-channel-peer",
},
Channels: ChannelsConfig{
WhatsApp: WhatsAppConfig{
Enabled: false,
BridgeURL: "ws://localhost:3001",
UseNative: false,
SessionStorePath: "",
AllowFrom: FlexibleStringSlice{},
},
Telegram: TelegramConfig{
Enabled: false,
Token: "",
AllowFrom: FlexibleStringSlice{},
Typing: TypingConfig{Enabled: true},
Placeholder: PlaceholderConfig{
Enabled: true,
Text: "Thinking... 💭",
},
},
Feishu: FeishuConfig{
Enabled: false,
AppID: "",
AppSecret: "",
EncryptKey: "",
VerificationToken: "",
AllowFrom: FlexibleStringSlice{},
},
Discord: DiscordConfig{
Enabled: false,
Token: "",
AllowFrom: FlexibleStringSlice{},
MentionOnly: false,
},
MaixCam: MaixCamConfig{
Enabled: false,
Host: "0.0.0.0",
Port: 18790,
AllowFrom: FlexibleStringSlice{},
},
QQ: QQConfig{
Enabled: false,
AppID: "",
AppSecret: "",
AllowFrom: FlexibleStringSlice{},
MaxMessageLength: 2000,
},
DingTalk: DingTalkConfig{
Enabled: false,
ClientID: "",
ClientSecret: "",
AllowFrom: FlexibleStringSlice{},
},
Slack: SlackConfig{
Enabled: false,
BotToken: "",
AppToken: "",
AllowFrom: FlexibleStringSlice{},
},
LINE: LINEConfig{
Enabled: false,
ChannelSecret: "",
ChannelAccessToken: "",
WebhookHost: "0.0.0.0",
WebhookPort: 18791,
WebhookPath: "/webhook/line",
AllowFrom: FlexibleStringSlice{},
GroupTrigger: GroupTriggerConfig{MentionOnly: true},
},
OneBot: OneBotConfig{
Enabled: false,
WSUrl: "ws://127.0.0.1:3001",
AccessToken: "",
ReconnectInterval: 5,
GroupTriggerPrefix: []string{},
AllowFrom: FlexibleStringSlice{},
},
WeCom: WeComConfig{
Enabled: false,
Token: "",
EncodingAESKey: "",
WebhookURL: "",
WebhookHost: "0.0.0.0",
WebhookPort: 18793,
WebhookPath: "/webhook/wecom",
AllowFrom: FlexibleStringSlice{},
ReplyTimeout: 5,
},
WeComApp: WeComAppConfig{
Enabled: false,
CorpID: "",
CorpSecret: "",
AgentID: 0,
Token: "",
EncodingAESKey: "",
WebhookHost: "0.0.0.0",
WebhookPort: 18792,
WebhookPath: "/webhook/wecom-app",
AllowFrom: FlexibleStringSlice{},
ReplyTimeout: 5,
},
WeComAIBot: WeComAIBotConfig{
Enabled: false,
Token: "",
EncodingAESKey: "",
WebhookPath: "/webhook/wecom-aibot",
AllowFrom: FlexibleStringSlice{},
ReplyTimeout: 5,
MaxSteps: 10,
WelcomeMessage: "Hello! I'm your AI assistant. How can I help you today?",
},
Pico: PicoConfig{
Enabled: false,
Token: "",
PingInterval: 30,
ReadTimeout: 60,
WriteTimeout: 10,
MaxConnections: 100,
AllowFrom: FlexibleStringSlice{},
},
},
Providers: ProvidersConfig{
OpenAI: OpenAIProviderConfig{WebSearch: true},
},
ModelList: []ModelConfig{
// ============================================
// Add your API key to the model you want to use
// ============================================
// Zhipu AI (智谱) - https://open.bigmodel.cn/usercenter/apikeys
{
ModelName: "glm-4.7",
Model: "zhipu/glm-4.7",
APIBase: "https://open.bigmodel.cn/api/paas/v4",
APIKey: "",
},
// OpenAI - https://platform.openai.com/api-keys
{
ModelName: "gpt-5.2",
Model: "openai/gpt-5.2",
APIBase: "https://api.openai.com/v1",
APIKey: "",
},
// Anthropic Claude - https://console.anthropic.com/settings/keys
{
ModelName: "claude-sonnet-4.6",
Model: "anthropic/claude-sonnet-4.6",
APIBase: "https://api.anthropic.com/v1",
APIKey: "",
},
// DeepSeek - https://platform.deepseek.com/
{
ModelName: "deepseek-chat",
Model: "deepseek/deepseek-chat",
APIBase: "https://api.deepseek.com/v1",
APIKey: "",
},
// Google Gemini - https://ai.google.dev/
{
ModelName: "gemini-2.0-flash",
Model: "gemini/gemini-2.0-flash-exp",
APIBase: "https://generativelanguage.googleapis.com/v1beta",
APIKey: "",
},
// Qwen (通义千问) - https://dashscope.console.aliyun.com/apiKey
{
ModelName: "qwen-plus",
Model: "qwen/qwen-plus",
APIBase: "https://dashscope.aliyuncs.com/compatible-mode/v1",
APIKey: "",
},
// Moonshot (月之暗面) - https://platform.moonshot.cn/console/api-keys
{
ModelName: "moonshot-v1-8k",
Model: "moonshot/moonshot-v1-8k",
APIBase: "https://api.moonshot.cn/v1",
APIKey: "",
},
// Groq - https://console.groq.com/keys
{
ModelName: "llama-3.3-70b",
Model: "groq/llama-3.3-70b-versatile",
APIBase: "https://api.groq.com/openai/v1",
APIKey: "",
},
// OpenRouter (100+ models) - https://openrouter.ai/keys
{
ModelName: "openrouter-auto",
Model: "openrouter/auto",
APIBase: "https://openrouter.ai/api/v1",
APIKey: "",
},
{
ModelName: "openrouter-gpt-5.2",
Model: "openrouter/openai/gpt-5.2",
APIBase: "https://openrouter.ai/api/v1",
APIKey: "",
},
// NVIDIA - https://build.nvidia.com/
{
ModelName: "nemotron-4-340b",
Model: "nvidia/nemotron-4-340b-instruct",
APIBase: "https://integrate.api.nvidia.com/v1",
APIKey: "",
},
// Cerebras - https://inference.cerebras.ai/
{
ModelName: "cerebras-llama-3.3-70b",
Model: "cerebras/llama-3.3-70b",
APIBase: "https://api.cerebras.ai/v1",
APIKey: "",
},
// Volcengine (火山引擎) - https://console.volcengine.com/ark
{
ModelName: "doubao-pro",
Model: "volcengine/doubao-pro-32k",
APIBase: "https://ark.cn-beijing.volces.com/api/v3",
APIKey: "",
},
// ShengsuanYun (神算云)
{
ModelName: "deepseek-v3",
Model: "shengsuanyun/deepseek-v3",
APIBase: "https://api.shengsuanyun.com/v1",
APIKey: "",
},
// Antigravity (Google Cloud Code Assist) - OAuth only
{
ModelName: "gemini-flash",
Model: "antigravity/gemini-3-flash",
AuthMethod: "oauth",
},
// GitHub Copilot - https://github.com/settings/tokens
{
ModelName: "copilot-gpt-5.2",
Model: "github-copilot/gpt-5.2",
APIBase: "http://localhost:4321",
AuthMethod: "oauth",
},
// Ollama (local) - https://ollama.com
{
ModelName: "llama3",
Model: "ollama/llama3",
APIBase: "http://localhost:11434/v1",
APIKey: "ollama",
},
// Mistral AI - https://console.mistral.ai/api-keys
{
ModelName: "mistral-small",
Model: "mistral/mistral-small-latest",
APIBase: "https://api.mistral.ai/v1",
APIKey: "",
},
// Avian - https://avian.io
{
ModelName: "deepseek-v3.2",
Model: "avian/deepseek/deepseek-v3.2",
APIBase: "https://api.avian.io/v1",
APIKey: "",
},
{
ModelName: "kimi-k2.5",
Model: "avian/moonshotai/kimi-k2.5",
APIBase: "https://api.avian.io/v1",
APIKey: "",
},
// VLLM (local) - http://localhost:8000
{
ModelName: "local-model",
Model: "vllm/custom-model",
APIBase: "http://localhost:8000/v1",
APIKey: "",
},
},
Gateway: GatewayConfig{
Host: "127.0.0.1",
Port: 18790,
},
Tools: ToolsConfig{
MediaCleanup: MediaCleanupConfig{
ToolConfig: ToolConfig{
Enabled: true,
},
MaxAge: 30,
Interval: 5,
},
Web: WebToolsConfig{
ToolConfig: ToolConfig{
Enabled: true,
},
Proxy: "",
FetchLimitBytes: 10 * 1024 * 1024, // 10MB by default
Brave: BraveConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
DuckDuckGo: DuckDuckGoConfig{
Enabled: true,
MaxResults: 5,
},
Perplexity: PerplexityConfig{
Enabled: false,
APIKey: "",
MaxResults: 5,
},
SearXNG: SearXNGConfig{
Enabled: false,
BaseURL: "",
MaxResults: 5,
},
GLMSearch: GLMSearchConfig{
Enabled: false,
APIKey: "",
BaseURL: "https://open.bigmodel.cn/api/paas/v4/web_search",
SearchEngine: "search_std",
MaxResults: 5,
},
},
Cron: CronToolsConfig{
ToolConfig: ToolConfig{
Enabled: true,
},
ExecTimeoutMinutes: 5,
},
Exec: ExecConfig{
ToolConfig: ToolConfig{
Enabled: true,
},
EnableDenyPatterns: true,
TimeoutSeconds: 60,
},
Skills: SkillsToolsConfig{
ToolConfig: ToolConfig{
Enabled: true,
},
Registries: SkillsRegistriesConfig{
ClawHub: ClawHubRegistryConfig{
Enabled: true,
BaseURL: "https://clawhub.ai",
},
},
MaxConcurrentSearches: 2,
SearchCache: SearchCacheConfig{
MaxSize: 50,
TTLSeconds: 300,
},
},
SendFile: ToolConfig{
Enabled: true,
},
MCP: MCPConfig{
ToolConfig: ToolConfig{
Enabled: false,
},
Servers: map[string]MCPServerConfig{},
},
AppendFile: ToolConfig{
Enabled: true,
},
EditFile: ToolConfig{
Enabled: true,
},
FindSkills: ToolConfig{
Enabled: true,
},
I2C: ToolConfig{
Enabled: false, // Hardware tool - Linux only
},
InstallSkill: ToolConfig{
Enabled: true,
},
ListDir: ToolConfig{
Enabled: true,
},
Message: ToolConfig{
Enabled: true,
},
ReadFile: ToolConfig{
Enabled: true,
},
Spawn: ToolConfig{
Enabled: true,
},
SPI: ToolConfig{
Enabled: false, // Hardware tool - Linux only
},
Subagent: ToolConfig{
Enabled: true,
},
WebFetch: ToolConfig{
Enabled: true,
},
WriteFile: ToolConfig{
Enabled: true,
},
},
Heartbeat: HeartbeatConfig{
Enabled: true,
Interval: 30,
},
Devices: DevicesConfig{
Enabled: false,
MonitorUSB: true,
},
}
}