Skip to content

feat(autostockpile): 支持保留调度券并完善识别中止流程#1506

Merged
MistEO merged 10 commits intov2from
feature/auto-stockpile
Mar 23, 2026
Merged

feat(autostockpile): 支持保留调度券并完善识别中止流程#1506
MistEO merged 10 commits intov2from
feature/auto-stockpile

Conversation

@single-ptilopsis
Copy link
Copy Markdown
Contributor

@single-ptilopsis single-ptilopsis commented Mar 21, 2026

  • 为 AutoStockpile 增加调度券 OCR、保留调度券配置和数量上限计算,购买阶段可按余额、周日逻辑与防溢出额度动态限购或直接跳过。
  • 重构识别结果与中止原因契约,区分可跳过告警与致命错误,收紧价格阈值/购买配置校验,并修正周日判定的时区与日界线。
  • 同步更新 AutoStockpile 的 Pipeline、任务配置、模板资源和多语言文案,引入统一的 Skip 分支与新的用户提示文本。

Summary by Sourcery

为 AutoStockpile 的识别与选择流程新增存货账单预留(stock bill reserve)支持,并优化中止处理逻辑,同时相应更新流水线、配置和文档。

新功能:

  • 在 AutoStockpile 采购流程中引入存货账单 OCR,并基于预留余额进行数量上限控制。
  • 在 AutoStockpile 流程中加入结构化的中止原因,并统一路由到统一的跳过(skip)分支。

增强:

  • 优化周日检测逻辑,改为使用服务器本地的日期边界,并强化对阈值、选择配置以及识别出的物品层级的校验。
  • 重构识别结果的返回载荷,将其整理为更丰富的数据契约(data contract),由选择器消费,包括配额与余额等详细信息。

文档:

  • 扩展 AutoStockpile 维护文档(中英文),涵盖预留存货账单配置、阈值解析以及区域/层级(region/tier)设置流程。
Original summary in English

Summary by Sourcery

Add stock bill reserve support and refined abort handling to AutoStockpile recognition and selection flows, updating pipelines, configuration, and docs accordingly.

New Features:

  • Introduce stock bill OCR and reserve-balance aware quantity limiting in AutoStockpile purchases.
  • Add structured abort reasons and routing to a unified skip branch in the AutoStockpile flow.

Enhancements:

  • Refine Sunday detection to use server-local day boundaries and tighten validation of thresholds, selection configs, and recognized item tiers.
  • Restructure recognition result payloads into a richer data contract consumed by the selector, including quota and balance details.

Documentation:

  • Expand AutoStockpile maintenance docs in Chinese and English to cover reserve stock bill configuration, threshold resolution, and region/tier setup workflows.

@single-ptilopsis single-ptilopsis changed the title feat(autostockpile): 添加保留调度券功能 feat(autostockpile): 支持保留调度券并完善识别中止流程 Mar 23, 2026
@single-ptilopsis single-ptilopsis marked this pull request as ready for review March 23, 2026 13:16
Copilot AI review requested due to automatic review settings March 23, 2026 13:16
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出一些整体性的反馈:

  • SelectItemAction.Run 中,你再次调用了 resolveGoodsRegion,但识别阶段其实已经完成了区域解析;可以考虑将解析好的区域(以及可能的锚点)放进 RecognitionData 中,这样可以避免重复解析,也能防止在识别和选择之间锚点变化导致的不一致。
  • routeSkipWithAbortReasonstopTaskWithFocus 中使用带内联 HTML 的 fmt.Printf,与其他聚焦/日志流程(使用的是 maafocus 和结构化日志)不一致;建议将所有面向用户的通知集中到一个统一机制中,避免混用不同的输出渠道和格式。
  • resolveQuantityUpperBound 中,当 reserveStockBill <= 0 时,你返回 MaxBuy: 0CappedQuantity: quotaCurrent,这样会让 MaxBuy 作为上限的语义变得不清晰;你可能希望将 MaxBuy 设置为 quotaCurrent 或者一个有文档说明的哨兵值(例如 math.MaxInt32),以便下游的日志和“最大可购买数量”的推理保持一致。
