refactor: remove Any from core/ + experts/ type signatures (185 sites)
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details

- core/ 105 sites: react.py(34), rewoo.py(30), config_driven.py(14), middleware.py(10), base.py(7), plan_executor.py(8), fallback.py(2)
- experts/ 80 sites: plan.py(15), _phase_executor.py(11), orchestrator.py(11), _debate_runner.py(9), config.py(9), board_orchestrator.py(6), _synthesizer.py(5), board.py(5), _review_gate.py(3), _rollback_handler.py(2), _divergence_detector.py(2), team.py(2)
- Strategy: object > TYPE_CHECKING Protocol > TYPE_CHECKING import
- No recursive TypeAlias (Pydantic v2 RecursionError)

Tests: 1139 passed, 0 regressions
ruff: 0 new errors
This commit is contained in:
chiguyong 2026-07-01 03:39:54 +08:00
parent 38b9602964
commit b3f7159fcd
19 changed files with 179 additions and 187 deletions

View File

@ -13,7 +13,7 @@ import logging
import time import time
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
import redis.asyncio as aioredis import redis.asyncio as aioredis
@ -71,7 +71,7 @@ class BaseAgent(ABC):
# 可插拔能力(由子类或配置注入) # 可插拔能力(由子类或配置注入)
self._tools: list["Tool"] = [] self._tools: list["Tool"] = []
self._memory: "Memory | None" = None self._memory: "Memory | None" = None
self._memory_retriever: Any | None = None self._memory_retriever: object | None = None
# 外部依赖注入(由 start() 时设置) # 外部依赖注入(由 start() 时设置)
self._registry = None self._registry = None
@ -192,7 +192,7 @@ class BaseAgent(ABC):
lines.append(f" - {msg}") lines.append(f" - {msg}")
return "\n".join(lines) return "\n".join(lines)
def _build_skill_context(self) -> dict[str, Any] | None: def _build_skill_context(self) -> dict[str, object] | None:
"""从当前技能配置构建 skill_context用于 QualityGate skill_match 校验""" """从当前技能配置构建 skill_context用于 QualityGate skill_match 校验"""
if not self._skill: if not self._skill:
return None return None
@ -216,17 +216,17 @@ class BaseAgent(ABC):
self._memory = memory self._memory = memory
return self return self
def use_memory_retriever(self, retriever: Any) -> "BaseAgent": def use_memory_retriever(self, retriever: object) -> "BaseAgent":
"""设置记忆检索器,用于上下文注入""" """设置记忆检索器,用于上下文注入"""
self._memory_retriever = retriever self._memory_retriever = retriever
return self return self
def set_registry(self, registry: Any) -> "BaseAgent": def set_registry(self, registry: object) -> "BaseAgent":
"""注入注册中心""" """注入注册中心"""
self._registry = registry self._registry = registry
return self return self
def set_dispatcher(self, dispatcher: Any) -> "BaseAgent": def set_dispatcher(self, dispatcher: object) -> "BaseAgent":
"""注入任务分发器""" """注入任务分发器"""
self._dispatcher = dispatcher self._dispatcher = dispatcher
return self return self
@ -489,7 +489,7 @@ class BaseAgent(ABC):
target_agent: str, target_agent: str,
task: TaskMessage, task: TaskMessage,
reason: str, reason: str,
context: dict[str, Any] | None = None, context: dict[str, object] | None = None,
): ):
"""将当前任务转交给另一个 Agent""" """将当前任务转交给另一个 Agent"""
if self._redis is None: if self._redis is None:

View File

@ -10,7 +10,7 @@
import json import json
import logging import logging
import os import os
from typing import Any, Callable, Coroutine from typing import Callable, Coroutine
import yaml import yaml
@ -39,12 +39,12 @@ class AgentConfig:
task_mode: str = "llm_generate", task_mode: str = "llm_generate",
supported_tasks: list[str] | None = None, supported_tasks: list[str] | None = None,
max_concurrency: int = 1, max_concurrency: int = 1,
input_schema: dict[str, Any] | None = None, input_schema: dict[str, object] | None = None,
output_schema: dict[str, Any] | None = None, output_schema: dict[str, object] | None = None,
prompt: dict[str, str] | None = None, prompt: dict[str, str] | None = None,
llm: dict[str, Any] | None = None, llm: dict[str, object] | None = None,
tools: list[str] | None = None, tools: list[str] | None = None,
memory: dict[str, Any] | None = None, memory: dict[str, object] | None = None,
custom_handler: str | None = None, custom_handler: str | None = None,
): ):
self.name = name self.name = name
@ -96,7 +96,7 @@ class AgentConfig:
) )
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> "AgentConfig": def from_dict(cls, data: dict[str, object]) -> "AgentConfig":
"""从字典创建配置""" """从字典创建配置"""
return cls( return cls(
name=data["name"], name=data["name"],
@ -128,7 +128,7 @@ class AgentConfig:
) )
return cls.from_dict(data) return cls.from_dict(data)
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
d = { d = {
"name": self.name, "name": self.name,
@ -197,11 +197,11 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
self, self,
config: AgentConfig, config: AgentConfig,
tool_registry: ToolRegistry | None = None, tool_registry: ToolRegistry | None = None,
llm_client: Any = None, llm_client: object | None = None,
custom_handlers: dict[str, Callable[..., Coroutine]] | None = None, custom_handlers: dict[str, Callable[..., Coroutine]] | None = None,
llm_gateway: Any = None, # NEW v2 param: LLMGateway llm_gateway: object | None = None, # NEW v2 param: LLMGateway
mcp_servers: dict[str, str] | None = None, # NEW v2 param: MCP server URLs mcp_servers: dict[str, str] | None = None, # NEW v2 param: MCP server URLs
compressor: Any = None, # CompressionStrategy | None compressor: object | None = None, # CompressionStrategy | None
): ):
# v2: If SkillConfig, extract skill info # v2: If SkillConfig, extract skill info
from agentkit.skills.base import SkillConfig, Skill from agentkit.skills.base import SkillConfig, Skill
@ -310,12 +310,12 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
logger.info(f"Merged skill tool '{tool.name}' into agent '{self.name}'") logger.info(f"Merged skill tool '{tool.name}' into agent '{self.name}'")
# v2: Register MCP tools if mcp_servers provided # v2: Register MCP tools if mcp_servers provided
self._mcp_clients: list[Any] = [] self._mcp_clients: list[object] = []
self._mcp_servers: dict[str, str] = mcp_servers or {} self._mcp_servers: dict[str, str] = mcp_servers or {}
self._mcp_tools_registered = False self._mcp_tools_registered = False
# Memory integration: 从 config.memory 自动实例化 MemoryRetriever # Memory integration: 从 config.memory 自动实例化 MemoryRetriever
self._memory_retriever: Any | None = None self._memory_retriever: object | None = None
if config.memory: if config.memory:
try: try:
from agentkit.memory.retriever import MemoryRetriever from agentkit.memory.retriever import MemoryRetriever
@ -903,7 +903,7 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
) )
return await self.handle_task(enhanced_task) return await self.handle_task(enhanced_task)
def _wrap_llm_client(self, llm_client: Any): def _wrap_llm_client(self, llm_client: object):
"""Wrap legacy llm_client into LLMGateway""" """Wrap legacy llm_client into LLMGateway"""
from agentkit.llm.gateway import LLMGateway from agentkit.llm.gateway import LLMGateway
from agentkit.llm.protocol import LLMProvider, LLMRequest, LLMResponse, TokenUsage from agentkit.llm.protocol import LLMProvider, LLMRequest, LLMResponse, TokenUsage
@ -911,7 +911,7 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
class ClientProvider(LLMProvider): class ClientProvider(LLMProvider):
"""Adapter: wraps legacy llm_client as an LLMProvider""" """Adapter: wraps legacy llm_client as an LLMProvider"""
def __init__(self, raw_client: Any): def __init__(self, raw_client: object):
self._raw_client = raw_client self._raw_client = raw_client
async def chat(self, request: LLMRequest) -> LLMResponse: async def chat(self, request: LLMRequest) -> LLMResponse:

View File

