AstrBot 4.0.0b3__py3-none-any.whl → 4.0.0b5__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.
@@ -37,7 +37,10 @@ async def check_dashboard(astrbot_root: Path) -> None:
37
37
  ):
38
38
  click.echo("正在安装管理面板...")
39
39
  await download_dashboard(
40
- path="data/dashboard.zip", extract_path=str(astrbot_root)
40
+ path="data/dashboard.zip",
41
+ extract_path=str(astrbot_root),
42
+ version=f"v{VERSION}",
43
+ latest=False,
41
44
  )
42
45
  click.echo("管理面板安装完成")
43
46
 
@@ -50,7 +53,10 @@ async def check_dashboard(astrbot_root: Path) -> None:
50
53
  version = dashboard_version.split("v")[1]
51
54
  click.echo(f"管理面板版本: {version}")
52
55
  await download_dashboard(
53
- path="data/dashboard.zip", extract_path=str(astrbot_root)
56
+ path="data/dashboard.zip",
57
+ extract_path=str(astrbot_root),
58
+ version=f"v{VERSION}",
59
+ latest=False,
54
60
  )
55
61
  except Exception as e:
56
62
  click.echo(f"下载管理面板失败: {e}")
@@ -59,7 +65,10 @@ async def check_dashboard(astrbot_root: Path) -> None:
59
65
  click.echo("初始化管理面板目录...")
60
66
  try:
61
67
  await download_dashboard(
62
- path=str(astrbot_root / "dashboard.zip"), extract_path=str(astrbot_root)
68
+ path=str(astrbot_root / "dashboard.zip"),
69
+ extract_path=str(astrbot_root),
70
+ version=f"v{VERSION}",
71
+ latest=False,
63
72
  )
64
73
  click.echo("管理面板初始化完成")
65
74
  except Exception as e:
@@ -36,13 +36,21 @@ class AstrBotConfigManager:
36
36
  self.confs: dict[str, AstrBotConfig] = {}
37
37
  """uuid / "default" -> AstrBotConfig"""
38
38
  self.confs["default"] = default_config
39
+ self.abconf_data = None
39
40
  self._load_all_configs()
40
41
 
42
+ def _get_abconf_data(self) -> dict:
43
+ """获取所有的 abconf 数据"""
44
+ if self.abconf_data is None:
45
+ self.abconf_data = self.sp.get(
46
+ "abconf_mapping", {}, scope="global", scope_id="global"
47
+ )
48
+ return self.abconf_data
49
+
41
50
  def _load_all_configs(self):
42
51
  """Load all configurations from the shared preferences."""
43
- abconf_data = self.sp.get(
44
- "abconf_mapping", {}, scope="global", scope_id="global"
45
- )
52
+ abconf_data = self._get_abconf_data()
53
+ self.abconf_data = abconf_data
46
54
  for uuid_, meta in abconf_data.items():
47
55
  filename = meta["path"]
48
56
  conf_path = os.path.join(get_astrbot_config_path(), filename)
@@ -72,9 +80,7 @@ class AstrBotConfigManager:
72
80
  ConfInfo: 包含配置文件的 uuid, 路径和名称等信息, 是一个 dict 类型
