Files
aiagent/backend/app/agent_runtime/schemas.py
renjianbo 7f4aeb021b fix: Feishu channel agents file_write permission blocked + memory system tests & docs
- Fix 8 Feishu agent handlers to use permission_level="acceptEdits" so file_write
  tool works without Web UI approval popup (lingxi/renshenguo/suyao/tiantian/orange/main/schedule)
- Add P5-P7 memory improvements: offline keyword fallback, team sharing, file-based memory
- Add auto_dream_service for daily memory consolidation
- Add 99 memory system test cases (basic 18 + advanced 43 + pytest 38)
- Add platform capability assessment report and unfinished project checklist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-14 20:35:12 +08:00

204 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Agent Runtime 配置与数据结构 Schema
"""
from __future__ import annotations
import logging
logger = logging.getLogger(__name__)
logger.warning("SCHEMAS_MODULE_LOADED_V3_FIELD_VALIDATOR")
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, field_validator
class AgentToolConfig(BaseModel):
"""Agent 可用工具配置"""
# 若为空列表则使用全部已注册工具
include_tools: List[str] = Field(default_factory=list, description="允许的工具名称白名单")
exclude_tools: List[str] = Field(default_factory=list, description="排除的工具名称黑名单")
require_approval: List[str] = Field(default_factory=list, description="需要人工审批的工具名列表")
@field_validator("include_tools", "exclude_tools", "require_approval", "cache_tool_whitelist", "auto_approve_rules", "deny_tools", mode="before")
@classmethod
def coerce_none_to_empty(cls, v: Any) -> Any:
return v if v is not None else []
approval_timeout_ms: int = Field(default=60000, description="审批超时(毫秒),超时使用默认策略")
approval_default: str = Field(default="deny", description="超时默认策略: approve | deny | skip")
# 结果缓存
cache_enabled: bool = Field(default=True, description="是否启用工具结果缓存(确定性工具默认开启)")
cache_tool_whitelist: List[str] = Field(default_factory=list, description="启用缓存的工具名(空=确定性工具默认)")
cache_ttl_ms: int = Field(default=3600000, description="缓存 TTL毫秒默认 1 小时")
# 工具安全分级 (P3 — 参考 Claude Code PermissionMode)
permission_level: str = Field(
default="default",
description="权限级别: bypass | acceptEdits | default | plan"
)
auto_approve_rules: List[Dict[str, Any]] = Field(
default_factory=list,
description="自动批准规则: [{tool_pattern, param_conditions, description}]"
)
deny_tools: List[str] = Field(default_factory=list, description="禁用的工具名列表")
class AgentMemoryConfig(BaseModel):
"""Agent 记忆配置"""
enabled: bool = True
max_history_messages: int = 20 # 注入 LLM 的上文最大消息数
session_key: Optional[str] = None # 会话标识,默认自动生成
persist_to_db: bool = True # 是否写入 MySQL 长期记忆
vector_memory_enabled: bool = True # 是否启用向量记忆(语义检索)
vector_memory_top_k: int = 5 # 向量检索 Top-K
vector_memory_rerank: bool = False # 是否启用 LLM Rerank向量 top-20 → LLM 精选 top-K
memory_type_filter: Optional[List[str]] = None # 记忆类型过滤,如 ["user","project"]None=全部
team_id: Optional[str] = None # 团队共享 ID非空时记忆在团队间共享
team_share_enabled: bool = False # 是否将新记忆自动发布到团队池
learning_enabled: bool = True # 是否启用自主学习(工具模式学习)
# 文件式记忆 (MEMORY.md — 参考 Claude Code memdir)
memory_dir_enabled: bool = False # 是否启用文件式自动记忆
memory_dir_path: str = "" # 记忆目录路径(空=自动使用项目 .claude/memory
# 对话自动压缩 (参考 Claude Code src/services/compact/)
compaction: Optional[Any] = None # CompactionConfig — 惰性导入避免循环依赖
class AgentLLMConfig(BaseModel):
"""Agent 模型配置"""
provider: str = "openai" # openai / deepseek
model: str = "gpt-4o-mini"
temperature: float = 0.7
max_tokens: Optional[int] = None
api_key: Optional[str] = None
base_url: Optional[str] = None
max_iterations: int = 10 # ReAct 循环最大步数
request_timeout: float = 120.0
extra_body: Optional[Dict[str, Any]] = None
self_review_threshold: float = 0.6 # self-review 通过阈值0-1
cache_enabled: bool = False # LLM 响应缓存(默认关闭,语义缓存有风险)
cache_ttl_ms: int = 300000 # LLM 缓存 TTL默认 5 分钟
fallback_llm: Optional[Dict[str, Any]] = None # 降级模型配置 {provider, model, api_key, base_url}
# 计划模式 (P2 — 参考 Claude Code EnterPlanModeTool)
plan_mode_enabled: bool = False # 是否启用计划模式
plan_approval_required: bool = True # 是否需要用户审批计划
plan_model: Optional[str] = None # 计划生成使用的模型(默认复用主模型)
# 上下文窗口 (用于 Compaction 触发计算)
context_window: int = 128000 # 模型上下文窗口大小token 数)
class AgentBudgetConfig(BaseModel):
"""Agent 执行预算配置"""
max_llm_invocations: int = 200 # LLM 调用次数上限
max_tool_calls: int = 500 # 工具调用次数上限
class AgentTokenBudgetConfig(BaseModel):
"""Token 预算管理配置 — 参考 Claude Code tokenBudget.ts"""
enabled: bool = True
context_window: int = 0 # 模型上下文窗口0=自动检测)
output_reserve: int = 8192 # 留给模型输出的空间
warning_threshold_pct: float = Field(default=0.75, ge=0.1, le=1.0)
compact_threshold_pct: float = Field(default=0.85, ge=0.1, le=1.0)
hard_limit_pct: float = Field(default=0.95, ge=0.1, le=1.0)
user_budget: Optional[int] = None # 用户累计 token 目标(如 500000
auto_continue: bool = False # 预算用尽自动继续
compaction_after_warning: bool = True
max_compaction_attempts: int = 3
class AgentPromptSectionsConfig(BaseModel):
"""系统提示词分层装配配置 — 参考 Claude Code systemPromptSections.ts"""
# 是否启用分层装配(关闭则退回到简单的 system_prompt 字符串)
enabled: bool = True
# 静态段开关(段名 → 是否启用)
static_sections: Dict[str, bool] = Field(default_factory=lambda: {
"persona": True,
"capabilities": True,
"tool_instructions": True,
"safety_rules": True,
"output_style": True,
})
# 动态段开关
dynamic_sections: Dict[str, bool] = Field(default_factory=lambda: {
"environment": True,
"language": True,
"memory_context": True,
"conversation_summary": True,
"tool_list": False, # 工具列表默认关闭(太长)
})
# 语言偏好(用于 language 段)
language: Optional[str] = None
class AgentConfig(BaseModel):
"""Agent 完整配置"""
name: str = "default_agent"
system_prompt: str = "你是一个有用的AI助手。请使用可用工具来帮助用户完成任务。"
llm: AgentLLMConfig = Field(default_factory=AgentLLMConfig)
tools: AgentToolConfig = Field(default_factory=AgentToolConfig)
memory: AgentMemoryConfig = Field(default_factory=AgentMemoryConfig)
budget: AgentBudgetConfig = Field(default_factory=AgentBudgetConfig)
user_id: Optional[str] = None
# 持久记忆 / 向量记忆的 scope_id不设时沿用 user_id 或 name易与其他 Agent 串记忆)
memory_scope_id: Optional[str] = None
# 是否开启输出质量自检(结束前用轻量 LLM 评审,不达标则追加修正)
self_review_enabled: bool = False
# 系统提示词分层装配 (P2 — 参考 Claude Code prompts.ts + systemPromptSections.ts)
prompt_sections: AgentPromptSectionsConfig = Field(default_factory=AgentPromptSectionsConfig)
# Token 预算管理 (P2 — 参考 Claude Code tokenBudget.ts)
token_budget: AgentTokenBudgetConfig = Field(default_factory=AgentTokenBudgetConfig)
class AgentMessage(BaseModel):
"""Agent 对话消息"""
role: str # user / assistant / tool
content: str
tool_calls: Optional[List[Dict[str, Any]]] = None
tool_call_id: Optional[str] = None
name: Optional[str] = None
class AgentStep(BaseModel):
"""Agent 单步执行记录(用于执行追踪)"""
iteration: int = Field(..., description="第几步")
type: str = Field(..., description="步骤类型: think / tool_call / tool_result / final")
content: str = Field(default="", description="步骤内容")
tool_name: Optional[str] = Field(default=None, description="工具名称tool_call/tool_result 类型时)")
tool_input: Optional[Dict[str, Any]] = Field(default=None, description="工具输入参数")
tool_result: Optional[str] = Field(default=None, description="工具执行结果")
reasoning: Optional[str] = Field(default=None, description="思考过程")
class TokenUsageInfo(BaseModel):
"""Token 预算信息 — 随 AgentResult 返回给前端展示用量条"""
input_tokens: int = 0
input_remaining: int = 0
input_usage_pct: float = 0.0
effective_window: int = 128_000
context_window: int = 128_000
cumulative_total: int = 0
cumulative_prompt: int = 0
cumulative_completion: int = 0
llm_call_count: int = 0
is_warning: bool = False
is_critical: bool = False
is_exhausted: bool = False
compaction_attempts: int = 0
user_budget: Optional[int] = None
user_budget_used: Optional[int] = None
user_budget_remaining: Optional[int] = None
user_budget_pct: Optional[float] = None
class AgentResult(BaseModel):
"""Agent 执行结果"""
success: bool = True
content: str = ""
truncated: bool = False
iterations_used: int = 0
tool_calls_made: int = 0
error: Optional[str] = None
steps: List[AgentStep] = Field(default_factory=list, description="执行追踪步骤详情")
token_usage: Optional[TokenUsageInfo] = Field(default=None, description="Token 预算摘要")