@ -9,7 +9,6 @@ no LLM). See ``docs/plans/2026-06-29-003-feat-agent-wave2-medium-coupling-plan.m
""" """
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from agentkit.core.exceptions import ( from agentkit.core.exceptions import (
LLMProviderError, LLMProviderError,
@ -54,7 +53,7 @@ class EmergencyError:
retryable: bool # whether a user retry might succeed retryable: bool # whether a user retry might succeed
original_error: str # str(exc) for traceability original_error: str # str(exc) for traceability
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
return { return {
"error_code": self.error_code, "error_code": self.error_code,
"message": self.message, "message": self.message,

View File

@ -24,7 +24,7 @@ from __future__ import annotations
import json import json
import logging import logging
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any, Awaitable, Callable, Protocol, runtime_checkable from typing import Awaitable, Callable, Protocol, runtime_checkable
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -37,14 +37,14 @@ class RequestContext:
""" """
messages: list[dict[str, str]] messages: list[dict[str, str]]
tools: list[Any] = field(default_factory=list) tools: list[object] = field(default_factory=list)
system_prompt: str | None = None system_prompt: str | None = None
model: str = "default" model: str = "default"
agent_name: str = "" agent_name: str = ""
task_type: str = "" task_type: str = ""
task_id: str | None = None task_id: str | None = None
# 中间件间共享状态压缩结果、token 用量、循环检测状态等) # 中间件间共享状态压缩结果、token 用量、循环检测状态等)
metadata: dict[str, Any] = field(default_factory=dict) metadata: dict[str, object] = field(default_factory=dict)
@runtime_checkable @runtime_checkable
@ -57,7 +57,7 @@ class Middleware(Protocol):
async def before(self, ctx: RequestContext) -> RequestContext: ... async def before(self, ctx: RequestContext) -> RequestContext: ...
async def after(self, ctx: RequestContext, result: Any) -> Any: ... async def after(self, ctx: RequestContext, result: object) -> object: ...
class MiddlewareChain: class MiddlewareChain:
@ -81,8 +81,8 @@ class MiddlewareChain:
async def execute( async def execute(
self, self,
ctx: RequestContext, ctx: RequestContext,
handler: Callable[[RequestContext], Awaitable[Any]], handler: Callable[[RequestContext], Awaitable[object]],
) -> Any: ) -> object:
"""执行中间件链 + handler。 """执行中间件链 + handler。
洋葱模型before 顺序执行 handler after 逆序执行 洋葱模型before 顺序执行 handler after 逆序执行
@ -125,7 +125,7 @@ class SummarizationMiddleware:
after: 无操作压缩在 before 完成 after: 无操作压缩在 before 完成
""" """
def __init__(self, compressor: Any = None) -> None: def __init__(self, compressor: object | None = None) -> None:
self._compressor = compressor self._compressor = compressor
async def before(self, ctx: RequestContext) -> RequestContext: async def before(self, ctx: RequestContext) -> RequestContext:
@ -143,7 +143,7 @@ class SummarizationMiddleware:
logger.warning(f"SummarizationMiddleware: compression failed: {e}") logger.warning(f"SummarizationMiddleware: compression failed: {e}")
return ctx return ctx
async def after(self, ctx: RequestContext, result: Any) -> Any: async def after(self, ctx: RequestContext, result: object) -> object:
return result return result
@ -157,7 +157,7 @@ class TokenUsageMiddleware:
async def before(self, ctx: RequestContext) -> RequestContext: async def before(self, ctx: RequestContext) -> RequestContext:
return ctx return ctx
async def after(self, ctx: RequestContext, result: Any) -> Any: async def after(self, ctx: RequestContext, result: object) -> object:
# 从 ReActResult 或类似结构提取 token 用量 # 从 ReActResult 或类似结构提取 token 用量
# ReActResult 有 total_tokens 属性(非 token_usage # ReActResult 有 total_tokens 属性(非 token_usage
usage = getattr(result, "total_tokens", None) usage = getattr(result, "total_tokens", None)
@ -184,7 +184,7 @@ class LoopDetectionMiddleware:
ctx.metadata["loop_detection_window"] = [] ctx.metadata["loop_detection_window"] = []
return ctx return ctx
async def after(self, ctx: RequestContext, result: Any) -> Any: async def after(self, ctx: RequestContext, result: object) -> object:
trajectory = getattr(result, "trajectory", None) or [] trajectory = getattr(result, "trajectory", None) or []
if len(trajectory) < self._threshold: if len(trajectory) < self._threshold:
return result return result

View File

@ -16,9 +16,9 @@ import asyncio
import logging import logging
import random import random
import time import time
from dataclasses import dataclass, field from dataclasses import dataclass
from enum import Enum from enum import Enum
from typing import Any, Callable, Awaitable from typing import Callable, Awaitable
from agentkit.core.plan_schema import ExecutionPlan, PlanStep, PlanStepStatus from agentkit.core.plan_schema import ExecutionPlan, PlanStep, PlanStepStatus
from agentkit.core.protocol import TaskMessage, TaskResult, TaskStatus from agentkit.core.protocol import TaskMessage, TaskResult, TaskStatus
@ -42,7 +42,7 @@ class StepExecutionResult:
step_id: str step_id: str
status: PlanStepStatus status: PlanStepStatus
result: dict[str, Any] | None = None result: dict[str, object] | None = None
error: str | None = None error: str | None = None
retry_count: int = 0 retry_count: int = 0
duration_ms: float = 0.0 duration_ms: float = 0.0
@ -91,7 +91,7 @@ class PlanExecutor:
def __init__( def __init__(
self, self,
agent_pool: Any, agent_pool: object,
max_retries: int = 2, max_retries: int = 2,
step_timeout: float = 300.0, step_timeout: float = 300.0,
max_parallel: int = 5, max_parallel: int = 5,
@ -207,7 +207,7 @@ class PlanExecutor:
async def _execute_step_with_retry( async def _execute_step_with_retry(
self, self,
step: PlanStep, step: PlanStep,
input_data: dict[str, Any], input_data: dict[str, object],
original_task: TaskMessage, original_task: TaskMessage,
) -> StepExecutionResult: ) -> StepExecutionResult:
"""执行单个步骤,支持重试 """执行单个步骤,支持重试
@ -281,9 +281,9 @@ class PlanExecutor:
async def _execute_step_once( async def _execute_step_once(
self, self,
step: PlanStep, step: PlanStep,
input_data: dict[str, Any], input_data: dict[str, object],
original_task: TaskMessage, original_task: TaskMessage,
) -> dict[str, Any]: ) -> dict[str, object]:
"""执行单个步骤一次 """执行单个步骤一次
通过 AgentPool 创建 Agent 执行步骤 通过 AgentPool 创建 Agent 执行步骤
@ -463,7 +463,7 @@ class PlanExecutor:
self, self,
step: PlanStep, step: PlanStep,
step_results: dict[str, StepExecutionResult], step_results: dict[str, StepExecutionResult],
) -> dict[str, Any]: ) -> dict[str, object]:
"""将依赖步骤的结果注入到当前步骤的输入中 """将依赖步骤的结果注入到当前步骤的输入中
兼容 Orchestrator subtask_results 累积模式 兼容 Orchestrator subtask_results 累积模式
@ -471,7 +471,7 @@ class PlanExecutor:
enriched = dict(step.input_data) enriched = dict(step.input_data)
if step.dependencies: if step.dependencies:
dep_results: dict[str, dict[str, Any]] = {} dep_results: dict[str, dict[str, object]] = {}
for dep_id in step.dependencies: for dep_id in step.dependencies:
if dep_id in step_results: if dep_id in step_results:
dep_result = step_results[dep_id] dep_result = step_results[dep_id]

View File

@ -13,7 +13,7 @@ from collections import Counter, deque
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Awaitable, Callable
from agentkit.core.exceptions import LLMProviderError, LoopDetectedError, TaskCancelledError, TaskTimeoutError from agentkit.core.exceptions import LLMProviderError, LoopDetectedError, TaskCancelledError, TaskTimeoutError
from agentkit.core.protocol import CancellationToken from agentkit.core.protocol import CancellationToken
@ -43,13 +43,13 @@ class ReActStep:
step: int step: int
action: str # "tool_call" or "final_answer" action: str # "tool_call" or "final_answer"
tool_name: str | None = None tool_name: str | None = None
arguments: dict[str, Any] | None = None arguments: dict[str, object] | None = None
result: Any = None result: object = None
content: str | None = None content: str | None = None
tokens: int = 0 tokens: int = 0
async def _ensure_async_iterable(obj: Any, label: str = "<obj>"): async def _ensure_async_iterable(obj: object, label: str = "<obj>"):
"""Defensive helper: ensure the given object is an async iterable. """Defensive helper: ensure the given object is an async iterable.
Guards against the recurring ``'async for' requires an object with Guards against the recurring ``'async for' requires an object with
@ -133,7 +133,7 @@ class ReActEvent:
event_type: str # "thinking","token","tool_call","tool_result","confirmation_request","confirmation_result","phase_violation","step","final_answer","final_result","error" event_type: str # "thinking","token","tool_call","tool_result","confirmation_request","confirmation_result","phase_violation","step","final_answer","final_result","error"
step: int step: int
data: dict[str, Any] = field(default_factory=dict) data: dict[str, object] = field(default_factory=dict)
timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat()) timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
@ -230,7 +230,7 @@ class ReActEngine:
# step and yields phase_violation ReActEvents. Non-streaming execute() # step and yields phase_violation ReActEvents. Non-streaming execute()
# simply ignores the accumulator (the error dict returned to the LLM is # simply ignores the accumulator (the error dict returned to the LLM is
# the only signal there). # the only signal there).
self._phase_violations: list[dict[str, Any]] = [] self._phase_violations: list[dict[str, object]] = []
def reset(self) -> None: def reset(self) -> None:
"""Reset internal state for reuse across conversations. """Reset internal state for reuse across conversations.
@ -299,8 +299,8 @@ class ReActEngine:
return False return False
def _check_phase_permission( def _check_phase_permission(
self, tool_name: str, arguments: dict[str, Any] self, tool_name: str, arguments: dict[str, object]
) -> dict[str, Any] | None: ) -> dict[str, object] | None:
"""Return None if tool is allowed; return a structured error dict if blocked. """Return None if tool is allowed; return a structured error dict if blocked.
The error dict replaces what `_execute_tool` would have returned The error dict replaces what `_execute_tool` would have returned
@ -351,7 +351,7 @@ class ReActEngine:
return violation return violation
return None return None
def _check_tool_loop(self, tool_calls: list[Any]) -> str | None: def _check_tool_loop(self, tool_calls: list[object]) -> str | None:
"""检测重复工具调用模式。 """检测重复工具调用模式。
将当前步的工具调用 hash 加入滑动窗口若同一 hash 在窗口内出现 将当前步的工具调用 hash 加入滑动窗口若同一 hash 在窗口内出现
@ -406,10 +406,10 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
timeout_seconds: float | None = None, timeout_seconds: float | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult: ) -> ReActResult:
"""执行 ReAct 循环 """执行 ReAct 循环
@ -536,7 +536,7 @@ class ReActEngine:
async def _run_loop_and_extract( async def _run_loop_and_extract(
self, self,
**kwargs: Any, **kwargs: object,
) -> ReActResult: ) -> ReActResult:
"""Collect all events from _execute_loop and extract the final ReActResult. """Collect all events from _execute_loop and extract the final ReActResult.
@ -564,9 +564,9 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
stream: bool = False, stream: bool = False,
effective_timeout: float = 0.0, effective_timeout: float = 0.0,
) -> AsyncGenerator[ReActEvent, None]: ) -> AsyncGenerator[ReActEvent, None]:
@ -666,7 +666,7 @@ class ReActEngine:
) )
# 构建初始消息 # 构建初始消息
conversation: list[dict[str, Any]] = [] conversation: list[dict[str, object]] = []
system_content = self._build_system_message( system_content = self._build_system_message(
stable=system_prompt or "", stable=system_prompt or "",
volatile=memory_context, volatile=memory_context,
@ -726,7 +726,7 @@ class ReActEngine:
# 流式模式:用 chat_streamyield token events # 流式模式:用 chat_streamyield token events
stream_content_chunks: list[str] = [] stream_content_chunks: list[str] = []
stream_usage = None stream_usage = None
stream_tool_calls: list[Any] = [] stream_tool_calls: list[object] = []
stream_model = model stream_model = model
# U3/G8: delta_flush 节流 buffer # U3/G8: delta_flush 节流 buffer
_flush_buffer: list[str] = [] _flush_buffer: list[str] = []
@ -840,7 +840,7 @@ class ReActEngine:
) )
# Act: 记录 assistant 消息(含 tool_calls到对话历史 # Act: 记录 assistant 消息(含 tool_calls到对话历史
assistant_msg: dict[str, Any] = { assistant_msg: dict[str, object] = {
"role": "assistant", "role": "assistant",
"content": response.content or "", "content": response.content or "",
"tool_calls": [ "tool_calls": [
@ -874,7 +874,7 @@ class ReActEngine:
if i in parallelizable_set if i in parallelizable_set
] ]
all_results: list[Any] = [None] * len(response.tool_calls) all_results: list[object] = [None] * len(response.tool_calls)
# Execute serial tools first (handles confirmation flow) # Execute serial tools first (handles confirmation flow)
for i, tc in serial_calls: for i, tc in serial_calls:
@ -1452,10 +1452,10 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
timeout_seconds: float | None = None, timeout_seconds: float | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> AsyncGenerator[ReActEvent, None]: ) -> AsyncGenerator[ReActEvent, None]:
"""Execute ReAct loop, yielding ReActEvent objects. """Execute ReAct loop, yielding ReActEvent objects.
@ -1514,7 +1514,7 @@ class ReActEngine:
volatile: str, volatile: str,
*, *,
model: str, model: str,
) -> str | list[dict[str, Any]] | None: ) -> str | list[dict[str, object]] | None:
"""构建双块结构 system message(stable + volatile)。 """构建双块结构 system message(stable + volatile)。
- prompt_cache_enable=False 或无 stable+volatile 返回 str( None) - prompt_cache_enable=False 或无 stable+volatile 返回 str( None)
@ -1535,7 +1535,7 @@ class ReActEngine:
provider_name = self._get_provider_name(model) provider_name = self._get_provider_name(model)
if provider_name == "anthropic": if provider_name == "anthropic":
blocks: list[dict[str, Any]] = [] blocks: list[dict[str, object]] = []
if stable: if stable:
blocks.append( blocks.append(
{ {
@ -1675,8 +1675,8 @@ class ReActEngine:
@staticmethod @staticmethod
def _build_response_from_stream( def _build_response_from_stream(
content: str, content: str,
tool_calls: list[Any], tool_calls: list[object],
usage: Any, usage: object,
model: str, model: str,
) -> LLMResponse: ) -> LLMResponse:
"""Build an LLMResponse from accumulated stream chunks.""" """Build an LLMResponse from accumulated stream chunks."""
@ -1723,7 +1723,7 @@ class ReActEngine:
async def _build_tool_result_message( async def _build_tool_result_message(
self, self,
tool_call_id: str, tool_call_id: str,
result: Any, result: object,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
tool_name: str | None = None, tool_name: str | None = None,
) -> dict: ) -> dict:
@ -1742,7 +1742,7 @@ class ReActEngine:
} }
async def _execute_tool( async def _execute_tool(
self, tool_name: str, arguments: dict[str, Any], tools: list[Tool] self, tool_name: str, arguments: dict[str, object], tools: list[Tool]
) -> dict: ) -> dict:
"""执行工具调用,处理成功和失败情况""" """执行工具调用,处理成功和失败情况"""
# U3/G6: phase enforcement — check before dispatch. If the tool is # U3/G6: phase enforcement — check before dispatch. If the tool is
@ -1788,11 +1788,11 @@ class ReActEngine:
async def _execute_tool_with_confirmation( async def _execute_tool_with_confirmation(
self, self,
tc: Any, tc: object,
tools: list[Tool], tools: list[Tool],
step: int, step: int,
confirmation_handler: Any, confirmation_handler: Callable[..., Awaitable[object]] | None,
) -> tuple[Any, list[ReActEvent]]: ) -> tuple[object, list[ReActEvent]]:
"""Execute a tool call with confirmation flow support. """Execute a tool call with confirmation flow support.
Used in the parallel execution path for serial (non-parallelizable) tools Used in the parallel execution path for serial (non-parallelizable) tools
@ -1886,7 +1886,7 @@ class ReActEngine:
return tool_result, events return tool_result, events
def _should_execute_parallel(self, tool_calls: list[Any]) -> bool: def _should_execute_parallel(self, tool_calls: list[object]) -> bool:
"""Determine if tool calls should be executed in parallel. """Determine if tool calls should be executed in parallel.
- parallel_tools=True: always parallel (if >1 tool) - parallel_tools=True: always parallel (if >1 tool)
@ -1905,7 +1905,7 @@ class ReActEngine:
return len(parallelizable_indices) > 1 return len(parallelizable_indices) > 1
return False return False
def _get_parallelizable_indices(self, tool_calls: list[Any]) -> list[int]: def _get_parallelizable_indices(self, tool_calls: list[object]) -> list[int]:
"""Get indices of tool_calls that have _parallelizable=true in arguments. """Get indices of tool_calls that have _parallelizable=true in arguments.
LLM marks parallelizable tools by including _parallelizable: true LLM marks parallelizable tools by including _parallelizable: true
@ -1918,7 +1918,7 @@ class ReActEngine:
indices.append(i) indices.append(i)
return indices return indices
def _parse_text_tool_calls(self, content: str) -> list[dict[str, Any]]: def _parse_text_tool_calls(self, content: str) -> list[dict[str, object]]:
"""从文本中解析工具调用模式 """从文本中解析工具调用模式
支持格式 支持格式
@ -1926,7 +1926,7 @@ class ReActEngine:
2. ```tool\n{"name": "...", "arguments": {...}}\n``` 2. ```tool\n{"name": "...", "arguments": {...}}\n```
3. <tool_use>\n{"name": "...", "arguments": {...}}\n</tool_use> 3. <tool_use>\n{"name": "...", "arguments": {...}}\n</tool_use>
""" """
calls: list[dict[str, Any]] = [] calls: list[dict[str, object]] = []
# 格式 1: Action: tool_name(args) # 格式 1: Action: tool_name(args)
action_pattern = re.compile(r"Action:\s*(\w+)\((.+?)\)", re.DOTALL) action_pattern = re.compile(r"Action:\s*(\w+)\((.+?)\)", re.DOTALL)
@ -1999,7 +1999,7 @@ class ReActEngine:
return calls return calls
@staticmethod @staticmethod
def _extract_tool_call_from_malformed(text: str) -> dict[str, Any] | None: def _extract_tool_call_from_malformed(text: str) -> dict[str, object] | None:
"""从畸形文本中尝试提取工具调用。 """从畸形文本中尝试提取工具调用。
处理场景 处理场景
@ -2066,7 +2066,7 @@ class ReActEngine:
return None return None
name = name_match.group(1) name = name_match.group(1)
arguments: dict[str, Any] = {} arguments: dict[str, object] = {}
# 提取 "key": "value" 模式 # 提取 "key": "value" 模式
for kv_match in re.finditer(r'"(\w+)"\s*:\s*"([^"]*)"', text): for kv_match in re.finditer(r'"(\w+)"\s*:\s*"([^"]*)"', text):
key = kv_match.group(1) key = kv_match.group(1)

View File

@ -11,7 +11,7 @@ import logging
import re import re
import time import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Awaitable, Callable
from agentkit.core.exceptions import LLMProviderError, TaskCancelledError, TaskTimeoutError from agentkit.core.exceptions import LLMProviderError, TaskCancelledError, TaskTimeoutError
from agentkit.core.protocol import CancellationToken from agentkit.core.protocol import CancellationToken
@ -52,7 +52,7 @@ class ReWOOPlanStep:
step_id: int step_id: int
tool_name: str tool_name: str
arguments: dict[str, Any] arguments: dict[str, object]
reasoning: str = "" reasoning: str = ""
@ -164,10 +164,10 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
timeout_seconds: float | None = None, timeout_seconds: float | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult: ) -> ReActResult:
"""执行 ReWOO 三阶段流程 """执行 ReWOO 三阶段流程
@ -241,9 +241,9 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult: ) -> ReActResult:
tools = tools or [] tools = tools or []
tool_schemas = self._build_tool_schemas(tools) if tools else None tool_schemas = self._build_tool_schemas(tools) if tools else None
@ -350,7 +350,7 @@ class ReWOOEngine:
# 如果计划为空(无需工具),直接让 LLM 回答 # 如果计划为空(无需工具),直接让 LLM 回答
if not plan.steps: if not plan.steps:
llm_messages: list[dict[str, Any]] = [] llm_messages: list[dict[str, object]] = []
if effective_system_prompt: if effective_system_prompt:
llm_messages.append({"role": "system", "content": effective_system_prompt}) llm_messages.append({"role": "system", "content": effective_system_prompt})
llm_messages.extend(messages) llm_messages.extend(messages)
@ -399,7 +399,7 @@ class ReWOOEngine:
) )
# ── Phase 2: Execution ── # ── Phase 2: Execution ──
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
# 协作式取消检查 # 协作式取消检查
if cancellation_token is not None: if cancellation_token is not None:
@ -524,10 +524,10 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
timeout_seconds: float | None = None, timeout_seconds: float | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
): ):
"""Execute ReWOO flow, yielding ReActEvent objects. """Execute ReWOO flow, yielding ReActEvent objects.
@ -637,7 +637,7 @@ class ReWOOEngine:
# Empty plan: direct answer # Empty plan: direct answer
if not plan.steps: if not plan.steps:
llm_messages: list[dict[str, Any]] = [] llm_messages: list[dict[str, object]] = []
if effective_system_prompt: if effective_system_prompt:
llm_messages.append({"role": "system", "content": effective_system_prompt}) llm_messages.append({"role": "system", "content": effective_system_prompt})
llm_messages.extend(messages) llm_messages.extend(messages)
@ -676,7 +676,7 @@ class ReWOOEngine:
return return
# ── Phase 2: Execution ── # ── Phase 2: Execution ──
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
if cancellation_token is not None: if cancellation_token is not None:
cancellation_token.check() cancellation_token.check()
@ -806,10 +806,10 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
total_tokens: int = 0, total_tokens: int = 0,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
): ):
"""Stream version: try fallback strategies in configured order, yielding events from the first successful one. """Stream version: try fallback strategies in configured order, yielding events from the first successful one.
@ -902,7 +902,7 @@ class ReWOOEngine:
"reasoning": plan.reasoning, "reasoning": plan.reasoning,
"steps": [{"step_id": s.step_id, "tool_name": s.tool_name, "arguments": s.arguments, "reasoning": s.reasoning} for s in plan.steps], "steps": [{"step_id": s.step_id, "tool_name": s.tool_name, "arguments": s.arguments, "reasoning": s.reasoning} for s in plan.steps],
}) })
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
if cancellation_token is not None: if cancellation_token is not None:
cancellation_token.check() cancellation_token.check()
@ -934,9 +934,9 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
): ):
"""Stream: ReAct fallback""" """Stream: ReAct fallback"""
logger.warning("ReWOO planning failed in stream mode, falling back to ReActEngine") logger.warning("ReWOO planning failed in stream mode, falling back to ReActEngine")
@ -969,7 +969,7 @@ class ReWOOEngine:
"""Stream: Direct LLM fallback""" """Stream: Direct LLM fallback"""
logger.warning("Falling back to direct LLM call in stream mode") logger.warning("Falling back to direct LLM call in stream mode")
try: try:
direct_messages: list[dict[str, Any]] = [] direct_messages: list[dict[str, object]] = []
if effective_system_prompt: if effective_system_prompt:
direct_messages.append({"role": "system", "content": effective_system_prompt}) direct_messages.append({"role": "system", "content": effective_system_prompt})
direct_messages.extend(messages) direct_messages.extend(messages)
@ -1012,7 +1012,7 @@ class ReWOOEngine:
"reasoning": plan.reasoning, "reasoning": plan.reasoning,
"steps": [{"step_id": s.step_id, "tool_name": s.tool_name, "arguments": s.arguments, "reasoning": s.reasoning} for s in plan.steps], "steps": [{"step_id": s.step_id, "tool_name": s.tool_name, "arguments": s.arguments, "reasoning": s.reasoning} for s in plan.steps],
}) })
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
if cancellation_token is not None: if cancellation_token is not None:
cancellation_token.check() cancellation_token.check()
@ -1043,11 +1043,11 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
trajectory: list[ReActStep] | None = None, trajectory: list[ReActStep] | None = None,
total_tokens: int = 0, total_tokens: int = 0,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult | None: ) -> ReActResult | None:
"""按配置的 fallback 策略顺序尝试回退,返回第一个成功的结果 """按配置的 fallback 策略顺序尝试回退,返回第一个成功的结果
@ -1136,7 +1136,7 @@ class ReWOOEngine:
# Execute the simplified plan # Execute the simplified plan
trajectory: list[ReActStep] = [] trajectory: list[ReActStep] = []
total_tokens = simplified_tokens total_tokens = simplified_tokens
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
if cancellation_token is not None: if cancellation_token is not None:
cancellation_token.check() cancellation_token.check()
@ -1195,9 +1195,9 @@ class ReWOOEngine:
memory_retriever: "MemoryRetriever | None" = None, memory_retriever: "MemoryRetriever | None" = None,
task_id: str | None = None, task_id: str | None = None,
compressor: "CompressionStrategy | None" = None, compressor: "CompressionStrategy | None" = None,
retrieval_config: dict[str, Any] | None = None, retrieval_config: dict[str, object] | None = None,
cancellation_token: CancellationToken | None = None, cancellation_token: CancellationToken | None = None,
confirmation_handler: Any | None = None, confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult | None: ) -> ReActResult | None:
"""ReAct fallback: delegate to ReActEngine""" """ReAct fallback: delegate to ReActEngine"""
logger.warning("ReWOO planning failed, falling back to ReActEngine") logger.warning("ReWOO planning failed, falling back to ReActEngine")
@ -1240,7 +1240,7 @@ class ReWOOEngine:
"""Direct fallback: simple LLM call without tools""" """Direct fallback: simple LLM call without tools"""
logger.warning("Falling back to direct LLM call") logger.warning("Falling back to direct LLM call")
try: try:
direct_messages: list[dict[str, Any]] = [] direct_messages: list[dict[str, object]] = []
if effective_system_prompt: if effective_system_prompt:
direct_messages.append({"role": "system", "content": effective_system_prompt}) direct_messages.append({"role": "system", "content": effective_system_prompt})
direct_messages.extend(messages) direct_messages.extend(messages)
@ -1319,7 +1319,7 @@ class ReWOOEngine:
if plan is not None and plan.steps: if plan is not None and plan.steps:
trajectory: list[ReActStep] = [] trajectory: list[ReActStep] = []
total_tokens = plan_tokens total_tokens = plan_tokens
tool_results: list[dict[str, Any]] = [] tool_results: list[dict[str, object]] = []
for plan_step in plan.steps: for plan_step in plan.steps:
if cancellation_token is not None: if cancellation_token is not None:
cancellation_token.check() cancellation_token.check()
@ -1396,7 +1396,7 @@ class ReWOOEngine:
tool_descriptions = self._build_tool_descriptions(tools) tool_descriptions = self._build_tool_descriptions(tools)
# 构建规划消息 # 构建规划消息
planning_messages: list[dict[str, Any]] = [ planning_messages: list[dict[str, object]] = [
{"role": "system", "content": _PLANNING_SYSTEM_PROMPT}, {"role": "system", "content": _PLANNING_SYSTEM_PROMPT},
] ]
@ -1451,7 +1451,7 @@ class ReWOOEngine:
async def _synthesis_phase( async def _synthesis_phase(
self, self,
messages: list[dict[str, str]], messages: list[dict[str, str]],
tool_results: list[dict[str, Any]], tool_results: list[dict[str, object]],
model: str, model: str,
agent_name: str, agent_name: str,
task_type: str, task_type: str,
@ -1468,7 +1468,7 @@ class ReWOOEngine:
cancellation_token.check() cancellation_token.check()
# 构建综合消息 # 构建综合消息
synthesis_messages: list[dict[str, Any]] = [ synthesis_messages: list[dict[str, object]] = [
{"role": "system", "content": _SYNTHESIS_SYSTEM_PROMPT}, {"role": "system", "content": _SYNTHESIS_SYSTEM_PROMPT},
] ]
@ -1600,7 +1600,7 @@ class ReWOOEngine:
return None return None
async def _execute_tool( async def _execute_tool(
self, tool_name: str, arguments: dict[str, Any], tools: list[Tool] self, tool_name: str, arguments: dict[str, object], tools: list[Tool]
) -> dict: ) -> dict:
"""执行工具调用,处理成功和失败情况""" """执行工具调用,处理成功和失败情况"""
tool = self._find_tool(tool_name, tools) tool = self._find_tool(tool_name, tools)

View File

@ -9,7 +9,7 @@ import asyncio
import json import json
import logging import logging
import re import re
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from .expert import Expert from .expert import Expert
from .plan import PhaseStatus, PlanPhase, TeamPlan from .plan import PhaseStatus, PlanPhase, TeamPlan
@ -28,7 +28,7 @@ class DebateRunnerMixin:
_phase_semaphore: asyncio.Semaphore _phase_semaphore: asyncio.Semaphore
MAX_DEBATE_ROUNDS: int MAX_DEBATE_ROUNDS: int
async def _execute_debate_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, Any]: async def _execute_debate_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, object]:
"""Execute a DEBATE phase: Lead-facilitated structured debate (5 stages). """Execute a DEBATE phase: Lead-facilitated structured debate (5 stages).
Parse config Lead opens experts argue in parallel rounds Lead Parse config Lead opens experts argue in parallel rounds Lead
summarizes Lead adjudicates write conclusion to workspace.""" summarizes Lead adjudicates write conclusion to workspace."""
@ -86,7 +86,7 @@ class DebateRunnerMixin:
) )
# Debate history for context (Lead opening + expert arguments + Lead summaries) # Debate history for context (Lead opening + expert arguments + Lead summaries)
history: list[dict[str, Any]] = [ history: list[dict[str, object]] = [
{"expert": lead.config.name, "content": opening, "round": 0, "role": "moderator"} {"expert": lead.config.name, "content": opening, "round": 0, "role": "moderator"}
] ]
@ -103,7 +103,7 @@ class DebateRunnerMixin:
break break
# Experts argue in parallel (with concurrency limit) # Experts argue in parallel (with concurrency limit)
async def _bounded_debate(e: Any) -> str: async def _bounded_debate(e: object) -> str:
async with self._phase_semaphore: async with self._phase_semaphore:
return await self._generate_debate_argument(e, topic, history, round_num) return await self._generate_debate_argument(e, topic, history, round_num)
@ -234,7 +234,7 @@ class DebateRunnerMixin:
return f"辩论主题:{topic}。请各位专家发表看法。" return f"辩论主题:{topic}。请各位专家发表看法。"
async def _generate_debate_argument( async def _generate_debate_argument(
self, expert: Expert, topic: str, history: list[dict[str, Any]], round_num: int self, expert: Expert, topic: str, history: list[dict[str, object]], round_num: int
) -> str: ) -> str:
"""Generate an expert's debate argument for the current round.""" """Generate an expert's debate argument for the current round."""
gateway = self._get_llm_gateway(expert) gateway = self._get_llm_gateway(expert)
@ -269,7 +269,7 @@ class DebateRunnerMixin:
return response.content.strip() return response.content.strip()
async def _generate_debate_summary( async def _generate_debate_summary(
self, lead: Expert, topic: str, history: list[dict[str, Any]], round_num: int self, lead: Expert, topic: str, history: list[dict[str, object]], round_num: int
) -> str: ) -> str:
"""Generate Lead's summary of the current debate round.""" """Generate Lead's summary of the current debate round."""
gateway = self._get_llm_gateway(lead) gateway = self._get_llm_gateway(lead)
@ -307,8 +307,8 @@ class DebateRunnerMixin:
return f"[第 {round_num} 轮辩论完成,小结生成失败]" return f"[第 {round_num} 轮辩论完成,小结生成失败]"
async def _generate_debate_verdict( async def _generate_debate_verdict(
self, lead: Expert, topic: str, history: list[dict[str, Any]] self, lead: Expert, topic: str, history: list[dict[str, object]]
) -> dict[str, Any]: ) -> dict[str, object]:
"""Generate Lead's final verdict for the debate.""" """Generate Lead's final verdict for the debate."""
gateway = self._get_llm_gateway(lead) gateway = self._get_llm_gateway(lead)
if not gateway: if not gateway:
@ -371,7 +371,7 @@ class DebateRunnerMixin:
"conclusion": f"辩论主题:{topic}。裁决生成失败,建议参考辩论历史自行判断。", "conclusion": f"辩论主题:{topic}。裁决生成失败,建议参考辩论历史自行判断。",
} }
def _format_debate_history(self, history: list[dict[str, Any]]) -> str: def _format_debate_history(self, history: list[dict[str, object]]) -> str:
"""Format debate history as readable text for LLM prompts.""" """Format debate history as readable text for LLM prompts."""
if not history: if not history:
return "" return ""