73
81
  """
74
82
  # uuid -> { "umop": list, "path": str, "name": str }
75
- abconf_data = self.sp.get(
76
- "abconf_mapping", {}, scope="global", scope_id="global"
77
- )
83
+ abconf_data = self._get_abconf_data()
78
84
  if isinstance(umo, MessageSession):
79
85
  umo = str(umo)
80
86
  else:
@@ -115,6 +121,7 @@ class AstrBotConfigManager:
115
121
  "name": random_word,
116
122
  }
117
123
  self.sp.put("abconf_mapping", abconf_data, scope="global", scope_id="global")
124
+ self.abconf_data = abconf_data
118
125
 
119
126
  def get_conf(self, umo: str | MessageSession | None) -> AstrBotConfig:
120
127
  """获取指定 umo 的配置文件。如果不存在,则 fallback 到默认配置文件。"""
@@ -147,9 +154,7 @@ class AstrBotConfigManager:
147
154
  """获取所有配置文件的元数据列表"""
148
155
  conf_list = []
149
156
  conf_list.append(DEFAULT_CONFIG_CONF_INFO)
150
- abconf_mapping = self.sp.get(
151
- "abconf_mapping", {}, scope="global", scope_id="global"
152
- )
157
+ abconf_mapping = self._get_abconf_data()
153
158
  for uuid_, meta in abconf_mapping.items():
154
159
  conf_list.append(ConfInfo(**meta, id=uuid_))
155
160
  return conf_list
@@ -218,6 +223,7 @@ class AstrBotConfigManager:
218
223
  # 从映射中移除
219
224
  del abconf_data[conf_id]
220
225
  self.sp.put("abconf_mapping", abconf_data, scope="global", scope_id="global")
226
+ self.abconf_data = abconf_data
221
227
 
222
228
  logger.info(f"成功删除配置文件 {conf_id}")
223
229
  return True
@@ -263,6 +269,7 @@ class AstrBotConfigManager:
263
269
 
264
270
  # 保存更新
265
271
  self.sp.put("abconf_mapping", abconf_data, scope="global", scope_id="global")
272
+ self.abconf_data = abconf_data
266
273
  logger.info(f"成功更新配置文件 {conf_id} 的信息")
267
274
  return True
268
275
 
@@ -6,7 +6,7 @@ import os
6
6
 
7
7
  from astrbot.core.utils.astrbot_path import get_astrbot_data_path
8
8
 
9
- VERSION = "4.0.0-beta.3"
9
+ VERSION = "4.0.0-beta.5"
10
10
  DB_PATH = os.path.join(get_astrbot_data_path(), "data_v4.db")
11
11
 
12
12
  # 默认配置
@@ -866,6 +866,9 @@ CONFIG_METADATA_2 = {
866
866
  "provider_type": "text_to_speech",
867
867
  "enable": False,
868
868
  "edge-tts-voice": "zh-CN-XiaoxiaoNeural",
869
+ "rate": "+0%",
870
+ "volume": "+0%",
871
+ "pitch": "+0Hz",
869
872
  "timeout": 20,
870
873
  },
871
874
  "GSV TTS(本地加载)": {
@@ -1913,7 +1916,7 @@ CONFIG_METADATA_3 = {
1913
1916
  "type": "bool",
1914
1917
  },
1915
1918
  "provider_settings.identifier": {
1916
- "description": "用户感知",
1919
+ "description": "用户识别",
1917
1920
  "type": "bool",
1918
1921
  },
1919
1922
  "provider_settings.datetime_system_prompt": {
@@ -1926,7 +1929,7 @@ CONFIG_METADATA_3 = {
1926
1929
  },
1927
1930
  "provider_settings.max_agent_step": {
1928
1931
  "description": "工具调用轮数上限",
1929
- "type": "bool",
1932
+ "type": "int",
1930
1933
  },
1931
1934
  "provider_settings.streaming_response": {
1932
1935
  "description": "流式回复",
@@ -2288,7 +2291,7 @@ CONFIG_METADATA_3_SYSTEM = {
2288
2291
  "condition": {
2289
2292
  "t2i_strategy": "remote",
2290
2293
  },
2291
- "_special": "t2i_template"
2294
+ "_special": "t2i_template",
2292
2295
  },
2293
2296
  "log_level": {
2294
2297
  "description": "控制台日志级别",
@@ -2321,6 +2324,11 @@ CONFIG_METADATA_3_SYSTEM = {
2321
2324
  "type": "string",
2322
2325
  "hint": "启用后,会以添加环境变量的方式设置代理。格式为 `http://ip:port`",
2323
2326
  },
2327
+ "no_proxy": {
2328
+ "description": "直连地址列表",
2329
+ "type": "list",
2330
+ "items": {"type": "string"},
2331
+ },
2324
2332
  },
2325
2333
  }
2326
2334
  },
@@ -299,7 +299,9 @@ class LLMRequestSubStage(Stage):
299
299
  self.max_context_length - 1,
300
300
  )
301
301
  self.streaming_response: bool = settings["streaming_response"]
302
- self.max_step: int = settings.get("max_agent_step", 10)
302
+ self.max_step: int = settings.get("max_agent_step", 30)
303
+ if isinstance(self.max_step, bool): # workaround: #2622
304
+ self.max_step = 30
303
305
  self.show_tool_use: bool = settings.get("show_tool_use_status", True)
304
306
 
305
307
  for bwp in self.bot_wake_prefixs:
@@ -434,7 +436,9 @@ class LLMRequestSubStage(Stage):
434
436
  provider_cfg = provider.provider_config.get("modalities", ["tool_use"])
435
437
  # 如果模型不支持工具使用,但请求中包含工具列表,则清空。
436
438
  if "tool_use" not in provider_cfg:
437
- logger.debug(f"用户设置提供商 {provider} 不支持工具使用,清空工具列表。")
439
+ logger.debug(
440
+ f"用户设置提供商 {provider} 不支持工具使用,清空工具列表。"
441
+ )
438
442
  req.func_tool = None
439
443
  # 插件可用性设置
440
444
  if event.plugins_name is not None and req.func_tool:
@@ -67,12 +67,19 @@ class AiocqhttpMessageEvent(AstrMessageEvent):
67
67
  session_id: str,
68
68
  messages: list[dict],
69
69
  ):
70
- if event:
71
- await bot.send(event=event, message=messages)
72
- elif is_group:
70
+ # session_id 必须是纯数字字符串
71
+ session_id = int(session_id) if session_id.isdigit() else None
72
+
73
+ if is_group and isinstance(session_id, int):
73
74
  await bot.send_group_msg(group_id=session_id, message=messages)
74
- else:
75
+ elif not is_group and isinstance(session_id, int):
75
76
  await bot.send_private_msg(user_id=session_id, message=messages)
77
+ elif isinstance(event, Event): # 最后兜底
78
+ await bot.send(event=event, message=messages)
79
+ else:
80
+ raise ValueError(
81
+ f"无法发送消息:缺少有效的数字 session_id({session_id}) 或 event({event})"
82
+ )
76
83
 
77
84
  @classmethod
78
85
  async def send_message(
@@ -83,7 +90,15 @@ class AiocqhttpMessageEvent(AstrMessageEvent):
83
90
  is_group: bool = False,
84
91
  session_id: str = None,
85
92
  ):
86
- """发送消息"""
93
+ """发送消息至 QQ 协议端(aiocqhttp)。
94
+
95
+ Args:
96
+ bot (CQHttp): aiocqhttp 机器人实例
97
+ message_chain (MessageChain): 要发送的消息链
98
+ event (Event | None, optional): aiocqhttp 事件对象.
99
+ is_group (bool, optional): 是否为群消息.
100
+ session_id (str | None, optional): 会话 ID(群号或 QQ 号
101
+ """
87
102
 
88
103
  # 转发消息、文件消息不能和普通消息混在一起发送
89
104
  send_one_by_one = any(
@@ -122,18 +137,15 @@ class AiocqhttpMessageEvent(AstrMessageEvent):
122
137
 
123
138
  async def send(self, message: MessageChain):
124
139
  """发送消息"""
125
- event = self.message_obj.raw_message
126
- assert isinstance(event, Event), "Event must be an instance of aiocqhttp.Event"
127
- is_group = False
128
- if self.get_group_id():
129
- is_group = True
130
- session_id = self.get_group_id()
131
- else:
132
- session_id = self.get_sender_id()
140
+ event = getattr(self.message_obj, "raw_message", None)
141
+
142
+ is_group = bool(self.get_group_id())
143
+ session_id = self.get_group_id() if is_group else self.get_sender_id()
144
+
133
145
  await self.send_message(
134
146
  bot=self.bot,
135
147
  message_chain=message,
136
- event=event,
148
+ event=event, # 不强制要求一定是 Event
137
149
  is_group=is_group,
138
150
  session_id=session_id,
139
151
  )
@@ -4,9 +4,11 @@ import json
4
4
  from astrbot.core.utils.io import download_image_by_url
5
5
  from astrbot import logger
6
6
  from dataclasses import dataclass, field
7
- from typing import List, Dict, Type
7
+ from typing import List, Dict, Type, Any
8
8
  from astrbot.core.agent.tool import ToolSet
9
9
  from openai.types.chat.chat_completion import ChatCompletion
10
+ from google.genai.types import GenerateContentResponse
11
+ from anthropic.types import Message
10
12
  from openai.types.chat.chat_completion_message_tool_call import (
11
13
  ChatCompletionMessageToolCall,
12
14
  )
@@ -30,11 +32,11 @@ class ProviderMetaData:
30
32
  desc: str = ""
31
33
  """提供商适配器描述."""
32
34
  provider_type: ProviderType = ProviderType.CHAT_COMPLETION
33
- cls_type: Type = None
35
+ cls_type: Type | None = None
34
36
 
35
- default_config_tmpl: dict = None
37
+ default_config_tmpl: dict | None = None
36
38
  """平台的默认配置模板"""
37
- provider_display_name: str = None
39
+ provider_display_name: str | None = None
38
40
  """显示在 WebUI 配置页中的提供商名称,如空则是 type"""
39
41
 
40
42
 
@@ -58,7 +60,7 @@ class ToolCallMessageSegment:
58
60
  class AssistantMessageSegment:
59
61
  """OpenAI 格式的上下文中 role 为 assistant 的消息段。参考: https://platform.openai.com/docs/guides/function-calling"""
60
62
 
61
- content: str = None
63
+ content: str | None = None
62
64
  tool_calls: List[ChatCompletionMessageToolCall | Dict] = field(default_factory=list)
63
65
  role: str = "assistant"
64
66
 
@@ -205,17 +207,17 @@ class ProviderRequest:
205
207
  class LLMResponse:
206
208
  role: str
207
209
  """角色, assistant, tool, err"""
208
- result_chain: MessageChain = None
210
+ result_chain: MessageChain | None = None
209
211
  """返回的消息链"""
210
- tools_call_args: List[Dict[str, any]] = field(default_factory=list)
212
+ tools_call_args: List[Dict[str, Any]] = field(default_factory=list)
211
213
  """工具调用参数"""
212
214
  tools_call_name: List[str] = field(default_factory=list)
213
215
  """工具调用名称"""
214
216
  tools_call_ids: List[str] = field(default_factory=list)
215
217
  """工具调用 ID"""
216
218
 
217
- raw_completion: ChatCompletion = None
218
- _new_record: Dict[str, any] = None
219
+ raw_completion: ChatCompletion | GenerateContentResponse | Message | None = None
220
+ _new_record: Dict[str, Any] | None = None
219
221
 
220
222
  _completion_text: str = ""
221
223
 
@@ -226,12 +228,12 @@ class LLMResponse:
226
228
  self,
227
229
  role: str,
228
230
  completion_text: str = "",
229
- result_chain: MessageChain = None,
230
- tools_call_args: List[Dict[str, any]] = None,
231
- tools_call_name: List[str] = None,
232
- tools_call_ids: List[str] = None,
233
- raw_completion: ChatCompletion = None,
234
- _new_record: Dict[str, any] = None,
231
+ result_chain: MessageChain | None = None,
232
+ tools_call_args: List[Dict[str, Any]] | None = None,
233
+ tools_call_name: List[str] | None = None,
234
+ tools_call_ids: List[str] | None = None,
235
+ raw_completion: ChatCompletion | None = None,
236
+ _new_record: Dict[str, Any] | None = None,
235
237
  is_chunk: bool = False,
236
238
  ):
