AstrBot 4.10.2__py3-none-any.whl → 4.10.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/builtin_stars/astrbot/long_term_memory.py +186 -0
- astrbot/builtin_stars/astrbot/main.py +120 -0
- astrbot/builtin_stars/astrbot/metadata.yaml +4 -0
- astrbot/builtin_stars/astrbot/process_llm_request.py +245 -0
- astrbot/builtin_stars/builtin_commands/commands/__init__.py +31 -0
- astrbot/builtin_stars/builtin_commands/commands/admin.py +77 -0
- astrbot/builtin_stars/builtin_commands/commands/alter_cmd.py +173 -0
- astrbot/builtin_stars/builtin_commands/commands/conversation.py +366 -0
- astrbot/builtin_stars/builtin_commands/commands/help.py +88 -0
- astrbot/builtin_stars/builtin_commands/commands/llm.py +20 -0
- astrbot/builtin_stars/builtin_commands/commands/persona.py +142 -0
- astrbot/builtin_stars/builtin_commands/commands/plugin.py +120 -0
- astrbot/builtin_stars/builtin_commands/commands/provider.py +329 -0
- astrbot/builtin_stars/builtin_commands/commands/setunset.py +36 -0
- astrbot/builtin_stars/builtin_commands/commands/sid.py +36 -0
- astrbot/builtin_stars/builtin_commands/commands/t2i.py +23 -0
- astrbot/builtin_stars/builtin_commands/commands/tool.py +31 -0
- astrbot/builtin_stars/builtin_commands/commands/tts.py +36 -0
- astrbot/builtin_stars/builtin_commands/commands/utils/rst_scene.py +26 -0
- astrbot/builtin_stars/builtin_commands/main.py +237 -0
- astrbot/builtin_stars/builtin_commands/metadata.yaml +4 -0
- astrbot/builtin_stars/python_interpreter/main.py +536 -0
- astrbot/builtin_stars/python_interpreter/metadata.yaml +4 -0
- astrbot/builtin_stars/python_interpreter/requirements.txt +1 -0
- astrbot/builtin_stars/python_interpreter/shared/api.py +22 -0
- astrbot/builtin_stars/reminder/main.py +266 -0
- astrbot/builtin_stars/reminder/metadata.yaml +4 -0
- astrbot/builtin_stars/session_controller/main.py +114 -0
- astrbot/builtin_stars/session_controller/metadata.yaml +5 -0
- astrbot/builtin_stars/web_searcher/engines/__init__.py +111 -0
- astrbot/builtin_stars/web_searcher/engines/bing.py +30 -0
- astrbot/builtin_stars/web_searcher/engines/sogo.py +52 -0
- astrbot/builtin_stars/web_searcher/main.py +436 -0
- astrbot/builtin_stars/web_searcher/metadata.yaml +4 -0
- astrbot/cli/__init__.py +1 -1
- astrbot/core/agent/message.py +32 -1
- astrbot/core/agent/runners/tool_loop_agent_runner.py +26 -8
- astrbot/core/astr_agent_hooks.py +6 -0
- astrbot/core/backup/__init__.py +26 -0
- astrbot/core/backup/constants.py +77 -0
- astrbot/core/backup/exporter.py +477 -0
- astrbot/core/backup/importer.py +761 -0
- astrbot/core/config/astrbot_config.py +2 -0
- astrbot/core/config/default.py +47 -6
- astrbot/core/knowledge_base/chunking/recursive.py +10 -2
- astrbot/core/log.py +1 -1
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +184 -174
- astrbot/core/pipeline/result_decorate/stage.py +65 -57
- astrbot/core/pipeline/waking_check/stage.py +31 -3
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +15 -29
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +1 -6
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +15 -1
- astrbot/core/platform/sources/lark/lark_adapter.py +2 -10
- astrbot/core/platform/sources/misskey/misskey_adapter.py +0 -5
- astrbot/core/platform/sources/misskey/misskey_utils.py +0 -3
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +4 -9
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +4 -9
- astrbot/core/platform/sources/satori/satori_adapter.py +6 -1
- astrbot/core/platform/sources/slack/slack_adapter.py +3 -6
- astrbot/core/platform/sources/webchat/webchat_adapter.py +0 -1
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +3 -5
- astrbot/core/provider/entities.py +41 -10
- astrbot/core/provider/provider.py +3 -1
- astrbot/core/provider/sources/anthropic_source.py +140 -30
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +14 -6
- astrbot/core/provider/sources/gemini_source.py +112 -29
- astrbot/core/provider/sources/minimax_tts_api_source.py +4 -1
- astrbot/core/provider/sources/openai_source.py +93 -56
- astrbot/core/provider/sources/xai_source.py +29 -0
- astrbot/core/provider/sources/xinference_stt_provider.py +24 -12
- astrbot/core/star/context.py +1 -1
- astrbot/core/star/star_manager.py +52 -13
- astrbot/core/utils/astrbot_path.py +34 -0
- astrbot/core/utils/pip_installer.py +20 -1
- astrbot/dashboard/routes/__init__.py +2 -0
- astrbot/dashboard/routes/backup.py +1093 -0
- astrbot/dashboard/routes/config.py +45 -0
- astrbot/dashboard/routes/log.py +44 -10
- astrbot/dashboard/server.py +9 -1
- {astrbot-4.10.2.dist-info → astrbot-4.10.4.dist-info}/METADATA +1 -1
- {astrbot-4.10.2.dist-info → astrbot-4.10.4.dist-info}/RECORD +84 -44
- {astrbot-4.10.2.dist-info → astrbot-4.10.4.dist-info}/WHEEL +0 -0
- {astrbot-4.10.2.dist-info → astrbot-4.10.4.dist-info}/entry_points.txt +0 -0
- {astrbot-4.10.2.dist-info → astrbot-4.10.4.dist-info}/licenses/LICENSE +0 -0
astrbot/core/config/default.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import Any, TypedDict
|
|
|
5
5
|
|
|
6
6
|
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
7
7
|
|
|
8
|
-
VERSION = "4.10.
|
|
8
|
+
VERSION = "4.10.4"
|
|
9
9
|
DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
|
|
10
10
|
|
|
11
11
|
WEBHOOK_SUPPORTED_PLATFORMS = [
|
|
@@ -905,6 +905,7 @@ CONFIG_METADATA_2 = {
|
|
|
905
905
|
"key": [],
|
|
906
906
|
"api_base": "https://api.anthropic.com/v1",
|
|
907
907
|
"timeout": 120,
|
|
908
|
+
"anth_thinking_config": {"budget": 0},
|
|
908
909
|
},
|
|
909
910
|
"Moonshot": {
|
|
910
911
|
"id": "moonshot",
|
|
@@ -920,7 +921,7 @@ CONFIG_METADATA_2 = {
|
|
|
920
921
|
"xAI": {
|
|
921
922
|
"id": "xai",
|
|
922
923
|
"provider": "xai",
|
|
923
|
-
"type": "
|
|
924
|
+
"type": "xai_chat_completion",
|
|
924
925
|
"provider_type": "chat_completion",
|
|
925
926
|
"enable": True,
|
|
926
927
|
"key": [],
|
|
@@ -1286,7 +1287,7 @@ CONFIG_METADATA_2 = {
|
|
|
1286
1287
|
"minimax-is-timber-weight": False,
|
|
1287
1288
|
"minimax-voice-id": "female-shaonv",
|
|
1288
1289
|
"minimax-timber-weight": '[\n {\n "voice_id": "Chinese (Mandarin)_Warm_Girl",\n "weight": 25\n },\n {\n "voice_id": "Chinese (Mandarin)_BashfulGirl",\n "weight": 50\n }\n]',
|
|
1289
|
-
"minimax-voice-emotion": "
|
|
1290
|
+
"minimax-voice-emotion": "auto",
|
|
1290
1291
|
"minimax-voice-latex": False,
|
|
1291
1292
|
"minimax-voice-english-normalization": False,
|
|
1292
1293
|
"timeout": 20,
|
|
@@ -1450,7 +1451,32 @@ CONFIG_METADATA_2 = {
|
|
|
1450
1451
|
"description": "自定义请求体参数",
|
|
1451
1452
|
"type": "dict",
|
|
1452
1453
|
"items": {},
|
|
1453
|
-
"hint": "
|
|
1454
|
+
"hint": "用于在请求时添加额外的参数,如 temperature、top_p、max_tokens 等。",
|
|
1455
|
+
"template_schema": {
|
|
1456
|
+
"temperature": {
|
|
1457
|
+
"name": "Temperature",
|
|
1458
|
+
"description": "温度参数",
|
|
1459
|
+
"hint": "控制输出的随机性,范围通常为 0-2。值越高越随机。",
|
|
1460
|
+
"type": "float",
|
|
1461
|
+
"default": 0.6,
|
|
1462
|
+
"slider": {"min": 0, "max": 2, "step": 0.1},
|
|
1463
|
+
},
|
|
1464
|
+
"top_p": {
|
|
1465
|
+
"name": "Top-p",
|
|
1466
|
+
"description": "Top-p 采样",
|
|
1467
|
+
"hint": "核采样参数,范围通常为 0-1。控制模型考虑的概率质量。",
|
|
1468
|
+
"type": "float",
|
|
1469
|
+
"default": 1.0,
|
|
1470
|
+
"slider": {"min": 0, "max": 1, "step": 0.01},
|
|
1471
|
+
},
|
|
1472
|
+
"max_tokens": {
|
|
1473
|
+
"name": "Max Tokens",
|
|
1474
|
+
"description": "最大令牌数",
|
|
1475
|
+
"hint": "生成的最大令牌数。",
|
|
1476
|
+
"type": "int",
|
|
1477
|
+
"default": 8192,
|
|
1478
|
+
},
|
|
1479
|
+
},
|
|
1454
1480
|
},
|
|
1455
1481
|
"provider": {
|
|
1456
1482
|
"type": "string",
|
|
@@ -1787,6 +1813,17 @@ CONFIG_METADATA_2 = {
|
|
|
1787
1813
|
},
|
|
1788
1814
|
},
|
|
1789
1815
|
},
|
|
1816
|
+
"anth_thinking_config": {
|
|
1817
|
+
"description": "Thinking Config",
|
|
1818
|
+
"type": "object",
|
|
1819
|
+
"items": {
|
|
1820
|
+
"budget": {
|
|
1821
|
+
"description": "Thinking Budget",
|
|
1822
|
+
"type": "int",
|
|
1823
|
+
"hint": "Anthropic thinking.budget_tokens param. Must >= 1024. See: https://platform.claude.com/docs/en/build-with-claude/extended-thinking",
|
|
1824
|
+
},
|
|
1825
|
+
},
|
|
1826
|
+
},
|
|
1790
1827
|
"minimax-group-id": {
|
|
1791
1828
|
"type": "string",
|
|
1792
1829
|
"description": "用户组",
|
|
@@ -1858,15 +1895,18 @@ CONFIG_METADATA_2 = {
|
|
|
1858
1895
|
"minimax-voice-emotion": {
|
|
1859
1896
|
"type": "string",
|
|
1860
1897
|
"description": "情绪",
|
|
1861
|
-
"hint": "
|
|
1898
|
+
"hint": "控制合成语音的情绪。当为 auto 时,将根据文本内容自动选择情绪。",
|
|
1862
1899
|
"options": [
|
|
1900
|
+
"auto",
|
|
1863
1901
|
"happy",
|
|
1864
1902
|
"sad",
|
|
1865
1903
|
"angry",
|
|
1866
1904
|
"fearful",
|
|
1867
1905
|
"disgusted",
|
|
1868
1906
|
"surprised",
|
|
1869
|
-
"
|
|
1907
|
+
"calm",
|
|
1908
|
+
"fluent",
|
|
1909
|
+
"whisper",
|
|
1870
1910
|
],
|
|
1871
1911
|
},
|
|
1872
1912
|
"minimax-voice-latex": {
|
|
@@ -3049,4 +3089,5 @@ DEFAULT_VALUE_MAP = {
|
|
|
3049
3089
|
"text": "",
|
|
3050
3090
|
"list": [],
|
|
3051
3091
|
"object": {},
|
|
3092
|
+
"template_list": [],
|
|
3052
3093
|
}
|
|
@@ -149,8 +149,16 @@ class RecursiveCharacterChunker(BaseChunker):
|
|
|
149
149
|
分割后的文本块列表
|
|
150
150
|
|
|
151
151
|
"""
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
if chunk_size is None:
|
|
153
|
+
chunk_size = self.chunk_size
|
|
154
|
+
if overlap is None:
|
|
155
|
+
overlap = self.chunk_overlap
|
|
156
|
+
if chunk_size <= 0:
|
|
157
|
+
raise ValueError("chunk_size must be greater than 0")
|
|
158
|
+
if overlap < 0:
|
|
159
|
+
raise ValueError("chunk_overlap must be non-negative")
|
|
160
|
+
if overlap >= chunk_size:
|
|
161
|
+
raise ValueError("chunk_overlap must be less than chunk_size")
|
|
154
162
|
result = []
|
|
155
163
|
for i in range(0, len(text), chunk_size - overlap):
|
|
156
164
|
end = min(i + chunk_size, len(text))
|
astrbot/core/log.py
CHANGED
|
@@ -58,7 +58,7 @@ def is_plugin_path(pathname):
|
|
|
58
58
|
return False
|
|
59
59
|
|
|
60
60
|
norm_path = os.path.normpath(pathname)
|
|
61
|
-
return ("data/plugins" in norm_path) or ("
|
|
61
|
+
return ("data/plugins" in norm_path) or ("astrbot/builtin_stars/" in norm_path)
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
def get_short_level_name(level_name):
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
from collections.abc import AsyncGenerator
|
|
7
7
|
|
|
8
8
|
from astrbot.core import logger
|
|
9
|
+
from astrbot.core.agent.message import Message
|
|
9
10
|
from astrbot.core.agent.tool import ToolSet
|
|
10
11
|
from astrbot.core.astr_agent_context import AstrAgentContext
|
|
11
12
|
from astrbot.core.conversation_mgr import Conversation
|
|
@@ -294,6 +295,7 @@ class InternalAgentSubStage(Stage):
|
|
|
294
295
|
event: AstrMessageEvent,
|
|
295
296
|
req: ProviderRequest,
|
|
296
297
|
llm_response: LLMResponse | None,
|
|
298
|
+
all_messages: list[Message],
|
|
297
299
|
):
|
|
298
300
|
if (
|
|
299
301
|
not req
|
|
@@ -307,31 +309,23 @@ class InternalAgentSubStage(Stage):
|
|
|
307
309
|
logger.debug("LLM 响应为空,不保存记录。")
|
|
308
310
|
return
|
|
309
311
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
messages.extend(tcr.to_openai_messages())
|
|
324
|
-
messages.append(
|
|
325
|
-
{
|
|
326
|
-
"role": "assistant",
|
|
327
|
-
"content": llm_response.completion_text or "*No response*",
|
|
328
|
-
}
|
|
329
|
-
)
|
|
330
|
-
messages = list(filter(lambda item: "_no_save" not in item, messages))
|
|
312
|
+
# using agent context messages to save to history
|
|
313
|
+
message_to_save = []
|
|
314
|
+
for message in all_messages:
|
|
315
|
+
if message.role == "system":
|
|
316
|
+
# we do not save system messages to history
|
|
317
|
+
continue
|
|
318
|
+
if message.role in ["assistant", "user"] and getattr(
|
|
319
|
+
message, "_no_save", None
|
|
320
|
+
):
|
|
321
|
+
# we do not save user and assistant messages that are marked as _no_save
|
|
322
|
+
continue
|
|
323
|
+
message_to_save.append(message.model_dump())
|
|
324
|
+
|
|
331
325
|
await self.conv_manager.update_conversation(
|
|
332
326
|
event.unified_msg_origin,
|
|
333
327
|
req.conversation.cid,
|
|
334
|
-
history=
|
|
328
|
+
history=message_to_save,
|
|
335
329
|
)
|
|
336
330
|
|
|
337
331
|
def _fix_messages(self, messages: list[dict]) -> list[dict]:
|
|
@@ -355,174 +349,190 @@ class InternalAgentSubStage(Stage):
|
|
|
355
349
|
) -> AsyncGenerator[None, None]:
|
|
356
350
|
req: ProviderRequest | None = None
|
|
357
351
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
streaming_response = self.streaming_response
|
|
366
|
-
if (enable_streaming := event.get_extra("enable_streaming")) is not None:
|
|
367
|
-
streaming_response = bool(enable_streaming)
|
|
368
|
-
|
|
369
|
-
logger.debug("ready to request llm provider")
|
|
370
|
-
async with session_lock_manager.acquire_lock(event.unified_msg_origin):
|
|
371
|
-
logger.debug("acquired session lock for llm request")
|
|
372
|
-
if event.get_extra("provider_request"):
|
|
373
|
-
req = event.get_extra("provider_request")
|
|
374
|
-
assert isinstance(req, ProviderRequest), (
|
|
375
|
-
"provider_request 必须是 ProviderRequest 类型。"
|
|
352
|
+
try:
|
|
353
|
+
provider = self._select_provider(event)
|
|
354
|
+
if provider is None:
|
|
355
|
+
return
|
|
356
|
+
if not isinstance(provider, Provider):
|
|
357
|
+
logger.error(
|
|
358
|
+
f"选择的提供商类型无效({type(provider)}),跳过 LLM 请求处理。"
|
|
376
359
|
)
|
|
360
|
+
return
|
|
377
361
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if
|
|
386
|
-
req
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return
|
|
391
|
-
|
|
392
|
-
req.prompt = event.message_str[len(provider_wake_prefix) :]
|
|
393
|
-
# func_tool selection 现在已经转移到 packages/astrbot 插件中进行选择。
|
|
394
|
-
# req.func_tool = self.ctx.plugin_manager.context.get_llm_tool_manager()
|
|
395
|
-
for comp in event.message_obj.message:
|
|
396
|
-
if isinstance(comp, Image):
|
|
397
|
-
image_path = await comp.convert_to_file_path()
|
|
398
|
-
req.image_urls.append(image_path)
|
|
399
|
-
|
|
400
|
-
conversation = await self._get_session_conv(event)
|
|
401
|
-
req.conversation = conversation
|
|
402
|
-
req.contexts = json.loads(conversation.history)
|
|
403
|
-
|
|
404
|
-
event.set_extra("provider_request", req)
|
|
405
|
-
|
|
406
|
-
# fix contexts json str
|
|
407
|
-
if isinstance(req.contexts, str):
|
|
408
|
-
req.contexts = json.loads(req.contexts)
|
|
409
|
-
|
|
410
|
-
# apply file extract
|
|
411
|
-
if self.file_extract_enabled:
|
|
412
|
-
try:
|
|
413
|
-
await self._apply_file_extract(event, req)
|
|
414
|
-
except Exception as e:
|
|
415
|
-
logger.error(f"Error occurred while applying file extract: {e}")
|
|
362
|
+
streaming_response = self.streaming_response
|
|
363
|
+
if (enable_streaming := event.get_extra("enable_streaming")) is not None:
|
|
364
|
+
streaming_response = bool(enable_streaming)
|
|
365
|
+
|
|
366
|
+
logger.debug("ready to request llm provider")
|
|
367
|
+
async with session_lock_manager.acquire_lock(event.unified_msg_origin):
|
|
368
|
+
logger.debug("acquired session lock for llm request")
|
|
369
|
+
if event.get_extra("provider_request"):
|
|
370
|
+
req = event.get_extra("provider_request")
|
|
371
|
+
assert isinstance(req, ProviderRequest), (
|
|
372
|
+
"provider_request 必须是 ProviderRequest 类型。"
|
|
373
|
+
)
|
|
416
374
|
|
|
417
|
-
|
|
418
|
-
|
|
375
|
+
if req.conversation:
|
|
376
|
+
req.contexts = json.loads(req.conversation.history)
|
|
419
377
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
378
|
+
else:
|
|
379
|
+
req = ProviderRequest()
|
|
380
|
+
req.prompt = ""
|
|
381
|
+
req.image_urls = []
|
|
382
|
+
if sel_model := event.get_extra("selected_model"):
|
|
383
|
+
req.model = sel_model
|
|
384
|
+
if provider_wake_prefix and not event.message_str.startswith(
|
|
385
|
+
provider_wake_prefix
|
|
386
|
+
):
|
|
387
|
+
return
|
|
388
|
+
|
|
389
|
+
req.prompt = event.message_str[len(provider_wake_prefix) :]
|
|
390
|
+
# func_tool selection 现在已经转移到 astrbot/builtin_stars/astrbot 插件中进行选择。
|
|
391
|
+
# req.func_tool = self.ctx.plugin_manager.context.get_llm_tool_manager()
|
|
392
|
+
for comp in event.message_obj.message:
|
|
393
|
+
if isinstance(comp, Image):
|
|
394
|
+
image_path = await comp.convert_to_file_path()
|
|
395
|
+
req.image_urls.append(image_path)
|
|
396
|
+
|
|
397
|
+
conversation = await self._get_session_conv(event)
|
|
398
|
+
req.conversation = conversation
|
|
399
|
+
req.contexts = json.loads(conversation.history)
|
|
400
|
+
|
|
401
|
+
event.set_extra("provider_request", req)
|
|
402
|
+
|
|
403
|
+
# fix contexts json str
|
|
404
|
+
if isinstance(req.contexts, str):
|
|
405
|
+
req.contexts = json.loads(req.contexts)
|
|
406
|
+
|
|
407
|
+
# apply file extract
|
|
408
|
+
if self.file_extract_enabled:
|
|
409
|
+
try:
|
|
410
|
+
await self._apply_file_extract(event, req)
|
|
411
|
+
except Exception as e:
|
|
412
|
+
logger.error(f"Error occurred while applying file extract: {e}")
|
|
413
|
+
|
|
414
|
+
if not req.prompt and not req.image_urls:
|
|
415
|
+
return
|
|
423
416
|
|
|
424
|
-
|
|
425
|
-
|
|
417
|
+
# call event hook
|
|
418
|
+
if await call_event_hook(event, EventType.OnLLMRequestEvent, req):
|
|
419
|
+
return
|
|
426
420
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
req.contexts = self._truncate_contexts(req.contexts)
|
|
430
|
-
self._fix_messages(req.contexts)
|
|
421
|
+
# apply knowledge base feature
|
|
422
|
+
await self._apply_kb(event, req)
|
|
431
423
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
424
|
+
# truncate contexts to fit max length
|
|
425
|
+
if req.contexts:
|
|
426
|
+
req.contexts = self._truncate_contexts(req.contexts)
|
|
427
|
+
self._fix_messages(req.contexts)
|
|
435
428
|
|
|
436
|
-
|
|
437
|
-
|
|
429
|
+
# session_id
|
|
430
|
+
if not req.session_id:
|
|
431
|
+
req.session_id = event.unified_msg_origin
|
|
438
432
|
|
|
439
|
-
|
|
440
|
-
|
|
433
|
+
# check provider modalities, if provider does not support image/tool_use, clear them in request.
|
|
434
|
+
self._modalities_fix(provider, req)
|
|
441
435
|
|
|
442
|
-
|
|
443
|
-
self.
|
|
444
|
-
and not event.platform_meta.support_streaming_message
|
|
445
|
-
)
|
|
446
|
-
# 备份 req.contexts
|
|
447
|
-
backup_contexts = copy.deepcopy(req.contexts)
|
|
436
|
+
# filter tools, only keep tools from this pipeline's selected plugins
|
|
437
|
+
self._plugin_tool_fix(event, req)
|
|
448
438
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
context=self.ctx.plugin_manager.context,
|
|
456
|
-
event=event,
|
|
457
|
-
)
|
|
458
|
-
await agent_runner.reset(
|
|
459
|
-
provider=provider,
|
|
460
|
-
request=req,
|
|
461
|
-
run_context=AgentContextWrapper(
|
|
462
|
-
context=astr_agent_ctx,
|
|
463
|
-
tool_call_timeout=self.tool_call_timeout,
|
|
464
|
-
),
|
|
465
|
-
tool_executor=FunctionToolExecutor(),
|
|
466
|
-
agent_hooks=MAIN_AGENT_HOOKS,
|
|
467
|
-
streaming=streaming_response,
|
|
468
|
-
)
|
|
439
|
+
stream_to_general = (
|
|
440
|
+
self.unsupported_streaming_strategy == "turn_off"
|
|
441
|
+
and not event.platform_meta.support_streaming_message
|
|
442
|
+
)
|
|
443
|
+
# 备份 req.contexts
|
|
444
|
+
backup_contexts = copy.deepcopy(req.contexts)
|
|
469
445
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
446
|
+
# run agent
|
|
447
|
+
agent_runner = AgentRunner()
|
|
448
|
+
logger.debug(
|
|
449
|
+
f"handle provider[id: {provider.provider_config['id']}] request: {req}",
|
|
450
|
+
)
|
|
451
|
+
astr_agent_ctx = AstrAgentContext(
|
|
452
|
+
context=self.ctx.plugin_manager.context,
|
|
453
|
+
event=event,
|
|
454
|
+
)
|
|
455
|
+
await agent_runner.reset(
|
|
456
|
+
provider=provider,
|
|
457
|
+
request=req,
|
|
458
|
+
run_context=AgentContextWrapper(
|
|
459
|
+
context=astr_agent_ctx,
|
|
460
|
+
tool_call_timeout=self.tool_call_timeout,
|
|
482
461
|
),
|
|
462
|
+
tool_executor=FunctionToolExecutor(),
|
|
463
|
+
agent_hooks=MAIN_AGENT_HOOKS,
|
|
464
|
+
streaming=streaming_response,
|
|
483
465
|
)
|
|
484
|
-
|
|
485
|
-
if
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
chain = MessageChain().chain
|
|
497
|
-
event.set_result(
|
|
498
|
-
MessageEventResult(
|
|
499
|
-
chain=chain,
|
|
500
|
-
result_content_type=ResultContentType.STREAMING_FINISH,
|
|
466
|
+
|
|
467
|
+
if streaming_response and not stream_to_general:
|
|
468
|
+
# 流式响应
|
|
469
|
+
event.set_result(
|
|
470
|
+
MessageEventResult()
|
|
471
|
+
.set_result_content_type(ResultContentType.STREAMING_RESULT)
|
|
472
|
+
.set_async_stream(
|
|
473
|
+
run_agent(
|
|
474
|
+
agent_runner,
|
|
475
|
+
self.max_step,
|
|
476
|
+
self.show_tool_use,
|
|
477
|
+
show_reasoning=self.show_reasoning,
|
|
501
478
|
),
|
|
502
|
-
)
|
|
503
|
-
|
|
504
|
-
async for _ in run_agent(
|
|
505
|
-
agent_runner,
|
|
506
|
-
self.max_step,
|
|
507
|
-
self.show_tool_use,
|
|
508
|
-
stream_to_general,
|
|
509
|
-
show_reasoning=self.show_reasoning,
|
|
510
|
-
):
|
|
479
|
+
),
|
|
480
|
+
)
|
|
511
481
|
yield
|
|
482
|
+
if agent_runner.done():
|
|
483
|
+
if final_llm_resp := agent_runner.get_final_llm_resp():
|
|
484
|
+
if final_llm_resp.completion_text:
|
|
485
|
+
chain = (
|
|
486
|
+
MessageChain()
|
|
487
|
+
.message(final_llm_resp.completion_text)
|
|
488
|
+
.chain
|
|
489
|
+
)
|
|
490
|
+
elif final_llm_resp.result_chain:
|
|
491
|
+
chain = final_llm_resp.result_chain.chain
|
|
492
|
+
else:
|
|
493
|
+
chain = MessageChain().chain
|
|
494
|
+
event.set_result(
|
|
495
|
+
MessageEventResult(
|
|
496
|
+
chain=chain,
|
|
497
|
+
result_content_type=ResultContentType.STREAMING_FINISH,
|
|
498
|
+
),
|
|
499
|
+
)
|
|
500
|
+
else:
|
|
501
|
+
async for _ in run_agent(
|
|
502
|
+
agent_runner,
|
|
503
|
+
self.max_step,
|
|
504
|
+
self.show_tool_use,
|
|
505
|
+
stream_to_general,
|
|
506
|
+
show_reasoning=self.show_reasoning,
|
|
507
|
+
):
|
|
508
|
+
yield
|
|
509
|
+
|
|
510
|
+
# 恢复备份的 contexts
|
|
511
|
+
req.contexts = backup_contexts
|
|
512
|
+
|
|
513
|
+
await self._save_to_history(
|
|
514
|
+
event,
|
|
515
|
+
req,
|
|
516
|
+
agent_runner.get_final_llm_resp(),
|
|
517
|
+
agent_runner.run_context.messages,
|
|
518
|
+
)
|
|
512
519
|
|
|
513
|
-
#
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
await self._save_to_history(event, req, agent_runner.get_final_llm_resp())
|
|
520
|
+
# 异步处理 WebChat 特殊情况
|
|
521
|
+
if event.get_platform_name() == "webchat":
|
|
522
|
+
asyncio.create_task(self._handle_webchat(event, req, provider))
|
|
517
523
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
524
|
+
asyncio.create_task(
|
|
525
|
+
Metric.upload(
|
|
526
|
+
llm_tick=1,
|
|
527
|
+
model_name=agent_runner.provider.get_model(),
|
|
528
|
+
provider_type=agent_runner.provider.meta().type,
|
|
529
|
+
),
|
|
530
|
+
)
|
|
521
531
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
532
|
+
except Exception as e:
|
|
533
|
+
logger.error(f"Error occurred while processing agent: {e}")
|
|
534
|
+
await event.send(
|
|
535
|
+
MessageChain().message(
|
|
536
|
+
f"Error occurred while processing agent request: {e}"
|
|
537
|
+
)
|
|
538
|
+
)
|