AstrBot 4.10.5__py3-none-any.whl → 4.11.0__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/api/event/filter/__init__.py +4 -0
- astrbot/builtin_stars/builtin_commands/commands/tts.py +2 -2
- astrbot/cli/__init__.py +1 -1
- astrbot/core/agent/context/compressor.py +243 -0
- astrbot/core/agent/context/config.py +35 -0
- astrbot/core/agent/context/manager.py +120 -0
- astrbot/core/agent/context/token_counter.py +64 -0
- astrbot/core/agent/context/truncator.py +141 -0
- astrbot/core/agent/runners/tool_loop_agent_runner.py +48 -1
- astrbot/core/config/default.py +89 -28
- astrbot/core/conversation_mgr.py +4 -0
- astrbot/core/core_lifecycle.py +1 -0
- astrbot/core/db/__init__.py +1 -0
- astrbot/core/db/migration/migra_token_usage.py +61 -0
- astrbot/core/db/po.py +7 -0
- astrbot/core/db/sqlite.py +5 -1
- astrbot/core/pipeline/process_stage/method/agent_request.py +1 -1
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +70 -57
- astrbot/core/pipeline/result_decorate/stage.py +1 -1
- astrbot/core/pipeline/session_status_check/stage.py +1 -1
- astrbot/core/pipeline/waking_check/stage.py +1 -1
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +1 -1
- astrbot/core/provider/entities.py +5 -0
- astrbot/core/provider/manager.py +27 -12
- astrbot/core/provider/sources/openai_source.py +2 -1
- astrbot/core/star/context.py +14 -1
- astrbot/core/star/register/__init__.py +2 -0
- astrbot/core/star/register/star_handler.py +24 -0
- astrbot/core/star/session_llm_manager.py +38 -26
- astrbot/core/star/session_plugin_manager.py +23 -11
- astrbot/core/star/star_handler.py +1 -0
- astrbot/core/umop_config_router.py +9 -6
- astrbot/core/utils/migra_helper.py +8 -0
- astrbot/dashboard/routes/backup.py +1 -0
- {astrbot-4.10.5.dist-info → astrbot-4.11.0.dist-info}/METADATA +3 -1
- {astrbot-4.10.5.dist-info → astrbot-4.11.0.dist-info}/RECORD +39 -33
- {astrbot-4.10.5.dist-info → astrbot-4.11.0.dist-info}/WHEEL +0 -0
- {astrbot-4.10.5.dist-info → astrbot-4.11.0.dist-info}/entry_points.txt +0 -0
- {astrbot-4.10.5.dist-info → astrbot-4.11.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -227,7 +227,7 @@ class WakingCheckStage(Stage):
|
|
|
227
227
|
event._extras.pop("parsed_params", None)
|
|
228
228
|
|
|
229
229
|
# 根据会话配置过滤插件处理器
|
|
230
|
-
activated_handlers = SessionPluginManager.filter_handlers_by_session(
|
|
230
|
+
activated_handlers = await SessionPluginManager.filter_handlers_by_session(
|
|
231
231
|
event,
|
|
232
232
|
activated_handlers,
|
|
233
233
|
)
|
|
@@ -191,7 +191,7 @@ class WeixinOfficialAccountPlatformAdapter(Platform):
|
|
|
191
191
|
if self.active_send_mode:
|
|
192
192
|
await self.convert_message(msg, None)
|
|
193
193
|
else:
|
|
194
|
-
if msg.id in self.wexin_event_workers:
|
|
194
|
+
if str(msg.id) in self.wexin_event_workers:
|
|
195
195
|
future = self.wexin_event_workers[str(cast(str | int, msg.id))]
|
|
196
196
|
logger.debug(f"duplicate message id checked: {msg.id}")
|
|
197
197
|
else:
|
|
@@ -344,6 +344,11 @@ class LLMResponse:
|
|
|
344
344
|
self.raw_completion = raw_completion
|
|
345
345
|
self.is_chunk = is_chunk
|
|
346
346
|
|
|
347
|
+
if id is not None:
|
|
348
|
+
self.id = id
|
|
349
|
+
if usage is not None:
|
|
350
|
+
self.usage = usage
|
|
351
|
+
|
|
347
352
|
@property
|
|
348
353
|
def completion_text(self):
|
|
349
354
|
if self.result_chain:
|
astrbot/core/provider/manager.py
CHANGED
|
@@ -119,19 +119,34 @@ class ProviderManager:
|
|
|
119
119
|
TTSProvider,
|
|
120
120
|
):
|
|
121
121
|
self.curr_tts_provider_inst = prov
|
|
122
|
-
sp.
|
|
122
|
+
await sp.put_async(
|
|
123
|
+
key="curr_provider_tts",
|
|
124
|
+
value=provider_id,
|
|
125
|
+
scope="global",
|
|
126
|
+
scope_id="global",
|
|
127
|
+
)
|
|
123
128
|
elif provider_type == ProviderType.SPEECH_TO_TEXT and isinstance(
|
|
124
129
|
prov,
|
|
125
130
|
STTProvider,
|
|
126
131
|
):
|
|
127
132
|
self.curr_stt_provider_inst = prov
|
|
128
|
-
sp.
|
|
133
|
+
await sp.put_async(
|
|
134
|
+
key="curr_provider_stt",
|
|
135
|
+
value=provider_id,
|
|
136
|
+
scope="global",
|
|
137
|
+
scope_id="global",
|
|
138
|
+
)
|
|
129
139
|
elif provider_type == ProviderType.CHAT_COMPLETION and isinstance(
|
|
130
140
|
prov,
|
|
131
141
|
Provider,
|
|
132
142
|
):
|
|
133
143
|
self.curr_provider_inst = prov
|
|
134
|
-
sp.
|
|
144
|
+
await sp.put_async(
|
|
145
|
+
key="curr_provider",
|
|
146
|
+
value=provider_id,
|
|
147
|
+
scope="global",
|
|
148
|
+
scope_id="global",
|
|
149
|
+
)
|
|
135
150
|
|
|
136
151
|
async def get_provider_by_id(self, provider_id: str) -> Providers | None:
|
|
137
152
|
"""根据提供商 ID 获取提供商实例"""
|
|
@@ -206,21 +221,21 @@ class ProviderManager:
|
|
|
206
221
|
logger.error(traceback.format_exc())
|
|
207
222
|
logger.error(e)
|
|
208
223
|
|
|
209
|
-
selected_provider_id = sp.
|
|
210
|
-
"curr_provider",
|
|
211
|
-
self.provider_settings.get("default_provider_id"),
|
|
224
|
+
selected_provider_id = await sp.get_async(
|
|
225
|
+
key="curr_provider",
|
|
226
|
+
default=self.provider_settings.get("default_provider_id"),
|
|
212
227
|
scope="global",
|
|
213
228
|
scope_id="global",
|
|
214
229
|
)
|
|
215
|
-
selected_stt_provider_id = sp.
|
|
216
|
-
"curr_provider_stt",
|
|
217
|
-
self.provider_stt_settings.get("provider_id"),
|
|
230
|
+
selected_stt_provider_id = await sp.get_async(
|
|
231
|
+
key="curr_provider_stt",
|
|
232
|
+
default=self.provider_stt_settings.get("provider_id"),
|
|
218
233
|
scope="global",
|
|
219
234
|
scope_id="global",
|
|
220
235
|
)
|
|
221
|
-
selected_tts_provider_id = sp.
|
|
222
|
-
"curr_provider_tts",
|
|
223
|
-
self.provider_tts_settings.get("provider_id"),
|
|
236
|
+
selected_tts_provider_id = await sp.get_async(
|
|
237
|
+
key="curr_provider_tts",
|
|
238
|
+
default=self.provider_tts_settings.get("provider_id"),
|
|
224
239
|
scope="global",
|
|
225
240
|
scope_id="global",
|
|
226
241
|
)
|
|
@@ -378,7 +378,8 @@ class ProviderOpenAIOfficial(Provider):
|
|
|
378
378
|
new_content.append(part)
|
|
379
379
|
message["content"] = new_content
|
|
380
380
|
# reasoning key is "reasoning_content"
|
|
381
|
-
|
|
381
|
+
if reasoning_content:
|
|
382
|
+
message["reasoning_content"] = reasoning_content
|
|
382
383
|
|
|
383
384
|
async def _handle_api_error(
|
|
384
385
|
self,
|
astrbot/core/star/context.py
CHANGED
|
@@ -149,9 +149,12 @@ class Context:
|
|
|
149
149
|
contexts: context messages for the LLM
|
|
150
150
|
max_steps: Maximum number of tool calls before stopping the loop
|
|
151
151
|
**kwargs: Additional keyword arguments. The kwargs will not be passed to the LLM directly for now, but can include:
|
|
152
|
+
stream: bool - whether to stream the LLM response
|
|
152
153
|
agent_hooks: BaseAgentRunHooks[AstrAgentContext] - hooks to run during agent execution
|
|
153
154
|
agent_context: AstrAgentContext - context to use for the agent
|
|
154
155
|
|
|
156
|
+
other kwargs will be DIRECTLY passed to the runner.reset() method
|
|
157
|
+
|
|
155
158
|
Returns:
|
|
156
159
|
The final LLMResponse after tool calls are completed.
|
|
157
160
|
|
|
@@ -194,6 +197,15 @@ class Context:
|
|
|
194
197
|
)
|
|
195
198
|
agent_runner = ToolLoopAgentRunner()
|
|
196
199
|
tool_executor = FunctionToolExecutor()
|
|
200
|
+
|
|
201
|
+
streaming = kwargs.get("stream", False)
|
|
202
|
+
|
|
203
|
+
other_kwargs = {
|
|
204
|
+
k: v
|
|
205
|
+
for k, v in kwargs.items()
|
|
206
|
+
if k not in ["stream", "agent_hooks", "agent_context"]
|
|
207
|
+
}
|
|
208
|
+
|
|
197
209
|
await agent_runner.reset(
|
|
198
210
|
provider=prov,
|
|
199
211
|
request=request,
|
|
@@ -203,7 +215,8 @@ class Context:
|
|
|
203
215
|
),
|
|
204
216
|
tool_executor=tool_executor,
|
|
205
217
|
agent_hooks=agent_hooks,
|
|
206
|
-
streaming=
|
|
218
|
+
streaming=streaming,
|
|
219
|
+
**other_kwargs,
|
|
207
220
|
)
|
|
208
221
|
async for _ in agent_runner.step_until_done(max_steps):
|
|
209
222
|
pass
|
|
@@ -12,6 +12,7 @@ from .star_handler import (
|
|
|
12
12
|
register_on_llm_request,
|
|
13
13
|
register_on_llm_response,
|
|
14
14
|
register_on_platform_loaded,
|
|
15
|
+
register_on_waiting_llm_request,
|
|
15
16
|
register_permission_type,
|
|
16
17
|
register_platform_adapter_type,
|
|
17
18
|
register_regex,
|
|
@@ -30,6 +31,7 @@ __all__ = [
|
|
|
30
31
|
"register_on_llm_request",
|
|
31
32
|
"register_on_llm_response",
|
|
32
33
|
"register_on_platform_loaded",
|
|
34
|
+
"register_on_waiting_llm_request",
|
|
33
35
|
"register_permission_type",
|
|
34
36
|
"register_platform_adapter_type",
|
|
35
37
|
"register_regex",
|
|
@@ -339,6 +339,30 @@ def register_on_platform_loaded(**kwargs):
|
|
|
339
339
|
return decorator
|
|
340
340
|
|
|
341
341
|
|
|
342
|
+
def register_on_waiting_llm_request(**kwargs):
|
|
343
|
+
"""当等待调用 LLM 时的通知事件(在获取锁之前)
|
|
344
|
+
|
|
345
|
+
此钩子在消息确定要调用 LLM 但还未开始排队等锁时触发,
|
|
346
|
+
适合用于发送"正在思考中..."等用户反馈提示。
|
|
347
|
+
|
|
348
|
+
Examples:
|
|
349
|
+
```py
|
|
350
|
+
@on_waiting_llm_request()
|
|
351
|
+
async def on_waiting_llm(self, event: AstrMessageEvent) -> None:
|
|
352
|
+
await event.send("🤔 正在思考中...")
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
def decorator(awaitable):
|
|
358
|
+
_ = get_handler_or_create(
|
|
359
|
+
awaitable, EventType.OnWaitingLLMRequestEvent, **kwargs
|
|
360
|
+
)
|
|
361
|
+
return awaitable
|
|
362
|
+
|
|
363
|
+
return decorator
|
|
364
|
+
|
|
365
|
+
|
|
342
366
|
def register_on_llm_request(**kwargs):
|
|
343
367
|
"""当有 LLM 请求时的事件
|
|
344
368
|
|
|
@@ -12,7 +12,7 @@ class SessionServiceManager:
|
|
|
12
12
|
# =============================================================================
|
|
13
13
|
|
|
14
14
|
@staticmethod
|
|
15
|
-
def is_llm_enabled_for_session(session_id: str) -> bool:
|
|
15
|
+
async def is_llm_enabled_for_session(session_id: str) -> bool:
|
|
16
16
|
"""检查LLM是否在指定会话中启用
|
|
17
17
|
|
|
18
18
|
Args:
|
|
@@ -23,11 +23,11 @@ class SessionServiceManager:
|
|
|
23
23
|
|
|
24
24
|
"""
|
|
25
25
|
# 获取会话服务配置
|
|
26
|
-
session_services = sp.
|
|
27
|
-
"session_service_config",
|
|
28
|
-
{},
|
|
26
|
+
session_services = await sp.get_async(
|
|
29
27
|
scope="umo",
|
|
30
28
|
scope_id=session_id,
|
|
29
|
+
key="session_service_config",
|
|
30
|
+
default={},
|
|
31
31
|
)
|
|
32
32
|
|
|
33
33
|
# 如果配置了该会话的LLM状态,返回该状态
|
|
@@ -39,7 +39,7 @@ class SessionServiceManager:
|
|
|
39
39
|
return True
|
|
40
40
|
|
|
41
41
|
@staticmethod
|
|
42
|
-
def set_llm_status_for_session(session_id: str, enabled: bool) -> None:
|
|
42
|
+
async def set_llm_status_for_session(session_id: str, enabled: bool) -> None:
|
|
43
43
|
"""设置LLM在指定会话中的启停状态
|
|
44
44
|
|
|
45
45
|
Args:
|
|
@@ -48,18 +48,24 @@ class SessionServiceManager:
|
|
|
48
48
|
|
|
49
49
|
"""
|
|
50
50
|
session_config = (
|
|
51
|
-
sp.
|
|
51
|
+
await sp.get_async(
|
|
52
|
+
scope="umo",
|
|
53
|
+
scope_id=session_id,
|
|
54
|
+
key="session_service_config",
|
|
55
|
+
default={},
|
|
56
|
+
)
|
|
57
|
+
or {}
|
|
52
58
|
)
|
|
53
59
|
session_config["llm_enabled"] = enabled
|
|
54
|
-
sp.
|
|
55
|
-
"session_service_config",
|
|
56
|
-
session_config,
|
|
60
|
+
await sp.put_async(
|
|
57
61
|
scope="umo",
|
|
58
62
|
scope_id=session_id,
|
|
63
|
+
key="session_service_config",
|
|
64
|
+
value=session_config,
|
|
59
65
|
)
|
|
60
66
|
|
|
61
67
|
@staticmethod
|
|
62
|
-
def should_process_llm_request(event: AstrMessageEvent) -> bool:
|
|
68
|
+
async def should_process_llm_request(event: AstrMessageEvent) -> bool:
|
|
63
69
|
"""检查是否应该处理LLM请求
|
|
64
70
|
|
|
65
71
|
Args:
|
|
@@ -70,14 +76,14 @@ class SessionServiceManager:
|
|
|
70
76
|
|
|
71
77
|
"""
|
|
72
78
|
session_id = event.unified_msg_origin
|
|
73
|
-
return SessionServiceManager.is_llm_enabled_for_session(session_id)
|
|
79
|
+
return await SessionServiceManager.is_llm_enabled_for_session(session_id)
|
|
74
80
|
|
|
75
81
|
# =============================================================================
|
|
76
82
|
# TTS 相关方法
|
|
77
83
|
# =============================================================================
|
|
78
84
|
|
|
79
85
|
@staticmethod
|
|
80
|
-
def is_tts_enabled_for_session(session_id: str) -> bool:
|
|
86
|
+
async def is_tts_enabled_for_session(session_id: str) -> bool:
|
|
81
87
|
"""检查TTS是否在指定会话中启用
|
|
82
88
|
|
|
83
89
|
Args:
|
|
@@ -88,11 +94,11 @@ class SessionServiceManager:
|
|
|
88
94
|
|
|
89
95
|
"""
|
|
90
96
|
# 获取会话服务配置
|
|
91
|
-
session_services = sp.
|
|
92
|
-
"session_service_config",
|
|
93
|
-
{},
|
|
97
|
+
session_services = await sp.get_async(
|
|
94
98
|
scope="umo",
|
|
95
99
|
scope_id=session_id,
|
|
100
|
+
key="session_service_config",
|
|
101
|
+
default={},
|
|
96
102
|
)
|
|
97
103
|
|
|
98
104
|
# 如果配置了该会话的TTS状态,返回该状态
|
|
@@ -104,7 +110,7 @@ class SessionServiceManager:
|
|
|
104
110
|
return True
|
|
105
111
|
|
|
106
112
|
@staticmethod
|
|
107
|
-
def set_tts_status_for_session(session_id: str, enabled: bool) -> None:
|
|
113
|
+
async def set_tts_status_for_session(session_id: str, enabled: bool) -> None:
|
|
108
114
|
"""设置TTS在指定会话中的启停状态
|
|
109
115
|
|
|
110
116
|
Args:
|
|
@@ -113,14 +119,20 @@ class SessionServiceManager:
|
|
|
113
119
|
|
|
114
120
|
"""
|
|
115
121
|
session_config = (
|
|
116
|
-
sp.
|
|
122
|
+
await sp.get_async(
|
|
123
|
+
scope="umo",
|
|
124
|
+
scope_id=session_id,
|
|
125
|
+
key="session_service_config",
|
|
126
|
+
default={},
|
|
127
|
+
)
|
|
128
|
+
or {}
|
|
117
129
|
)
|
|
118
130
|
session_config["tts_enabled"] = enabled
|
|
119
|
-
sp.
|
|
120
|
-
"session_service_config",
|
|
121
|
-
session_config,
|
|
131
|
+
await sp.put_async(
|
|
122
132
|
scope="umo",
|
|
123
133
|
scope_id=session_id,
|
|
134
|
+
key="session_service_config",
|
|
135
|
+
value=session_config,
|
|
124
136
|
)
|
|
125
137
|
|
|
126
138
|
logger.info(
|
|
@@ -128,7 +140,7 @@ class SessionServiceManager:
|
|
|
128
140
|
)
|
|
129
141
|
|
|
130
142
|
@staticmethod
|
|
131
|
-
def should_process_tts_request(event: AstrMessageEvent) -> bool:
|
|
143
|
+
async def should_process_tts_request(event: AstrMessageEvent) -> bool:
|
|
132
144
|
"""检查是否应该处理TTS请求
|
|
133
145
|
|
|
134
146
|
Args:
|
|
@@ -139,14 +151,14 @@ class SessionServiceManager:
|
|
|
139
151
|
|
|
140
152
|
"""
|
|
141
153
|
session_id = event.unified_msg_origin
|
|
142
|
-
return SessionServiceManager.is_tts_enabled_for_session(session_id)
|
|
154
|
+
return await SessionServiceManager.is_tts_enabled_for_session(session_id)
|
|
143
155
|
|
|
144
156
|
# =============================================================================
|
|
145
157
|
# 会话整体启停相关方法
|
|
146
158
|
# =============================================================================
|
|
147
159
|
|
|
148
160
|
@staticmethod
|
|
149
|
-
def is_session_enabled(session_id: str) -> bool:
|
|
161
|
+
async def is_session_enabled(session_id: str) -> bool:
|
|
150
162
|
"""检查会话是否整体启用
|
|
151
163
|
|
|
152
164
|
Args:
|
|
@@ -157,11 +169,11 @@ class SessionServiceManager:
|
|
|
157
169
|
|
|
158
170
|
"""
|
|
159
171
|
# 获取会话服务配置
|
|
160
|
-
session_services = sp.
|
|
161
|
-
"session_service_config",
|
|
162
|
-
{},
|
|
172
|
+
session_services = await sp.get_async(
|
|
163
173
|
scope="umo",
|
|
164
174
|
scope_id=session_id,
|
|
175
|
+
key="session_service_config",
|
|
176
|
+
default={},
|
|
165
177
|
)
|
|
166
178
|
|
|
167
179
|
# 如果配置了该会话的整体状态,返回该状态
|
|
@@ -8,7 +8,10 @@ class SessionPluginManager:
|
|
|
8
8
|
"""管理会话级别的插件启停状态"""
|
|
9
9
|
|
|
10
10
|
@staticmethod
|
|
11
|
-
def is_plugin_enabled_for_session(
|
|
11
|
+
async def is_plugin_enabled_for_session(
|
|
12
|
+
session_id: str,
|
|
13
|
+
plugin_name: str,
|
|
14
|
+
) -> bool:
|
|
12
15
|
"""检查插件是否在指定会话中启用
|
|
13
16
|
|
|
14
17
|
Args:
|
|
@@ -20,11 +23,11 @@ class SessionPluginManager:
|
|
|
20
23
|
|
|
21
24
|
"""
|
|
22
25
|
# 获取会话插件配置
|
|
23
|
-
session_plugin_config = sp.
|
|
24
|
-
"session_plugin_config",
|
|
25
|
-
{},
|
|
26
|
+
session_plugin_config = await sp.get_async(
|
|
26
27
|
scope="umo",
|
|
27
28
|
scope_id=session_id,
|
|
29
|
+
key="session_plugin_config",
|
|
30
|
+
default={},
|
|
28
31
|
)
|
|
29
32
|
session_config = session_plugin_config.get(session_id, {})
|
|
30
33
|
|
|
@@ -43,7 +46,10 @@ class SessionPluginManager:
|
|
|
43
46
|
return True
|
|
44
47
|
|
|
45
48
|
@staticmethod
|
|
46
|
-
def filter_handlers_by_session(
|
|
49
|
+
async def filter_handlers_by_session(
|
|
50
|
+
event: AstrMessageEvent,
|
|
51
|
+
handlers: list,
|
|
52
|
+
) -> list:
|
|
47
53
|
"""根据会话配置过滤处理器列表
|
|
48
54
|
|
|
49
55
|
Args:
|
|
@@ -59,6 +65,15 @@ class SessionPluginManager:
|
|
|
59
65
|
session_id = event.unified_msg_origin
|
|
60
66
|
filtered_handlers = []
|
|
61
67
|
|
|
68
|
+
session_plugin_config = await sp.get_async(
|
|
69
|
+
scope="umo",
|
|
70
|
+
scope_id=session_id,
|
|
71
|
+
key="session_plugin_config",
|
|
72
|
+
default={},
|
|
73
|
+
)
|
|
74
|
+
session_config = session_plugin_config.get(session_id, {})
|
|
75
|
+
disabled_plugins = session_config.get("disabled_plugins", [])
|
|
76
|
+
|
|
62
77
|
for handler in handlers:
|
|
63
78
|
# 获取处理器对应的插件
|
|
64
79
|
plugin = star_map.get(handler.handler_module_path)
|
|
@@ -76,14 +91,11 @@ class SessionPluginManager:
|
|
|
76
91
|
continue
|
|
77
92
|
|
|
78
93
|
# 检查插件是否在当前会话中启用
|
|
79
|
-
if
|
|
80
|
-
session_id,
|
|
81
|
-
plugin.name,
|
|
82
|
-
):
|
|
83
|
-
filtered_handlers.append(handler)
|
|
84
|
-
else:
|
|
94
|
+
if plugin.name in disabled_plugins:
|
|
85
95
|
logger.debug(
|
|
86
96
|
f"插件 {plugin.name} 在会话 {session_id} 中被禁用,跳过处理器 {handler.handler_name}",
|
|
87
97
|
)
|
|
98
|
+
else:
|
|
99
|
+
filtered_handlers.append(handler)
|
|
88
100
|
|
|
89
101
|
return filtered_handlers
|
|
@@ -184,6 +184,7 @@ class EventType(enum.Enum):
|
|
|
184
184
|
OnPlatformLoadedEvent = enum.auto() # 平台加载完成
|
|
185
185
|
|
|
186
186
|
AdapterMessageEvent = enum.auto() # 收到适配器发来的消息
|
|
187
|
+
OnWaitingLLMRequestEvent = enum.auto() # 等待调用 LLM(在获取锁之前,仅通知)
|
|
187
188
|
OnLLMRequestEvent = enum.auto() # 收到 LLM 请求(可以是用户也可以是插件)
|
|
188
189
|
OnLLMResponseEvent = enum.auto() # LLM 响应后
|
|
189
190
|
OnDecoratingResultEvent = enum.auto() # 发送消息前
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fnmatch
|
|
2
|
+
|
|
1
3
|
from astrbot.core.utils.shared_preferences import SharedPreferences
|
|
2
4
|
|
|
3
5
|
|
|
@@ -9,14 +11,15 @@ class UmopConfigRouter:
|
|
|
9
11
|
"""UMOP 到配置文件 ID 的映射"""
|
|
10
12
|
self.sp = sp
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
async def initialize(self):
|
|
15
|
+
await self._load_routing_table()
|
|
13
16
|
|
|
14
|
-
def _load_routing_table(self):
|
|
17
|
+
async def _load_routing_table(self):
|
|
15
18
|
"""加载路由表"""
|
|
16
19
|
# 从 SharedPreferences 中加载 umop_to_conf_id 映射
|
|
17
|
-
sp_data = self.sp.
|
|
18
|
-
"umop_config_routing",
|
|
19
|
-
{},
|
|
20
|
+
sp_data = await self.sp.get_async(
|
|
21
|
+
key="umop_config_routing",
|
|
22
|
+
default={},
|
|
20
23
|
scope="global",
|
|
21
24
|
scope_id="global",
|
|
22
25
|
)
|
|
@@ -30,7 +33,7 @@ class UmopConfigRouter:
|
|
|
30
33
|
if len(p1_ls) != 3 or len(p2_ls) != 3:
|
|
31
34
|
return False # 非法格式
|
|
32
35
|
|
|
33
|
-
return all(p == "" or
|
|
36
|
+
return all(p == "" or fnmatch.fnmatchcase(t, p) for p, t in zip(p1_ls, p2_ls))
|
|
34
37
|
|
|
35
38
|
def get_conf_id_for_umop(self, umo: str) -> str | None:
|
|
36
39
|
"""根据 UMO 获取对应的配置文件 ID
|
|
@@ -3,6 +3,7 @@ import traceback
|
|
|
3
3
|
from astrbot.core import astrbot_config, logger
|
|
4
4
|
from astrbot.core.astrbot_config_mgr import AstrBotConfig, AstrBotConfigManager
|
|
5
5
|
from astrbot.core.db.migration.migra_45_to_46 import migrate_45_to_46
|
|
6
|
+
from astrbot.core.db.migration.migra_token_usage import migrate_token_usage
|
|
6
7
|
from astrbot.core.db.migration.migra_webchat_session import migrate_webchat_session
|
|
7
8
|
|
|
8
9
|
|
|
@@ -139,6 +140,13 @@ async def migra(
|
|
|
139
140
|
logger.error(f"Migration for webchat session failed: {e!s}")
|
|
140
141
|
logger.error(traceback.format_exc())
|
|
141
142
|
|
|
143
|
+
# migration for token_usage column
|
|
144
|
+
try:
|
|
145
|
+
await migrate_token_usage(db)
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logger.error(f"Migration for token_usage column failed: {e!s}")
|
|
148
|
+
logger.error(traceback.format_exc())
|
|
149
|
+
|
|
142
150
|
# migra third party agent runner configs
|
|
143
151
|
_c = False
|
|
144
152
|
providers = astrbot_config["provider"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AstrBot
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.11.0
|
|
4
4
|
Summary: Easy-to-use multi-platform LLM chatbot and development framework
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: Astrbot,Astrbot Module,Astrbot Plugin
|
|
@@ -193,6 +193,7 @@ uv run main.py
|
|
|
193
193
|
|
|
194
194
|
**社区维护**
|
|
195
195
|
|
|
196
|
+
- [Matrix](https://github.com/stevessr/astrbot_plugin_matrix_adapter)
|
|
196
197
|
- [KOOK](https://github.com/wuyan1003/astrbot_plugin_kook_adapter)
|
|
197
198
|
- [VoceChat](https://github.com/HikariFroya/astrbot_plugin_vocechat)
|
|
198
199
|
- [Bilibili 私信](https://github.com/Hina-Chat/astrbot_plugin_bilibili_adapter)
|
|
@@ -269,6 +270,7 @@ pre-commit install
|
|
|
269
270
|
- 5 群:822130018
|
|
270
271
|
- 6 群:753075035
|
|
271
272
|
- 7 群:743746109
|
|
273
|
+
- 8 群:1030353265
|
|
272
274
|
- 开发者群:975206796
|
|
273
275
|
|
|
274
276
|
### Telegram 群组
|