Files
aiagent/backend/app/agent_runtime/schemas.py

206 lines
9.7 KiB
Python
Raw Normal View History

"""
Agent Runtime 配置与数据结构 Schema
"""
from __future__ import annotations
fix: 修复35个安全与功能缺陷,补全知识进化/数字孪生/行为采集模块 ## 安全修复 (12项) - Webhook接口添加全局Token认证,过滤敏感请求头 - 修复JWT Base64 padding公式,防止签名验证绕过 - 数据库密码/飞书Token从源码移除,改为环境变量 - 工作流引擎添加路径遍历防护 (_resolve_safe_path) - eval()添加模板长度上限检查 - 审批API添加认证依赖 - 前端v-html增强XSS转义,console.log仅开发模式输出 - 500错误不再暴露内部异常详情 ## Agent运行时修复 (7项) - 删除_inject_knowledge_context中未定义db变量的finally块 - 工具执行添加try/except保护,异常不崩溃Agent - LLM重试计入budget计数器 - self_review异常时passed=False - max_iterations截断标记success=False - 工具参数JSON解析失败时记录警告日志 - run()开始时重置_llm_invocations计数器 ## 配置与基础设施 - DEBUG默认False,SQL_ECHO独立配置项 - init_db()补全13个缺失模型导入 - 新增WEBHOOK_AUTH_TOKEN/SQL_ECHO配置项 - 新增.env.example模板文件 ## 前端修复 (12项) - 登录改用URLSearchParams替代FormData - 401拦截器通过Pinia store统一清理状态 - SSE流超时从60s延长至300s - final/error事件时清除streamTimeout - localStorage聊天记录添加24h TTL - safeParseArgCount替代模板中裸JSON.parse - fetchUser 401时同时清除user对象 ## 新增模块 - 知识进化: knowledge_extractor/retriever/tasks - 数字孪生: shadow_executor/comparison模型 - 行为采集: behavior_middleware/collector/fingerprint_engine - 代码审查: code_review_agent/document_review_agent - 反馈学习: feedback_learner - 瓶颈检测/优化引擎/成本估算/需求估算 - 速率限制器 (rate_limiter) - Alembic迁移 015-020 ## 文档 - 商业化落地计划 - 8篇docs文档 (架构/API/部署/开发/贡献等) - Docker Compose生产配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-10 19:50:20 +08:00
import logging
logger = logging.getLogger(__name__)
logger.warning("SCHEMAS_MODULE_LOADED_V3_FIELD_VALIDATOR")
from typing import Any, Dict, List, Optional
fix: 修复35个安全与功能缺陷,补全知识进化/数字孪生/行为采集模块 ## 安全修复 (12项) - Webhook接口添加全局Token认证,过滤敏感请求头 - 修复JWT Base64 padding公式,防止签名验证绕过 - 数据库密码/飞书Token从源码移除,改为环境变量 - 工作流引擎添加路径遍历防护 (_resolve_safe_path) - eval()添加模板长度上限检查 - 审批API添加认证依赖 - 前端v-html增强XSS转义,console.log仅开发模式输出 - 500错误不再暴露内部异常详情 ## Agent运行时修复 (7项) - 删除_inject_knowledge_context中未定义db变量的finally块 - 工具执行添加try/except保护,异常不崩溃Agent - LLM重试计入budget计数器 - self_review异常时passed=False - max_iterations截断标记success=False - 工具参数JSON解析失败时记录警告日志 - run()开始时重置_llm_invocations计数器 ## 配置与基础设施 - DEBUG默认False,SQL_ECHO独立配置项 - init_db()补全13个缺失模型导入 - 新增WEBHOOK_AUTH_TOKEN/SQL_ECHO配置项 - 新增.env.example模板文件 ## 前端修复 (12项) - 登录改用URLSearchParams替代FormData - 401拦截器通过Pinia store统一清理状态 - SSE流超时从60s延长至300s - final/error事件时清除streamTimeout - localStorage聊天记录添加24h TTL - safeParseArgCount替代模板中裸JSON.parse - fetchUser 401时同时清除user对象 ## 新增模块 - 知识进化: knowledge_extractor/retriever/tasks - 数字孪生: shadow_executor/comparison模型 - 行为采集: behavior_middleware/collector/fingerprint_engine - 代码审查: code_review_agent/document_review_agent - 反馈学习: feedback_learner - 瓶颈检测/优化引擎/成本估算/需求估算 - 速率限制器 (rate_limiter) - Alembic迁移 015-020 ## 文档 - 商业化落地计划 - 8篇docs文档 (架构/API/部署/开发/贡献等) - Docker Compose生产配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-10 19:50:20 +08:00
from pydantic import BaseModel, Field, field_validator
from app.agent_runtime.permissions import DEFAULT_REQUIRE_APPROVAL_TOOLS
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=lambda: list(DEFAULT_REQUIRE_APPROVAL_TOOLS), description="需要人工审批的工具名列表(默认包含 destructive 工具)")
fix: 修复35个安全与功能缺陷,补全知识进化/数字孪生/行为采集模块 ## 安全修复 (12项) - Webhook接口添加全局Token认证,过滤敏感请求头 - 修复JWT Base64 padding公式,防止签名验证绕过 - 数据库密码/飞书Token从源码移除,改为环境变量 - 工作流引擎添加路径遍历防护 (_resolve_safe_path) - eval()添加模板长度上限检查 - 审批API添加认证依赖 - 前端v-html增强XSS转义,console.log仅开发模式输出 - 500错误不再暴露内部异常详情 ## Agent运行时修复 (7项) - 删除_inject_knowledge_context中未定义db变量的finally块 - 工具执行添加try/except保护,异常不崩溃Agent - LLM重试计入budget计数器 - self_review异常时passed=False - max_iterations截断标记success=False - 工具参数JSON解析失败时记录警告日志 - run()开始时重置_llm_invocations计数器 ## 配置与基础设施 - DEBUG默认False,SQL_ECHO独立配置项 - init_db()补全13个缺失模型导入 - 新增WEBHOOK_AUTH_TOKEN/SQL_ECHO配置项 - 新增.env.example模板文件 ## 前端修复 (12项) - 登录改用URLSearchParams替代FormData - 401拦截器通过Pinia store统一清理状态 - SSE流超时从60s延长至300s - final/error事件时清除streamTimeout - localStorage聊天记录添加24h TTL - safeParseArgCount替代模板中裸JSON.parse - fetchUser 401时同时清除user对象 ## 新增模块 - 知识进化: knowledge_extractor/retriever/tasks - 数字孪生: shadow_executor/comparison模型 - 行为采集: behavior_middleware/collector/fingerprint_engine - 代码审查: code_review_agent/document_review_agent - 反馈学习: feedback_learner - 瓶颈检测/优化引擎/成本估算/需求估算 - 速率限制器 (rate_limiter) - Alembic迁移 015-020 ## 文档 - 商业化落地计划 - 8篇docs文档 (架构/API/部署/开发/贡献等) - Docker Compose生产配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-10 19:50:20 +08:00
@field_validator("include_tools", "exclude_tools", "require_approval", "cache_tool_whitelist", "auto_approve_rules", "deny_tools", mode="before")
fix: 修复35个安全与功能缺陷,补全知识进化/数字孪生/行为采集模块 ## 安全修复 (12项) - Webhook接口添加全局Token认证,过滤敏感请求头 - 修复JWT Base64 padding公式,防止签名验证绕过 - 数据库密码/飞书Token从源码移除,改为环境变量 - 工作流引擎添加路径遍历防护 (_resolve_safe_path) - eval()添加模板长度上限检查 - 审批API添加认证依赖 - 前端v-html增强XSS转义,console.log仅开发模式输出 - 500错误不再暴露内部异常详情 ## Agent运行时修复 (7项) - 删除_inject_knowledge_context中未定义db变量的finally块 - 工具执行添加try/except保护,异常不崩溃Agent - LLM重试计入budget计数器 - self_review异常时passed=False - max_iterations截断标记success=False - 工具参数JSON解析失败时记录警告日志 - run()开始时重置_llm_invocations计数器 ## 配置与基础设施 - DEBUG默认False,SQL_ECHO独立配置项 - init_db()补全13个缺失模型导入 - 新增WEBHOOK_AUTH_TOKEN/SQL_ECHO配置项 - 新增.env.example模板文件 ## 前端修复 (12项) - 登录改用URLSearchParams替代FormData - 401拦截器通过Pinia store统一清理状态 - SSE流超时从60s延长至300s - final/error事件时清除streamTimeout - localStorage聊天记录添加24h TTL - safeParseArgCount替代模板中裸JSON.parse - fetchUser 401时同时清除user对象 ## 新增模块 - 知识进化: knowledge_extractor/retriever/tasks - 数字孪生: shadow_executor/comparison模型 - 行为采集: behavior_middleware/collector/fingerprint_engine - 代码审查: code_review_agent/document_review_agent - 反馈学习: feedback_learner - 瓶颈检测/优化引擎/成本估算/需求估算 - 速率限制器 (rate_limiter) - Alembic迁移 015-020 ## 文档 - 商业化落地计划 - 8篇docs文档 (架构/API/部署/开发/贡献等) - Docker Compose生产配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-10 19:50:20 +08:00
@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
parent_agent_id: Optional[str] = None # 父 Agent ID继承经验
# 对话自动压缩 (参考 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 预算摘要")