237
239
  """初始化 LLMResponse
@@ -15,7 +15,7 @@ from astrbot import logger
15
15
  from astrbot.api.provider import Provider
16
16
  from astrbot.core.message.message_event_result import MessageChain
17
17
  from astrbot.core.provider.entities import LLMResponse
18
- from astrbot.core.provider.func_tool_manager import FuncCall
18
+ from astrbot.core.provider.func_tool_manager import ToolSet
19
19
  from astrbot.core.utils.io import download_image_by_url
20
20
 
21
21
  from ..register import register_provider_adapter
@@ -61,7 +61,7 @@ class ProviderGoogleGenAI(Provider):
61
61
  default_persona,
62
62
  )
63
63
  self.api_keys: list = provider_config.get("key", [])
64
- self.chosen_api_key: str = self.api_keys[0] if len(self.api_keys) > 0 else None
64
+ self.chosen_api_key: str = self.api_keys[0] if len(self.api_keys) > 0 else ""
65
65
  self.timeout: int = int(provider_config.get("timeout", 180))
66
66
 
67
67
  self.api_base: Optional[str] = provider_config.get("api_base", None)
@@ -96,6 +96,9 @@ class ProviderGoogleGenAI(Provider):
96
96
 
97
97
  async def _handle_api_error(self, e: APIError, keys: list[str]) -> bool:
98
98
  """处理API错误,返回是否需要重试"""
99
+ if e.message is None:
100
+ e.message = ""
101
+
99
102
  if e.code == 429 or "API key not valid" in e.message:
100
103
  keys.remove(self.chosen_api_key)
101
104
  if len(keys) > 0:
@@ -119,7 +122,7 @@ class ProviderGoogleGenAI(Provider):
119
122
  async def _prepare_query_config(
120
123
  self,
121
124
  payloads: dict,
122
- tools: Optional[FuncCall] = None,
125
+ tools: Optional[ToolSet] = None,
123
126
  system_instruction: Optional[str] = None,
124
127
  modalities: Optional[list[str]] = None,
125
128
  temperature: float = 0.7,
@@ -321,11 +324,15 @@ class ProviderGoogleGenAI(Provider):
321
324
 
322
325
  @staticmethod
323
326
  def _process_content_parts(
324
- result: types.GenerateContentResponse, llm_response: LLMResponse
327
+ candidate: types.Candidate, llm_response: LLMResponse
325
328
  ) -> MessageChain:
326
329
  """处理内容部分并构建消息链"""
327
- finish_reason = result.candidates[0].finish_reason
328
- result_parts: Optional[types.Part] = result.candidates[0].content.parts
330
+ if not candidate.content:
331
+ logger.warning(f"收到的 candidate.content 为空: {candidate}")
332
+ raise Exception("API 返回的 candidate.content 为空。")
333
+
334
+ finish_reason = candidate.finish_reason
335
+ result_parts: list[types.Part] | None = candidate.content.parts
329
336
 
330
337
  if finish_reason == types.FinishReason.SAFETY:
331
338
  raise Exception("模型生成内容未通过 Gemini 平台的安全检查")
@@ -343,22 +350,28 @@ class ProviderGoogleGenAI(Provider):
343
350
  raise Exception("模型生成内容违反 Gemini 平台政策")
344
351
 
345
352
  if not result_parts:
346
- logger.debug(result.candidates)
347
- raise Exception("API 返回的内容为空。")
353
+ logger.warning(f"收到的 candidate.content.parts 为空: {candidate}")
354
+ raise Exception("API 返回的 candidate.content.parts 为空。")
348
355
 
349
356
  chain = []
350
357
  part: types.Part
351
358
 
352
359
  # 暂时这样Fallback
353
360
  if all(
354
- part.inline_data and part.inline_data.mime_type.startswith("image/")
361
+ part.inline_data
362
+ and part.inline_data.mime_type
363
+ and part.inline_data.mime_type.startswith("image/")
355
364
  for part in result_parts
356
365
  ):
357
366
  chain.append(Comp.Plain("这是图片"))
358
367
  for part in result_parts:
359
368
  if part.text:
360
369
  chain.append(Comp.Plain(part.text))
361
- elif part.function_call:
370
+ elif (
371
+ part.function_call
372
+ and part.function_call.name is not None
373
+ and part.function_call.args is not None
374
+ ):
362
375
  llm_response.role = "tool"
363
376
  llm_response.tools_call_name.append(part.function_call.name)
364
377
  llm_response.tools_call_args.append(part.function_call.args)
@@ -366,11 +379,16 @@ class ProviderGoogleGenAI(Provider):
366
379
  llm_response.tools_call_ids.append(
367
380
  part.function_call.id or part.function_call.name
368
381
  )
369
- elif part.inline_data and part.inline_data.mime_type.startswith("image/"):
382
+ elif (
383
+ part.inline_data
384
+ and part.inline_data.mime_type
385
+ and part.inline_data.mime_type.startswith("image/")
386
+ and part.inline_data.data
387
+ ):
370
388
  chain.append(Comp.Image.fromBytes(part.inline_data.data))
371
389
  return MessageChain(chain=chain)
372
390
 
373
- async def _query(self, payloads: dict, tools: FuncCall) -> LLMResponse:
391
+ async def _query(self, payloads: dict, tools: ToolSet | None) -> LLMResponse:
374
392
  """非流式请求 Gemini API"""
375
393
  system_instruction = next(
376
394
  (msg["content"] for msg in payloads["messages"] if msg["role"] == "system"),
@@ -396,6 +414,10 @@ class ProviderGoogleGenAI(Provider):
396
414
  config=config,
397
415
  )
398
416
 
417
+ if not result.candidates:
418
+ logger.error(f"请求失败, 返回的 candidates 为空: {result}")
419
+ raise Exception("请求失败, 返回的 candidates 为空。")
420
+
399
421
  if result.candidates[0].finish_reason == types.FinishReason.RECITATION:
400
422
  if temperature > 2:
401
423
  raise Exception("温度参数已超过最大值2,仍然发生recitation")
@@ -408,6 +430,8 @@ class ProviderGoogleGenAI(Provider):
408
430
  break
409
431
 
410
432
  except APIError as e:
433
+ if e.message is None:
434
+ e.message = ""
411
435
  if "Developer instruction is not enabled" in e.message:
412
436
  logger.warning(
413
437
  f"{self.get_model()} 不支持 system prompt,已自动去除(影响人格设置)"
@@ -432,11 +456,13 @@ class ProviderGoogleGenAI(Provider):
432
456
 
433
457
  llm_response = LLMResponse("assistant")
434
458
  llm_response.raw_completion = result
435
- llm_response.result_chain = self._process_content_parts(result, llm_response)
459
+ llm_response.result_chain = self._process_content_parts(
460
+ result.candidates[0], llm_response
461
+ )
436
462
  return llm_response
437
463
 
438
464
  async def _query_stream(
439
- self, payloads: dict, tools: FuncCall
465
+ self, payloads: dict, tools: ToolSet | None
440
466
  ) -> AsyncGenerator[LLMResponse, None]:
441
467
  """流式请求 Gemini API"""
442
468
  system_instruction = next(
@@ -459,6 +485,8 @@ class ProviderGoogleGenAI(Provider):
459
485
  )
460
486
  break
461
487
  except APIError as e:
488
+ if e.message is None:
489
+ e.message = ""
462
490
  if "Developer instruction is not enabled" in e.message:
463
491
  logger.warning(
464
492
  f"{self.get_model()} 不支持 system prompt,已自动去除(影响人格设置)"
@@ -478,13 +506,20 @@ class ProviderGoogleGenAI(Provider):
478
506
  async for chunk in result:
479
507
  llm_response = LLMResponse("assistant", is_chunk=True)
480
508
 
509
+ if not chunk.candidates:
510
+ logger.warning(f"收到的 chunk 中 candidates 为空: {chunk}")
511
+ continue
512
+ if not chunk.candidates[0].content:
513
+ logger.warning(f"收到的 chunk 中 content 为空: {chunk}")
514
+ continue
515
+
481
516
  if chunk.candidates[0].content.parts and any(
482
517
  part.function_call for part in chunk.candidates[0].content.parts
483
518
  ):
484
519
  llm_response = LLMResponse("assistant", is_chunk=False)
485
520
  llm_response.raw_completion = chunk
486
521
  llm_response.result_chain = self._process_content_parts(
487
- chunk, llm_response
522
+ chunk.candidates[0], llm_response
488
523
  )
489
524
  yield llm_response
490
525
  return
@@ -500,7 +535,7 @@ class ProviderGoogleGenAI(Provider):
500
535
  final_response = LLMResponse("assistant", is_chunk=False)
501
536
  final_response.raw_completion = chunk
502
537
  final_response.result_chain = self._process_content_parts(
503
- chunk, final_response
538
+ chunk.candidates[0], final_response
504
539
  )
505
540
  break
506
541
 
@@ -566,6 +601,8 @@ class ProviderGoogleGenAI(Provider):
566
601
  continue
567
602
  break
568
603
 
604
+ raise Exception("请求失败。")
605
+
569
606
  async def text_chat_stream(
570
607
  self,
571
608
  prompt,
@@ -621,7 +658,9 @@ class ProviderGoogleGenAI(Provider):
621
658
  return [
622
659
  m.name.replace("models/", "")
623
660
  for m in models
624
- if "generateContent" in m.supported_actions
661
+ if m.supported_actions
662
+ and "generateContent" in m.supported_actions
663
+ and m.name
625
664
  ]
626
665
  except APIError as e:
627
666
  raise Exception(f"获取模型列表失败: {e.message}")
@@ -636,7 +675,7 @@ class ProviderGoogleGenAI(Provider):
636
675
  self.chosen_api_key = key
637
676
  self._init_client()
638
677
 
639
- async def assemble_context(self, text: str, image_urls: list[str] = None):
678
+ async def assemble_context(self, text: str, image_urls: list[str] | None = None):
640
679
  """
