refactor: tech debt Wave 1+2 (except Exception 收尾 + core/experts Any 治理) #10

Merged
fischer merged 2 commits from refactor/tech-debt-wave-1-2 into main 2026-07-01 03:54:53 +08:00
19 changed files with 179 additions and 187 deletions
Showing only changes of commit b3f7159fcd - Show all commits

View File

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

View File

@ -10,7 +10,7 @@
import json
import logging
import os
from typing import Any, Callable, Coroutine
from typing import Callable, Coroutine
import yaml
@ -39,12 +39,12 @@ class AgentConfig:
task_mode: str = "llm_generate",
supported_tasks: list[str] | None = None,
max_concurrency: int = 1,
input_schema: dict[str, Any] | None = None,
output_schema: dict[str, Any] | None = None,
input_schema: dict[str, object] | None = None,
output_schema: dict[str, object] | 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,
memory: dict[str, Any] | None = None,
memory: dict[str, object] | None = None,
custom_handler: str | None = None,
):
self.name = name
@ -96,7 +96,7 @@ class AgentConfig:
)
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "AgentConfig":
def from_dict(cls, data: dict[str, object]) -> "AgentConfig":
"""从字典创建配置"""
return cls(
name=data["name"],
@ -128,7 +128,7 @@ class AgentConfig:
)
return cls.from_dict(data)
def to_dict(self) -> dict[str, Any]:
def to_dict(self) -> dict[str, object]:
"""序列化为字典"""
d = {
"name": self.name,
@ -197,11 +197,11 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
self,
config: AgentConfig,
tool_registry: ToolRegistry | None = None,
llm_client: Any = None,
llm_client: object | 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
compressor: Any = None, # CompressionStrategy | None
compressor: object | None = None, # CompressionStrategy | None
):
# v2: If SkillConfig, extract skill info
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}'")
# 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_tools_registered = False
# Memory integration: 从 config.memory 自动实例化 MemoryRetriever
self._memory_retriever: Any | None = None
self._memory_retriever: object | None = None
if config.memory:
try:
from agentkit.memory.retriever import MemoryRetriever
@ -903,7 +903,7 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
)
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"""
from agentkit.llm.gateway import LLMGateway
from agentkit.llm.protocol import LLMProvider, LLMRequest, LLMResponse, TokenUsage
@ -911,7 +911,7 @@ class ConfigDrivenAgent(BaseAgent, EvolutionMixin):
class ClientProvider(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
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 typing import Any
from agentkit.core.exceptions import (
LLMProviderError,
@ -54,7 +53,7 @@ class EmergencyError:
retryable: bool # whether a user retry might succeed
original_error: str # str(exc) for traceability
def to_dict(self) -> dict[str, Any]:
def to_dict(self) -> dict[str, object]:
return {
"error_code": self.error_code,
"message": self.message,

View File

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

View File

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

View File

@ -13,7 +13,7 @@ from collections import Counter, deque
from collections.abc import AsyncGenerator
from dataclasses import dataclass, field
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.protocol import CancellationToken
@ -43,13 +43,13 @@ class ReActStep:
step: int
action: str # "tool_call" or "final_answer"
tool_name: str | None = None
arguments: dict[str, Any] | None = None
result: Any = None
arguments: dict[str, object] | None = None
result: object = None
content: str | None = None
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.
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"
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())
@ -230,7 +230,7 @@ class ReActEngine:
# step and yields phase_violation ReActEvents. Non-streaming execute()
# simply ignores the accumulator (the error dict returned to the LLM is
# the only signal there).
self._phase_violations: list[dict[str, Any]] = []
self._phase_violations: list[dict[str, object]] = []
def reset(self) -> None:
"""Reset internal state for reuse across conversations.
@ -299,8 +299,8 @@ class ReActEngine:
return False
def _check_phase_permission(
self, tool_name: str, arguments: dict[str, Any]
) -> dict[str, Any] | None:
self, tool_name: str, arguments: dict[str, object]
) -> dict[str, object] | None:
"""Return None if tool is allowed; return a structured error dict if blocked.
The error dict replaces what `_execute_tool` would have returned
@ -351,7 +351,7 @@ class ReActEngine:
return violation
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 在窗口内出现
@ -406,10 +406,10 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None,
task_id: str | 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,
timeout_seconds: float | None = None,
confirmation_handler: Any | None = None,
confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> ReActResult:
"""执行 ReAct 循环
@ -536,7 +536,7 @@ class ReActEngine:
async def _run_loop_and_extract(
self,
**kwargs: Any,
**kwargs: object,
) -> ReActResult:
"""Collect all events from _execute_loop and extract the final ReActResult.
@ -564,9 +564,9 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None,
task_id: str | 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,
confirmation_handler: Any | None = None,
confirmation_handler: Callable[..., Awaitable[object]] | None = None,
stream: bool = False,
effective_timeout: float = 0.0,
) -> 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(
stable=system_prompt or "",
volatile=memory_context,
@ -726,7 +726,7 @@ class ReActEngine:
# 流式模式:用 chat_streamyield token events
stream_content_chunks: list[str] = []
stream_usage = None
stream_tool_calls: list[Any] = []
stream_tool_calls: list[object] = []
stream_model = model
# U3/G8: delta_flush 节流 buffer
_flush_buffer: list[str] = []
@ -840,7 +840,7 @@ class ReActEngine:
)
# Act: 记录 assistant 消息(含 tool_calls到对话历史
assistant_msg: dict[str, Any] = {
assistant_msg: dict[str, object] = {
"role": "assistant",
"content": response.content or "",
"tool_calls": [
@ -874,7 +874,7 @@ class ReActEngine:
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)
for i, tc in serial_calls:
@ -1452,10 +1452,10 @@ class ReActEngine:
memory_retriever: "MemoryRetriever | None" = None,
task_id: str | 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,
timeout_seconds: float | None = None,
confirmation_handler: Any | None = None,
confirmation_handler: Callable[..., Awaitable[object]] | None = None,
) -> AsyncGenerator[ReActEvent, None]:
"""Execute ReAct loop, yielding ReActEvent objects.
@ -1514,7 +1514,7 @@ class ReActEngine:
volatile: str,
*,
model: str,
) -> str | list[dict[str, Any]] | None:
) -> str | list[dict[str, object]] | None:
"""构建双块结构 system message(stable + volatile)。
- prompt_cache_enable=False 或无 stable+volatile 返回 str( None)
@ -1535,7 +1535,7 @@ class ReActEngine:
provider_name = self._get_provider_name(model)
if provider_name == "anthropic":
blocks: list[dict[str, Any]] = []
blocks: list[dict[str, object]] = []
if stable:
blocks.append(
{
@ -1675,8 +1675,8 @@ class ReActEngine:
@staticmethod
def _build_response_from_stream(
content: str,
tool_calls: list[Any],
usage: Any,
tool_calls: list[object],
usage: object,
model: str,
) -> LLMResponse:
"""Build an LLMResponse from accumulated stream chunks."""
@ -1723,7 +1723,7 @@ class ReActEngine:
async def _build_tool_result_message(
self,
tool_call_id: str,
result: Any,
result: object,
compressor: "CompressionStrategy | None" = None,
tool_name: str | None = None,
) -> dict:
@ -1742,7 +1742,7 @@ class ReActEngine:
}
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:
"""执行工具调用,处理成功和失败情况"""
# U3/G6: phase enforcement — check before dispatch. If the tool is
@ -1788,11 +1788,11 @@ class ReActEngine:
async def _execute_tool_with_confirmation(
self,
tc: Any,
tc: object,
tools: list[Tool],
step: int,
confirmation_handler: Any,
) -> tuple[Any, list[ReActEvent]]:
confirmation_handler: Callable[..., Awaitable[object]] | None,
) -> tuple[object, list[ReActEvent]]:
"""Execute a tool call with confirmation flow support.
Used in the parallel execution path for serial (non-parallelizable) tools
@ -1886,7 +1886,7 @@ class ReActEngine:
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.
- parallel_tools=True: always parallel (if >1 tool)
@ -1905,7 +1905,7 @@ class ReActEngine:
return len(parallelizable_indices) > 1
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.
LLM marks parallelizable tools by including _parallelizable: true
@ -1918,7 +1918,7 @@ class ReActEngine:
indices.append(i)
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```
3. <tool_use>\n{"name": "...", "arguments": {...}}\n</tool_use>
"""
calls: list[dict[str, Any]] = []
calls: list[dict[str, object]] = []
# 格式 1: Action: tool_name(args)
action_pattern = re.compile(r"Action:\s*(\w+)\((.+?)\)", re.DOTALL)
@ -1999,7 +1999,7 @@ class ReActEngine:
return calls
@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
name = name_match.group(1)
arguments: dict[str, Any] = {}
arguments: dict[str, object] = {}
# 提取 "key": "value" 模式
for kv_match in re.finditer(r'"(\w+)"\s*:\s*"([^"]*)"', text):
key = kv_match.group(1)

View File

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

View File

@ -9,7 +9,7 @@ import asyncio
import json
import logging
import re
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING
from .expert import Expert
from .plan import PhaseStatus, PlanPhase, TeamPlan
@ -28,7 +28,7 @@ class DebateRunnerMixin:
_phase_semaphore: asyncio.Semaphore
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).
Parse config Lead opens experts argue in parallel rounds Lead
summarizes Lead adjudicates write conclusion to workspace."""
@ -86,7 +86,7 @@ class DebateRunnerMixin:
)
# 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"}
]
@ -103,7 +103,7 @@ class DebateRunnerMixin:
break
# 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:
return await self._generate_debate_argument(e, topic, history, round_num)
@ -234,7 +234,7 @@ class DebateRunnerMixin:
return f"辩论主题:{topic}。请各位专家发表看法。"
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:
"""Generate an expert's debate argument for the current round."""
gateway = self._get_llm_gateway(expert)
@ -269,7 +269,7 @@ class DebateRunnerMixin:
return response.content.strip()
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:
"""Generate Lead's summary of the current debate round."""
gateway = self._get_llm_gateway(lead)
@ -307,8 +307,8 @@ class DebateRunnerMixin:
return f"[第 {round_num} 轮辩论完成,小结生成失败]"
async def _generate_debate_verdict(
self, lead: Expert, topic: str, history: list[dict[str, Any]]
) -> dict[str, Any]:
self, lead: Expert, topic: str, history: list[dict[str, object]]
) -> dict[str, object]:
"""Generate Lead's final verdict for the debate."""
gateway = self._get_llm_gateway(lead)
if not gateway:
@ -371,7 +371,7 @@ class DebateRunnerMixin:
"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."""
if not history:
return ""

View File

@ -6,7 +6,7 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING
from .expert import Expert
from .plan import PhaseStatus, PhaseType, PlanPhase, TeamPlan
@ -23,7 +23,7 @@ class DivergenceDetectorMixin:
# Shared state provided by TeamOrchestrator (annotations only)
_team: ExpertTeam
_debate_count: int
_checkpoint: Any
_checkpoint: object
MAX_DEBATES: int
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 logging
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.protocol import TaskMessage, TaskResult, TaskStatus
@ -37,7 +37,7 @@ class PhaseExecutorMixin:
# U4: State offloading helpers — keep memory lean for long-horizon runs.
_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."""
if not isinstance(content, str):
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}")
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."""
if phase.phase_type == PhaseType.DEBATE:
return await self._execute_debate_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)."""
expert, agent, lead = await self._prepare_phase_context(phase, plan)
last_error: str | None = None
result: dict[str, Any] | None = None
result: dict[str, object] | None = None
try:
# U3: 返工循环 — 最多 MAX_REWORKS + 1 次1 次初始 + MAX_REWORKS 次返工)
@ -135,11 +135,11 @@ class PhaseExecutorMixin:
self,
expert: Expert,
phase: PlanPhase,
dependency_outputs: dict[str, Any],
dependency_outputs: dict[str, object],
collaboration_outputs: dict[str, str],
) -> TaskMessage:
"""Build TaskMessage for execution with context isolation."""
input_data: dict[str, Any] = {
input_data: dict[str, object] = {
"task": phase.task_description,
"team_id": self._team.team_id,
"phase_id": phase.id,
@ -180,12 +180,12 @@ class PhaseExecutorMixin:
lead: Expert,
phase: PlanPhase,
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
(result, last_error, passed, feedback, degraded). Raises RuntimeError on retry
exhaustion."""
# 每次迭代重新读取依赖输出(前置阶段可能在返工期间完成)
dependency_outputs: dict[str, Any] = {}
dependency_outputs: dict[str, object] = {}
for dep_id in phase.depends_on:
dep_phase = plan.get_phase(dep_id)
if dep_phase and dep_phase.status == PhaseStatus.COMPLETED and dep_phase.result:
@ -216,7 +216,7 @@ class PhaseExecutorMixin:
# 执行专家任务带重试MAX_RETRIES 处理瞬时失败)
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):
try:
task_result: TaskResult = await agent.execute(task_msg)
@ -265,7 +265,7 @@ class PhaseExecutorMixin:
lead: Expert,
phase: PlanPhase,
plan: TeamPlan,
result: dict[str, Any],
result: dict[str, object],
passed: bool,
feedback: str,
degraded: bool = False,

View File

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

View File

@ -6,7 +6,7 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING
from agentkit.orchestrator.rollback import RollbackExecutor
@ -27,7 +27,7 @@ class RollbackHandlerMixin:
_rollback_timeout: float
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:
"""Mark all phases that depend on the failed phase as FAILED."""
for ph in plan.phases:

View File

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

View File

@ -16,7 +16,6 @@ import enum
import logging
import time
import uuid
from typing import Any
from .config import ExpertConfig
from .expert import Expert
@ -72,7 +71,7 @@ class BoardTeam:
# Discussion state
self._topic: str = ""
self._history: list[dict[str, Any]] = []
self._history: list[dict[str, object]] = []
self._current_round: int = 0
self._max_rounds: int = max_rounds
self._user_interventions: list[str] = [] # Pending user messages
@ -125,7 +124,7 @@ class BoardTeam:
return self._max_rounds
@property
def history(self) -> list[dict[str, Any]]:
def history(self) -> list[dict[str, object]]:
return self._history.copy()
def get_expert(self, name: str) -> Expert | None:
@ -254,7 +253,7 @@ class BoardTeam:
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.
The moderator summarizes each round's key points, replacing
@ -291,7 +290,7 @@ class BoardTeam:
# Parse compressed history back to entries
# 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
for line in compressed.split("\n"):
line = line.strip()

View File

@ -19,7 +19,6 @@ from __future__ import annotations
import asyncio
import logging
from typing import Any
from .expert import Expert
from .board import BoardTeam, BoardStatus
@ -43,7 +42,7 @@ class BoardOrchestrator:
def __init__(self, team: BoardTeam) -> None:
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.
Flow:
@ -351,7 +350,7 @@ class BoardOrchestrator:
logger.warning(f"Moderator summary generation failed: {e}")
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.
The moderator gives:
@ -428,7 +427,7 @@ class BoardOrchestrator:
"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.
Uses existing discussion history to provide a basic summary.
@ -491,7 +490,7 @@ class BoardOrchestrator:
return True
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.
Falls back to other active experts if the primary target has no gateway.
@ -509,7 +508,7 @@ class BoardOrchestrator:
return gateway
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.
Events are emitted via handoff_transport for WebSocket relay.

View File

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

View File

@ -14,7 +14,6 @@ import asyncio
import json
import logging
import re
from typing import Any
from agentkit.core.exceptions import LLMProviderError
from agentkit.llm.gateway import LLMGateway
@ -72,7 +71,7 @@ class TeamOrchestrator(
self,
team: ExpertTeam,
max_concurrent_phases: int | None = None,
checkpoint: Any = None,
checkpoint: object | None = None,
workspace_root: str | None = None,
rollback_timeout: float | None = None,
) -> None:
@ -95,7 +94,7 @@ class TeamOrchestrator(
self._workspace_root = workspace_root
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 layers (parallel within layer) synthesize. Returns dict with
status/result/phase_results/plan."""
@ -175,7 +174,7 @@ class TeamOrchestrator(
# 4. Set EXECUTING status, execute phases
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)
@ -183,9 +182,9 @@ class TeamOrchestrator(
self,
lead: Expert,
plan: TeamPlan,
phase_results: dict[str, dict[str, Any]],
phase_results: dict[str, dict[str, object]],
task: str,
) -> dict[str, Any]:
) -> dict[str, object]:
"""Execute the pipeline loop: run pending phases, synthesize, return result.
Shared by execute() and resume(). phase_results may be pre-populated
@ -220,7 +219,7 @@ class TeamOrchestrator(
break
# 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:
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})
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,
continue via _run_pipeline. Returns same dict shape as execute()."""
if self._checkpoint is None:
@ -362,7 +361,7 @@ class TeamOrchestrator(
# 3. Load checkpoints, mark completed phases
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()
failed_phase_ids: set[str] = set()
@ -492,7 +491,7 @@ class TeamOrchestrator(
# First pass: create phases with IDs, build name->id mapping
name_to_id: dict[str, str] = {}
raw_phases: list[dict[str, Any]] = []
raw_phases: list[dict[str, object]] = []
for item in items:
if not isinstance(item, dict):
@ -584,7 +583,7 @@ class TeamOrchestrator(
return gateway
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."""
if self._team.handoff_transport:
try:

View File

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

View File

@ -17,7 +17,6 @@ import enum
import logging
import time
import uuid
from typing import Any
from .config import ExpertConfig
from .expert import Expert
@ -63,7 +62,7 @@ class ExpertTeam:
workspace: SharedWorkspace | None = None,
pool: AgentPool | 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())
# U4: Accept redis_client for SharedWorkspace state offloading.