-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix: anthropic chat provider query error #4212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - 我发现了 2 个问题,并给出了一些整体性的反馈:
- 硬编码的
max_tokens = 1024默认值有点像“魔法数字”;建议从配置或共享常量中派生这个值,这样就可以根据不同模型/提供方进行调整,而不是固定写死在代码里。 - 在校验
tool_calls时,isinstance(message["tool_calls"], list)会在值不是列表时静默忽略;如果这是用户输入,你可能需要把单个tool_call规范化为列表,或者至少进行日志记录/抛错,以便让无效结构更容易被发现。 - 把
text_chat_stream的默认值从...改为None会改变缺失参数的检测方式;请再次确认调用方或内部逻辑没有依赖Ellipsis作为区分“未设置”和“明确传入 None”的哨兵值。
用于 AI Agent 的提示词
请根据以下代码审查意见进行修改:
## 整体评论
- 硬编码的 `max_tokens = 1024` 默认值有点像“魔法数字”;建议从配置或共享常量中派生这个值,这样就可以根据不同模型/提供方进行调整,而不是固定写死在代码里。
- 在校验 `tool_calls` 时,`isinstance(message["tool_calls"], list)` 会在值不是列表时静默忽略;如果这是用户输入,你可能需要把单个 `tool_call` 规范化为列表,或者至少进行日志记录/抛错,以便让无效结构更容易被发现。
- 把 `text_chat_stream` 的默认值从 `...` 改为 `None` 会改变缺失参数的检测方式;请再次确认调用方或内部逻辑没有依赖 `Ellipsis` 作为区分“未设置”和“明确传入 None”的哨兵值。
## 单条评论
### 评论 1
<location> `astrbot/core/provider/sources/anthropic_source.py:71` </location>
<code_context>
if isinstance(message["content"], str):
blocks.append({"type": "text", "text": message["content"]})
- if "tool_calls" in message:
+ if "tool_calls" in message and isinstance(message["tool_calls"], list):
for tool_call in message["tool_calls"]:
blocks.append( # noqa: PERF401
</code_context>
<issue_to_address>
**issue (bug_risk):** 仅对 `tool_calls` 使用列表类型判断,可能会静默丢弃有效的可迭代值。
之前任何为真值的 `tool_calls` 可迭代对象都会被遍历;现在非列表的可迭代对象(例如元组、生成器)会被静默忽略。为避免这种行为变化悄然发生,建议要么通过 `message["tool_calls"] = list(message["tool_calls"])` 进行规范化,要么在 `tool_calls` 存在但不是列表时进行抛错/记录日志,让类型问题被暴露出来而不是被跳过。
</issue_to_address>
### 评论 2
<location> `astrbot/core/provider/sources/anthropic_source.py:135` </location>
<code_context>
extra_body = self.provider_config.get("custom_extra_body", {})
+ if "max_tokens" not in payloads:
+ payloads["max_tokens"] = 1024
+
</code_context>
<issue_to_address>
**suggestion:** 在两个地方硬编码 `max_tokens=1024` 可能缺乏灵活性,而且容易与配置或模型上限产生偏差。
现在只要调用方省略 `max_tokens`,就会使用这个默认值,这可能会相较于之前的行为截断响应长度,并且 `_query` 和 `_query_stream` 中都重复了这段逻辑。建议从 `provider_config` 或模型特定的映射中派生一个统一的默认值,并在两个位置复用它,这样更便于调整并与模型/部署的限制保持一致。
建议实现如下:
```python
extra_body = self.provider_config.get("custom_extra_body", {})
# 从 provider_config/model 限制中推导可配置的默认 max_tokens
default_max_tokens = self.provider_config.get("max_tokens", 1024)
if "max_tokens" not in payloads and default_max_tokens is not None:
payloads["max_tokens"] = default_max_tokens
completion = await self.client.messages.create(
```
在 `_query_stream` 方法(或等价的流式路径)中很可能存在类似的 `if "max_tokens" not in payloads:` 代码块。
在那里的替换方式也相同:去掉硬编码的 `1024`,改为计算 `default_max_tokens = self.provider_config.get("max_tokens", 1024)`,在 `payloads` 中缺少 `max_tokens` 时使用该值作为后备。
如果你有模型特定的上限,可以把 `self.provider_config.get("max_tokens", 1024)` 替换成基于模型的查找(例如通过 `self.model` 或部署名称),但保留相同的整体模式。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- The hardcoded
max_tokens = 1024default is a bit of a magic number; consider deriving it from configuration or a shared constant so it can be tuned per-model/provider rather than being fixed in code. - When validating
tool_calls,isinstance(message["tool_calls"], list)silently drops non-list values; if this is user input, you may want to normalize single tool_calls into a list or at least log/raise to make invalid shapes more visible. - Changing
text_chat_streamdefaults from...toNonealters how missing arguments are detected; double-check that callers or internal logic are not relying onEllipsisas a sentinel to distinguish between “unset” and “explicitly passed None.”
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The hardcoded `max_tokens = 1024` default is a bit of a magic number; consider deriving it from configuration or a shared constant so it can be tuned per-model/provider rather than being fixed in code.
- When validating `tool_calls`, `isinstance(message["tool_calls"], list)` silently drops non-list values; if this is user input, you may want to normalize single tool_calls into a list or at least log/raise to make invalid shapes more visible.
- Changing `text_chat_stream` defaults from `...` to `None` alters how missing arguments are detected; double-check that callers or internal logic are not relying on `Ellipsis` as a sentinel to distinguish between “unset” and “explicitly passed None.”
## Individual Comments
### Comment 1
<location> `astrbot/core/provider/sources/anthropic_source.py:71` </location>
<code_context>
if isinstance(message["content"], str):
blocks.append({"type": "text", "text": message["content"]})
- if "tool_calls" in message:
+ if "tool_calls" in message and isinstance(message["tool_calls"], list):
for tool_call in message["tool_calls"]:
blocks.append( # noqa: PERF401
</code_context>
<issue_to_address>
**issue (bug_risk):** Guarding on list type for `tool_calls` may silently drop valid iterable values.
Previously any truthy `tool_calls` iterable would be iterated; now non-list iterables (e.g., tuples, generators) are silently ignored. To avoid this behavior change going unnoticed, either normalize with `message["tool_calls"] = list(message["tool_calls"])` or raise/log when `tool_calls` is present but not a list so type issues are surfaced rather than skipped.
</issue_to_address>
### Comment 2
<location> `astrbot/core/provider/sources/anthropic_source.py:135` </location>
<code_context>
extra_body = self.provider_config.get("custom_extra_body", {})
+ if "max_tokens" not in payloads:
+ payloads["max_tokens"] = 1024
+
</code_context>
<issue_to_address>
**suggestion:** Hard-coded `max_tokens=1024` in two places may be inflexible and easy to drift from config or model limits.
This default now applies whenever callers omit `max_tokens`, which may truncate responses relative to prior behavior, and is duplicated in both `_query` and `_query_stream`. Consider deriving a single default from `provider_config` or a model-specific mapping and reusing it in both places so it’s easier to adjust and aligned with model/deployment limits.
Suggested implementation:
```python
extra_body = self.provider_config.get("custom_extra_body", {})
# Derive a configurable default max_tokens, aligned with provider_config/model limits
default_max_tokens = self.provider_config.get("max_tokens", 1024)
if "max_tokens" not in payloads and default_max_tokens is not None:
payloads["max_tokens"] = default_max_tokens
completion = await self.client.messages.create(
```
There is likely a similar `if "max_tokens" not in payloads:` block in the `_query_stream` method (or equivalent streaming path).
Apply the same replacement there: remove the hard-coded `1024` and instead compute `default_max_tokens = self.provider_config.get("max_tokens", 1024)` and use that as the fallback when `max_tokens` is absent from `payloads`.
If you have model-specific limits, you can substitute `self.provider_config.get("max_tokens", 1024)` with a model-aware lookup (e.g., from `self.model` or deployment name) while keeping the same pattern.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if isinstance(message["content"], str): | ||
| blocks.append({"type": "text", "text": message["content"]}) | ||
| if "tool_calls" in message: | ||
| if "tool_calls" in message and isinstance(message["tool_calls"], list): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): 仅对 tool_calls 使用列表类型判断,可能会静默丢弃有效的可迭代值。
之前任何为真值的 tool_calls 可迭代对象都会被遍历;现在非列表的可迭代对象(例如元组、生成器)会被静默忽略。为避免这种行为变化悄然发生,建议要么通过 message["tool_calls"] = list(message["tool_calls"]) 进行规范化,要么在 tool_calls 存在但不是列表时进行抛错/记录日志,让类型问题被暴露出来而不是被跳过。
Original comment in English
issue (bug_risk): Guarding on list type for tool_calls may silently drop valid iterable values.
Previously any truthy tool_calls iterable would be iterated; now non-list iterables (e.g., tuples, generators) are silently ignored. To avoid this behavior change going unnoticed, either normalize with message["tool_calls"] = list(message["tool_calls"]) or raise/log when tool_calls is present but not a list so type issues are surfaced rather than skipped.
Modifications / 改动点
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
通过验证工具调用数据并始终提供
max_tokens值,确保 Anthropic 提供方的请求更加健壮。Bug Fixes:
tool_calls为列表时才进行迭代,避免在构建 Anthropic 负载时出现错误。max_tokens时,将其默认设置为1024,防止 Anthropic 的非流式和流式请求遗漏max_tokens。text_chat_stream参数的默认值设置,使得在没有prompt、图片 URL 或上下文的调用情况下也能更安全地处理。Original summary in English
Summary by Sourcery
Ensure Anthropic provider requests are robust by validating tool call data and always supplying a max_tokens value.
Bug Fixes: