fix linter bug
This commit is contained in:
@@ -24,7 +24,7 @@ from .backends import CustomSandboxBackend, MergedReadOnlyBackend
|
||||
from .config import get_effective_config, apply_config_to_env
|
||||
from .llm import get_chat_model
|
||||
from .mcp import load_mcp_tools
|
||||
from .middleware import create_memory_middleware, create_skills_middleware
|
||||
from .middleware import create_memory_middleware
|
||||
from .prompts import RESEARCHER_INSTRUCTIONS, get_system_prompt
|
||||
from .utils import load_subagents
|
||||
from .tools import tavily_search, think_tool, skill_manager, view_image
|
||||
|
||||
@@ -4,10 +4,14 @@ This module provides an extensible interface for different messaging channels
|
||||
(iMessage, Telegram, Discord) to communicate with the EvoScientist agent.
|
||||
"""
|
||||
|
||||
from .base import Channel, RawIncoming, IncomingMessage, OutgoingMessage
|
||||
from .base import Channel, RawIncoming, IncomingMessage, OutgoingMessage, chunk_text
|
||||
from .bus import MessageBus, InboundMessage, OutboundMessage
|
||||
from .capabilities import ChannelCapabilities
|
||||
from .channel_manager import ChannelManager, register_channel, create_channel, available_channels
|
||||
from .consumer import InboundConsumer
|
||||
from .formatter import UnifiedFormatter
|
||||
from .middleware import TypingManager
|
||||
from .plugin import ChannelPlugin, ChannelMeta, ReloadPolicy
|
||||
from .standalone import run_standalone
|
||||
|
||||
# Backward compat: ChannelServer is now Channel itself
|
||||
@@ -27,6 +31,7 @@ __all__ = [
|
||||
"run_standalone",
|
||||
"register_channel",
|
||||
"create_channel",
|
||||
"available_channels",
|
||||
# New modules
|
||||
"ChannelCapabilities",
|
||||
"UnifiedFormatter",
|
||||
@@ -37,11 +42,3 @@ __all__ = [
|
||||
"ChannelMeta",
|
||||
"ReloadPolicy",
|
||||
]
|
||||
|
||||
from .capabilities import ChannelCapabilities
|
||||
from .formatter import UnifiedFormatter
|
||||
from .middleware import TypingManager
|
||||
from .base import chunk_text
|
||||
|
||||
# Plugin architecture
|
||||
from .plugin import ChannelPlugin, ChannelMeta, ReloadPolicy
|
||||
|
||||
@@ -7,7 +7,7 @@ streaming, threading, etc.) without per-channel branching in core logic.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
|
||||
FormatType = Literal["html", "markdown", "slack_mrkdwn", "discord", "plain"]
|
||||
|
||||
@@ -11,7 +11,6 @@ account management (formerly ``account.py``), and pipeline assembly
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import importlib
|
||||
import json
|
||||
import logging
|
||||
@@ -22,9 +21,9 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
|
||||
from .base import Channel, RawIncoming, OutboundMessage
|
||||
from .base import Channel, OutboundMessage
|
||||
from .bus import MessageBus
|
||||
from .bus.events import InboundMessage
|
||||
from .middleware import OutboundMiddlewareBase
|
||||
from .plugin import ChannelPlugin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -245,10 +244,6 @@ class AccountManager:
|
||||
# Inbound / outbound pipelines (formerly pipeline.py)
|
||||
# ═════════════════════════════════════════════════════════════════════
|
||||
|
||||
from .middleware import (
|
||||
OutboundMiddlewareBase,
|
||||
)
|
||||
|
||||
|
||||
class OutboundPipeline:
|
||||
"""Processes outgoing messages through a middleware chain."""
|
||||
|
||||
@@ -12,7 +12,7 @@ common account patterns:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import logging
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, AsyncIterator, Callable, TypeVar
|
||||
|
||||
from .base import Channel
|
||||
|
||||
@@ -4,7 +4,6 @@ import asyncio
|
||||
import json
|
||||
import logging
|
||||
from urllib.parse import quote_plus
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -212,7 +211,6 @@ class DingTalkChannel(Channel, WebSocketMixin, TokenMixin):
|
||||
return
|
||||
|
||||
sender_id = payload.get("senderStaffId") or payload.get("senderId", "")
|
||||
conv_id = payload.get("conversationId", "")
|
||||
is_group = payload.get("conversationType") == "2"
|
||||
# For send API (oToMessages/batchSend), userIds needs staffId, not conversationId
|
||||
chat_id = sender_id
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@@ -50,12 +50,24 @@ def _strip_html(text: str) -> str:
|
||||
|
||||
@dataclass
|
||||
class EmailConfig(BaseChannelConfig):
|
||||
imap_host: str = ""; imap_port: int = 993; imap_username: str = ""; imap_password: str = ""
|
||||
imap_mailbox: str = "INBOX"; imap_use_ssl: bool = True
|
||||
smtp_host: str = ""; smtp_port: int = 587; smtp_username: str = ""; smtp_password: str = ""
|
||||
smtp_use_tls: bool = True; from_address: str = ""
|
||||
poll_interval: int = 30; mark_seen: bool = True; max_body_chars: int = 12000
|
||||
subject_prefix: str = "Re: "; allowed_senders: set[str] | None = None; text_chunk_limit: int = 4096
|
||||
imap_host: str = ""
|
||||
imap_port: int = 993
|
||||
imap_username: str = ""
|
||||
imap_password: str = ""
|
||||
imap_mailbox: str = "INBOX"
|
||||
imap_use_ssl: bool = True
|
||||
smtp_host: str = ""
|
||||
smtp_port: int = 587
|
||||
smtp_username: str = ""
|
||||
smtp_password: str = ""
|
||||
smtp_use_tls: bool = True
|
||||
from_address: str = ""
|
||||
poll_interval: int = 30
|
||||
mark_seen: bool = True
|
||||
max_body_chars: int = 12000
|
||||
subject_prefix: str = "Re: "
|
||||
allowed_senders: set[str] | None = None
|
||||
text_chunk_limit: int = 4096
|
||||
|
||||
|
||||
class EmailChannel(Channel, PollingMixin):
|
||||
@@ -352,7 +364,8 @@ class EmailChannel(Channel, PollingMixin):
|
||||
await self._stop_polling()
|
||||
if self._imap:
|
||||
try:
|
||||
self._imap.close(); self._imap.logout()
|
||||
self._imap.close()
|
||||
self._imap.logout()
|
||||
except Exception:
|
||||
pass
|
||||
self._imap = None
|
||||
|
||||
@@ -16,16 +16,19 @@ Send API:
|
||||
- ``POST /open-apis/im/v1/messages?receive_id_type=chat_id``
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from typing import Any
|
||||
from typing import Any, TYPE_CHECKING
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from aiohttp import web
|
||||
|
||||
from ..base import Channel, RawIncoming, ChannelError
|
||||
from ..capabilities import FEISHU as FEISHU_CAPS
|
||||
from ..mixins import WebhookMixin, TokenMixin
|
||||
|
||||
@@ -14,11 +14,10 @@ import asyncio
|
||||
import dataclasses
|
||||
import logging
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
from collections import OrderedDict, defaultdict, deque
|
||||
from collections import OrderedDict, deque
|
||||
from collections.abc import Awaitable
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable
|
||||
|
||||
from .bus.events import InboundMessage, OutboundMessage
|
||||
@@ -527,7 +526,7 @@ class RetryMiddleware:
|
||||
"""
|
||||
|
||||
def __init__(self, channel_name: str = "unknown") -> None:
|
||||
from .retry import RetryConfig, DEFAULT_RETRY, RETRY_PRESETS
|
||||
from .retry import DEFAULT_RETRY, RETRY_PRESETS
|
||||
self._config = RETRY_PRESETS.get(channel_name, DEFAULT_RETRY)
|
||||
self._channel_name = channel_name
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ import asyncio
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
from typing import Any, Callable
|
||||
from typing import Any
|
||||
|
||||
from .base import Channel, ChannelError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -209,7 +209,6 @@ class QQChannel(Channel):
|
||||
from pathlib import Path
|
||||
chat_id = self._resolve_media_chat_id(recipient, metadata)
|
||||
msg_type = (metadata or {}).get("msg_type", "c2c")
|
||||
msg_id = (metadata or {}).get("event_id", "")
|
||||
ext = Path(file_path).suffix.lower()
|
||||
file_type = self._FILE_TYPE_MAP.get(ext, 1) # default to image
|
||||
|
||||
|
||||
@@ -15,9 +15,8 @@ import json
|
||||
import logging
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from collections import deque
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ async def validate_signal(
|
||||
rpc_port: int = 7583,
|
||||
) -> tuple[bool, str]:
|
||||
"""Validate Signal setup by checking signal-cli availability."""
|
||||
import asyncio, subprocess
|
||||
import asyncio
|
||||
import subprocess
|
||||
|
||||
if not phone_number:
|
||||
return False, "phone_number is required"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@@ -17,16 +17,20 @@ Both backends use httpx (already a core dependency) and aiohttp for
|
||||
webhook server — matching the Feishu channel pattern.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from aiohttp import web
|
||||
|
||||
from ..mixins import WebhookMixin, TokenMixin
|
||||
from ..base import Channel, RawIncoming, ChannelError
|
||||
@@ -412,7 +416,7 @@ class WeChatChannel(Channel, WebhookMixin, TokenMixin):
|
||||
if ann:
|
||||
annotations.append(ann)
|
||||
else:
|
||||
annotations.append(f"[image: no download source]")
|
||||
annotations.append("[image: no download source]")
|
||||
elif msg_type == "voice":
|
||||
recognition = xml_data.get("Recognition", "")
|
||||
media_id = xml_data.get("MediaId", "")
|
||||
|
||||
@@ -13,11 +13,9 @@ References:
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import Optional
|
||||
|
||||
# Crypto imports — all from the Python standard library + pycryptodome
|
||||
# (but we'll use a pure-Python fallback if not available)
|
||||
|
||||
@@ -14,9 +14,15 @@ Usage:
|
||||
await server.stop()
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from aiohttp import web
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -89,7 +95,7 @@ class VerifyServer:
|
||||
def is_verified(self) -> bool:
|
||||
return self._verified.is_set()
|
||||
|
||||
async def _handle(self, request) -> "web.Response":
|
||||
async def _handle(self, request) -> web.Response:
|
||||
"""Handle GET verification request.
|
||||
|
||||
During onboarding we use a lenient approach:
|
||||
@@ -163,7 +169,7 @@ class VerifyServer:
|
||||
self._verified.set()
|
||||
return web.Response(text=echostr)
|
||||
|
||||
async def _handle_post(self, request) -> "web.Response":
|
||||
async def _handle_post(self, request) -> web.Response:
|
||||
"""Handle POST — just acknowledge during verification phase."""
|
||||
from aiohttp import web
|
||||
return web.Response(text="success")
|
||||
|
||||
@@ -162,7 +162,7 @@ async def _bus_inbound_consumer(
|
||||
"""
|
||||
from ..stream import events as _stream_events_mod
|
||||
from ..stream.display import (
|
||||
console, display_final_results, create_streaming_display,
|
||||
console, create_streaming_display,
|
||||
)
|
||||
from ..stream.state import StreamState
|
||||
from ..channels.consumer import _format_todo_list
|
||||
|
||||
@@ -483,10 +483,6 @@ def cmd_interactive(
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer)
|
||||
state["thread_id"] = generate_thread_id()
|
||||
state["resumed"] = False
|
||||
# Sync shared refs if channel is running
|
||||
if _ChannelState.is_running():
|
||||
_ChannelState.agent = state["agent"]
|
||||
_ChannelState.thread_id = state["thread_id"]
|
||||
console.print(f"[green]New session:[/green] [yellow]{state['thread_id']}[/yellow]")
|
||||
if state["workspace_dir"]:
|
||||
console.print(f"[dim]Workspace:[/dim] [cyan]{_shorten_path(state['workspace_dir'])}[/cyan]\n")
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage
|
||||
from EvoScientist.channels.bus.events import InboundMessage
|
||||
from EvoScientist.channels.bus.message_bus import MessageBus
|
||||
from EvoScientist.channels.channel_manager import ChannelManager
|
||||
from EvoScientist.channels.base import Channel, IncomingMessage, OutgoingMessage
|
||||
from EvoScientist.channels.base import Channel, OutgoingMessage
|
||||
|
||||
|
||||
def _run(coro):
|
||||
|
||||
@@ -15,13 +15,10 @@ Test groups:
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import re
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -38,7 +35,7 @@ from EvoScientist.channels.bus.events import (
|
||||
OutboundMessage as BusOutbound,
|
||||
)
|
||||
from EvoScientist.channels.bus.message_bus import MessageBus
|
||||
from EvoScientist.channels.channel_manager import ChannelManager, ChannelHealth
|
||||
from EvoScientist.channels.channel_manager import ChannelManager
|
||||
from EvoScientist.channels.consumer import InboundConsumer
|
||||
from EvoScientist.channels.middleware import DedupCache
|
||||
from EvoScientist.channels.retry import RetryConfig, RetryInfo, retry_async
|
||||
@@ -363,7 +360,7 @@ class TestMarkdownUtils:
|
||||
|
||||
result = convert_markdown(
|
||||
text,
|
||||
code_block_formatter=lambda l, c: f"[CODE]{c}[/CODE]",
|
||||
code_block_formatter=lambda lang, c: f"[CODE]{c}[/CODE]",
|
||||
inline_code_formatter=lambda c: f"[IC]{c}[/IC]",
|
||||
inline_rules=[],
|
||||
escape_fn=bad_escape,
|
||||
@@ -382,7 +379,7 @@ class TestMarkdownUtils:
|
||||
text = "Normal text with \x00BLOCK0\x00 in it"
|
||||
result = convert_markdown(
|
||||
text,
|
||||
code_block_formatter=lambda l, c: f"<pre>{c}</pre>",
|
||||
code_block_formatter=lambda lang, c: f"<pre>{c}</pre>",
|
||||
inline_code_formatter=lambda c: f"<code>{c}</code>",
|
||||
inline_rules=[],
|
||||
)
|
||||
@@ -393,7 +390,7 @@ class TestMarkdownUtils:
|
||||
text = "before `` after"
|
||||
result = convert_markdown(
|
||||
text,
|
||||
code_block_formatter=lambda l, c: c,
|
||||
code_block_formatter=lambda lang, c: c,
|
||||
inline_code_formatter=lambda c: f"[{c}]",
|
||||
inline_rules=[],
|
||||
)
|
||||
@@ -1213,7 +1210,7 @@ class TestInboundConsumer:
|
||||
async def _test():
|
||||
consumer = self._make_consumer()
|
||||
# Start and immediately stop
|
||||
task = asyncio.create_task(consumer.run())
|
||||
asyncio.create_task(consumer.run())
|
||||
await asyncio.sleep(0.1)
|
||||
await consumer.stop()
|
||||
await asyncio.sleep(0.1)
|
||||
@@ -1232,7 +1229,7 @@ class TestInboundConsumerErrorHandling:
|
||||
ch = StubChannel()
|
||||
mgr.register(ch)
|
||||
|
||||
consumer = InboundConsumer(
|
||||
_consumer = InboundConsumer(
|
||||
bus=bus, manager=mgr, agent=MagicMock(),
|
||||
thread_id="",
|
||||
)
|
||||
|
||||
@@ -5,9 +5,8 @@ import asyncio
|
||||
import pytest
|
||||
|
||||
from EvoScientist.channels.bus.message_bus import MessageBus
|
||||
from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage
|
||||
from EvoScientist.channels.channel_manager import ChannelManager
|
||||
from EvoScientist.channels.base import Channel, InboundMessage, OutboundMessage
|
||||
from EvoScientist.channels.base import Channel, OutboundMessage
|
||||
|
||||
|
||||
def _run(coro):
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import asyncio
|
||||
from dataclasses import dataclass
|
||||
|
||||
import pytest
|
||||
|
||||
from EvoScientist.channels.base import Channel, RawIncoming
|
||||
from EvoScientist.channels.capabilities import ChannelCapabilities
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from EvoScientist.channels.bus.events import InboundMessage, OutboundMessage
|
||||
from EvoScientist.channels.bus.message_bus import MessageBus
|
||||
|
||||
Reference in New Issue
Block a user