View File

@ -6,7 +6,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from .expert import Expert from .expert import Expert
from .plan import PhaseStatus, PhaseType, PlanPhase, TeamPlan from .plan import PhaseStatus, PhaseType, PlanPhase, TeamPlan
@ -23,7 +23,7 @@ class DivergenceDetectorMixin:
# Shared state provided by TeamOrchestrator (annotations only) # Shared state provided by TeamOrchestrator (annotations only)
_team: ExpertTeam _team: ExpertTeam
_debate_count: int _debate_count: int
_checkpoint: Any _checkpoint: object
MAX_DEBATES: int MAX_DEBATES: int
async def _maybe_add_plan_review_debate(self, lead: Expert, plan: TeamPlan, task: str) -> None: async def _maybe_add_plan_review_debate(self, lead: Expert, plan: TeamPlan, task: str) -> None:

View File

@ -9,7 +9,7 @@ import asyncio
import copy import copy
import logging import logging
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from agentkit.core.config_driven import ConfigDrivenAgent from agentkit.core.config_driven import ConfigDrivenAgent
from agentkit.core.protocol import TaskMessage, TaskResult, TaskStatus from agentkit.core.protocol import TaskMessage, TaskResult, TaskStatus
@ -37,7 +37,7 @@ class PhaseExecutorMixin:
# U4: State offloading helpers — keep memory lean for long-horizon runs. # U4: State offloading helpers — keep memory lean for long-horizon runs.
_OFFLOAD_SUMMARY_LIMIT = 500 _OFFLOAD_SUMMARY_LIMIT = 500
def _offload_result(self, content: str, ref_key: str) -> dict[str, Any]: def _offload_result(self, content: str, ref_key: str) -> dict[str, object]:
"""Create an offloaded result: summary in memory, full content in workspace.""" """Create an offloaded result: summary in memory, full content in workspace."""
if not isinstance(content, str): if not isinstance(content, str):
content = str(content) if content is not None else "" content = str(content) if content is not None else ""
@ -64,17 +64,17 @@ class PhaseExecutorMixin:
logger.warning(f"Failed to read offloaded output '{ref_key}': {e}") logger.warning(f"Failed to read offloaded output '{ref_key}': {e}")
return content return content
async def _execute_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, Any]: async def _execute_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, object]:
"""Execute a single phase, dispatching by phase_type.""" """Execute a single phase, dispatching by phase_type."""
if phase.phase_type == PhaseType.DEBATE: if phase.phase_type == PhaseType.DEBATE:
return await self._execute_debate_phase(phase, plan) return await self._execute_debate_phase(phase, plan)
return await self._execute_execution_phase(phase, plan) return await self._execute_execution_phase(phase, plan)
async def _execute_execution_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, Any]: async def _execute_execution_phase(self, phase: PlanPhase, plan: TeamPlan) -> dict[str, object]:
"""Execute a standard EXECUTION phase. Split into 3 sub-methods (U2, KTD3 isolation).""" """Execute a standard EXECUTION phase. Split into 3 sub-methods (U2, KTD3 isolation)."""
expert, agent, lead = await self._prepare_phase_context(phase, plan) expert, agent, lead = await self._prepare_phase_context(phase, plan)
last_error: str | None = None last_error: str | None = None
result: dict[str, Any] | None = None result: dict[str, object] | None = None
try: try:
# U3: 返工循环 — 最多 MAX_REWORKS + 1 次1 次初始 + MAX_REWORKS 次返工) # U3: 返工循环 — 最多 MAX_REWORKS + 1 次1 次初始 + MAX_REWORKS 次返工)
@ -135,11 +135,11 @@ class PhaseExecutorMixin:
self, self,
expert: Expert, expert: Expert,
phase: PlanPhase, phase: PlanPhase,
dependency_outputs: dict[str, Any], dependency_outputs: dict[str, object],
collaboration_outputs: dict[str, str], collaboration_outputs: dict[str, str],
) -> TaskMessage: ) -> TaskMessage:
"""Build TaskMessage for execution with context isolation.""" """Build TaskMessage for execution with context isolation."""
input_data: dict[str, Any] = { input_data: dict[str, object] = {
"task": phase.task_description, "task": phase.task_description,
"team_id": self._team.team_id, "team_id": self._team.team_id,
"phase_id": phase.id, "phase_id": phase.id,
@ -180,12 +180,12 @@ class PhaseExecutorMixin:
lead: Expert, lead: Expert,
phase: PlanPhase, phase: PlanPhase,
plan: TeamPlan, plan: TeamPlan,
) -> tuple[dict[str, Any], str | None, bool, str, bool]: ) -> tuple[dict[str, object], str | None, bool, str, bool]:
"""Run one rework iteration: read deps, build input, execute, review. Returns """Run one rework iteration: read deps, build input, execute, review. Returns
(result, last_error, passed, feedback, degraded). Raises RuntimeError on retry (result, last_error, passed, feedback, degraded). Raises RuntimeError on retry
exhaustion.""" exhaustion."""
# 每次迭代重新读取依赖输出(前置阶段可能在返工期间完成) # 每次迭代重新读取依赖输出(前置阶段可能在返工期间完成)
dependency_outputs: dict[str, Any] = {} dependency_outputs: dict[str, object] = {}
for dep_id in phase.depends_on: for dep_id in phase.depends_on:
dep_phase = plan.get_phase(dep_id) dep_phase = plan.get_phase(dep_id)
if dep_phase and dep_phase.status == PhaseStatus.COMPLETED and dep_phase.result: if dep_phase and dep_phase.status == PhaseStatus.COMPLETED and dep_phase.result:
@ -216,7 +216,7 @@ class PhaseExecutorMixin:
# 执行专家任务带重试MAX_RETRIES 处理瞬时失败) # 执行专家任务带重试MAX_RETRIES 处理瞬时失败)
last_error: str | None = None last_error: str | None = None
result: dict[str, Any] | None = None result: dict[str, object] | None = None
for attempt in range(self.MAX_RETRIES + 1): for attempt in range(self.MAX_RETRIES + 1):
try: try:
task_result: TaskResult = await agent.execute(task_msg) task_result: TaskResult = await agent.execute(task_msg)
@ -265,7 +265,7 @@ class PhaseExecutorMixin:
lead: Expert, lead: Expert,
phase: PlanPhase, phase: PlanPhase,
plan: TeamPlan, plan: TeamPlan,
result: dict[str, Any], result: dict[str, object],
passed: bool, passed: bool,
feedback: str, feedback: str,
degraded: bool = False, degraded: bool = False,

