xiaoxixi acf74981b2 feat(memory): relevance-gated auto recall with hard timeout
Replace the unconditional top-5 keyword recall with a deterministic,
layered gate so only relevant Knowledge entries reach the prompt.

- New src/memory/recall.rs: tokenization with stopword filtering and a
  bounded term list; ranking combines lexical relevance, importance and
  recency; double gate (min_relevance + min_score) drops weak or stale
  matches; hard tokio::time::timeout wraps the SQL search so a slow FTS5
  query never delays a turn.
- MemoryConfig gains recall_min_relevance, recall_min_score,
  recall_recency_half_life_days, recall_timeout_ms (default 1000ms);
  recall_limit is now actually wired instead of being a dead field.
- MemoryManager::recall_for_context exposes the gated path; the
  memory_recall tool keeps the raw search.
- Storage::search_memories / search_memories_by_time share a single
  jieba-based tokenizer via the new module; search_memories_by_terms
  accepts pre-tokenized input for the gated path.
- Docs and example configs (README, about-picobot references, both
  config.example.json templates) updated to reflect the new behavior.
2026-08-21 17:29:48 +08:00

121 lines
3.4 KiB
JSON

{
"providers": {
"aliyun": {
"type": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": "<DASHSCOPE_API_KEY>",
"extra_headers": {}
},
"openai": {
"type": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": "<OPENAI_API_KEY>",
"extra_headers": {}
},
"anthropic": {
"type": "anthropic",
"base_url": "https://api.anthropic.com/v1",
"api_key": "<ANTHROPIC_API_KEY>",
"extra_headers": {}
}
},
"models": {
"qwen-plus": {
"model_id": "qwen-plus",
"temperature": 0.0,
"max_tokens": 8192,
"token_limit": 128000
},
"gpt-4o": {
"model_id": "gpt-4o",
"temperature": 0.7,
"max_tokens": 4096,
"input_type": ["text", "image"]
},
"claude-sonnet-4-20250514": {
"model_id": "claude-sonnet-4-20250514",
"temperature": 0.7,
"max_tokens": 8192,
"input_type": ["text", "image"]
}
},
"agents": {
"default": {
"provider": "aliyun",
"model": "qwen-plus",
"max_tool_iterations": 99
}
},
"context_compaction": {
"enabled": true,
"reserve_tokens": 16384,
"keep_recent_tokens": 20000
},
"gateway": {
"host": "127.0.0.1",
"port": 19876,
"require_pairing": true,
"scheduler": {
"enabled": true,
"poll_interval_secs": 60,
"max_concurrent": 1,
"execution_timeout_secs": 900
}
},
"client": {
"gateway_url": "ws://127.0.0.1:19876/ws"
},
"channels": {
"feishu": {
"enabled": true,
"app_id": "<FEISHU_APP_ID>",
"app_secret": "<FEISHU_APP_SECRET>",
"allow_from": ["*"],
"require_mention": true,
"agent": "default",
"media_dir": "~/.picobot/media/feishu",
"reaction_emoji": "Typing",
"live_updates": false,
"live_update_interval_ms": 500,
"max_image_bytes": 10485760,
"max_file_bytes": 26214400,
"media_dir_max_bytes": 536870912,
"request_timeout_secs": 30
}
},
"memory": {
"consolidation_provider": null,
"consolidation_model": null,
"recall_limit": 5,
"recall_min_relevance": 0.25,
"recall_min_score": 0.25,
"recall_recency_half_life_days": 30,
"recall_timeout_ms": 1000,
"idle_consolidation_minutes": 10,
"timeline_retention_days": 90,
"max_failures_before_degrade": 3
},
"mcp": {
"servers": [],
"tool_timeout_secs": 180
},
"browser": {
"enabled": true,
"command": "agent-browser",
"headless": true,
"browser_executable_path": null,
"max_sessions": 4,
"idle_timeout_secs": 3600,
"command_timeout_secs": 120,
"max_output_chars": 50000,
"content_boundaries": true,
"allowed_domains": [],
"allow_private_hosts": false,
"artifact_dir": "~/.picobot/media/browser",
"persistence": {
"profile_dir": "~/.picobot/browser/profiles"
}
},
"workspace_dir": "~/.picobot/workspace"
}