给 AI Agent 的提示
请根据这次代码审查中的评论进行修改:

## 总体评论
-`SelectItemAction.Run` 中,你再次调用了 `resolveGoodsRegion`,但识别阶段其实已经完成了区域解析;可以考虑将解析好的区域(以及可能的锚点)放进 `RecognitionData` 中,这样可以避免重复解析,也能防止在识别和选择之间锚点变化导致的不一致。
-`routeSkipWithAbortReason``stopTaskWithFocus` 中使用带内联 HTML 的 `fmt.Printf`,与其他聚焦/日志流程(使用的是 `maafocus` 和结构化日志)不一致;建议将所有面向用户的通知集中到一个统一机制中,避免混用不同的输出渠道和格式。
-`resolveQuantityUpperBound` 中,当 `reserveStockBill <= 0` 时,你返回 `MaxBuy: 0``CappedQuantity: quotaCurrent`,这样会让 `MaxBuy` 作为上限的语义变得不清晰;你可能希望将 `MaxBuy` 设置为 `quotaCurrent` 或者一个有文档说明的哨兵值(例如 `math.MaxInt32`),以便下游的日志和“最大可购买数量”的推理保持一致。

Sourcery 对开源项目免费——如果你觉得我们的审查有帮助,欢迎分享 ✨
帮我变得更有用!请对每条评论点选 👍 或 👎,我会根据你的反馈改进今后的代码审查。
Original comment in English

Hey - I've left some high level feedback:

  • In SelectItemAction.Run you re-call resolveGoodsRegion even though the recognition phase has already resolved region; consider carrying the resolved region (and possibly anchor) in RecognitionData to avoid duplicate resolution and potential inconsistencies if the anchor changes between recognition and selection.
  • The use of fmt.Printf with inline HTML in routeSkipWithAbortReason and stopTaskWithFocus is inconsistent with the rest of the focus/logging flow (which uses maafocus and structured logs); consider centralizing user-facing notifications through a single mechanism to avoid mixing output channels and formats.
  • In resolveQuantityUpperBound, when reserveStockBill <= 0 you return MaxBuy: 0 and CappedQuantity: quotaCurrent, which makes MaxBuy misleading as an upper bound; you may want to set MaxBuy to quotaCurrent or a documented sentinel (e.g., math.MaxInt32) so downstream logging and reasoning about max purchasable quantity remain consistent.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `SelectItemAction.Run` you re-call `resolveGoodsRegion` even though the recognition phase has already resolved region; consider carrying the resolved region (and possibly anchor) in `RecognitionData` to avoid duplicate resolution and potential inconsistencies if the anchor changes between recognition and selection.
- The use of `fmt.Printf` with inline HTML in `routeSkipWithAbortReason` and `stopTaskWithFocus` is inconsistent with the rest of the focus/logging flow (which uses `maafocus` and structured logs); consider centralizing user-facing notifications through a single mechanism to avoid mixing output channels and formats.
- In `resolveQuantityUpperBound`, when `reserveStockBill <= 0` you return `MaxBuy: 0` and `CappedQuantity: quotaCurrent`, which makes `MaxBuy` misleading as an upper bound; you may want to set `MaxBuy` to `quotaCurrent` or a documented sentinel (e.g., `math.MaxInt32`) so downstream logging and reasoning about max purchasable quantity remain consistent.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

本 PR 为 AutoStockpile 增加“保留调度券”能力,并将识别/中止结果契约重构为“可跳过告警 vs 致命错误”,配套更新 Pipeline、任务选项与多语言文案,以实现更清晰可控的跳过/停止行为。

Changes:

  • 新增调度券 OCR(Helper 节点 + Go 侧解析/限购上限计算),并在任务配置中加入按地区的“保留调度券”开关与数量输入。
  • 重构识别结果结构与中止原因(AbortReason),在识别与选择阶段统一走 Skip 分支或致命停止分支。
  • 更新 AutoStockpile Pipeline(统一 Skip 节点、替换模板图资源)、维护文档与 locales 文案。