View File

@ -10,7 +10,6 @@ import json
import logging import logging
import re import re
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from agentkit.core.exceptions import LLMProviderError from agentkit.core.exceptions import LLMProviderError
@ -45,7 +44,7 @@ class ReviewGateMixin:
"""Mixin: Lead 验收阶段输出质量 + 解析风险标记。由 TeamOrchestrator 组合。""" """Mixin: Lead 验收阶段输出质量 + 解析风险标记。由 TeamOrchestrator 组合。"""
async def _review_phase_output( async def _review_phase_output(
self, lead: Expert, phase: PlanPhase, result: dict[str, Any] self, lead: Expert, phase: PlanPhase, result: dict[str, object]
) -> ReviewResult: ) -> ReviewResult:
"""Lead 验收阶段输出质量。 """Lead 验收阶段输出质量。
@ -93,7 +92,7 @@ class ReviewGateMixin:
) )
# P2: 优先尝试直接解析整个响应为 JSON避免贪婪正则匹配过多 # P2: 优先尝试直接解析整个响应为 JSON避免贪婪正则匹配过多
review: dict[str, Any] | None = None review: dict[str, object] | None = None
try: try:
review = json.loads(response.content) review = json.loads(response.content)
except (json.JSONDecodeError, TypeError): except (json.JSONDecodeError, TypeError):

