AstrBot 4.7.3__py3-none-any.whl → 4.7.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astrbot/cli/__init__.py +1 -1
- astrbot/core/agent/message.py +21 -5
- astrbot/core/config/default.py +56 -1
- astrbot/core/message/components.py +6 -1
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +64 -5
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +15 -2
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +1 -1
- astrbot/core/platform/sources/telegram/tg_adapter.py +3 -1
- astrbot/core/provider/provider.py +35 -0
- astrbot/core/utils/file_extract.py +23 -0
- astrbot/dashboard/routes/config.py +13 -165
- astrbot/dashboard/routes/plugin.py +65 -6
- {astrbot-4.7.3.dist-info → astrbot-4.7.4.dist-info}/METADATA +1 -1
- {astrbot-4.7.3.dist-info → astrbot-4.7.4.dist-info}/RECORD +17 -16
- {astrbot-4.7.3.dist-info → astrbot-4.7.4.dist-info}/WHEEL +0 -0
- {astrbot-4.7.3.dist-info → astrbot-4.7.4.dist-info}/entry_points.txt +0 -0
- {astrbot-4.7.3.dist-info → astrbot-4.7.4.dist-info}/licenses/LICENSE +0 -0
astrbot/cli/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "4.7.
|
|
1
|
+
__version__ = "4.7.4"
|
astrbot/core/agent/message.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
from typing import Any, ClassVar, Literal, cast
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel, GetCoreSchemaHandler
|
|
6
|
+
from pydantic import BaseModel, GetCoreSchemaHandler, model_validator
|
|
7
7
|
from pydantic_core import core_schema
|
|
8
8
|
|
|
9
9
|
|
|
@@ -145,23 +145,39 @@ class Message(BaseModel):
|
|
|
145
145
|
"tool",
|
|
146
146
|
]
|
|
147
147
|
|
|
148
|
-
content: str | list[ContentPart]
|
|
148
|
+
content: str | list[ContentPart] | None = None
|
|
149
149
|
"""The content of the message."""
|
|
150
150
|
|
|
151
|
+
tool_calls: list[ToolCall] | list[dict] | None = None
|
|
152
|
+
"""The tool calls of the message."""
|
|
153
|
+
|
|
154
|
+
tool_call_id: str | None = None
|
|
155
|
+
"""The ID of the tool call."""
|
|
156
|
+
|
|
157
|
+
@model_validator(mode="after")
|
|
158
|
+
def check_content_required(self):
|
|
159
|
+
# assistant + tool_calls is not None: allow content to be None
|
|
160
|
+
if self.role == "assistant" and self.tool_calls is not None:
|
|
161
|
+
return self
|
|
162
|
+
|
|
163
|
+
# other all cases: content is required
|
|
164
|
+
if self.content is None:
|
|
165
|
+
raise ValueError(
|
|
166
|
+
"content is required unless role='assistant' and tool_calls is not None"
|
|
167
|
+
)
|
|
168
|
+
return self
|
|
169
|
+
|
|
151
170
|
|
|
152
171
|
class AssistantMessageSegment(Message):
|
|
153
172
|
"""A message segment from the assistant."""
|
|
154
173
|
|
|
155
174
|
role: Literal["assistant"] = "assistant"
|
|
156
|
-
content: str | list[ContentPart] | None = None
|
|
157
|
-
tool_calls: list[ToolCall] | list[dict] | None = None
|
|
158
175
|
|
|
159
176
|
|
|
160
177
|
class ToolCallMessageSegment(Message):
|
|
161
178
|
"""A message segment representing a tool call."""
|
|
162
179
|
|
|
163
180
|
role: Literal["tool"] = "tool"
|
|
164
|
-
tool_call_id: str
|
|
165
181
|
|
|
166
182
|
|
|
167
183
|
class UserMessageSegment(Message):
|
astrbot/core/config/default.py
CHANGED
|
@@ -4,7 +4,7 @@ import os
|
|
|
4
4
|
|
|
5
5
|
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
6
6
|
|
|
7
|
-
VERSION = "4.7.
|
|
7
|
+
VERSION = "4.7.4"
|
|
8
8
|
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
|
|
9
9
|
|
|
10
10
|
# 默认配置
|
|
@@ -73,8 +73,14 @@ DEFAULT_CONFIG = {
|
|
|
73
73
|
"coze_agent_runner_provider_id": "",
|
|
74
74
|
"dashscope_agent_runner_provider_id": "",
|
|
75
75
|
"unsupported_streaming_strategy": "realtime_segmenting",
|
|
76
|
+
"reachability_check": False,
|
|
76
77
|
"max_agent_step": 30,
|
|
77
78
|
"tool_call_timeout": 60,
|
|
79
|
+
"file_extract": {
|
|
80
|
+
"enable": False,
|
|
81
|
+
"provider": "moonshotai",
|
|
82
|
+
"moonshotai_api_key": "",
|
|
83
|
+
},
|
|
78
84
|
},
|
|
79
85
|
"provider_stt_settings": {
|
|
80
86
|
"enable": False,
|
|
@@ -2068,6 +2074,20 @@ CONFIG_METADATA_2 = {
|
|
|
2068
2074
|
"tool_call_timeout": {
|
|
2069
2075
|
"type": "int",
|
|
2070
2076
|
},
|
|
2077
|
+
"file_extract": {
|
|
2078
|
+
"type": "object",
|
|
2079
|
+
"items": {
|
|
2080
|
+
"enable": {
|
|
2081
|
+
"type": "bool",
|
|
2082
|
+
},
|
|
2083
|
+
"provider": {
|
|
2084
|
+
"type": "string",
|
|
2085
|
+
},
|
|
2086
|
+
"moonshotai_api_key": {
|
|
2087
|
+
"type": "string",
|
|
2088
|
+
},
|
|
2089
|
+
},
|
|
2090
|
+
},
|
|
2071
2091
|
},
|
|
2072
2092
|
},
|
|
2073
2093
|
"provider_stt_settings": {
|
|
@@ -2402,6 +2422,36 @@ CONFIG_METADATA_3 = {
|
|
|
2402
2422
|
"provider_settings.enable": True,
|
|
2403
2423
|
},
|
|
2404
2424
|
},
|
|
2425
|
+
# "file_extract": {
|
|
2426
|
+
# "description": "文档解析能力 [beta]",
|
|
2427
|
+
# "type": "object",
|
|
2428
|
+
# "items": {
|
|
2429
|
+
# "provider_settings.file_extract.enable": {
|
|
2430
|
+
# "description": "启用文档解析能力",
|
|
2431
|
+
# "type": "bool",
|
|
2432
|
+
# },
|
|
2433
|
+
# "provider_settings.file_extract.provider": {
|
|
2434
|
+
# "description": "文档解析提供商",
|
|
2435
|
+
# "type": "string",
|
|
2436
|
+
# "options": ["moonshotai"],
|
|
2437
|
+
# "condition": {
|
|
2438
|
+
# "provider_settings.file_extract.enable": True,
|
|
2439
|
+
# },
|
|
2440
|
+
# },
|
|
2441
|
+
# "provider_settings.file_extract.moonshotai_api_key": {
|
|
2442
|
+
# "description": "Moonshot AI API Key",
|
|
2443
|
+
# "type": "string",
|
|
2444
|
+
# "condition": {
|
|
2445
|
+
# "provider_settings.file_extract.provider": "moonshotai",
|
|
2446
|
+
# "provider_settings.file_extract.enable": True,
|
|
2447
|
+
# },
|
|
2448
|
+
# },
|
|
2449
|
+
# },
|
|
2450
|
+
# "condition": {
|
|
2451
|
+
# "provider_settings.agent_runner_type": "local",
|
|
2452
|
+
# "provider_settings.enable": True,
|
|
2453
|
+
# },
|
|
2454
|
+
# },
|
|
2405
2455
|
"others": {
|
|
2406
2456
|
"description": "其他配置",
|
|
2407
2457
|
"type": "object",
|
|
@@ -2496,6 +2546,11 @@ CONFIG_METADATA_3 = {
|
|
|
2496
2546
|
"description": "开启 TTS 时同时输出语音和文字内容",
|
|
2497
2547
|
"type": "bool",
|
|
2498
2548
|
},
|
|
2549
|
+
"provider_settings.reachability_check": {
|
|
2550
|
+
"description": "提供商可达性检测",
|
|
2551
|
+
"type": "bool",
|
|
2552
|
+
"hint": "/provider 命令列出模型时是否并发检测连通性。开启后会主动调用模型测试连通性,可能产生额外 token 消耗。",
|
|
2553
|
+
},
|
|
2499
2554
|
},
|
|
2500
2555
|
"condition": {
|
|
2501
2556
|
"provider_settings.enable": True,
|
|
@@ -722,7 +722,12 @@ class File(BaseMessageComponent):
|
|
|
722
722
|
"""下载文件"""
|
|
723
723
|
download_dir = os.path.join(get_astrbot_data_path(), "temp")
|
|
724
724
|
os.makedirs(download_dir, exist_ok=True)
|
|
725
|
-
|
|
725
|
+
if self.name:
|
|
726
|
+
name, ext = os.path.splitext(self.name)
|
|
727
|
+
filename = f"{name}_{uuid.uuid4().hex[:8]}{ext}"
|
|
728
|
+
else:
|
|
729
|
+
filename = f"{uuid.uuid4().hex}"
|
|
730
|
+
file_path = os.path.join(download_dir, filename)
|
|
726
731
|
await download_file(self.url, file_path)
|
|
727
732
|
self.file_ = os.path.abspath(file_path)
|
|
728
733
|
|
|
@@ -9,7 +9,7 @@ from astrbot.core import logger
|
|
|
9
9
|
from astrbot.core.agent.tool import ToolSet
|
|
10
10
|
from astrbot.core.astr_agent_context import AstrAgentContext
|
|
11
11
|
from astrbot.core.conversation_mgr import Conversation
|
|
12
|
-
from astrbot.core.message.components import Image
|
|
12
|
+
from astrbot.core.message.components import File, Image, Reply
|
|
13
13
|
from astrbot.core.message.message_event_result import (
|
|
14
14
|
MessageChain,
|
|
15
15
|
MessageEventResult,
|
|
@@ -22,6 +22,7 @@ from astrbot.core.provider.entities import (
|
|
|
22
22
|
ProviderRequest,
|
|
23
23
|
)
|
|
24
24
|
from astrbot.core.star.star_handler import EventType, star_map
|
|
25
|
+
from astrbot.core.utils.file_extract import extract_file_moonshotai
|
|
25
26
|
from astrbot.core.utils.metrics import Metric
|
|
26
27
|
from astrbot.core.utils.session_lock import session_lock_manager
|
|
27
28
|
|
|
@@ -56,6 +57,13 @@ class InternalAgentSubStage(Stage):
|
|
|
56
57
|
self.show_reasoning = settings.get("display_reasoning_text", False)
|
|
57
58
|
self.kb_agentic_mode: bool = conf.get("kb_agentic_mode", False)
|
|
58
59
|
|
|
60
|
+
file_extract_conf: dict = settings.get("file_extract", {})
|
|
61
|
+
self.file_extract_enabled: bool = file_extract_conf.get("enable", False)
|
|
62
|
+
self.file_extract_prov: str = file_extract_conf.get("provider", "moonshotai")
|
|
63
|
+
self.file_extract_msh_api_key: str = file_extract_conf.get(
|
|
64
|
+
"moonshotai_api_key", ""
|
|
65
|
+
)
|
|
66
|
+
|
|
59
67
|
self.conv_manager = ctx.plugin_manager.context.conversation_manager
|
|
60
68
|
|
|
61
69
|
def _select_provider(self, event: AstrMessageEvent):
|
|
@@ -114,6 +122,50 @@ class InternalAgentSubStage(Stage):
|
|
|
114
122
|
req.func_tool = ToolSet()
|
|
115
123
|
req.func_tool.add_tool(KNOWLEDGE_BASE_QUERY_TOOL)
|
|
116
124
|
|
|
125
|
+
async def _apply_file_extract(
|
|
126
|
+
self,
|
|
127
|
+
event: AstrMessageEvent,
|
|
128
|
+
req: ProviderRequest,
|
|
129
|
+
):
|
|
130
|
+
"""Apply file extract to the provider request"""
|
|
131
|
+
file_paths = []
|
|
132
|
+
file_names = []
|
|
133
|
+
for comp in event.message_obj.message:
|
|
134
|
+
if isinstance(comp, File):
|
|
135
|
+
file_paths.append(await comp.get_file())
|
|
136
|
+
file_names.append(comp.name)
|
|
137
|
+
elif isinstance(comp, Reply) and comp.chain:
|
|
138
|
+
for reply_comp in comp.chain:
|
|
139
|
+
if isinstance(reply_comp, File):
|
|
140
|
+
file_paths.append(await reply_comp.get_file())
|
|
141
|
+
file_names.append(reply_comp.name)
|
|
142
|
+
if not file_paths:
|
|
143
|
+
return
|
|
144
|
+
if not req.prompt:
|
|
145
|
+
req.prompt = "总结一下文件里面讲了什么?"
|
|
146
|
+
if self.file_extract_prov == "moonshotai":
|
|
147
|
+
if not self.file_extract_msh_api_key:
|
|
148
|
+
logger.error("Moonshot AI API key for file extract is not set")
|
|
149
|
+
return
|
|
150
|
+
file_contents = await asyncio.gather(
|
|
151
|
+
*[
|
|
152
|
+
extract_file_moonshotai(file_path, self.file_extract_msh_api_key)
|
|
153
|
+
for file_path in file_paths
|
|
154
|
+
]
|
|
155
|
+
)
|
|
156
|
+
else:
|
|
157
|
+
logger.error(f"Unsupported file extract provider: {self.file_extract_prov}")
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
# add file extract results to contexts
|
|
161
|
+
for file_content, file_name in zip(file_contents, file_names):
|
|
162
|
+
req.contexts.append(
|
|
163
|
+
{
|
|
164
|
+
"role": "system",
|
|
165
|
+
"content": f"File Extract Results of user uploaded files:\n{file_content}\nFile Name: {file_name or 'Unknown'}",
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
|
|
117
169
|
def _truncate_contexts(
|
|
118
170
|
self,
|
|
119
171
|
contexts: list[dict],
|
|
@@ -346,6 +398,17 @@ class InternalAgentSubStage(Stage):
|
|
|
346
398
|
|
|
347
399
|
event.set_extra("provider_request", req)
|
|
348
400
|
|
|
401
|
+
# fix contexts json str
|
|
402
|
+
if isinstance(req.contexts, str):
|
|
403
|
+
req.contexts = json.loads(req.contexts)
|
|
404
|
+
|
|
405
|
+
# apply file extract
|
|
406
|
+
if self.file_extract_enabled:
|
|
407
|
+
try:
|
|
408
|
+
await self._apply_file_extract(event, req)
|
|
409
|
+
except Exception as e:
|
|
410
|
+
logger.error(f"Error occurred while applying file extract: {e}")
|
|
411
|
+
|
|
349
412
|
if not req.prompt and not req.image_urls:
|
|
350
413
|
return
|
|
351
414
|
|
|
@@ -356,10 +419,6 @@ class InternalAgentSubStage(Stage):
|
|
|
356
419
|
# apply knowledge base feature
|
|
357
420
|
await self._apply_kb(event, req)
|
|
358
421
|
|
|
359
|
-
# fix contexts json str
|
|
360
|
-
if isinstance(req.contexts, str):
|
|
361
|
-
req.contexts = json.loads(req.contexts)
|
|
362
|
-
|
|
363
422
|
# truncate contexts to fit max length
|
|
364
423
|
if req.contexts:
|
|
365
424
|
req.contexts = self._truncate_contexts(req.contexts)
|
|
@@ -246,7 +246,13 @@ class AiocqhttpAdapter(Platform):
|
|
|
246
246
|
if m["data"].get("url") and m["data"].get("url").startswith("http"):
|
|
247
247
|
# Lagrange
|
|
248
248
|
logger.info("guessing lagrange")
|
|
249
|
-
|
|
249
|
+
# 检查多个可能的文件名字段
|
|
250
|
+
file_name = (
|
|
251
|
+
m["data"].get("file_name", "")
|
|
252
|
+
or m["data"].get("name", "")
|
|
253
|
+
or m["data"].get("file", "")
|
|
254
|
+
or "file"
|
|
255
|
+
)
|
|
250
256
|
abm.message.append(File(name=file_name, url=m["data"]["url"]))
|
|
251
257
|
else:
|
|
252
258
|
try:
|
|
@@ -265,7 +271,14 @@ class AiocqhttpAdapter(Platform):
|
|
|
265
271
|
)
|
|
266
272
|
if ret and "url" in ret:
|
|
267
273
|
file_url = ret["url"] # https
|
|
268
|
-
|
|
274
|
+
# 优先从 API 返回值获取文件名,其次从原始消息数据获取
|
|
275
|
+
file_name = (
|
|
276
|
+
ret.get("file_name", "")
|
|
277
|
+
or ret.get("name", "")
|
|
278
|
+
or m["data"].get("file", "")
|
|
279
|
+
or m["data"].get("file_name", "")
|
|
280
|
+
)
|
|
281
|
+
a = File(name=file_name, url=file_url)
|
|
269
282
|
abm.message.append(a)
|
|
270
283
|
else:
|
|
271
284
|
logger.error(f"获取文件失败: {ret}")
|
|
@@ -250,7 +250,7 @@ class DingtalkPlatformAdapter(Platform):
|
|
|
250
250
|
|
|
251
251
|
async def terminate(self):
|
|
252
252
|
def monkey_patch_close():
|
|
253
|
-
raise
|
|
253
|
+
raise KeyboardInterrupt("Graceful shutdown")
|
|
254
254
|
|
|
255
255
|
self.client_.open_connection = monkey_patch_close
|
|
256
256
|
await self.client_.websocket.close(code=1000, reason="Graceful shutdown")
|
|
@@ -381,7 +381,9 @@ class TelegramPlatformAdapter(Platform):
|
|
|
381
381
|
f"Telegram document file_path is None, cannot save the file {file_name}.",
|
|
382
382
|
)
|
|
383
383
|
else:
|
|
384
|
-
message.message.append(
|
|
384
|
+
message.message.append(
|
|
385
|
+
Comp.File(file=file_path, name=file_name, url=file_path)
|
|
386
|
+
)
|
|
385
387
|
|
|
386
388
|
elif update.message.video:
|
|
387
389
|
file = await update.message.video.get_file()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import abc
|
|
2
2
|
import asyncio
|
|
3
|
+
import os
|
|
3
4
|
from collections.abc import AsyncGenerator
|
|
4
5
|
|
|
5
6
|
from astrbot.core.agent.message import Message
|
|
@@ -11,6 +12,7 @@ from astrbot.core.provider.entities import (
|
|
|
11
12
|
ToolCallsResult,
|
|
12
13
|
)
|
|
13
14
|
from astrbot.core.provider.register import provider_cls_map
|
|
15
|
+
from astrbot.core.utils.astrbot_path import get_astrbot_path
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class AbstractProvider(abc.ABC):
|
|
@@ -43,6 +45,14 @@ class AbstractProvider(abc.ABC):
|
|
|
43
45
|
)
|
|
44
46
|
return meta
|
|
45
47
|
|
|
48
|
+
async def test(self):
|
|
49
|
+
"""test the provider is a
|
|
50
|
+
|
|
51
|
+
raises:
|
|
52
|
+
Exception: if the provider is not available
|
|
53
|
+
"""
|
|
54
|
+
...
|
|
55
|
+
|
|
46
56
|
|
|
47
57
|
class Provider(AbstractProvider):
|
|
48
58
|
"""Chat Provider"""
|
|
@@ -165,6 +175,12 @@ class Provider(AbstractProvider):
|
|
|
165
175
|
|
|
166
176
|
return dicts
|
|
167
177
|
|
|
178
|
+
async def test(self, timeout: float = 45.0):
|
|
179
|
+
await asyncio.wait_for(
|
|
180
|
+
self.text_chat(prompt="REPLY `PONG` ONLY"),
|
|
181
|
+
timeout=timeout,
|
|
182
|
+
)
|
|
183
|
+
|
|
168
184
|
|
|
169
185
|
class STTProvider(AbstractProvider):
|
|
170
186
|
def __init__(self, provider_config: dict, provider_settings: dict) -> None:
|
|
@@ -177,6 +193,14 @@ class STTProvider(AbstractProvider):
|
|
|
177
193
|
"""获取音频的文本"""
|
|
178
194
|
raise NotImplementedError
|
|
179
195
|
|
|
196
|
+
async def test(self):
|
|
197
|
+
sample_audio_path = os.path.join(
|
|
198
|
+
get_astrbot_path(),
|
|
199
|
+
"samples",
|
|
200
|
+
"stt_health_check.wav",
|
|
201
|
+
)
|
|
202
|
+
await self.get_text(sample_audio_path)
|
|
203
|
+
|
|
180
204
|
|
|
181
205
|
class TTSProvider(AbstractProvider):
|
|
182
206
|
def __init__(self, provider_config: dict, provider_settings: dict) -> None:
|
|
@@ -189,6 +213,9 @@ class TTSProvider(AbstractProvider):
|
|
|
189
213
|
"""获取文本的音频,返回音频文件路径"""
|
|
190
214
|
raise NotImplementedError
|
|
191
215
|
|
|
216
|
+
async def test(self):
|
|
217
|
+
await self.get_audio("hi")
|
|
218
|
+
|
|
192
219
|
|
|
193
220
|
class EmbeddingProvider(AbstractProvider):
|
|
194
221
|
def __init__(self, provider_config: dict, provider_settings: dict) -> None:
|
|
@@ -211,6 +238,9 @@ class EmbeddingProvider(AbstractProvider):
|
|
|
211
238
|
"""获取向量的维度"""
|
|
212
239
|
...
|
|
213
240
|
|
|
241
|
+
async def test(self):
|
|
242
|
+
await self.get_embedding("astrbot")
|
|
243
|
+
|
|
214
244
|
async def get_embeddings_batch(
|
|
215
245
|
self,
|
|
216
246
|
texts: list[str],
|
|
@@ -294,3 +324,8 @@ class RerankProvider(AbstractProvider):
|
|
|
294
324
|
) -> list[RerankResult]:
|
|
295
325
|
"""获取查询和文档的重排序分数"""
|
|
296
326
|
...
|
|
327
|
+
|
|
328
|
+
async def test(self):
|
|
329
|
+
result = await self.rerank("Apple", documents=["apple", "banana"])
|
|
330
|
+
if not result:
|
|
331
|
+
raise Exception("Rerank provider test failed, no results returned")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from openai import AsyncOpenAI
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def extract_file_moonshotai(file_path: str, api_key: str) -> str:
|
|
7
|
+
"""Extract text from a file using Moonshot AI API"""
|
|
8
|
+
"""
|
|
9
|
+
Args:
|
|
10
|
+
file_path: The path to the file to extract text from
|
|
11
|
+
api_key: The API key to use to extract text from the file
|
|
12
|
+
Returns:
|
|
13
|
+
The text extracted from the file
|
|
14
|
+
"""
|
|
15
|
+
client = AsyncOpenAI(
|
|
16
|
+
api_key=api_key,
|
|
17
|
+
base_url="https://api.moonshot.cn/v1",
|
|
18
|
+
)
|
|
19
|
+
file_object = await client.files.create(
|
|
20
|
+
file=Path(file_path),
|
|
21
|
+
purpose="file-extract", # type: ignore
|
|
22
|
+
)
|
|
23
|
+
return (await client.files.content(file_id=file_object.id)).text
|
|
@@ -18,11 +18,8 @@ from astrbot.core.config.i18n_utils import ConfigMetadataI18n
|
|
|
18
18
|
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
19
19
|
from astrbot.core.platform.register import platform_cls_map, platform_registry
|
|
20
20
|
from astrbot.core.provider import Provider
|
|
21
|
-
from astrbot.core.provider.entities import ProviderType
|
|
22
|
-
from astrbot.core.provider.provider import RerankProvider
|
|
23
21
|
from astrbot.core.provider.register import provider_registry
|
|
24
22
|
from astrbot.core.star.star import star_registry
|
|
25
|
-
from astrbot.core.utils.astrbot_path import get_astrbot_path
|
|
26
23
|
|
|
27
24
|
from .route import Response, Route, RouteContext
|
|
28
25
|
|
|
@@ -356,169 +353,20 @@ class ConfigRoute(Route):
|
|
|
356
353
|
f"Attempting to check provider: {status_info['name']} (ID: {status_info['id']}, Type: {status_info['type']}, Model: {status_info['model']})",
|
|
357
354
|
)
|
|
358
355
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
logger.debug(f"Sending 'Ping' to provider: {status_info['name']}")
|
|
362
|
-
response = await asyncio.wait_for(
|
|
363
|
-
provider.text_chat(prompt="REPLY `PONG` ONLY"),
|
|
364
|
-
timeout=45.0,
|
|
365
|
-
)
|
|
366
|
-
logger.debug(
|
|
367
|
-
f"Received response from {status_info['name']}: {response}",
|
|
368
|
-
)
|
|
369
|
-
if response is not None:
|
|
370
|
-
status_info["status"] = "available"
|
|
371
|
-
response_text_snippet = ""
|
|
372
|
-
if (
|
|
373
|
-
hasattr(response, "completion_text")
|
|
374
|
-
and response.completion_text
|
|
375
|
-
):
|
|
376
|
-
response_text_snippet = (
|
|
377
|
-
response.completion_text[:70] + "..."
|
|
378
|
-
if len(response.completion_text) > 70
|
|
379
|
-
else response.completion_text
|
|
380
|
-
)
|
|
381
|
-
elif hasattr(response, "result_chain") and response.result_chain:
|
|
382
|
-
try:
|
|
383
|
-
response_text_snippet = (
|
|
384
|
-
response.result_chain.get_plain_text()[:70] + "..."
|
|
385
|
-
if len(response.result_chain.get_plain_text()) > 70
|
|
386
|
-
else response.result_chain.get_plain_text()
|
|
387
|
-
)
|
|
388
|
-
except Exception as _:
|
|
389
|
-
pass
|
|
390
|
-
logger.info(
|
|
391
|
-
f"Provider {status_info['name']} (ID: {status_info['id']}) is available. Response snippet: '{response_text_snippet}'",
|
|
392
|
-
)
|
|
393
|
-
else:
|
|
394
|
-
status_info["error"] = (
|
|
395
|
-
"Test call returned None, but expected an LLMResponse object."
|
|
396
|
-
)
|
|
397
|
-
logger.warning(
|
|
398
|
-
f"Provider {status_info['name']} (ID: {status_info['id']}) test call returned None.",
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
except asyncio.TimeoutError:
|
|
402
|
-
status_info["error"] = (
|
|
403
|
-
"Connection timed out after 45 seconds during test call."
|
|
404
|
-
)
|
|
405
|
-
logger.warning(
|
|
406
|
-
f"Provider {status_info['name']} (ID: {status_info['id']}) timed out.",
|
|
407
|
-
)
|
|
408
|
-
except Exception as e:
|
|
409
|
-
error_message = str(e)
|
|
410
|
-
status_info["error"] = error_message
|
|
411
|
-
logger.warning(
|
|
412
|
-
f"Provider {status_info['name']} (ID: {status_info['id']}) is unavailable. Error: {error_message}",
|
|
413
|
-
)
|
|
414
|
-
logger.debug(
|
|
415
|
-
f"Traceback for {status_info['name']}:\n{traceback.format_exc()}",
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
elif provider_capability_type == ProviderType.EMBEDDING:
|
|
419
|
-
try:
|
|
420
|
-
# For embedding, we can call the get_embedding method with a short prompt.
|
|
421
|
-
embedding_result = await provider.get_embedding("health_check")
|
|
422
|
-
if isinstance(embedding_result, list) and (
|
|
423
|
-
not embedding_result or isinstance(embedding_result[0], float)
|
|
424
|
-
):
|
|
425
|
-
status_info["status"] = "available"
|
|
426
|
-
else:
|
|
427
|
-
status_info["status"] = "unavailable"
|
|
428
|
-
status_info["error"] = (
|
|
429
|
-
f"Embedding test failed: unexpected result type {type(embedding_result)}"
|
|
430
|
-
)
|
|
431
|
-
except Exception as e:
|
|
432
|
-
logger.error(
|
|
433
|
-
f"Error testing embedding provider {provider_name}: {e}",
|
|
434
|
-
exc_info=True,
|
|
435
|
-
)
|
|
436
|
-
status_info["status"] = "unavailable"
|
|
437
|
-
status_info["error"] = f"Embedding test failed: {e!s}"
|
|
438
|
-
|
|
439
|
-
elif provider_capability_type == ProviderType.TEXT_TO_SPEECH:
|
|
440
|
-
try:
|
|
441
|
-
# For TTS, we can call the get_audio method with a short prompt.
|
|
442
|
-
audio_result = await provider.get_audio("你好")
|
|
443
|
-
if isinstance(audio_result, str) and audio_result:
|
|
444
|
-
status_info["status"] = "available"
|
|
445
|
-
else:
|
|
446
|
-
status_info["status"] = "unavailable"
|
|
447
|
-
status_info["error"] = (
|
|
448
|
-
f"TTS test failed: unexpected result type {type(audio_result)}"
|
|
449
|
-
)
|
|
450
|
-
except Exception as e:
|
|
451
|
-
logger.error(
|
|
452
|
-
f"Error testing TTS provider {provider_name}: {e}",
|
|
453
|
-
exc_info=True,
|
|
454
|
-
)
|
|
455
|
-
status_info["status"] = "unavailable"
|
|
456
|
-
status_info["error"] = f"TTS test failed: {e!s}"
|
|
457
|
-
elif provider_capability_type == ProviderType.SPEECH_TO_TEXT:
|
|
458
|
-
try:
|
|
459
|
-
logger.debug(
|
|
460
|
-
f"Sending health check audio to provider: {status_info['name']}",
|
|
461
|
-
)
|
|
462
|
-
sample_audio_path = os.path.join(
|
|
463
|
-
get_astrbot_path(),
|
|
464
|
-
"samples",
|
|
465
|
-
"stt_health_check.wav",
|
|
466
|
-
)
|
|
467
|
-
if not os.path.exists(sample_audio_path):
|
|
468
|
-
status_info["status"] = "unavailable"
|
|
469
|
-
status_info["error"] = (
|
|
470
|
-
"STT test failed: sample audio file not found."
|
|
471
|
-
)
|
|
472
|
-
logger.warning(
|
|
473
|
-
f"STT test for {status_info['name']} failed: sample audio file not found at {sample_audio_path}",
|
|
474
|
-
)
|
|
475
|
-
else:
|
|
476
|
-
text_result = await provider.get_text(sample_audio_path)
|
|
477
|
-
if isinstance(text_result, str) and text_result:
|
|
478
|
-
status_info["status"] = "available"
|
|
479
|
-
snippet = (
|
|
480
|
-
text_result[:70] + "..."
|
|
481
|
-
if len(text_result) > 70
|
|
482
|
-
else text_result
|
|
483
|
-
)
|
|
484
|
-
logger.info(
|
|
485
|
-
f"Provider {status_info['name']} (ID: {status_info['id']}) is available. Response snippet: '{snippet}'",
|
|
486
|
-
)
|
|
487
|
-
else:
|
|
488
|
-
status_info["status"] = "unavailable"
|
|
489
|
-
status_info["error"] = (
|
|
490
|
-
f"STT test failed: unexpected result type {type(text_result)}"
|
|
491
|
-
)
|
|
492
|
-
logger.warning(
|
|
493
|
-
f"STT test for {status_info['name']} failed: unexpected result type {type(text_result)}",
|
|
494
|
-
)
|
|
495
|
-
except Exception as e:
|
|
496
|
-
logger.error(
|
|
497
|
-
f"Error testing STT provider {provider_name}: {e}",
|
|
498
|
-
exc_info=True,
|
|
499
|
-
)
|
|
500
|
-
status_info["status"] = "unavailable"
|
|
501
|
-
status_info["error"] = f"STT test failed: {e!s}"
|
|
502
|
-
elif provider_capability_type == ProviderType.RERANK:
|
|
503
|
-
try:
|
|
504
|
-
assert isinstance(provider, RerankProvider)
|
|
505
|
-
await provider.rerank("Apple", documents=["apple", "banana"])
|
|
506
|
-
status_info["status"] = "available"
|
|
507
|
-
except Exception as e:
|
|
508
|
-
logger.error(
|
|
509
|
-
f"Error testing rerank provider {provider_name}: {e}",
|
|
510
|
-
exc_info=True,
|
|
511
|
-
)
|
|
512
|
-
status_info["status"] = "unavailable"
|
|
513
|
-
status_info["error"] = f"Rerank test failed: {e!s}"
|
|
514
|
-
|
|
515
|
-
else:
|
|
516
|
-
logger.debug(
|
|
517
|
-
f"Provider {provider_name} is not a Chat Completion or Embedding provider. Marking as available without test. Meta: {meta}",
|
|
518
|
-
)
|
|
356
|
+
try:
|
|
357
|
+
await provider.test()
|
|
519
358
|
status_info["status"] = "available"
|
|
520
|
-
|
|
521
|
-
"
|
|
359
|
+
logger.info(
|
|
360
|
+
f"Provider {status_info['name']} (ID: {status_info['id']}) is available.",
|
|
361
|
+
)
|
|
362
|
+
except Exception as e:
|
|
363
|
+
error_message = str(e)
|
|
364
|
+
status_info["error"] = error_message
|
|
365
|
+
logger.warning(
|
|
366
|
+
f"Provider {status_info['name']} (ID: {status_info['id']}) is unavailable. Error: {error_message}",
|
|
367
|
+
)
|
|
368
|
+
logger.debug(
|
|
369
|
+
f"Traceback for {status_info['name']}:\n{traceback.format_exc()}",
|
|
522
370
|
)
|
|
523
371
|
|
|
524
372
|
return status_info
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import json
|
|
2
3
|
import os
|
|
3
4
|
import ssl
|
|
@@ -19,6 +20,10 @@ from astrbot.core.star.star_manager import PluginManager
|
|
|
19
20
|
|
|
20
21
|
from .route import Response, Route, RouteContext
|
|
21
22
|
|
|
23
|
+
PLUGIN_UPDATE_CONCURRENCY = (
|
|
24
|
+
3 # limit concurrent updates to avoid overwhelming plugin sources
|
|
25
|
+
)
|
|
26
|
+
|
|
22
27
|
|
|
23
28
|
class PluginRoute(Route):
|
|
24
29
|
def __init__(
|
|
@@ -33,6 +38,7 @@ class PluginRoute(Route):
|
|
|
33
38
|
"/plugin/install": ("POST", self.install_plugin),
|
|
34
39
|
"/plugin/install-upload": ("POST", self.install_plugin_upload),
|
|
35
40
|
"/plugin/update": ("POST", self.update_plugin),
|
|
41
|
+
"/plugin/update-all": ("POST", self.update_all_plugins),
|
|
36
42
|
"/plugin/uninstall": ("POST", self.uninstall_plugin),
|
|
37
43
|
"/plugin/market_list": ("GET", self.get_online_plugins),
|
|
38
44
|
"/plugin/off": ("POST", self.off_plugin),
|
|
@@ -63,7 +69,7 @@ class PluginRoute(Route):
|
|
|
63
69
|
.__dict__
|
|
64
70
|
)
|
|
65
71
|
|
|
66
|
-
data = await request.
|
|
72
|
+
data = await request.get_json()
|
|
67
73
|
plugin_name = data.get("name", None)
|
|
68
74
|
try:
|
|
69
75
|
success, message = await self.plugin_manager.reload(plugin_name)
|
|
@@ -346,7 +352,7 @@ class PluginRoute(Route):
|
|
|
346
352
|
.__dict__
|
|
347
353
|
)
|
|
348
354
|
|
|
349
|
-
post_data = await request.
|
|
355
|
+
post_data = await request.get_json()
|
|
350
356
|
repo_url = post_data["url"]
|
|
351
357
|
|
|
352
358
|
proxy: str = post_data.get("proxy", None)
|
|
@@ -393,7 +399,7 @@ class PluginRoute(Route):
|
|
|
393
399
|
.__dict__
|
|
394
400
|
)
|
|
395
401
|
|
|
396
|
-
post_data = await request.
|
|
402
|
+
post_data = await request.get_json()
|
|
397
403
|
plugin_name = post_data["name"]
|
|
398
404
|
delete_config = post_data.get("delete_config", False)
|
|
399
405
|
delete_data = post_data.get("delete_data", False)
|
|
@@ -418,7 +424,7 @@ class PluginRoute(Route):
|
|
|
418
424
|
.__dict__
|
|
419
425
|
)
|
|
420
426
|
|
|
421
|
-
post_data = await request.
|
|
427
|
+
post_data = await request.get_json()
|
|
422
428
|
plugin_name = post_data["name"]
|
|
423
429
|
proxy: str = post_data.get("proxy", None)
|
|
424
430
|
try:
|
|
@@ -432,6 +438,59 @@ class PluginRoute(Route):
|
|
|
432
438
|
logger.error(f"/api/plugin/update: {traceback.format_exc()}")
|
|
433
439
|
return Response().error(str(e)).__dict__
|
|
434
440
|
|
|
441
|
+
async def update_all_plugins(self):
|
|
442
|
+
if DEMO_MODE:
|
|
443
|
+
return (
|
|
444
|
+
Response()
|
|
445
|
+
.error("You are not permitted to do this operation in demo mode")
|
|
446
|
+
.__dict__
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
post_data = await request.get_json()
|
|
450
|
+
plugin_names: list[str] = post_data.get("names") or []
|
|
451
|
+
proxy: str = post_data.get("proxy", "")
|
|
452
|
+
|
|
453
|
+
if not isinstance(plugin_names, list) or not plugin_names:
|
|
454
|
+
return Response().error("插件列表不能为空").__dict__
|
|
455
|
+
|
|
456
|
+
results = []
|
|
457
|
+
sem = asyncio.Semaphore(PLUGIN_UPDATE_CONCURRENCY)
|
|
458
|
+
|
|
459
|
+
async def _update_one(name: str):
|
|
460
|
+
async with sem:
|
|
461
|
+
try:
|
|
462
|
+
logger.info(f"批量更新插件 {name}")
|
|
463
|
+
await self.plugin_manager.update_plugin(name, proxy)
|
|
464
|
+
return {"name": name, "status": "ok", "message": "更新成功"}
|
|
465
|
+
except Exception as e:
|
|
466
|
+
logger.error(
|
|
467
|
+
f"/api/plugin/update-all: 更新插件 {name} 失败: {traceback.format_exc()}",
|
|
468
|
+
)
|
|
469
|
+
return {"name": name, "status": "error", "message": str(e)}
|
|
470
|
+
|
|
471
|
+
raw_results = await asyncio.gather(
|
|
472
|
+
*(_update_one(name) for name in plugin_names),
|
|
473
|
+
return_exceptions=True,
|
|
474
|
+
)
|
|
475
|
+
for name, result in zip(plugin_names, raw_results):
|
|
476
|
+
if isinstance(result, asyncio.CancelledError):
|
|
477
|
+
raise result
|
|
478
|
+
if isinstance(result, BaseException):
|
|
479
|
+
results.append(
|
|
480
|
+
{"name": name, "status": "error", "message": str(result)}
|
|
481
|
+
)
|
|
482
|
+
else:
|
|
483
|
+
results.append(result)
|
|
484
|
+
|
|
485
|
+
failed = [r for r in results if r["status"] == "error"]
|
|
486
|
+
message = (
|
|
487
|
+
"批量更新完成,全部成功。"
|
|
488
|
+
if not failed
|
|
489
|
+
else f"批量更新完成,其中 {len(failed)}/{len(results)} 个插件失败。"
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
return Response().ok({"results": results}, message).__dict__
|
|
493
|
+
|
|
435
494
|
async def off_plugin(self):
|
|
436
495
|
if DEMO_MODE:
|
|
437
496
|
return (
|
|
@@ -440,7 +499,7 @@ class PluginRoute(Route):
|
|
|
440
499
|
.__dict__
|
|
441
500
|
)
|
|
442
501
|
|
|
443
|
-
post_data = await request.
|
|
502
|
+
post_data = await request.get_json()
|
|
444
503
|
plugin_name = post_data["name"]
|
|
445
504
|
try:
|
|
446
505
|
await self.plugin_manager.turn_off_plugin(plugin_name)
|
|
@@ -458,7 +517,7 @@ class PluginRoute(Route):
|
|
|
458
517
|
.__dict__
|
|
459
518
|
)
|
|
460
519
|
|
|
461
|
-
post_data = await request.
|
|
520
|
+
post_data = await request.get_json()
|
|
462
521
|
plugin_name = post_data["name"]
|
|
463
522
|
try:
|
|
464
523
|
await self.plugin_manager.turn_on_plugin(plugin_name)
|
|
@@ -8,7 +8,7 @@ astrbot/api/platform/__init__.py,sha256=HXvAy_KLtOJspoGVgDtLa7VjIZoF6WK3Puww55yy
|
|
|
8
8
|
astrbot/api/provider/__init__.py,sha256=mJVcon0snjn_xYirk2hntwba6ymIYYC-ZKKmxvx-jok,379
|
|
9
9
|
astrbot/api/star/__init__.py,sha256=OxgHGtWn3lEQGjb4twbpbWnRepUevPu7gxtDAkAsfhQ,250
|
|
10
10
|
astrbot/api/util/__init__.py,sha256=L1O_mFEUDk8V4lEPsT5iiNbIiOVh7HbrNmitqzUWMZg,180
|
|
11
|
-
astrbot/cli/__init__.py,sha256
|
|
11
|
+
astrbot/cli/__init__.py,sha256=-2lx1WPwUObUFzPGAM895DmnvFgEcMbD4Jj9dMh8L5c,22
|
|
12
12
|
astrbot/cli/__main__.py,sha256=QobgMyFoLNTgI_OYddhGOZ9ZvQeBVjjz79mA2cC2OEU,1758
|
|
13
13
|
astrbot/cli/commands/__init__.py,sha256=eAgppZQIqFO1ylQJFABeYrzQ0oZqPWjtE80aKIPB3ks,149
|
|
14
14
|
astrbot/cli/commands/cmd_conf.py,sha256=6-YLicBt_zjWTzaVLUJ1VQLQPbDEPYACB9IVnN8Zvng,6330
|
|
@@ -41,7 +41,7 @@ astrbot/core/agent/agent.py,sha256=wquvKo18JcsJM56dwKyFFAoGhc5qLyQaeqdZ-LlZsWQ,3
|
|
|
41
41
|
astrbot/core/agent/handoff.py,sha256=AxO0yx4Uscy0CO-3Q3fvDOfpfr3gUscLRplH7gH7-Lc,1194
|
|
42
42
|
astrbot/core/agent/hooks.py,sha256=ooe9uUz7czlVt2W7jTDwkRbI-qDrOOXWjCaXtiAkrvE,830
|
|
43
43
|
astrbot/core/agent/mcp_client.py,sha256=u52GPgpeZ1DCCVbI6x4kOGyodD_kweB8H1OgaVg-BZs,14085
|
|
44
|
-
astrbot/core/agent/message.py,sha256=
|
|
44
|
+
astrbot/core/agent/message.py,sha256=lSP67PoDzzcwcu_R0vcqVcTsnLmpn8SlV_Gkg3pzRRc,5931
|
|
45
45
|
astrbot/core/agent/response.py,sha256=ddJABXu03Uw3b-YGTvRafFLJEGa40o93pIEz_CRTb4g,261
|
|
46
46
|
astrbot/core/agent/run_context.py,sha256=h-teucYKYi5o4oTbAsIlkaa04yn2OSNC-ahIF2n6cwE,719
|
|
47
47
|
astrbot/core/agent/tool.py,sha256=3F-zcADIJkACNljrlDJBZZCJwqhxFkfpgoKvg5v0TQM,9276
|
|
@@ -56,7 +56,7 @@ astrbot/core/agent/runners/dify/dify_agent_runner.py,sha256=LYwpjOcBWf3XlwNVzrDv
|
|
|
56
56
|
astrbot/core/agent/runners/dify/dify_api_client.py,sha256=OXukDVgNx3VmYw6OCzjXyP8JmDWEFuy81sD9XnC4VRo,6530
|
|
57
57
|
astrbot/core/config/__init__.py,sha256=vZjtpC7vr-IvBgSUtbS04C0wpulmCG5tPmcEP1WYE_4,172
|
|
58
58
|
astrbot/core/config/astrbot_config.py,sha256=nGyvHyR9VJH9Pk0XKYyeDFVxjwbyVb9u0lIsuvpe3fg,6276
|
|
59
|
-
astrbot/core/config/default.py,sha256=
|
|
59
|
+
astrbot/core/config/default.py,sha256=EkY1L104przDcn11NozIQgFAQZooQq4s464mZ0hp180,146181
|
|
60
60
|
astrbot/core/config/i18n_utils.py,sha256=T2uLmhx1nohJIou14QQBjb2TSvdxDxtfUjVHpwy13z0,3841
|
|
61
61
|
astrbot/core/db/__init__.py,sha256=s4oIWazGk2U1-9dkr3bvq8M4g9nwOXy4e3f53zlvAJk,10326
|
|
62
62
|
astrbot/core/db/po.py,sha256=zFv5eU4tuM6E4ehGzugHnszWl6VBpS_rcD9IjjjkhXE,9398
|
|
@@ -94,7 +94,7 @@ astrbot/core/knowledge_base/retrieval/hit_stopwords.txt,sha256=8LikiRxpjLdAfJYyO
|
|
|
94
94
|
astrbot/core/knowledge_base/retrieval/manager.py,sha256=m_aphslIVJE8f7t9M9K32vS8-Ll4BO0Chnd0zdQae1M,8417
|
|
95
95
|
astrbot/core/knowledge_base/retrieval/rank_fusion.py,sha256=OeE4dSAsmyCt_ssAnMf7CQ4tQHlBFxjePgXVf_YwHmY,4441
|
|
96
96
|
astrbot/core/knowledge_base/retrieval/sparse_retriever.py,sha256=sOCZ9I636j3P5WGxjKXVu7Amp-2DB9jQVQn96Ff7asI,3815
|
|
97
|
-
astrbot/core/message/components.py,sha256=
|
|
97
|
+
astrbot/core/message/components.py,sha256=Cq8G8XsCY2PePvpCTCDbmaY4P8SSaMimb8nox8ZxUts,25707
|
|
98
98
|
astrbot/core/message/message_event_result.py,sha256=1jC6NLeO7lzcTCi2NO28057sWpTsDabICkmGsiggyhk,7204
|
|
99
99
|
astrbot/core/pipeline/__init__.py,sha256=nEepE3tnYYo0EYnzdLLyrp_k7XYg0LpQ3W6QuEeGL6k,1461
|
|
100
100
|
astrbot/core/pipeline/context.py,sha256=jfEyX9i34XM7uqeqqK6rKRDgBXfsV9UHgRpf9Wj_hnI,505
|
|
@@ -111,7 +111,7 @@ astrbot/core/pipeline/process_stage/stage.py,sha256=J01Xg8sNFFGU4Z6dZy6jJcQnwXfd
|
|
|
111
111
|
astrbot/core/pipeline/process_stage/utils.py,sha256=q4V5G0PZD5b5mPh1lM-6w79LKGpp7RR7-PqYFhWpopM,4061
|
|
112
112
|
astrbot/core/pipeline/process_stage/method/agent_request.py,sha256=GlGrGCsCASC4a3PpG6Oc1907aLdl_PrUMXrFiEiEEzc,2043
|
|
113
113
|
astrbot/core/pipeline/process_stage/method/star_request.py,sha256=icx3zkXLHDtX4SU5soe0UiOLgJjYW6ehoSBpMYSEE8U,2508
|
|
114
|
-
astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py,sha256=
|
|
114
|
+
astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py,sha256=sDU4b85nV7LswGngFeYOG9VUv-BRR7gufy00ptU_Utg,21175
|
|
115
115
|
astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py,sha256=Cr5isDXIaL4oFlkt2Mr6UuijPNfp_RjC6RiTtwuSpfg,7329
|
|
116
116
|
astrbot/core/pipeline/rate_limit_check/stage.py,sha256=9EVJ0zYtxATFsj7ADyWDYcSGBRqmrMiKWp1kkD9LONI,3962
|
|
117
117
|
astrbot/core/pipeline/respond/stage.py,sha256=im_UrME-g-YOk9TnrDFzFeYIvzZsGBy9BDCAp5PXuNM,10738
|
|
@@ -129,8 +129,8 @@ astrbot/core/platform/platform.py,sha256=UETCazEPfEfQq0utZSMOIKcgIvQ3XbKv2yldwvt
|
|
|
129
129
|
astrbot/core/platform/platform_metadata.py,sha256=b10aFNvC9HFYBJbedlaUxerLUyeVAOqvVksh2yE-s-M,707
|
|
130
130
|
astrbot/core/platform/register.py,sha256=KiAMpiuEP6H5RwR9ItOgQEth02urvasKhObjiy5X-Hc,1956
|
|
131
131
|
astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py,sha256=wuHJZu_Q86KQ83vaj_V-t3u5P7JIBURNtnFmYfCU4wM,8080
|
|
132
|
-
astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py,sha256=
|
|
133
|
-
astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py,sha256=
|
|
132
|
+
astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py,sha256=dwiynQ1iytm7v3gdK2uBWNUJntzQ5qF40f2opF2bfEM,17772
|
|
133
|
+
astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py,sha256=wWlOEuYuJ7jdbSr8P7yuwN8-xm0bDAegEYkPKBX_6R8,9198
|
|
134
134
|
astrbot/core/platform/sources/dingtalk/dingtalk_event.py,sha256=Ph8AP03qct0dFDHKB1be0VY8Slxe9yiwqMsd7Zhpvas,2696
|
|
135
135
|
astrbot/core/platform/sources/discord/client.py,sha256=dYu9ANCMeI9nY1K2FRquPOwTe1xLWHuVYslSLXoXNkY,4622
|
|
136
136
|
astrbot/core/platform/sources/discord/components.py,sha256=sh0vvqKcO1a293XNApcA-olunPTHbVWFauq-Nwvj-o4,3957
|
|
@@ -152,7 +152,7 @@ astrbot/core/platform/sources/satori/satori_event.py,sha256=agI9FYUwBZM2CnxPANxD
|
|
|
152
152
|
astrbot/core/platform/sources/slack/client.py,sha256=opkwKKwgaLxw3EpYILLAf7gzzC6KwpiUoq3TOewolh4,5633
|
|
153
153
|
astrbot/core/platform/sources/slack/slack_adapter.py,sha256=LUZY-A-fVD8y5mG_86nQJjgKZ2j8k5uiue1B5vqjBhg,16134
|
|
154
154
|
astrbot/core/platform/sources/slack/slack_event.py,sha256=qtd7AkYDrX5-rcf6-N3QX6Lm3YzvO8ipsUL8iFF6T_U,8926
|
|
155
|
-
astrbot/core/platform/sources/telegram/tg_adapter.py,sha256=
|
|
155
|
+
astrbot/core/platform/sources/telegram/tg_adapter.py,sha256=yNpzDpQlyWKyFhUNUHs7Tz_g3XT1yhEwuUK84QbCUpI,16129
|
|
156
156
|
astrbot/core/platform/sources/telegram/tg_event.py,sha256=Xh8IDfSLtjJqzyiZVX05LKT8adm7Q2YPUHHKIZ-rpI4,11641
|
|
157
157
|
astrbot/core/platform/sources/webchat/webchat_adapter.py,sha256=cQAkwFWyVsk5BLdQ7d82APfSea2q-6AZWldq9Q2FayU,6163
|
|
158
158
|
astrbot/core/platform/sources/webchat/webchat_event.py,sha256=iXkHFugb0ecwWjuKgoiiqjFA7nM8iWgVwbb7HWlLKcY,5720
|
|
@@ -180,7 +180,7 @@ astrbot/core/provider/entites.py,sha256=0eYiQ-xttqFTb3WZR2b1oemdZy3d5sevELvj9Fix
|
|
|
180
180
|
astrbot/core/provider/entities.py,sha256=AwD8KOG8dSlfQXSc1n8gx4xv2vW4niZDiaMoO1Y_dOw,12533
|
|
181
181
|
astrbot/core/provider/func_tool_manager.py,sha256=28fOKbpWOxiclwfcNkmP6sHSBlK4cZKwPXyNhFjjXps,21181
|
|
182
182
|
astrbot/core/provider/manager.py,sha256=_nXzEqWrOnIq-O845ECMJ79ez0TKQGzVJtRoYX8lCdo,22902
|
|
183
|
-
astrbot/core/provider/provider.py,sha256=
|
|
183
|
+
astrbot/core/provider/provider.py,sha256=BED65O2i4X1uArYGqNCHa6Yc_q1zJ5Vljcw_9zkCTDY,11641
|
|
184
184
|
astrbot/core/provider/register.py,sha256=0WMYrT9vbRjeq-72HD0oRT45kJmeKA96UgSItpTJbX8,1904
|
|
185
185
|
astrbot/core/provider/sources/anthropic_source.py,sha256=oSd7I8pCGwrmTKMQuxVza0vRNqgQw7nqhMxuZnc9ro0,15586
|
|
186
186
|
astrbot/core/provider/sources/azure_tts_source.py,sha256=uhPr4Dja6XANesAmrfZiuINNIlXej0NV7Goo8ahMm14,9387
|
|
@@ -230,6 +230,7 @@ astrbot/core/star/register/star.py,sha256=Eto7nD_HFuCNt-VJnXUXKv2D7a5TQ6qkhzLJ_i
|
|
|
230
230
|
astrbot/core/star/register/star_handler.py,sha256=kCIQVzI5EBWVAugkEsXHLTOoOQp3r5uTLYc4sPfdZls,17483
|
|
231
231
|
astrbot/core/utils/astrbot_path.py,sha256=tQFD55EFwGbpR1tpoJADpdElPS5iTFAZVLIxCVvKypY,1213
|
|
232
232
|
astrbot/core/utils/command_parser.py,sha256=Cwd4zzyKEoC-er0a-9WZ5n2g4F8eH9p6BHxD96gjaVM,617
|
|
233
|
+
astrbot/core/utils/file_extract.py,sha256=I9jgcaPYK74-BwuI18oUpoupnPYINeP3QFD3kFodqBA,697
|
|
233
234
|
astrbot/core/utils/io.py,sha256=oowzwkZC76-BKofm6vI2sJnrg6IgJubcmvoaSvX2AsM,10815
|
|
234
235
|
astrbot/core/utils/log_pipe.py,sha256=jphGRAdmzhBVRKdpJwOP1AtpbGlun9v7Cr50kHZtlyo,883
|
|
235
236
|
astrbot/core/utils/metrics.py,sha256=CxEkdV2gJai0mw1IbL4DJ81WiQ5mY7v9M_-T6UtRJDs,2427
|
|
@@ -253,13 +254,13 @@ astrbot/dashboard/utils.py,sha256=KrAv0lnPaVR0bx8yevT1CLGbSNsJizlfkKkPEtVVANI,53
|
|
|
253
254
|
astrbot/dashboard/routes/__init__.py,sha256=IKg0EzasXsd-OleSixE54Ul5wQcBeMHzVwhhjMFZ2dE,783
|
|
254
255
|
astrbot/dashboard/routes/auth.py,sha256=rYkvt3MpCY9BhWjG0DUoX3YaBkJT1Id7M2pKqTmXbvo,2946
|
|
255
256
|
astrbot/dashboard/routes/chat.py,sha256=v1nfoq3jSqiUnVZd9DilvPDgKz6_kIo8WdUG_dwZkXk,15525
|
|
256
|
-
astrbot/dashboard/routes/config.py,sha256=
|
|
257
|
+
astrbot/dashboard/routes/config.py,sha256=W6hAtplTlb5_Q6JlflXl3OXMU5peNui16nBXGUQBWBw,32997
|
|
257
258
|
astrbot/dashboard/routes/conversation.py,sha256=sFHgkpNDdTR9qkSOC_JfSjzkfTuv63iaMxvh52wQUzM,10773
|
|
258
259
|
astrbot/dashboard/routes/file.py,sha256=gULvXP9PnVOQlyv_PCEzZQE5ptnGQEjFPvwOLxdVgb4,708
|
|
259
260
|
astrbot/dashboard/routes/knowledge_base.py,sha256=_3jjcpBjfErP9NI-h4FYBaw3lm5_eIhmfF-uju94Icg,39873
|
|
260
261
|
astrbot/dashboard/routes/log.py,sha256=84OFiLM-Cnqf3HxFne-ykUezfnArlwH4HyY8MJxch00,2143
|
|
261
262
|
astrbot/dashboard/routes/persona.py,sha256=MEcNHMxJmyvZ3ZhytI5IP7L3FSlMr1JDvdd5efN9Q-M,7833
|
|
262
|
-
astrbot/dashboard/routes/plugin.py,sha256=
|
|
263
|
+
astrbot/dashboard/routes/plugin.py,sha256=t0XQdodA5SM7clgUmQAWfE744qlCeOaGUWpDfOrfxZg,22807
|
|
263
264
|
astrbot/dashboard/routes/route.py,sha256=GT5fYW9fxYmdVj5_6-Wob7nw_-JXuUNDMXGPWKZUbd8,1547
|
|
264
265
|
astrbot/dashboard/routes/session_management.py,sha256=3h-zlkiAN4MQQLETGORNoWDtnGCSbqxnK2mTu6jMeCY,14998
|
|
265
266
|
astrbot/dashboard/routes/stat.py,sha256=OgNM491WFuDSAQbbJUGl4_UsqrQNefOGMMRIPLLoVBQ,6780
|
|
@@ -267,8 +268,8 @@ astrbot/dashboard/routes/static_file.py,sha256=7KnNcOb1BVqSTft114LhGsDkfg69X2jHE
|
|
|
267
268
|
astrbot/dashboard/routes/t2i.py,sha256=F6smxdL99MF7cRw3hqS6-2GErw8Zhsv0V0mfBUeEk-c,8931
|
|
268
269
|
astrbot/dashboard/routes/tools.py,sha256=YsVFrwVIhxAI-Ikme7YPrHVnPVTkJ1IaH7n6ciREjdE,14663
|
|
269
270
|
astrbot/dashboard/routes/update.py,sha256=qXiqQ_dbqRVftOzGgCQrvK8-qopVK6zKhhVVJ9SK26U,6648
|
|
270
|
-
astrbot-4.7.
|
|
271
|
-
astrbot-4.7.
|
|
272
|
-
astrbot-4.7.
|
|
273
|
-
astrbot-4.7.
|
|
274
|
-
astrbot-4.7.
|
|
271
|
+
astrbot-4.7.4.dist-info/METADATA,sha256=iusOE8piaKakYH70-h3ORFCKHzqmmOkImyJpgvHaVIM,10370
|
|
272
|
+
astrbot-4.7.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
273
|
+
astrbot-4.7.4.dist-info/entry_points.txt,sha256=OEF09YmhBWYuViXrvTLLpstF4ccmNwDL8r7nnFD0pfI,53
|
|
274
|
+
astrbot-4.7.4.dist-info/licenses/LICENSE,sha256=zPfQj5Mq8-gThIiBcxETr7t8gND9bZWOjTGQAr80TQI,34500
|
|
275
|
+
astrbot-4.7.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|