mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 09:50:21 +08:00
Merge pull request #163 from AAEE86/master
fix: Antigravity 跨格式转换链 tool call ID 完整传递
This commit is contained in:
@@ -106,7 +106,8 @@ class ToolResultBlock:
|
|||||||
"""工具结果内容块"""
|
"""工具结果内容块"""
|
||||||
|
|
||||||
type: ContentType = field(default=ContentType.TOOL_RESULT, init=False)
|
type: ContentType = field(default=ContentType.TOOL_RESULT, init=False)
|
||||||
tool_use_id: str = "" # 对应的 ToolUseBlock.tool_id
|
tool_use_id: str = "" # 对应的 ToolUseBlock.tool_id(用于 Claude/Antigravity id 字段)
|
||||||
|
tool_name: str | None = None # 工具名称(用于 Gemini function_response.name 字段)
|
||||||
# 工具输出可能是纯文本,也可能是结构化 JSON(Gemini functionResponse 等)
|
# 工具输出可能是纯文本,也可能是结构化 JSON(Gemini functionResponse 等)
|
||||||
output: Any = None
|
output: Any = None
|
||||||
content_text: str | None = None
|
content_text: str | None = None
|
||||||
|
|||||||
@@ -480,14 +480,14 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
parts.append({"text": b.text})
|
parts.append({"text": b.text})
|
||||||
continue
|
continue
|
||||||
if isinstance(b, ToolUseBlock):
|
if isinstance(b, ToolUseBlock):
|
||||||
parts.append(
|
fc: dict[str, Any] = {
|
||||||
{
|
"name": b.tool_name,
|
||||||
"functionCall": {
|
"args": b.tool_input or {},
|
||||||
"name": b.tool_name,
|
}
|
||||||
"args": b.tool_input or {},
|
# 保留 tool_id 用于 Claude/Antigravity 兼容
|
||||||
}
|
if b.tool_id:
|
||||||
}
|
fc["id"] = b.tool_id
|
||||||
)
|
parts.append({"functionCall": fc})
|
||||||
continue
|
continue
|
||||||
if isinstance(b, ImageBlock):
|
if isinstance(b, ImageBlock):
|
||||||
if b.data and b.media_type:
|
if b.data and b.media_type:
|
||||||
@@ -672,6 +672,10 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
if not isinstance(args, dict):
|
if not isinstance(args, dict):
|
||||||
args = {}
|
args = {}
|
||||||
|
|
||||||
|
# 优先使用 Antigravity/Claude 注入的 id
|
||||||
|
fc_id = func_call.get("id")
|
||||||
|
tool_id = fc_id if isinstance(fc_id, str) and fc_id else None
|
||||||
|
|
||||||
block_index = int(ss.get("next_block_index") or 2)
|
block_index = int(ss.get("next_block_index") or 2)
|
||||||
ss["next_block_index"] = block_index + 1
|
ss["next_block_index"] = block_index + 1
|
||||||
|
|
||||||
@@ -679,7 +683,7 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
ContentBlockStartEvent(
|
ContentBlockStartEvent(
|
||||||
block_index=block_index,
|
block_index=block_index,
|
||||||
block_type=ContentType.TOOL_USE,
|
block_type=ContentType.TOOL_USE,
|
||||||
tool_id=None,
|
tool_id=tool_id,
|
||||||
tool_name=name or None,
|
tool_name=name or None,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -687,7 +691,7 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
events.append(
|
events.append(
|
||||||
ToolCallDeltaEvent(
|
ToolCallDeltaEvent(
|
||||||
block_index=block_index,
|
block_index=block_index,
|
||||||
tool_id="",
|
tool_id=tool_id or "",
|
||||||
input_delta=json.dumps(args, ensure_ascii=False),
|
input_delta=json.dumps(args, ensure_ascii=False),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -801,6 +805,7 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
tool_blocks[int(event.block_index)] = {
|
tool_blocks[int(event.block_index)] = {
|
||||||
"name": event.tool_name or "",
|
"name": event.tool_name or "",
|
||||||
"json": "",
|
"json": "",
|
||||||
|
"id": event.tool_id or "", # 保留 tool_id 用于 Claude/Antigravity 兼容
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -842,6 +847,7 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
|
|
||||||
name = str(entry.get("name") or "")
|
name = str(entry.get("name") or "")
|
||||||
raw_json = str(entry.get("json") or "")
|
raw_json = str(entry.get("json") or "")
|
||||||
|
tool_id = str(entry.get("id") or "")
|
||||||
args: dict[str, Any] = {}
|
args: dict[str, Any] = {}
|
||||||
if raw_json:
|
if raw_json:
|
||||||
try:
|
try:
|
||||||
@@ -851,7 +857,11 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
args = {}
|
args = {}
|
||||||
|
|
||||||
out.append(base_chunk([{"functionCall": {"name": name, "args": args}}]))
|
fc: dict[str, Any] = {"name": name, "args": args}
|
||||||
|
# 保留 tool_id 用于 Claude/Antigravity 兼容
|
||||||
|
if tool_id:
|
||||||
|
fc["id"] = tool_id
|
||||||
|
out.append(base_chunk([{"functionCall": fc}]))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
if isinstance(event, MessageStopEvent):
|
if isinstance(event, MessageStopEvent):
|
||||||
@@ -1286,9 +1296,15 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
args = func_call.get("args")
|
args = func_call.get("args")
|
||||||
if not isinstance(args, dict):
|
if not isinstance(args, dict):
|
||||||
args = {}
|
args = {}
|
||||||
|
# 优先使用 Antigravity/Claude 注入的 id,回退到生成的 id
|
||||||
|
fc_id = func_call.get("id")
|
||||||
|
if isinstance(fc_id, str) and fc_id:
|
||||||
|
tool_id = fc_id
|
||||||
|
else:
|
||||||
|
tool_id = f"toolu_{name}" if name else "toolu_0"
|
||||||
blocks.append(
|
blocks.append(
|
||||||
ToolUseBlock(
|
ToolUseBlock(
|
||||||
tool_id=f"toolu_{name}" if name else "toolu_0",
|
tool_id=tool_id,
|
||||||
tool_name=name,
|
tool_name=name,
|
||||||
tool_input=args,
|
tool_input=args,
|
||||||
extra={"gemini": part},
|
extra={"gemini": part},
|
||||||
@@ -1314,9 +1330,17 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
else:
|
else:
|
||||||
output = response
|
output = response
|
||||||
|
|
||||||
|
# 优先使用 Antigravity/Claude 注入的 id,回退到 name
|
||||||
|
fr_id = func_resp.get("id")
|
||||||
|
if isinstance(fr_id, str) and fr_id:
|
||||||
|
tool_use_id = fr_id
|
||||||
|
else:
|
||||||
|
tool_use_id = name
|
||||||
|
|
||||||
blocks.append(
|
blocks.append(
|
||||||
ToolResultBlock(
|
ToolResultBlock(
|
||||||
tool_use_id=name,
|
tool_use_id=tool_use_id,
|
||||||
|
tool_name=name or None, # 保留工具名称用于输出
|
||||||
output=output,
|
output=output,
|
||||||
content_text=content_text,
|
content_text=content_text,
|
||||||
is_error=False,
|
is_error=False,
|
||||||
@@ -1372,11 +1396,16 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(b, ToolUseBlock) and role == "model":
|
if isinstance(b, ToolUseBlock) and role == "model":
|
||||||
parts.append({"function_call": {"name": b.tool_name, "args": b.tool_input or {}}})
|
fc: dict[str, Any] = {"name": b.tool_name, "args": b.tool_input or {}}
|
||||||
|
# 保留 tool_id 用于 Claude/Antigravity 兼容
|
||||||
|
if b.tool_id:
|
||||||
|
fc["id"] = b.tool_id
|
||||||
|
parts.append({"function_call": fc})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(b, ToolResultBlock) and role == "user":
|
if isinstance(b, ToolResultBlock) and role == "user":
|
||||||
# 兼容旧转换器:name 直接使用 tool_use_id,response 固定包一层 result
|
# name 使用 tool_name(工具名称),id 使用 tool_use_id(call id)
|
||||||
|
# 如果没有 tool_name,回退到 tool_use_id 以保持向后兼容
|
||||||
value: Any
|
value: Any
|
||||||
if b.content_text is not None:
|
if b.content_text is not None:
|
||||||
value = b.content_text
|
value = b.content_text
|
||||||
@@ -1385,14 +1414,16 @@ class GeminiNormalizer(FormatNormalizer):
|
|||||||
else:
|
else:
|
||||||
value = b.output
|
value = b.output
|
||||||
|
|
||||||
parts.append(
|
# 优先使用 tool_name 作为 name,回退到 tool_use_id
|
||||||
{
|
name = b.tool_name if b.tool_name else b.tool_use_id
|
||||||
"function_response": {
|
fr: dict[str, Any] = {
|
||||||
"name": b.tool_use_id,
|
"name": name,
|
||||||
"response": {"result": value},
|
"response": {"result": value},
|
||||||
}
|
}
|
||||||
}
|
# 保留 tool_use_id 作为 id 用于 Claude/Antigravity 兼容
|
||||||
)
|
if b.tool_use_id:
|
||||||
|
fr["id"] = b.tool_use_id
|
||||||
|
parts.append({"function_response": fr})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return {"role": role, "parts": parts}
|
return {"role": role, "parts": parts}
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ MIN_SIGNATURE_LENGTH = 50 # 与 Antigravity-Manager 对齐
|
|||||||
# ============== Thinking Budget ==============
|
# ============== Thinking Budget ==============
|
||||||
THINKING_BUDGET_AUTO_CAP = 24576
|
THINKING_BUDGET_AUTO_CAP = 24576
|
||||||
THINKING_BUDGET_DEFAULT_INJECT = 24576 # 对齐 AM wrapper.rs (was 16000)
|
THINKING_BUDGET_DEFAULT_INJECT = 24576 # 对齐 AM wrapper.rs (was 16000)
|
||||||
|
# 给输出留的空间(对齐 Antigravity-Manager:普通模型 8192,图像模型 2048)
|
||||||
|
OUTPUT_OVERHEAD = 8192
|
||||||
|
OUTPUT_OVERHEAD_IMAGE = 2048
|
||||||
|
# 模型最大输出限制(防止超限)
|
||||||
|
MODEL_MAX_OUTPUT_LIMIT = 65536
|
||||||
# 包含这些关键字的模型会自动注入 thinkingConfig(如果缺失)
|
# 包含这些关键字的模型会自动注入 thinkingConfig(如果缺失)
|
||||||
THINKING_MODELS_AUTO_INJECT_KEYWORDS = ("thinking", "gemini-2.0-pro", "gemini-3-pro")
|
THINKING_MODELS_AUTO_INJECT_KEYWORDS = ("thinking", "gemini-2.0-pro", "gemini-3-pro")
|
||||||
|
|
||||||
@@ -191,7 +196,10 @@ __all__ = [
|
|||||||
"IMAGE_GEN_UPSTREAM_MODEL",
|
"IMAGE_GEN_UPSTREAM_MODEL",
|
||||||
"MIN_SIGNATURE_LENGTH",
|
"MIN_SIGNATURE_LENGTH",
|
||||||
"MODEL_ALIAS_MAP",
|
"MODEL_ALIAS_MAP",
|
||||||
|
"MODEL_MAX_OUTPUT_LIMIT",
|
||||||
"NETWORKING_TOOL_KEYWORDS",
|
"NETWORKING_TOOL_KEYWORDS",
|
||||||
|
"OUTPUT_OVERHEAD",
|
||||||
|
"OUTPUT_OVERHEAD_IMAGE",
|
||||||
"PROD_BASE_URL",
|
"PROD_BASE_URL",
|
||||||
"REQUEST_USER_AGENT",
|
"REQUEST_USER_AGENT",
|
||||||
"RETRY_429_BASE_SECONDS",
|
"RETRY_429_BASE_SECONDS",
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ from src.services.provider.adapters.antigravity.constants import (
|
|||||||
IMAGE_ASPECT_RATIO_SUFFIXES,
|
IMAGE_ASPECT_RATIO_SUFFIXES,
|
||||||
IMAGE_GEN_UPSTREAM_MODEL,
|
IMAGE_GEN_UPSTREAM_MODEL,
|
||||||
MODEL_ALIAS_MAP,
|
MODEL_ALIAS_MAP,
|
||||||
|
MODEL_MAX_OUTPUT_LIMIT,
|
||||||
NETWORKING_TOOL_KEYWORDS,
|
NETWORKING_TOOL_KEYWORDS,
|
||||||
|
OUTPUT_OVERHEAD,
|
||||||
|
OUTPUT_OVERHEAD_IMAGE,
|
||||||
)
|
)
|
||||||
from src.services.provider.adapters.antigravity.constants import (
|
from src.services.provider.adapters.antigravity.constants import (
|
||||||
REQUEST_USER_AGENT as ANTIGRAVITY_REQUEST_USER_AGENT,
|
REQUEST_USER_AGENT as ANTIGRAVITY_REQUEST_USER_AGENT,
|
||||||
@@ -139,6 +142,10 @@ def _inject_claude_tool_ids_request(inner_request: dict[str, Any], model: str) -
|
|||||||
|
|
||||||
Google v1internal 在目标模型为 Claude 时要求 functionCall 带有 id 字段,
|
Google v1internal 在目标模型为 Claude 时要求 functionCall 带有 id 字段,
|
||||||
但标准 Gemini 协议不包含此字段。对齐 AM wrapper.rs #1522。
|
但标准 Gemini 协议不包含此字段。对齐 AM wrapper.rs #1522。
|
||||||
|
|
||||||
|
算法:
|
||||||
|
1. 第一遍:扫描所有 functionCall,为没有 id 的生成 id,并记录 (name, id) 队列
|
||||||
|
2. 第二遍:扫描所有 functionResponse,从对应 name 的队列中取出 id 使用
|
||||||
"""
|
"""
|
||||||
if "claude" not in model.lower():
|
if "claude" not in model.lower():
|
||||||
return
|
return
|
||||||
@@ -147,6 +154,14 @@ def _inject_claude_tool_ids_request(inner_request: dict[str, Any], model: str) -
|
|||||||
if not isinstance(contents, list):
|
if not isinstance(contents, list):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 第一遍:收集所有 functionCall 的 ID(按 name 分组,保持顺序)
|
||||||
|
# name -> [id1, id2, ...] 每个调用的 ID 按出现顺序排列
|
||||||
|
call_ids_by_name: dict[str, list[str]] = {}
|
||||||
|
# 所有 call ID 按原始出现顺序(用于 fallback 匹配)
|
||||||
|
all_call_ids_ordered: list[str] = []
|
||||||
|
# 用于生成新 ID 的计数器(全局,确保唯一性)
|
||||||
|
name_counters: dict[str, int] = {}
|
||||||
|
|
||||||
for content in contents:
|
for content in contents:
|
||||||
if not isinstance(content, dict):
|
if not isinstance(content, dict):
|
||||||
continue
|
continue
|
||||||
@@ -154,41 +169,98 @@ def _inject_claude_tool_ids_request(inner_request: dict[str, Any], model: str) -
|
|||||||
if not isinstance(parts, list):
|
if not isinstance(parts, list):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 每条消息维护独立的计数器(确保 Call 和 Response 生成匹配的 ID)
|
for part in parts:
|
||||||
name_counters: dict[str, int] = {}
|
if not isinstance(part, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
fc = part.get("functionCall") or part.get("function_call")
|
||||||
|
if isinstance(fc, dict):
|
||||||
|
name = fc.get("name", "")
|
||||||
|
if not isinstance(name, str) or not name:
|
||||||
|
name = "unknown"
|
||||||
|
|
||||||
|
fc_id = fc.get("id")
|
||||||
|
if fc_id is None:
|
||||||
|
# 生成新 ID
|
||||||
|
count = name_counters.get(name, 0)
|
||||||
|
fc_id = f"call_{name}_{count}"
|
||||||
|
fc["id"] = fc_id
|
||||||
|
name_counters[name] = count + 1
|
||||||
|
|
||||||
|
# 记录这个 call 的 ID,供后续 response 使用
|
||||||
|
if name not in call_ids_by_name:
|
||||||
|
call_ids_by_name[name] = []
|
||||||
|
call_ids_by_name[name].append(fc_id)
|
||||||
|
# 同时按原始出现顺序记录(用于 fallback)
|
||||||
|
all_call_ids_ordered.append(fc_id)
|
||||||
|
|
||||||
|
# 第二遍:为 functionResponse 分配匹配的 ID
|
||||||
|
# 使用索引追踪每个 name 已消费到第几个 ID
|
||||||
|
response_index_by_name: dict[str, int] = {}
|
||||||
|
# 已使用的 call ID 集合
|
||||||
|
used_call_ids: set[str] = set()
|
||||||
|
# fallback 用的有序索引
|
||||||
|
fallback_index = 0
|
||||||
|
|
||||||
|
for content in contents:
|
||||||
|
if not isinstance(content, dict):
|
||||||
|
continue
|
||||||
|
parts = content.get("parts")
|
||||||
|
if not isinstance(parts, list):
|
||||||
|
continue
|
||||||
|
|
||||||
for part in parts:
|
for part in parts:
|
||||||
if not isinstance(part, dict):
|
if not isinstance(part, dict):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 1. functionCall(Assistant 请求调用工具)
|
fr = part.get("functionResponse") or part.get("function_response")
|
||||||
fc = part.get("functionCall")
|
|
||||||
if isinstance(fc, dict) and fc.get("id") is None:
|
|
||||||
name = fc.get("name", "unknown")
|
|
||||||
if not isinstance(name, str):
|
|
||||||
name = "unknown"
|
|
||||||
count = name_counters.get(name, 0)
|
|
||||||
fc["id"] = f"call_{name}_{count}"
|
|
||||||
name_counters[name] = count + 1
|
|
||||||
|
|
||||||
# 2. functionResponse(User 回复工具结果)
|
|
||||||
fr = part.get("functionResponse")
|
|
||||||
if isinstance(fr, dict) and fr.get("id") is None:
|
if isinstance(fr, dict) and fr.get("id") is None:
|
||||||
name = fr.get("name", "unknown")
|
name = fr.get("name", "")
|
||||||
if not isinstance(name, str):
|
if not isinstance(name, str) or not name:
|
||||||
name = "unknown"
|
name = "unknown"
|
||||||
count = name_counters.get(name, 0)
|
|
||||||
fr["id"] = f"call_{name}_{count}"
|
assigned_id: str | None = None
|
||||||
name_counters[name] = count + 1
|
|
||||||
|
# 优先:从对应 name 的 call ID 队列中取出下一个 ID
|
||||||
|
call_ids = call_ids_by_name.get(name, [])
|
||||||
|
idx = response_index_by_name.get(name, 0)
|
||||||
|
while idx < len(call_ids):
|
||||||
|
cid = call_ids[idx]
|
||||||
|
idx += 1
|
||||||
|
if cid not in used_call_ids:
|
||||||
|
assigned_id = cid
|
||||||
|
used_call_ids.add(cid)
|
||||||
|
break
|
||||||
|
response_index_by_name[name] = idx
|
||||||
|
|
||||||
|
# Fallback:如果 name 是 unknown(原本为空),尝试使用下一个未使用的 call ID(按原始出现顺序)
|
||||||
|
if assigned_id is None and name == "unknown":
|
||||||
|
while fallback_index < len(all_call_ids_ordered):
|
||||||
|
cid = all_call_ids_ordered[fallback_index]
|
||||||
|
fallback_index += 1
|
||||||
|
if cid not in used_call_ids:
|
||||||
|
assigned_id = cid
|
||||||
|
used_call_ids.add(cid)
|
||||||
|
break
|
||||||
|
|
||||||
|
if assigned_id is not None:
|
||||||
|
fr["id"] = assigned_id
|
||||||
|
else:
|
||||||
|
# 没有匹配的 call ID(异常情况),生成一个新 ID
|
||||||
|
count = name_counters.get(name, 0)
|
||||||
|
fr["id"] = f"call_{name}_{count}"
|
||||||
|
name_counters[name] = count + 1
|
||||||
|
|
||||||
|
|
||||||
def _process_thinking_budget(inner_request: dict[str, Any], model: str) -> None:
|
def _process_thinking_budget(inner_request: dict[str, Any], model: str) -> None:
|
||||||
"""处理 Thinking Budget:自动注入 + Auto Cap。
|
"""处理 Thinking Budget:自动注入 + Auto Cap + maxOutputTokens 约束。
|
||||||
|
|
||||||
对齐 AM wrapper.rs:
|
对齐 AM wrapper.rs + CLIProxyAPI 混合方案:
|
||||||
- 对 flash/pro/thinking 模型处理 thinkingConfig
|
- 对 flash/pro/thinking 模型处理 thinkingConfig
|
||||||
- 自动注入 thinkingConfig(对已知需要 thinking 的模型)
|
- 自动注入 thinkingConfig(对已知需要 thinking 的模型)
|
||||||
- Auto Cap:budget 超过 24576 时裁剪
|
- Auto Cap:budget 超过 24576 时裁剪
|
||||||
|
- Claude 要求:maxOutputTokens 必须 > thinkingBudget
|
||||||
|
- 优先增加 maxOutputTokens;超限时才减少 budget
|
||||||
"""
|
"""
|
||||||
lower_model = model.lower()
|
lower_model = model.lower()
|
||||||
if not any(kw in lower_model for kw in ("flash", "pro", "thinking")):
|
if not any(kw in lower_model for kw in ("flash", "pro", "thinking")):
|
||||||
@@ -214,8 +286,35 @@ def _process_thinking_budget(inner_request: dict[str, Any], model: str) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
budget = thinking_config.get("thinkingBudget")
|
budget = thinking_config.get("thinkingBudget")
|
||||||
if isinstance(budget, int) and budget > THINKING_BUDGET_AUTO_CAP:
|
if not isinstance(budget, int):
|
||||||
thinking_config["thinkingBudget"] = THINKING_BUDGET_AUTO_CAP
|
return
|
||||||
|
|
||||||
|
# 1. 限制 budget 上限
|
||||||
|
if budget > THINKING_BUDGET_AUTO_CAP:
|
||||||
|
budget = THINKING_BUDGET_AUTO_CAP
|
||||||
|
thinking_config["thinkingBudget"] = budget
|
||||||
|
|
||||||
|
# 2. 确保 maxOutputTokens > thinkingBudget
|
||||||
|
current_max = gen_config.get("maxOutputTokens")
|
||||||
|
|
||||||
|
# 根据模型类型选择增量(对齐 Antigravity-Manager)
|
||||||
|
overhead = OUTPUT_OVERHEAD_IMAGE if "-image" in lower_model else OUTPUT_OVERHEAD
|
||||||
|
|
||||||
|
# 计算理想的 maxOutputTokens
|
||||||
|
ideal_max = budget + overhead
|
||||||
|
|
||||||
|
# 3. 确保不超过模型限制
|
||||||
|
if ideal_max > MODEL_MAX_OUTPUT_LIMIT:
|
||||||
|
# 超限时:减少 budget 而不是超限(对齐 CLIProxyAPI 策略)
|
||||||
|
ideal_max = MODEL_MAX_OUTPUT_LIMIT
|
||||||
|
# 确保 budget < ideal_max,保留 overhead 空间给输出
|
||||||
|
max_budget = ideal_max - overhead
|
||||||
|
if budget > max_budget:
|
||||||
|
thinking_config["thinkingBudget"] = max_budget
|
||||||
|
|
||||||
|
# 4. 应用修正
|
||||||
|
if current_max is None or (isinstance(current_max, int) and current_max <= budget):
|
||||||
|
gen_config["maxOutputTokens"] = ideal_max
|
||||||
|
|
||||||
|
|
||||||
def _clean_tool_declarations(inner_request: dict[str, Any]) -> None:
|
def _clean_tool_declarations(inner_request: dict[str, Any]) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user