View File

@ -6,7 +6,7 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from agentkit.orchestrator.rollback import RollbackExecutor from agentkit.orchestrator.rollback import RollbackExecutor
@ -27,7 +27,7 @@ class RollbackHandlerMixin:
_rollback_timeout: float _rollback_timeout: float
async def _mark_dependents_failed( async def _mark_dependents_failed(
self, failed_phase_id: str, plan: TeamPlan, phase_results: dict[str, dict[str, Any]] self, failed_phase_id: str, plan: TeamPlan, phase_results: dict[str, dict[str, object]]
) -> None: ) -> None:
"""Mark all phases that depend on the failed phase as FAILED.""" """Mark all phases that depend on the failed phase as FAILED."""
for ph in plan.phases: for ph in plan.phases:

View File

@ -7,7 +7,7 @@ from __future__ import annotations
import logging import logging
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING
from agentkit.core.protocol import TaskMessage, TaskResult from agentkit.core.protocol import TaskMessage, TaskResult
@ -29,7 +29,7 @@ class SynthesizerMixin:
async def _synthesize_results( async def _synthesize_results(
self, lead: Expert, task: str, completed_phases: list[PlanPhase] self, lead: Expert, task: str, completed_phases: list[PlanPhase]
) -> dict[str, Any]: ) -> dict[str, object]:
"""Lead Expert synthesizes results using BEST strategy. """Lead Expert synthesizes results using BEST strategy.
The Lead Expert evaluates all completed phase results and produces The Lead Expert evaluates all completed phase results and produces
@ -114,8 +114,8 @@ class SynthesizerMixin:
self, self,
task: str, task: str,
plan: TeamPlan, plan: TeamPlan,
phase_results: dict[str, dict[str, Any]], phase_results: dict[str, dict[str, object]],
) -> dict[str, Any]: ) -> dict[str, object]:
"""Fallback to single agent mode when pipeline execution fails. """Fallback to single agent mode when pipeline execution fails.
Uses the lead expert (or first active expert) to complete the original task. Uses the lead expert (or first active expert) to complete the original task.
@ -128,7 +128,7 @@ class SynthesizerMixin:
active = self._team.active_experts active = self._team.active_experts
expert = active[0] if active else None expert = active[0] if active else None
fallback_result: dict[str, Any] | None = None fallback_result: dict[str, object] | None = None
if expert: if expert:
try: try:
task_msg = TaskMessage( task_msg = TaskMessage(

View File

@ -16,7 +16,6 @@ import enum
import logging import logging
import time import time
import uuid import uuid
from typing import Any
from .config import ExpertConfig from .config import ExpertConfig
from .expert import Expert from .expert import Expert
@ -72,7 +71,7 @@ class BoardTeam:
# Discussion state # Discussion state
self._topic: str = "" self._topic: str = ""
self._history: list[dict[str, Any]] = [] self._history: list[dict[str, object]] = []
self._current_round: int = 0 self._current_round: int = 0
self._max_rounds: int = max_rounds self._max_rounds: int = max_rounds
self._user_interventions: list[str] = [] # Pending user messages self._user_interventions: list[str] = [] # Pending user messages
@ -125,7 +124,7 @@ class BoardTeam:
return self._max_rounds return self._max_rounds
@property @property
def history(self) -> list[dict[str, Any]]: def history(self) -> list[dict[str, object]]:
return self._history.copy() return self._history.copy()
def get_expert(self, name: str) -> Expert | None: def get_expert(self, name: str) -> Expert | None:
@ -254,7 +253,7 @@ class BoardTeam:
return "\n\n---\n\n".join(lines) return "\n\n---\n\n".join(lines)
async def compress_history(self, moderator: Expert, llm_gateway: Any) -> None: async def compress_history(self, moderator: Expert, llm_gateway: object) -> None:
"""Compress discussion history when it exceeds token threshold. """Compress discussion history when it exceeds token threshold.
The moderator summarizes each round's key points, replacing The moderator summarizes each round's key points, replacing
@ -291,7 +290,7 @@ class BoardTeam:
# Parse compressed history back to entries # Parse compressed history back to entries
# This is a best-effort compression; if parsing fails, keep original # This is a best-effort compression; if parsing fails, keep original
new_history: list[dict[str, Any]] = [] new_history: list[dict[str, object]] = []
current_round = 0 current_round = 0
for line in compressed.split("\n"): for line in compressed.split("\n"):
line = line.strip() line = line.strip()

View File

@ -19,7 +19,6 @@ from __future__ import annotations
import asyncio import asyncio
import logging import logging
from typing import Any
from .expert import Expert from .expert import Expert
from .board import BoardTeam, BoardStatus from .board import BoardTeam, BoardStatus
@ -43,7 +42,7 @@ class BoardOrchestrator:
def __init__(self, team: BoardTeam) -> None: def __init__(self, team: BoardTeam) -> None:
self._team = team self._team = team
async def execute(self, topic: str) -> dict[str, Any]: async def execute(self, topic: str) -> dict[str, object]:
"""Execute a board meeting discussion. """Execute a board meeting discussion.
Flow: Flow:
@ -351,7 +350,7 @@ class BoardOrchestrator:
logger.warning(f"Moderator summary generation failed: {e}") logger.warning(f"Moderator summary generation failed: {e}")
return f"[第 {round} 轮讨论完成,主持人小结生成失败]" return f"[第 {round} 轮讨论完成,主持人小结生成失败]"
async def _generate_final_conclusion(self, moderator: Expert, topic: str) -> dict[str, Any]: async def _generate_final_conclusion(self, moderator: Expert, topic: str) -> dict[str, object]:
"""Generate moderator's final conclusion. """Generate moderator's final conclusion.
The moderator gives: The moderator gives:
@ -428,7 +427,7 @@ class BoardOrchestrator:
"dissent_points": [], "dissent_points": [],
} }
async def _generate_fallback_conclusion(self, moderator: Expert, topic: str) -> dict[str, Any]: async def _generate_fallback_conclusion(self, moderator: Expert, topic: str) -> dict[str, object]:
"""Generate a fallback conclusion when execution fails. """Generate a fallback conclusion when execution fails.
Uses existing discussion history to provide a basic summary. Uses existing discussion history to provide a basic summary.
@ -491,7 +490,7 @@ class BoardOrchestrator:
return True return True
return False return False
def _get_llm_gateway(self, expert: Expert | None = None) -> Any: def _get_llm_gateway(self, expert: Expert | None = None) -> object:
"""Get LLM gateway from the given expert or the moderator's agent. """Get LLM gateway from the given expert or the moderator's agent.
Falls back to other active experts if the primary target has no gateway. Falls back to other active experts if the primary target has no gateway.
@ -509,7 +508,7 @@ class BoardOrchestrator:
return gateway return gateway
return None return None
async def _broadcast_event(self, event_type: str, data: dict[str, Any]) -> None: async def _broadcast_event(self, event_type: str, data: dict[str, object]) -> None:
"""Broadcast a board event to the team channel. """Broadcast a board event to the team channel.
Events are emitted via handoff_transport for WebSocket relay. Events are emitted via handoff_transport for WebSocket relay.

