This commit is contained in:
tcmofashi
2026-04-03 23:18:30 +08:00
parent 185361f2c3
commit 7b9e1cf925
40 changed files with 52 additions and 86 deletions

View File

@@ -6,7 +6,7 @@ without the overhead of an Agent.
import asyncio import asyncio
from agentlite import LLMClient, llm_complete, llm_stream from agentlite import LLMClient
from agentlite.config import AgentConfig, ProviderConfig, ModelConfig from agentlite.config import AgentConfig, ProviderConfig, ModelConfig
@@ -55,7 +55,7 @@ async def main():
) )
# Create client # Create client
client = LLMClient(config) LLMClient(config)
# Make a call # Make a call
# response = await client.complete( # response = await client.complete(
@@ -91,7 +91,7 @@ async def main():
temperature=0.8, temperature=0.8,
) )
client = LLMClient(provider=provider) LLMClient(provider=provider)
# response = await client.complete( # response = await client.complete(
# user_prompt="What are the benefits of type hints?", # user_prompt="What are the benefits of type hints?",

View File

@@ -6,8 +6,7 @@ This example shows how to use skills with an Agent.
import asyncio import asyncio
from pathlib import Path from pathlib import Path
from agentlite import Agent, OpenAIProvider from agentlite.skills import discover_skills, index_skills_by_name
from agentlite.skills import discover_skills, index_skills_by_name, SkillTool
async def main(): async def main():

View File

@@ -7,7 +7,6 @@ and delegate tasks to them using the Task tool.
import asyncio import asyncio
from agentlite import Agent, OpenAIProvider from agentlite import Agent, OpenAIProvider
from agentlite.labor_market import LaborMarket
from agentlite.tools.multiagent.task import Task from agentlite.tools.multiagent.task import Task
@@ -61,8 +60,8 @@ async def main():
parent.tools.add(Task(labor_market=parent.labor_market)) parent.tools.add(Task(labor_market=parent.labor_market))
print("Created parent agent with subagents:") print("Created parent agent with subagents:")
print(f" - coder: Writes code") print(" - coder: Writes code")
print(f" - reviewer: Reviews code") print(" - reviewer: Reviews code")
# Example 2: Using subagents # Example 2: Using subagents
print("\n=== Example 2: Delegating Tasks ===") print("\n=== Example 2: Delegating Tasks ===")

View File