641
680
  组装上下文。
642
681
  """
@@ -100,9 +100,9 @@ class ProviderOpenAIOfficial(Provider):
100
100
  del payloads[key]
101
101
 
102
102
  model = payloads.get("model", "")
103
- # 针对 qwen3 模型的特殊处理:非流式调用必须设置 enable_thinking=false
104
- if "qwen3" in model.lower():
105
- extra_body["enable_thinking"] = False
103
+ # 针对 qwen3 非 thinking 模型的特殊处理:非流式调用必须设置 enable_thinking=false
104
+ if "qwen3" in model.lower() and "thinking" not in model.lower():
105
+ extra_body["enable_thinking"] = False
106
106
  # 针对 deepseek 模型的特殊处理:deepseek-reasoner调用必须移除 tools ,否则将被切换至 deepseek-chat
107
107
  elif model == "deepseek-reasoner" and "tools" in payloads:
108
108
  del payloads["tools"]
astrbot/core/updator.py CHANGED
@@ -56,9 +56,7 @@ class AstrBotUpdator(RepoZipUpdator):
56
56
  try:
57
57
  if "astrbot" in os.path.basename(sys.argv[0]): # 兼容cli
58
58
  if os.name == "nt":
59
- args = [
60
- f'"{arg}"' if " " in arg else arg for arg in sys.argv[1:]
61
- ]
59
+ args = [f'"{arg}"' if " " in arg else arg for arg in sys.argv[1:]]
62
60
  else:
63
61
  args = sys.argv[1:]
64
62
  os.execl(sys.executable, py, "-m", "astrbot.cli.__main__", *args)
@@ -68,9 +66,13 @@ class AstrBotUpdator(RepoZipUpdator):
68
66
  logger.error(f"重启失败({py}, {e}),请尝试手动重启。")
69
67
  raise e
70
68
 
71
- async def check_update(self, url: str, current_version: str) -> ReleaseInfo:
69
+ async def check_update(
70
+ self, url: str, current_version: str, consider_prerelease: bool = True
71
+ ) -> ReleaseInfo:
72
72
  """检查更新"""
73
- return await super().check_update(self.ASTRBOT_RELEASE_API, VERSION)
73
+ return await super().check_update(
74
+ self.ASTRBOT_RELEASE_API, VERSION, consider_prerelease
75
+ )
74
76
 
75
77
  async def get_releases(self) -> list:
76
78
  return await self.fetch_release_info(self.ASTRBOT_RELEASE_API)
astrbot/core/utils/io.py CHANGED
@@ -227,7 +227,7 @@ async def download_dashboard(
227
227
  path = os.path.join(get_astrbot_data_path(), "dashboard.zip")
228
228
 
229
229
  if latest or len(str(version)) != 40:
230
- logger.info("准备下载最新发行版本的 AstrBot WebUI")
230
+ logger.info(f"准备下载 {version} 发行版本的 AstrBot WebUI 文件")
231
231
  ver_name = "latest" if latest else version
232
232
  dashboard_release_url = f"https://astrbot-registry.soulter.top/download/astrbot-dashboard/{ver_name}/dist.zip"
233
233
  try:
@@ -107,16 +107,38 @@ class RepoZipUpdator:
107
107
  """Semver 版本比较"""
108
108
  return VersionComparator.compare_version(v1, v2)
109
109
 
110
- async def check_update(self, url: str, current_version: str) -> ReleaseInfo | None:
110
+ async def check_update(
111
+ self, url: str, current_version: str, consider_prerelease: bool = True
112
+ ) -> ReleaseInfo | None:
111
113
  update_data = await self.fetch_release_info(url)
112
- tag_name = update_data[0]["tag_name"]
114
+
115
+ sel_release_data = None
116
+ if consider_prerelease:
117
+ tag_name = update_data[0]["tag_name"]
118
+ sel_release_data = update_data[0]
119
+ else:
120
+ for data in update_data:
121
+ # 跳过带有 alpha、beta 等预发布标签的版本
122
+ if re.search(
123
+ r"[\-_.]?(alpha|beta|rc|dev)[\-_.]?\d*$",
124
+ data["tag_name"],
125
+ re.IGNORECASE,
126
+ ):
127
+ continue
128
+ tag_name = data["tag_name"]
129
+ sel_release_data = data
130
+ break
131
+
132
+ if not sel_release_data or not tag_name:
133
+ logger.error("未找到合适的发布版本")
134
+ return None
113
135
 
114
136
  if self.compare_version(current_version, tag_name) >= 0:
115
137
  return None
116
138
  return ReleaseInfo(
117
139
  version=tag_name,
118
- published_at=update_data[0]["published_at"],
119
- body=update_data[0]["body"],
140
+ published_at=sel_release_data["published_at"],
141
+ body=f"{tag_name}\n\n{sel_release_data['body']}",
120
142
  )
121
143
 
122
144
  async def download_from_repo_url(self, target_path: str, repo_url: str, proxy=""):
@@ -18,6 +18,7 @@ from astrbot.core.provider.register import provider_registry
18
18
  from astrbot.core.star.star import star_registry
19
19
  from astrbot.core import logger, html_renderer
20
20
  from astrbot.core.provider import Provider
21
+ from astrbot.core.provider.provider import RerankProvider
21
22
  import asyncio
22
23
  from astrbot.core.utils.t2i.network_strategy import CUSTOM_T2I_TEMPLATE_PATH
23
24
 
@@ -481,6 +482,19 @@ class ConfigRoute(Route):
481
482
  )
482
483
  status_info["status"] = "unavailable"
483
484
  status_info["error"] = f"STT test failed: {str(e)}"
485
+ elif provider_capability_type == ProviderType.RERANK:
486
+ try:
487
+ assert isinstance(provider, RerankProvider)
488
+ await provider.rerank("Apple", documents=["apple", "banana"])
489
+ status_info["status"] = "available"
490
+ except Exception as e:
491
+ logger.error(
492
+ f"Error testing rerank provider {provider_name}: {e}",
493
+ exc_info=True,
494
+ )
495
+ status_info["status"] = "unavailable"
496
+ status_info["error"] = f"Rerank test failed: {str(e)}"
497
+
484
498
  else:
485
499
  logger.debug(
486
500
  f"Provider {provider_name} is not a Chat Completion or Embedding provider. Marking as available without test. Meta: {meta}"
@@ -57,7 +57,7 @@ class UpdateRoute(Route):
57
57
  .__dict__
58
58
  )
59
59
  else:
60
- ret = await self.astrbot_updator.check_update(None, None)
60
+ ret = await self.astrbot_updator.check_update(None, None, False)
61
61
  return Response(
62
62
  status="success",
63
63
  message=str(ret) if ret is not None else "已经是最新版本了。",
@@ -100,9 +100,7 @@ class UpdateRoute(Route):
100
100
  )
101
101
 
102
102
  try:
103
- await download_dashboard(
104
- latest=latest, version=version, proxy=proxy
105
- )
103
+ await download_dashboard(latest=latest, version=version, proxy=proxy)
106
104
  except Exception as e:
107
105
  logger.error(f"下载管理面板文件失败: {e}。")
108
106
 
@@ -133,7 +131,7 @@ class UpdateRoute(Route):
133
131
  async def update_dashboard(self):
134
132
  try:
135
133
  try:
136
- await download_dashboard()
134
+ await download_dashboard(version=f"v{VERSION}", latest=False)
137
135
  except Exception as e:
138
136
  logger.error(f"下载管理面板文件失败: {e}。")
139
137
  return Response().error(f"下载管理面板文件失败: {e}").__dict__
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AstrBot
3
- Version: 4.0.0b3
3
+ Version: 4.0.0b5
4
4
  Summary: 易上手的多平台 LLM 聊天机器人及开发框架
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.10
@@ -20,7 +20,7 @@ Requires-Dist: defusedxml>=0.7.1
20
20
  Requires-Dist: deprecated>=1.2.18
21
21
  Requires-Dist: dingtalk-stream>=0.22.1
22
22
  Requires-Dist: docstring-parser>=0.16
23
- Requires-Dist: faiss-cpu>=1.10.0
23
+ Requires-Dist: faiss-cpu==1.10.0
24
24
  Requires-Dist: filelock>=3.18.0
25
25
  Requires-Dist: google-genai>=1.14.0
26
26
  Requires-Dist: googlesearch-python>=1.3.0
@@ -16,12 +16,12 @@ astrbot/cli/commands/cmd_init.py,sha256=2fdhFlgOmqxQCorTyBmdxKY9_NfksV9MxnupUlre
16
16
  astrbot/cli/commands/cmd_plug.py,sha256=rs4ahzEeUPhLlggjxvfCXqmDWSYv66bI9bpO0NUu2oY,7381
17
17
  astrbot/cli/commands/cmd_run.py,sha256=myIZ4SSjwEOLNrv0fO2So-a3oe3jNL7T2sI8cZj-pfc,1972
18
18
  astrbot/cli/utils/__init__.py,sha256=EYu82Q-QKNhET-NjgdG0eqh8VY2uCc-EhPIkudhciaY,416
19
- astrbot/cli/utils/basic.py,sha256=r10dgm1o-PhWRThIojF-_PWVQQaN_KGH5-VW5ahvvxc,2433
19
+ astrbot/cli/utils/basic.py,sha256=Rxg0LdluIdwPIEbhk_1H6MzzEz2JbhP3d73SWcLfJqA,2751
20
20
  astrbot/cli/utils/plugin.py,sha256=Xr0xqEoZnC3zBHW1JDCFdpcFYqUJsqxnNY1ZZ4YbryA,8343
21
21
  astrbot/cli/utils/version_comparator.py,sha256=3gLFA94eswvFsBVDSJmOTLJKxTdCD9kkQFy2Lu7vcTc,3482
22
22
  astrbot/core/__init__.py,sha256=-1atHjMqQyequsw6A1heEr4LldE0JVII9MXcuQFSAQM,1218
23
23
  astrbot/core/astr_agent_context.py,sha256=4byUrIifQZFZwrDh0AtRLLBUvYX14tXhwiplShUNTt4,303
24
- astrbot/core/astrbot_config_mgr.py,sha256=d-VSfA3KllIjOGGZQ3v2vePevrA7vZyRFDvQyH9axW0,9753
24
+ astrbot/core/astrbot_config_mgr.py,sha256=Z1OwN1DKoZFdul9S8wWeRTiPjKnp0OiYQlmSloVw5nI,10024
25
25
  astrbot/core/conversation_mgr.py,sha256=R3kkMhHY7Qf8m74d-qXhUKvz_wTpa4id9-J8A21-YTI,11709
26
26
  astrbot/core/core_lifecycle.py,sha256=z8ivxD4OY5iBK8XO078OlmvSwnCtpTKtiuMF_AF1Adk,11588
27
27
  astrbot/core/event_bus.py,sha256=781lHFtnOfxBqS4CSxwTiPyoPvYOlbJce6arUGVfZEg,2536
@@ -30,8 +30,8 @@ astrbot/core/initial_loader.py,sha256=PYw4mdgZ3XPnxzUzYGhNGdlDZVL45ISy6hDI9RqpAB
30
30
  astrbot/core/log.py,sha256=wFCYVMMoyiMlGCI0PE8lYdJBd3SpxrkXjx1PvnlOEIU,8521
31
31
  astrbot/core/persona_mgr.py,sha256=iWvGsiHpky1fbPhmfQP1jDzHTWqv6g3GQ7ZROeOdaAc,7300
32
32
  astrbot/core/platform_message_history_mgr.py,sha256=qNd5No1HzaLKQ6XVFdJohaiwAB6cjJVXPSwgmxsUyAs,1514
33
- astrbot/core/updator.py,sha256=-1P57KNmoZVm6yYQkzvIckHgNtMgjjsvOMtYNHsSmkw,4543
34
- astrbot/core/zip_updator.py,sha256=VmifHQcpwnrsdxQsXMI7g8j07XzJGHhRT1E6XKleCX4,8067
33
+ astrbot/core/updator.py,sha256=voVD-08Jc-s7TBqiRboZk1DLlPQjcstr6LgPklIWlVk,4588
34
+ astrbot/core/zip_updator.py,sha256=iSwa3S2fHXGqYA3ie4SEMrWNy6fSDpW5toCygQFdKSQ,8828
35
35
  astrbot/core/agent/agent.py,sha256=uOriyVYpg1uDJj1yqcDix7Uj7k8mE5j9WbeX53ADk74,364
36
36
  astrbot/core/agent/handoff.py,sha256=_046TjTUda3CxtXR0ngb_z3f1XGTqx9pfhh28_Dl3Ts,1168
37
37
  astrbot/core/agent/hooks.py,sha256=AWCxG4pvq9uZ9D3yixhtsaqkIGTkYLAY7BsMxdfYC2Q,855
@@ -45,7 +45,7 @@ astrbot/core/agent/runners/base.py,sha256=exZS_d2BsrLz-xgeY9ZUPuXikBDUnKxO-dU3ZF
45
45
  astrbot/core/agent/runners/tool_loop_agent_runner.py,sha256=cuGBkpyyUEZaI4eo-UxAf199kEupicAo3IZMUwm6874,13976
46
46
  astrbot/core/config/__init__.py,sha256=0CO_3sKtI3WOwWT0k4i6TleWq1SAWJFfB8KjnYB8Zig,172
47
47
  astrbot/core/config/astrbot_config.py,sha256=X-b3c5m4msgJrdYFH2LXic5XKY0ViuUMdNZ335zqSBw,6335
48
- astrbot/core/config/default.py,sha256=D-jDl7avxY55mTNPW9XW-jzhmcq-RFHNE6CZIX8qiRM,112396
48
+ astrbot/core/config/default.py,sha256=ztYsHQaarCI_7HpNzOqNEx3O0qid1KlL25S7NCgiXzE,112728
49
49
  astrbot/core/db/__init__.py,sha256=CAtPQ7lfNSNE4hUylUBWks_49ah2amgYmw1V1lA9FwQ,8291
50
50
  astrbot/core/db/po.py,sha256=9MfQf4oEOYCUz7qnCjs4isWkGNpQKhaDVYqKIY8W-l0,7707
51
51
  astrbot/core/db/sqlite.py,sha256=F-t2NQr6p63VmuYG6LScFJtnXWNxVT5yWxnbHirJtCw,20138
@@ -73,7 +73,7 @@ astrbot/core/pipeline/content_safety_check/strategies/keywords.py,sha256=SiYIDjF
73
73
  astrbot/core/pipeline/content_safety_check/strategies/strategy.py,sha256=G32Xf42EgeyEnhyPLVYlUMiSnDNHUUnnz_MG0PXqfV4,1234
74
74
  astrbot/core/pipeline/preprocess_stage/stage.py,sha256=hHDUsSvOVlyzdWEQEk-P2oSNC0H4FmYI5WrdoP38Zbc,3329
75
75
  astrbot/core/pipeline/process_stage/stage.py,sha256=2hCX5LdUCzX2RbleMLF_Yqiot9YDyutF3ePPOZsWeA0,2677
76
- astrbot/core/pipeline/process_stage/method/llm_request.py,sha256=J90XLy_D76NsZqVV5w_I4gw_nfixLYkd67uBb4TJU7M,23748
76
+ astrbot/core/pipeline/process_stage/method/llm_request.py,sha256=CYDjQtTTDI05O06NPW-_TgD4mW4r1zKm4GwqH-EE49Y,23882
77
77
  astrbot/core/pipeline/process_stage/method/star_request.py,sha256=0KWbR0bnVXhMm0CgXnYD_OH3qjbUUvax1UmBWuGiLYU,2454
78
78
  astrbot/core/pipeline/rate_limit_check/stage.py,sha256=I_GkpSgioN0-T_catMwpRKtxx-TiMmvu8vV_FE5ORIA,4072
79
79
  astrbot/core/pipeline/respond/stage.py,sha256=uebafXVRXBr7dVwrREprNTGDxMMj8Rjo9-hPqc79WYQ,9975
@@ -90,7 +90,7 @@ astrbot/core/platform/message_type.py,sha256=uGn5KN8B_7b9F5nFTpvLAXRlXx2VFHP3JmJ
90
90
  astrbot/core/platform/platform.py,sha256=170_1Y1T5R-3nsu06y3i8Ote7zs8JASnskImp-IP04Q,1772
91
91
  astrbot/core/platform/platform_metadata.py,sha256=VRZSkV7u0OUoSxAXDu5EdEggrmcsbhk_7RUduTasoQo,488
92
92
  astrbot/core/platform/register.py,sha256=1cPxysZZ1ggfSPZfsv7Ll6qOVcTmLUw6vgaVRPjpxH8,1701
93
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py,sha256=5q6LvWZeMkClnGmzuD-rZm5LO1GYZiA6ccMubMsPVB0,7362
93
+ astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py,sha256=PN4h7TjH2UrQZX9bZmI6bGtmXgxHEx5GJREI-Vw0qX4,8036
94
94
  astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py,sha256=Bdwkk-BZ7653tx2cvhiBU0t2I0Za_iL9ozr1O-VKvxc,16141
95
95
  astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py,sha256=unEkE_KBwCLn9mOBs49WMUKqk8ddpaKN8MMyYep6rhg,8514
96
96
  astrbot/core/platform/sources/dingtalk/dingtalk_event.py,sha256=QcE0wUaB3hCSv4Cg3kApl5m0dfzkEyZTCjNbuHU52Ek,2721
@@ -124,7 +124,7 @@ astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py,s
124
124
  astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py,sha256=Mum478n1fELjOnVig-IFZqTb6sF7AUK1fSO2ThxYHrQ,7197
125
125
  astrbot/core/provider/__init__.py,sha256=fhD_KB1-KpqJ7woaXDXc7kdlmL3XPQz3xlc5IkFDJJ4,171
126
126
  astrbot/core/provider/entites.py,sha256=-353AdRDA6ST4AS48cQ1RRAXHSy3F7pVS_28hW4cG2U,388
127
- astrbot/core/provider/entities.py,sha256=X9Ma373oFkAGgKxuST5APEaMJ08mY6xbLG8kKKr9Mug,10714
127
+ astrbot/core/provider/entities.py,sha256=fTWfSdULPUfjODp1I7yGRHtD_n6ExAh6RXWDjE5ptCI,10937
128
128
  astrbot/core/provider/func_tool_manager.py,sha256=Qb6UrajD4Hkz5ZLmYCo3RJx8xTW5nFEmG-F_nzm9qXg,20819
129
129
  astrbot/core/provider/manager.py,sha256=hF6aBylf6TE5qnY4rXOrkviOAlwFpS7i3NjFp6cu6OE,20395
130
130
  astrbot/core/provider/provider.py,sha256=rzzlUTUn3cRCRgfd2PhA5RcboHkEDlk3Dw9Q1P3DoJ8,7203
@@ -137,13 +137,13 @@ astrbot/core/provider/sources/dify_source.py,sha256=Q0VmnacKwD-fOnvwYqbrRMspDYOl
137
137
  astrbot/core/provider/sources/edge_tts_source.py,sha256=foO2E0Wdc2wJy8yMbLUyX0cjkP6MD4vPCbc8q3Ckkug,4716
138
138
  astrbot/core/provider/sources/fishaudio_tts_api_source.py,sha256=1xN--JrZeqb2P7bDVVnGZi3hIQpLimYTkNwT8eCRRUQ,5439
139
139
  astrbot/core/provider/sources/gemini_embedding_source.py,sha256=FlVlacBLlxo4ZZgrBhurDQRuDYRGtR8Du35XuXEY9nI,2307
140
- astrbot/core/provider/sources/gemini_source.py,sha256=s8pQwE3_dwUIauXYPlYGj_9a1z6TsT_HC2naUcvvDeI,27189
140
+ astrbot/core/provider/sources/gemini_source.py,sha256=Gwn8nzMcsPsIVgDJ9G20tevUlYDyu_3g1_yaXsmvFPU,28649
141
141
  astrbot/core/provider/sources/gemini_tts_source.py,sha256=mNcb9G6Lb58L2zoSYzroQGyASGrv3k4ZjmOIVvhii_o,2886
142
142
  astrbot/core/provider/sources/gsv_selfhosted_source.py,sha256=7wSQ32AJv4cisjnedENfpThd1kHDqYvnMSCpwbpNNM4,5936
143
143
  astrbot/core/provider/sources/gsvi_tts_source.py,sha256=EoYuAf85NVcPPbyRWkE_doWF-7R8IM5o9ozxbbvaFRk,2025
144
144
  astrbot/core/provider/sources/minimax_tts_api_source.py,sha256=jNLP_4-UHq_Iekvjn3h7G6YZjTCGuII-hq-1RhzjSlE,5877
145
145
  astrbot/core/provider/sources/openai_embedding_source.py,sha256=IIz25EksuIWINKpLqfKG-9Qc4bJ398w24oMjoArXFUA,1669
146
- astrbot/core/provider/sources/openai_source.py,sha256=lmWHQ6x_81tkKNKvMu3F73IzxEenh-kpGP9GUtXKrt0,20679
146
+ astrbot/core/provider/sources/openai_source.py,sha256=5uFXPdoRv91oN3itUU7iTy12jhlqXhmCBCVbW3-PPGg,20727
147
147
  astrbot/core/provider/sources/openai_tts_api_source.py,sha256=ClRxEuBJ2-vM5rpMwwhOZXXJanq6asEAVPRvD9wYFrI,1626
148
148
  astrbot/core/provider/sources/sensevoice_selfhosted_source.py,sha256=2-NUDRiJJs3onxnrovdoVqUMI8bxGu2J2n3ZgwjxEm0,3828
149
149
  astrbot/core/provider/sources/vllm_rerank_source.py,sha256=lBgb7_nD51Z4JoFD6EBQpOs4w0Kd9f4m_rCx7-AeUBc,2075
@@ -176,7 +176,7 @@ astrbot/core/star/register/star_handler.py,sha256=a5iaYEtNJoTIBUAKCydib_vft_I1cr
176
176
  astrbot/core/utils/astrbot_path.py,sha256=ZK-OmCTOxH63GQ4kBMGZs9ybKmKuHMNXdW9RKqLbYRk,1227
177
177
  astrbot/core/utils/command_parser.py,sha256=ktdaw4kdvhfCHIGLTIX7AfMjT9CCL_iuJq1I-V9LEUA,603
178
178
  astrbot/core/utils/dify_api_client.py,sha256=RAKS3zjSl3nmhlNPCzN-byJZyZcwE6GR-8xZ9wzc-yE,5590
179
- astrbot/core/utils/io.py,sha256=Rzkae5TOU0MFItjgs1Ljkq9qOrkAsQpS_AmruYr2u6s,9607
179
+ astrbot/core/utils/io.py,sha256=5-5vtaAeP5YJsQpYqtu8RphS9NTKB8w-Kf5RkqBOcM0,9620
180
180
  astrbot/core/utils/log_pipe.py,sha256=AU-y7vvAUtegH3XRenJqsFpmH0UIV4zUfLWh-5uPkCI,883
181
181
  astrbot/core/utils/metrics.py,sha256=uFGS3ZU81vcUbhiIrc-VAy9t5Lc6Oxh13wGYcl3oVGY,2456
182
182
  astrbot/core/utils/path_util.py,sha256=_PKjMtQBGD_C7o5BzN4-NSsqCffPSr9NwiHQHTSehkM,3130
@@ -195,7 +195,7 @@ astrbot/dashboard/server.py,sha256=rjjHXo5J1qrHvoYi4MM9-YRbhunh1_ehdqwOrPGuz4U,8
195
195
  astrbot/dashboard/routes/__init__.py,sha256=Bn6_rbYtujttHKHEn8Smv2RiObhwWyH9TagW4HZSzGw,710
196
196
  astrbot/dashboard/routes/auth.py,sha256=igVjZWluaQpF-lrg-Ueb4IA553dA_Sn6pAxY34-83i8,2964
197
197
  astrbot/dashboard/routes/chat.py,sha256=oGnzzMUTJGnID6UPRWp9xtn6ObrZ_XwetPrVJ2aoI_E,11421
198
- astrbot/dashboard/routes/config.py,sha256=3U_Y10jErmczvYpfJAyI5WoWv6CH4AWvkS2DOzFobWc,32942
198
+ astrbot/dashboard/routes/config.py,sha256=0nh0fwMkE8dd1lhOhW7oZmZw3v9If8Q0NS5ftVnWY24,33588
199
199
  astrbot/dashboard/routes/conversation.py,sha256=9AopEmbxzRUcJ78fOlp5aFe9-7ptroaE5YrvAEuGBJQ,8886
200
200
  astrbot/dashboard/routes/file.py,sha256=y3yi4ari-ELwiDicuniBlvXhVe8d1JgWRl6FdC42v9k,706
201
201
  astrbot/dashboard/routes/log.py,sha256=uLQx-TCyg3j3etkEd0hVStFTE4S1C4Y8XEBsk0w7Gc8,1972
@@ -206,9 +206,9 @@ astrbot/dashboard/routes/session_management.py,sha256=h3b8DTDV99Dl0Gmbys7I2SlkC7
206
206
  astrbot/dashboard/routes/stat.py,sha256=KCtP0-f9g664gM2SOBgnU8uKx6zt93-5Kut-d7wd7zk,6910
207
207
  astrbot/dashboard/routes/static_file.py,sha256=7KnNcOb1BVqSTft114LhGsDkfg69X2jHEm0tOK0kW0Y,1169
208
208
  astrbot/dashboard/routes/tools.py,sha256=BWN0KYidJdY4zVVbLRaM5cSgDNrdJ7dlgFQI4WTqaUY,13990
209
- astrbot/dashboard/routes/update.py,sha256=8Qg9_oz3Z3FRzgRM7b2lT8LwbvORAmLV25NtmdbqnN8,6513
210
- astrbot-4.0.0b3.dist-info/METADATA,sha256=z6OsPddK8dXeTBo72q0nQ5lmiBz5mN4qdEirEhyzTwE,11363
211
- astrbot-4.0.0b3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
212
- astrbot-4.0.0b3.dist-info/entry_points.txt,sha256=OEF09YmhBWYuViXrvTLLpstF4ccmNwDL8r7nnFD0pfI,53
213
- astrbot-4.0.0b3.dist-info/licenses/LICENSE,sha256=zPfQj5Mq8-gThIiBcxETr7t8gND9bZWOjTGQAr80TQI,34500
214
- astrbot-4.0.0b3.dist-info/RECORD,,
209
+ astrbot/dashboard/routes/update.py,sha256=vhG6ET0GJNLTpfkKABYf3Aq5ChUCID1BvoZissWRBZg,6517
210
+ astrbot-4.0.0b5.dist-info/METADATA,sha256=HjDGJJkF_8KemNurR2M4_FyOTpQWdRcAXvTUKZ0T6wI,11363
211
+ astrbot-4.0.0b5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
212
+ astrbot-4.0.0b5.dist-info/entry_points.txt,sha256=OEF09YmhBWYuViXrvTLLpstF4ccmNwDL8r7nnFD0pfI,53
213
+ astrbot-4.0.0b5.dist-info/licenses/LICENSE,sha256=zPfQj5Mq8-gThIiBcxETr7t8gND9bZWOjTGQAr80TQI,34500
214
+ astrbot-4.0.0b5.dist-info/RECORD,,