View File

@ -3,7 +3,6 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any
from agentkit.core.config_driven import AgentConfig from agentkit.core.config_driven import AgentConfig
@ -24,12 +23,12 @@ class ExpertConfig(AgentConfig):
task_mode: str = "llm_generate", task_mode: str = "llm_generate",
supported_tasks: list[str] | None = None, supported_tasks: list[str] | None = None,
max_concurrency: int = 1, max_concurrency: int = 1,
input_schema: dict[str, Any] | None = None, input_schema: dict[str, object] | None = None,
output_schema: dict[str, Any] | None = None, output_schema: dict[str, object] | None = None,
prompt: dict[str, str] | None = None, prompt: dict[str, str] | None = None,
llm: dict[str, Any] | None = None, llm: dict[str, object] | None = None,
tools: list[str] | None = None, tools: list[str] | None = None,
memory: dict[str, Any] | None = None, memory: dict[str, object] | None = None,
custom_handler: str | None = None, custom_handler: str | None = None,
# Expert 专属字段 # Expert 专属字段
persona: str = "", persona: str = "",
@ -70,7 +69,7 @@ class ExpertConfig(AgentConfig):
self.decision_framework = decision_framework self.decision_framework = decision_framework
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> ExpertConfig: def from_dict(cls, data: dict[str, object]) -> ExpertConfig:
"""从字典创建配置""" """从字典创建配置"""
return cls( return cls(
name=data["name"], name=data["name"],
@ -98,7 +97,7 @@ class ExpertConfig(AgentConfig):
decision_framework=data.get("decision_framework", ""), decision_framework=data.get("decision_framework", ""),
) )
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典,包含 Expert 专属字段""" """序列化为字典,包含 Expert 专属字段"""
d = super().to_dict() d = super().to_dict()
d["persona"] = self.persona d["persona"] = self.persona
@ -125,7 +124,7 @@ class ExpertTemplate:
is_builtin: bool = False is_builtin: bool = False
description: str = "" description: str = ""
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
return { return {
"name": self.name, "name": self.name,
@ -135,7 +134,7 @@ class ExpertTemplate:
} }
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> ExpertTemplate: def from_dict(cls, data: dict[str, object]) -> ExpertTemplate:
"""从字典创建模板""" """从字典创建模板"""
config_data = data["config"] config_data = data["config"]
config = ExpertConfig.from_dict(config_data) config = ExpertConfig.from_dict(config_data)

View File

@ -14,7 +14,6 @@ import asyncio
import json import json
import logging import logging
import re import re
from typing import Any
from agentkit.core.exceptions import LLMProviderError from agentkit.core.exceptions import LLMProviderError
from agentkit.llm.gateway import LLMGateway from agentkit.llm.gateway import LLMGateway
@ -72,7 +71,7 @@ class TeamOrchestrator(
self, self,
team: ExpertTeam, team: ExpertTeam,
max_concurrent_phases: int | None = None, max_concurrent_phases: int | None = None,
checkpoint: Any = None, checkpoint: object | None = None,
workspace_root: str | None = None, workspace_root: str | None = None,
rollback_timeout: float | None = None, rollback_timeout: float | None = None,
) -> None: ) -> None:
@ -95,7 +94,7 @@ class TeamOrchestrator(
self._workspace_root = workspace_root self._workspace_root = workspace_root
self._rollback_timeout = rollback_timeout or self.DEFAULT_ROLLBACK_TIMEOUT self._rollback_timeout = rollback_timeout or self.DEFAULT_ROLLBACK_TIMEOUT
async def execute(self, task: str) -> dict[str, Any]: async def execute(self, task: str) -> dict[str, object]:
"""Execute a task in pipeline mode. Lead decomposes → topological sort → """Execute a task in pipeline mode. Lead decomposes → topological sort →
execute layers (parallel within layer) synthesize. Returns dict with execute layers (parallel within layer) synthesize. Returns dict with
status/result/phase_results/plan.""" status/result/phase_results/plan."""
@ -175,7 +174,7 @@ class TeamOrchestrator(
# 4. Set EXECUTING status, execute phases # 4. Set EXECUTING status, execute phases
self._team.set_status(TeamStatus.EXECUTING) self._team.set_status(TeamStatus.EXECUTING)
phase_results: dict[str, dict[str, Any]] = {} phase_results: dict[str, dict[str, object]] = {}
return await self._run_pipeline(lead, plan, phase_results, task) return await self._run_pipeline(lead, plan, phase_results, task)
@ -183,9 +182,9 @@ class TeamOrchestrator(
self, self,
lead: Expert, lead: Expert,
plan: TeamPlan, plan: TeamPlan,
phase_results: dict[str, dict[str, Any]], phase_results: dict[str, dict[str, object]],
task: str, task: str,
) -> dict[str, Any]: ) -> dict[str, object]:
"""Execute the pipeline loop: run pending phases, synthesize, return result. """Execute the pipeline loop: run pending phases, synthesize, return result.
Shared by execute() and resume(). phase_results may be pre-populated Shared by execute() and resume(). phase_results may be pre-populated
@ -220,7 +219,7 @@ class TeamOrchestrator(
break break
# Execute all phases in this layer in parallel (with concurrency limit) # Execute all phases in this layer in parallel (with concurrency limit)
async def _bounded_phase(ph: PlanPhase) -> dict[str, Any]: async def _bounded_phase(ph: PlanPhase) -> dict[str, object]:
async with self._phase_semaphore: async with self._phase_semaphore:
return await self._execute_phase(ph, plan) return await self._execute_phase(ph, plan)
@ -335,7 +334,7 @@ class TeamOrchestrator(
await self._broadcast_event("team_dissolved", {"team_id": self._team.team_id}) await self._broadcast_event("team_dissolved", {"team_id": self._team.team_id})
return await self._fallback_to_single_agent(task, plan, phase_results) return await self._fallback_to_single_agent(task, plan, phase_results)
async def resume(self, plan_id: str) -> dict[str, Any]: async def resume(self, plan_id: str) -> dict[str, object]:
"""Resume from last checkpoint: load plan, restore completed/failed phases, """Resume from last checkpoint: load plan, restore completed/failed phases,
continue via _run_pipeline. Returns same dict shape as execute().""" continue via _run_pipeline. Returns same dict shape as execute()."""
if self._checkpoint is None: if self._checkpoint is None:
@ -362,7 +361,7 @@ class TeamOrchestrator(
# 3. Load checkpoints, mark completed phases # 3. Load checkpoints, mark completed phases
checkpoints = await self._checkpoint.list_checkpoints(plan_id) checkpoints = await self._checkpoint.list_checkpoints(plan_id)
phase_results: dict[str, dict[str, Any]] = {} phase_results: dict[str, dict[str, object]] = {}
completed_phase_ids: set[str] = set() completed_phase_ids: set[str] = set()
failed_phase_ids: set[str] = set() failed_phase_ids: set[str] = set()
@ -492,7 +491,7 @@ class TeamOrchestrator(
# First pass: create phases with IDs, build name->id mapping # First pass: create phases with IDs, build name->id mapping
name_to_id: dict[str, str] = {} name_to_id: dict[str, str] = {}
raw_phases: list[dict[str, Any]] = [] raw_phases: list[dict[str, object]] = []
for item in items: for item in items:
if not isinstance(item, dict): if not isinstance(item, dict):
@ -584,7 +583,7 @@ class TeamOrchestrator(
return gateway return gateway
return None return None
async def _broadcast_event(self, event_type: str, data: dict[str, Any]) -> None: async def _broadcast_event(self, event_type: str, data: dict[str, object]) -> None:
"""Broadcast an orchestration event to the team channel via handoff_transport.""" """Broadcast an orchestration event to the team channel via handoff_transport."""
if self._team.handoff_transport: if self._team.handoff_transport:
try: try:

View File

@ -15,7 +15,6 @@ from __future__ import annotations
import enum import enum
import uuid import uuid
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Any
class MergeStrategy(str, enum.Enum): class MergeStrategy(str, enum.Enum):
@ -82,9 +81,9 @@ class SubTask:
description: str = "" description: str = ""
assigned_expert: str = "" assigned_expert: str = ""
status: SubTaskStatus = SubTaskStatus.PENDING status: SubTaskStatus = SubTaskStatus.PENDING
result: dict[str, Any] | None = None result: dict[str, object] | None = None
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
return { return {
"id": self.id, "id": self.id,
@ -95,7 +94,7 @@ class SubTask:
} }
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> SubTask: def from_dict(cls, data: dict[str, object]) -> SubTask:
"""从字典创建 SubTask""" """从字典创建 SubTask"""
return cls( return cls(
id=data.get("id", str(uuid.uuid4())), id=data.get("id", str(uuid.uuid4())),
@ -124,7 +123,7 @@ class CollaborationContract:
content_description: str = "" content_description: str = ""
status: str = "pending" status: str = "pending"
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
return { return {
"from_expert": self.from_expert, "from_expert": self.from_expert,
@ -134,7 +133,7 @@ class CollaborationContract:
} }
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> CollaborationContract: def from_dict(cls, data: dict[str, object]) -> CollaborationContract:
"""从字典创建 CollaborationContract""" """从字典创建 CollaborationContract"""
return cls( return cls(
from_expert=data.get("from_expert", ""), from_expert=data.get("from_expert", ""),
@ -176,9 +175,9 @@ class PlanPhase:
task_description: str = "" task_description: str = ""
depends_on: list[str] = field(default_factory=list) depends_on: list[str] = field(default_factory=list)
status: PhaseStatus = PhaseStatus.PENDING status: PhaseStatus = PhaseStatus.PENDING
result: dict[str, Any] | None = None result: dict[str, object] | None = None
phase_type: PhaseType = PhaseType.EXECUTION phase_type: PhaseType = PhaseType.EXECUTION
debate_config: dict[str, Any] | None = None debate_config: dict[str, object] | None = None
collaboration_contracts: list[CollaborationContract] = field(default_factory=list) collaboration_contracts: list[CollaborationContract] = field(default_factory=list)
rework_count: int = 0 rework_count: int = 0
review_feedback: str | None = None review_feedback: str | None = None
@ -188,7 +187,7 @@ class PlanPhase:
validation_command: str | None = None validation_command: str | None = None
rollback_command: str | None = None rollback_command: str | None = None
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
# Serialize result to string to match frontend ITeamPlanPhase.result type # Serialize result to string to match frontend ITeamPlanPhase.result type
result_str: str | None = None result_str: str | None = None
@ -197,7 +196,7 @@ class PlanPhase:
result_str = self.result.get("content", str(self.result)) result_str = self.result.get("content", str(self.result))
else: else:
result_str = str(self.result) result_str = str(self.result)
out: dict[str, Any] = { out: dict[str, object] = {
"id": self.id, "id": self.id,
"name": self.name, "name": self.name,
"assigned_expert": self.assigned_expert, "assigned_expert": self.assigned_expert,
@ -219,7 +218,7 @@ class PlanPhase:
return out return out
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> PlanPhase: def from_dict(cls, data: dict[str, object]) -> PlanPhase:
"""从字典创建 PlanPhase""" """从字典创建 PlanPhase"""
contracts_data = data.get("collaboration_contracts", []) contracts_data = data.get("collaboration_contracts", [])
if not isinstance(contracts_data, list): if not isinstance(contracts_data, list):
@ -272,7 +271,7 @@ class TeamPlan:
status: PlanStatus = PlanStatus.DRAFT status: PlanStatus = PlanStatus.DRAFT
lead_expert: str = "" lead_expert: str = ""
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, object]:
"""序列化为字典""" """序列化为字典"""
return { return {
"id": self.id, "id": self.id,
@ -284,7 +283,7 @@ class TeamPlan:
} }
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any]) -> TeamPlan: def from_dict(cls, data: dict[str, object]) -> TeamPlan:
"""从字典创建 TeamPlan""" """从字典创建 TeamPlan"""
subtasks = [SubTask.from_dict(st) for st in data.get("subtasks", [])] subtasks = [SubTask.from_dict(st) for st in data.get("subtasks", [])]
phases = [PlanPhase.from_dict(ph) for ph in data.get("phases", [])] phases = [PlanPhase.from_dict(ph) for ph in data.get("phases", [])]
@ -307,7 +306,7 @@ class TeamPlan:
return None return None
def update_subtask_status( def update_subtask_status(
self, subtask_id: str, status: SubTaskStatus, result: dict[str, Any] | None = None self, subtask_id: str, status: SubTaskStatus, result: dict[str, object] | None = None
) -> None: ) -> None:
"""更新子任务状态和可选的结果""" """更新子任务状态和可选的结果"""
st = self.get_subtask(subtask_id) st = self.get_subtask(subtask_id)
@ -343,7 +342,7 @@ class TeamPlan:
return None return None
def update_phase_status( def update_phase_status(
self, phase_id: str, status: PhaseStatus, result: dict[str, Any] | None = None self, phase_id: str, status: PhaseStatus, result: dict[str, object] | None = None
) -> None: ) -> None:
"""更新阶段状态和可选的结果""" """更新阶段状态和可选的结果"""
ph = self.get_phase(phase_id) ph = self.get_phase(phase_id)

View File

@ -17,7 +17,6 @@ import enum
import logging import logging
import time import time
import uuid import uuid
from typing import Any
from .config import ExpertConfig from .config import ExpertConfig
from .expert import Expert from .expert import Expert
@ -63,7 +62,7 @@ class ExpertTeam:
workspace: SharedWorkspace | None = None, workspace: SharedWorkspace | None = None,
pool: AgentPool | None = None, pool: AgentPool | None = None,
template_registry: ExpertTemplateRegistry | None = None, template_registry: ExpertTemplateRegistry | None = None,
redis_client: Any = None, redis_client: object | None = None,
): ):
self.team_id = team_id or str(uuid.uuid4()) self.team_id = team_id or str(uuid.uuid4())
# U4: Accept redis_client for SharedWorkspace state offloading. # U4: Accept redis_client for SharedWorkspace state offloading.