@@ -7,7 +7,6 @@ to enable/disable specific tools.
import asyncio import asyncio
from pathlib import Path from pathlib import Path
from agentlite import Agent, OpenAIProvider
from agentlite.tools import ( from agentlite.tools import (
ConfigurableToolset, ConfigurableToolset,
ToolSuiteConfig, ToolSuiteConfig,
@@ -57,7 +56,7 @@ async def main():
) )
) )
toolset = ConfigurableToolset(config) toolset = ConfigurableToolset(config)
print(f"File tool settings:") print("File tool settings:")
print(f" Max lines: {config.file_tools.max_lines}") print(f" Max lines: {config.file_tools.max_lines}")
print(f" Max bytes: {config.file_tools.max_bytes}") print(f" Max bytes: {config.file_tools.max_bytes}")
print(f" Allow outside work dir: {config.file_tools.allow_write_outside_work_dir}") print(f" Allow outside work dir: {config.file_tools.allow_write_outside_work_dir}")
@@ -66,7 +65,7 @@ async def main():
print("\n=== Example 5: Using with Agent ===") print("\n=== Example 5: Using with Agent ===")
# Create a safe configuration (no shell, no write outside work dir) # Create a safe configuration (no shell, no write outside work dir)
safe_config = ToolSuiteConfig( ToolSuiteConfig(
file_tools=FileToolsConfig( file_tools=FileToolsConfig(
allow_write_outside_work_dir=False, allow_write_outside_work_dir=False,
), ),

View File

@@ -8,7 +8,7 @@ from __future__ import annotations
import asyncio import asyncio
from collections.abc import AsyncIterator, Sequence from collections.abc import AsyncIterator, Sequence
from typing import TYPE_CHECKING, Any, Optional from typing import TYPE_CHECKING
from agentlite.message import ( from agentlite.message import (
ContentPart, ContentPart,
@@ -17,8 +17,8 @@ from agentlite.message import (
ToolCall, ToolCall,
ToolCallPart, ToolCallPart,
) )
from agentlite.provider import ChatProvider, StreamedMessage, TokenUsage from agentlite.provider import ChatProvider
from agentlite.tool import SimpleToolset, Tool, ToolResult, ToolType from agentlite.tool import SimpleToolset, ToolResult, ToolType
from agentlite.labor_market import LaborMarket from agentlite.labor_market import LaborMarket
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -311,7 +311,7 @@ class Agent:
# Execute all tool calls concurrently # Execute all tool calls concurrently
futures = [self.tools.handle(tc) for tc in tool_calls] futures = [self.tools.handle(tc) for tc in tool_calls]
for tc, future in zip(tool_calls, futures): for tc, future in zip(tool_calls, futures, strict=False):
try: try:
if asyncio.isfuture(future): if asyncio.isfuture(future):
result = await future result = await future

View File

@@ -6,7 +6,7 @@ models, and agent settings.
from __future__ import annotations from __future__ import annotations
from typing import Any, Literal, Optional, Union from typing import Literal, Optional
from pydantic import BaseModel, Field, SecretStr, model_validator from pydantic import BaseModel, Field, SecretStr, model_validator

View File

@@ -32,11 +32,10 @@ from __future__ import annotations
from collections.abc import AsyncIterator from collections.abc import AsyncIterator
from typing import Optional from typing import Optional
from agentlite.config import AgentConfig, ModelConfig, ProviderConfig from agentlite.config import AgentConfig
from agentlite.message import Message, TextPart from agentlite.message import Message, TextPart
from agentlite.provider import ChatProvider, TokenUsage from agentlite.provider import ChatProvider, TokenUsage
from agentlite.providers.openai import OpenAIProvider from agentlite.providers.openai import OpenAIProvider
from agentlite.tool import Tool
class LLMResponse: class LLMResponse:
@@ -174,7 +173,7 @@ class LLMClient:
try: try:
if usage is None and hasattr(stream, "usage") and stream.usage: if usage is None and hasattr(stream, "usage") and stream.usage:
usage = stream.usage usage = stream.usage
except: except Exception:
pass pass
content = "".join(content_parts) content = "".join(content_parts)

View File

@@ -6,10 +6,8 @@ tools from external MCP-compatible servers.
from __future__ import annotations from __future__ import annotations
import asyncio
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from agentlite.message import TextPart
from agentlite.tool import CallableTool, ToolOk, ToolResult, ToolError from agentlite.tool import CallableTool, ToolOk, ToolResult, ToolError
if TYPE_CHECKING: if TYPE_CHECKING:

View File

@@ -7,7 +7,7 @@ and provides the base types for streaming responses.
from __future__ import annotations from __future__ import annotations
from collections.abc import AsyncIterator, Sequence from collections.abc import AsyncIterator, Sequence
from typing import Protocol, runtime_checkable from typing import Protocol, Union, runtime_checkable
from pydantic import BaseModel from pydantic import BaseModel
@@ -44,8 +44,6 @@ class TokenUsage(BaseModel):
return self.input_tokens + self.output_tokens return self.input_tokens + self.output_tokens
from typing import Union
StreamedPart = Union[ContentPart, ToolCall, ToolCallPart] StreamedPart = Union[ContentPart, ToolCall, ToolCallPart]

View File

@@ -13,7 +13,6 @@ from typing import TYPE_CHECKING, Any
import httpx import httpx
from openai import AsyncOpenAI, OpenAIError from openai import AsyncOpenAI, OpenAIError
from openai.types.chat import ( from openai.types.chat import (
ChatCompletion,
ChatCompletionChunk, ChatCompletionChunk,
ChatCompletionMessageParam, ChatCompletionMessageParam,
ChatCompletionToolParam, ChatCompletionToolParam,
@@ -27,7 +26,6 @@ from agentlite.message import (
) )
from agentlite.provider import ( from agentlite.provider import (
APIConnectionError, APIConnectionError,
APIEmptyResponseError,
APIStatusError, APIStatusError,
APITimeoutError, APITimeoutError,
ChatProviderError, ChatProviderError,

View File

@@ -195,7 +195,6 @@ def discover_skills(skills_dir: Path) -> list["Skill"]:
>>> for skill in skills: >>> for skill in skills:
... print(f"{skill.name}: {skill.description}") ... print(f"{skill.name}: {skill.description}")
""" """
from agentlite.skills.models import Skill
if not skills_dir.is_dir(): if not skills_dir.is_dir():
return [] return []

View File

@@ -16,7 +16,7 @@ Example:
from __future__ import annotations from __future__ import annotations
from collections.abc import Iterable, Iterator from collections.abc import Iterable
from pathlib import Path from pathlib import Path
from typing import Literal, Optional from typing import Literal, Optional

View File

@@ -7,7 +7,7 @@ in a hierarchical agent architecture.
from __future__ import annotations from __future__ import annotations
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Optional
from pydantic import BaseModel, Field, model_validator from pydantic import BaseModel, Field, model_validator

View File

@@ -19,7 +19,6 @@ from typing import (
Protocol, Protocol,
TypeVar, TypeVar,
Union, Union,
cast,
Generic, Generic,
get_type_hints, get_type_hints,
) )
@@ -298,10 +297,6 @@ class CallableTool2(ABC, Generic[Params]):
return ToolError(message=f"Tool execution failed: {e}") return ToolError(message=f"Tool execution failed: {e}")
# Import Generic here to avoid issues with type checking
from typing import Generic
class Toolset(Protocol): class Toolset(Protocol):
"""Protocol for tool collections. """Protocol for tool collections.

View File

@@ -8,9 +8,9 @@ for enabling/disabling individual tools.
from __future__ import annotations from __future__ import annotations
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Optional
from agentlite.tool import CallableTool2, ToolOk, ToolError, ToolResult, SimpleToolset from agentlite.tool import SimpleToolset
from agentlite.tools.config import ( from agentlite.tools.config import (
ToolSuiteConfig, ToolSuiteConfig,
FileToolsConfig, FileToolsConfig,

View File

@@ -6,7 +6,6 @@ allowing users to enable/disable specific tools.
from __future__ import annotations from __future__ import annotations
from typing import Any
from pydantic import BaseModel, Field from pydantic import BaseModel, Field

View File

@@ -165,7 +165,6 @@ class ReadFile(CallableTool2[Params]):
for i, line in enumerate(selected_lines): for i, line in enumerate(selected_lines):
line_num = start_idx + i + 1 line_num = start_idx + i + 1
original_line = line
# Truncate if needed # Truncate if needed
if len(line) > self._max_line_length: if len(line) > self._max_line_length:

View File

@@ -3,7 +3,4 @@
This module provides tools for creating and managing subagents. This module provides tools for creating and managing subagents.
""" """
from agentlite.tools.multiagent.task import Task
from agentlite.tools.multiagent.create import CreateSubagent
__all__ = [] __all__ = []

View File

@@ -8,8 +8,6 @@ from typing import Optional
import asyncio import asyncio
import platform import platform
import shlex
from pathlib import Path
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -152,7 +150,7 @@ class Shell(CallableTool2[Params]):
if process.returncode == 0: if process.returncode == 0:
return ToolOk( return ToolOk(
output=output, output=output,
message=f"Command executed successfully (exit code 0).", message="Command executed successfully (exit code 0).",
) )
else: else:
return ToolError( return ToolError(

View File

@@ -7,7 +7,6 @@ from __future__ import annotations
import urllib.request import urllib.request
import urllib.error import urllib.error
from pathlib import Path
from pydantic import BaseModel, Field from pydantic import BaseModel, Field

View File

@@ -19,12 +19,10 @@ from agentlite import (
Message, Message,
TextPart, TextPart,
ToolCall, ToolCall,
ToolOk,
ToolError,
tool, tool,
) )
from agentlite.provider import ChatProvider, StreamedMessage, TokenUsage from agentlite.provider import StreamedMessage, TokenUsage
from agentlite.tool import Tool, ToolResult from agentlite.tool import Tool
# ============================================================================= # =============================================================================

View File

@@ -8,7 +8,7 @@ from __future__ import annotations
import pytest import pytest
from agentlite import Agent, TextPart from agentlite import Agent
@pytest.mark.integration @pytest.mark.integration

View File

@@ -17,7 +17,7 @@ import pytest
# Add src to path # Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
from agentlite import Agent, OpenAIProvider, LLMClient, llm_complete from agentlite import Agent, OpenAIProvider, LLMClient
from agentlite.skills import discover_skills, SkillTool, index_skills_by_name from agentlite.skills import discover_skills, SkillTool, index_skills_by_name
from agentlite.tools import ConfigurableToolset from agentlite.tools import ConfigurableToolset
@@ -74,7 +74,7 @@ async def test_agent_with_tools():
print("=" * 60) print("=" * 60)
try: try:
from agentlite.tools import ToolSuiteConfig, ReadFile, Glob from agentlite.tools import ToolSuiteConfig
provider = get_provider() provider = get_provider()
@@ -173,7 +173,6 @@ async def test_subagents():
print("=" * 60) print("=" * 60)
try: try:
from agentlite.labor_market import LaborMarket
from agentlite.tools.multiagent.task import Task from agentlite.tools.multiagent.task import Task
provider = get_provider() provider = get_provider()
@@ -246,7 +245,7 @@ async def test_skills():
skill_tool = SkillTool(skill_index, parent_agent=agent) skill_tool = SkillTool(skill_index, parent_agent=agent)
agent.tools.add(skill_tool) agent.tools.add(skill_tool)
print(f"✅ Added SkillTool to agent") print("✅ Added SkillTool to agent")
print("✅ Skills test PASSED") print("✅ Skills test PASSED")
return True return True

View File

@@ -5,7 +5,6 @@ from __future__ import annotations
import os import os
import sys import sys
import asyncio import asyncio
import signal
sys.path.insert(0, "/home/tcmofashi/proj/l2d_backend/agentlite/src") sys.path.insert(0, "/home/tcmofashi/proj/l2d_backend/agentlite/src")

View File

@@ -56,7 +56,7 @@ async def main():
start_time = time.time() start_time = time.time()
message = "Run 'echo test' and tell me the result." message = "Run 'echo test' and tell me the result."
logger.info(f"\n=== Starting Agent Run ===") logger.info("\n=== Starting Agent Run ===")
logger.info(f"Message: {message}") logger.info(f"Message: {message}")
logger.info(f"Max iterations: {agent.max_iterations}") logger.info(f"Max iterations: {agent.max_iterations}")
logger.info(f"Tools: {[t.name for t in agent.tools.tools]}") logger.info(f"Tools: {[t.name for t in agent.tools.tools]}")
@@ -178,7 +178,7 @@ async def main():
output_preview = output[:100] if output else "None" output_preview = output[:100] if output else "None"
logger.info(f" Output preview: {output_preview}...") logger.info(f" Output preview: {output_preview}...")
except asyncio.TimeoutError: except asyncio.TimeoutError:
logger.error(f" !!! Tool execution TIMEOUT") logger.error(" !!! Tool execution TIMEOUT")
output = "Tool execution timed out" output = "Tool execution timed out"
is_error = True is_error = True
except Exception as e: except Exception as e:
@@ -209,7 +209,7 @@ async def main():
final_response = f"Max iterations ({agent.max_iterations}) reached" final_response = f"Max iterations ({agent.max_iterations}) reached"
logger.info(f"\n{'=' * 60}") logger.info(f"\n{'=' * 60}")
logger.info(f"FINAL RESULT:") logger.info("FINAL RESULT:")
logger.info(f"{'=' * 60}") logger.info(f"{'=' * 60}")
logger.info(f"{final_response}") logger.info(f"{final_response}")
logger.info(f"Total iterations: {iterations}") logger.info(f"Total iterations: {iterations}")

View File

@@ -22,11 +22,6 @@ from agentlite import Agent, OpenAIProvider
from agentlite.tools import ( from agentlite.tools import (
ConfigurableToolset, ConfigurableToolset,
ToolSuiteConfig, ToolSuiteConfig,
Shell,
ReadFile,
WriteFile,
Glob,
Grep,
) )
# ============================================================================= # =============================================================================

View File

@@ -17,7 +17,7 @@ from pathlib import Path
import pytest import pytest
from agentlite import Agent, TextPart, tool from agentlite import Agent, tool
# ============================================================================= # =============================================================================

View File

@@ -16,7 +16,7 @@ from typing import Any
import pytest import pytest
import yaml import yaml
from agentlite import Agent, Message, TextPart, tool from agentlite import Agent, tool
def tool_output(result: Any) -> Any: def tool_output(result: Any) -> Any:

View File

@@ -6,7 +6,6 @@ and all exception types.
from __future__ import annotations from __future__ import annotations
import pytest
from agentlite.provider import ( from agentlite.provider import (
TokenUsage, TokenUsage,
@@ -106,7 +105,6 @@ class TestChatProviderProtocol:
def test_protocol_is_runtime_checkable(self): def test_protocol_is_runtime_checkable(self):
"""Test that ChatProvider is runtime checkable.""" """Test that ChatProvider is runtime checkable."""
# ChatProvider should have @runtime_checkable # ChatProvider should have @runtime_checkable
from typing import runtime_checkable
assert hasattr(ChatProvider, "__protocol_attrs__") assert hasattr(ChatProvider, "__protocol_attrs__")

View File

@@ -195,7 +195,6 @@ class TestToolDecoratorMemorixBug:
This is an integration-style test to ensure the decorated tool This is an integration-style test to ensure the decorated tool
has all required attributes for Agent usage. has all required attributes for Agent usage.
""" """
from agentlite import Agent, OpenAIProvider
@tool() @tool()
async def add_memory(content: str, importance: float = 0.5) -> dict: async def add_memory(content: str, importance: float = 0.5) -> dict:

View File

@@ -15,7 +15,7 @@ ROOT_PATH = Path(__file__).resolve().parent.parent
if str(ROOT_PATH) not in sys_path: if str(ROOT_PATH) not in sys_path:
sys_path.insert(0, str(ROOT_PATH)) sys_path.insert(0, str(ROOT_PATH))
from src.common.database.database_model import Expression, Jargon, ModifiedBy from src.common.database.database_model import Expression, Jargon, ModifiedBy # noqa: E402
def build_argument_parser() -> ArgumentParser: def build_argument_parser() -> ArgumentParser:

View File

@@ -239,8 +239,7 @@ def load_utils_via_file(monkeypatch):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_message_utils(monkeypatch): async def test_message_utils(monkeypatch):
load_message_via_file(monkeypatch) load_message_via_file(monkeypatch)
utils_module = load_utils_via_file(monkeypatch) load_utils_via_file(monkeypatch)
MessageUtils = utils_module.MessageUtils
@pytest.mark.asyncio @pytest.mark.asyncio

View File

@@ -22,9 +22,9 @@ if str(_root) not in sys.path:
if str(_maisaka_path) not in sys.path: if str(_maisaka_path) not in sys.path:
sys.path.insert(0, str(_maisaka_path)) sys.path.insert(0, str(_maisaka_path))
from src.prompt.prompt_manager import prompt_manager from src.prompt.prompt_manager import prompt_manager # noqa: E402
from src.maisaka.cli import BufferCLI from src.maisaka.cli import BufferCLI # noqa: E402
from src.maisaka.config import console from src.maisaka.config import console # noqa: E402
def main(): def main():

View File

@@ -36,8 +36,8 @@ def get_chat_name(chat_id: str) -> str:
elif chat_stream.user_nickname: elif chat_stream.user_nickname:
return f"{chat_stream.user_nickname}的私聊" return f"{chat_stream.user_nickname}的私聊"
if get_chat_manager: if _script_chat_manager:
chat_manager = get_chat_manager() chat_manager = _script_chat_manager
stream_name = chat_manager.get_stream_name(chat_id) stream_name = chat_manager.get_stream_name(chat_id)
if stream_name: if stream_name:
return stream_name return stream_name

View File

@@ -5,6 +5,7 @@ import sys
import time import time
import json import json
import importlib import importlib
from dataclasses import dataclass
from typing import Optional, Dict, Any from typing import Optional, Dict, Any
from datetime import datetime from datetime import datetime
@@ -23,7 +24,17 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from src.common.logger import initialize_logging, get_logger from src.common.logger import initialize_logging, get_logger
from src.common.database.database import db from src.common.database.database import db
from src.common.database.database_model import LLMUsage from src.common.database.database_model import LLMUsage
from maim_message import UserInfo, GroupInfo from src.common.data_models.mai_message_data_model import UserInfo, GroupInfo
try:
from maim_message import ChatStream, UserInfo, GroupInfo
except Exception:
@dataclass
class ChatStream:
stream_id: str
platform: str
user_info: UserInfo
group_info: GroupInfo
logger = get_logger("test_memory_retrieval") logger = get_logger("test_memory_retrieval")

View File

@@ -205,7 +205,7 @@ class HeartFChatting:
# TODO: Planner逻辑 # TODO: Planner逻辑
# TODO: 动作执行逻辑 # TODO: 动作执行逻辑
cycle_detail = self._end_cycle(current_cycle_detail) self._end_cycle(current_cycle_detail)
await asyncio.sleep(0.1) # 最小等待时间,避免过快循环 await asyncio.sleep(0.1) # 最小等待时间,避免过快循环
return True return True

View File

@@ -12,7 +12,6 @@ from src.chat.heart_flow.heartflow_message_processor import HeartFCMessageReceiv
from src.common.logger import get_logger from src.common.logger import get_logger
from src.common.utils.utils_message import MessageUtils from src.common.utils.utils_message import MessageUtils
from src.common.utils.utils_session import SessionUtils from src.common.utils.utils_session import SessionUtils
from src.config.config import global_config
from src.platform_io.route_key_factory import RouteKeyFactory from src.platform_io.route_key_factory import RouteKeyFactory
from src.core.announcement_manager import global_announcement_manager from src.core.announcement_manager import global_announcement_manager
from src.plugin_runtime.component_query import component_query_service from src.plugin_runtime.component_query import component_query_service

View File

@@ -1135,9 +1135,6 @@ class DefaultReplyer:
return content, reasoning_content, model_name, tool_calls return content, reasoning_content, model_name, tool_calls
async def get_prompt_info(self, message: str, sender: str, target: str): async def get_prompt_info(self, message: str, sender: str, target: str):
del message
del sender
del target
return "" return ""
related_info = "" related_info = ""
start_time = time.time() start_time = time.time()

View File

@@ -1058,12 +1058,9 @@ class StatisticOutputTask(AsyncTask):
from src.chat.message_receive.chat_manager import chat_manager as _stat_chat_manager from src.chat.message_receive.chat_manager import chat_manager as _stat_chat_manager
if chat_id in _stat_chat_manager.sessions: if chat_id in _stat_chat_manager.sessions:
session = _stat_chat_manager.sessions[chat_id]
name = _stat_chat_manager.get_session_name(chat_id) name = _stat_chat_manager.get_session_name(chat_id)
if name and name.strip(): if name and name.strip():
return name.strip() return name.strip()
if user_name and user_name.strip():
return user_name.strip()
# 如果从chat_stream获取失败尝试解析chat_id格式 # 如果从chat_stream获取失败尝试解析chat_id格式
if chat_id.startswith("g"): if chat_id.startswith("g"):

View File

@@ -92,7 +92,6 @@ class UniversalMessageSender:
""" """
# TODO: 重构至新的发送模型 # TODO: 重构至新的发送模型
message_preview = (message.processed_plain_text or "")[:200] message_preview = (message.processed_plain_text or "")[:200]
platform = message.platform
try: try:
# 尝试通过主 API 发送 # 尝试通过主 API 发送