Reviewed changes

Copilot reviewed 22 out of 24 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
docs/zh_cn/developers/auto-stockpile-maintain.md 更新维护指南:阈值解析、保留调度券说明、地区/档位自检清单等
docs/en_us/developers/auto-stockpile-maintain.md 同步英文维护指南,补充阈值与保留调度券说明
assets/tasks/AutoStockpile.json 增加按地区保留调度券选项;收紧价格阈值输入校验
assets/resource/pipeline/AutoStockpile/Task.json 更新模板图引用;用统一的 AutoStockpileSkip 取代旧兜底节点;加入 dev 跳过节点
assets/resource/pipeline/AutoStockpile/Main.json 调整 SubTask custom_action_param 配置(移除 continue)
assets/resource/pipeline/AutoStockpile/Helper.json 移除溢出 ColorMatch 节点;新增调度券 OCR 节点 AutoStockpileGetStockBill
assets/resource/image/AutoStockpile/StockRedistributionKettle.png 新增/替换模板图资源
assets/resource/image/AutoStockpile/RegionalDevelopmentFunctionLocked.png 新增/替换模板图资源
assets/misc/locales/zh_tw.json 增加保留调度券相关文案
assets/misc/locales/zh_cn.json 增加保留调度券相关文案
assets/misc/locales/ko_kr.json 增加保留调度券相关文案
assets/misc/locales/ja_jp.json 增加保留调度券相关文案
assets/misc/locales/en_us.json 增加保留调度券相关文案
agent/go-service/autostockpile/types.go 引入 AbortReason 契约、RecognitionResult/Data 拆分、阈值严格解析错误类型等
agent/go-service/autostockpile/thresholds.go 阈值覆盖解析改为严格正数解析
agent/go-service/autostockpile/stockbill.go 新增调度券 OCR 解析与“可购买数量上限”计算
agent/go-service/autostockpile/server_time.go 引入服务器时区与 04:00 日界线的周日判定
agent/go-service/autostockpile/selector.go 统一 Skip 分支路由;按 AbortReason 决定跳过/停止;加入数量决策与更丰富日志
agent/go-service/autostockpile/register.go 注册阶段初始化 AbortReason 文案表
agent/go-service/autostockpile/recognition.go 识别阶段:地区解析失败致命;支持调度券 OCR;识别结果按新契约输出;新增档位合法性校验
agent/go-service/autostockpile/quantity.go 新增购买数量决策与对应 Pipeline override 生成
agent/go-service/autostockpile/options.go 选项解析返回 AbortReason;按地区提取 reserve_stock_bill 并换算“万”单位
agent/go-service/autostockpile/abort_reason.json 新增 AbortReason -> 文案映射(embedded)
agent/go-service/autostockpile/abort_reason.go 新增 embedded 文案表加载/校验与查询 API

- 移除不稳定的溢出颜色兜底分支
- 溢出详情缺失时仅记录告警
- 删除旧识别节点并新增调度券 OCR 节点
- 新增调度券 OCR、保留额度配置与多语言文案
- 额度不足或无可用购买额度时在识别阶段提前结束
- 根据剩余调度券自动限制购买数量并兼容防溢出/周日逻辑
- 区域、购买配置、阈值和商品档位异常改为致命错误并直接停任务
- 调度券与商品 OCR 不可用时提前跳过本轮购买
- 识别结果新增调度券可用性状态,并统一焦点提示与中止分支
- 将 NoCandidate 分支重命名为 Skip,并同步调整数量决策与 Pipeline 路由
- 对 OCR 异常和致命错误区分提示方式,识别阶段可直接跳过或停止任务
- 将价格阈值与保留调度券输入限制为非空正整数
- 补充阈值回退、保留调度券与运行时覆盖行为
- 更正新增档位与地区时的维护入口和默认值位置
- 同步收敛中英文文档结构与常见坑说明
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 24 changed files in this pull request and generated 5 comments.

