diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/tool/arguments.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/tool/arguments.rs index 7d05a2772..7381e3559 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/tool/arguments.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/tool/arguments.rs @@ -75,6 +75,13 @@ pub(crate) struct ToolPage { pub limit: usize, } +/// 分页 `offset` 的绝对上限。 +/// +/// `max_offset=None` 的列表工具也必须封顶:`offset` 直接来自模型/客户端,若不设界, +/// 调用方用 `offset + page.len()` 计算 `nextOffset` 时会溢出(debug 直接 panic,release +/// 静默回绕成一个错误的小偏移)。这个上限远高于任何真实列表长度,只用来挡住溢出。 +pub(crate) const MAX_PAGE_OFFSET: usize = 1_000_000; + /// 解析 `offset`/`limit`。分页规则在三个列表工具之间一致,只有默认值与上限不同。 /// /// 调用点必须保证 `default_limit <= max_limit`:否则省略 `limit` 的请求会拿一个本身就越界的 @@ -106,8 +113,12 @@ pub(crate) fn page( }) .transpose()? .unwrap_or(0); - if let Some(max) = max_offset.filter(|max| offset > *max) { - return Err(ToolPageRejection::OffsetTooLarge { got: offset, max }); + let effective_max = max_offset.unwrap_or(MAX_PAGE_OFFSET); + if offset > effective_max { + return Err(ToolPageRejection::OffsetTooLarge { + got: offset, + max: effective_max, + }); } let limit = arguments .get("limit")