Comment on lines +32 to +40
val, err := strconv.ParseFloat(match[1], 64)
if err != nil {
continue
}
beforeSlash := strings.SplitN(match[0], "/", 2)[0]
if strings.Contains(beforeSlash, "万") {
return int(val * 10000), true
}
return int(val), true
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseStockBillAmount 把 OCR 提取到的浮点数直接 int(val*10000)/int(val) 截断成整数,存在浮点精度导致的误差/截断问题(例如 0.6 万可能因为二进制表示被截成 5999)。建议改为使用 math.Round(或在可能的情况下直接按字符串/整数解析)并同时考虑上限校验,避免异常大值导致溢出。

Copilot uses AI. Check for mistakes.
// 使用 parsePriceLimitValue 解析 int 或 string 格式
parsedValue, err := parsePriceLimitValue(rawValue)
if err != nil {
return 0, true, fmt.Errorf("%s: %w", key, err)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collectRegionReserveStockBillreserve_stock_bill_{Region} 的解析错误目前会走 SelectionConfigInvalidFatal(因为这里没有包一层 thresholdConfigError),导致用户看到的中止原因与“阈值配置无效”不一致。建议这里复用 parsePositiveThresholdValue/newThresholdConfigError 来包装错误,让上层能稳定映射到 AbortReasonThresholdConfigInvalidFatal

Suggested change
return 0, true, fmt.Errorf("%s: %w", key, err)
return 0, true, newThresholdConfigError(key, err)

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +159
}

// 将用户输入("万"单位)转换为实际数值,乘以 10000
return parsedValue * 10000, true, nil
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里将用户输入值 parsedValue 直接乘以 10000(万单位转换)存在 int 溢出风险:当输入过大时会发生回绕,导致后续比较/限购逻辑异常。建议在乘法前做上限检查(例如 parsedValue > math.MaxInt/10000 时返回错误或饱和到最大可表示值)。

Copilot uses AI. Check for mistakes.

overflowDetected := false
overflowAmount := 0
overflowCurrent := 0
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runOverflowDetailOCR 失败时,overflowCurrent 会保持默认值 0 并继续流程,最终写入 RecognitionData.Quota.Current=0。这会把“额度未知”伪装成“额度为 0”,在后续数量决策(尤其是启用保留调度券时的上限计算)中可能导致误判为不可购买/过度限购。建议显式携带“额度识别是否可用”的标记(或用 -1 之类的哨兵值)并在下游逻辑中按“未知”分支处理;或者在需要额度的场景下将其作为可跳过告警直接走 Skip。

Suggested change
overflowCurrent := 0
overflowCurrent := -1

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +62
if _, err := priceLimitTierIDFromAttachKey(key); err != nil {
return 0, err
}

var stringValue string
if err := json.Unmarshal(data, &stringValue); err == nil {
if strings.TrimSpace(stringValue) == "" {
return requireDefaultPriceLimitForTier(tierID)
}
}

threshold, err := parsePriceLimitValue(data)
if err != nil {
return 0, err
}

return normalizePriceLimitThreshold(tierID, threshold), nil
return parsePositiveThresholdValue(key, data)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parsePriceLimitOverrideValue 这里把完整 attach key 作为 parsePositiveThresholdValue 的 field 传入;而上游收集阈值时又会再用 key 做一次 fmt.Errorf("%s: %w", key, err) 包装,容易产生重复前缀(形如 price_limits_xxx: price_limits_xxx: ...)的错误文本。建议仅在一处添加字段前缀:要么这里传更短的 field(例如仅 tier/子字段名),要么保证调用方不再重复包一层 key。

Copilot uses AI. Check for mistakes.
@MistEO MistEO merged commit 9e07b68 into v2 Mar 23, 2026
22 checks passed
@MistEO MistEO deleted the feature/auto-stockpile branch March 23, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants