ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CLI-Anything × Slay the Spire 2:基于游戏内 Bridge Mod 的 HTTP 桥接式 Agent 化操控方案

CLI-Anything × Slay the Spire 2:基于游戏内 Bridge Mod 的 HTTP 桥接式 Agent 化操控方案 CLI-Anything × Slay the Spire 2基于游戏内 Bridge Mod 的 HTTP 桥接式 Agent 化操控方案【免费下载链接】CLI-AnythingCLI-Anything: Making ALL Software Agent-Native -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything本篇技术指南聚焦 CLI-Anything 仓库中slay_the_spire_ii子项目的核心设计文档 STS2.md完整解析它是如何通过游戏内.NET插件STS2_Bridge暴露本地 HTTP API让命令行工具乃至 AI Agent直接读写《Slay the Spire 2》实时游戏状态、下发各类游戏动作的。读完本文你将掌握该 harness 的架构分层、15 种决策状态Decision State的含义、从状态到动作的完整调用链以及可复制的实战命令序列。一、架构总览为什么不用 subprocess而用进程内 BridgeCLI-Anything 中的大多数 harness 都通过子进程包裹桌面应用。但《Slay the Spire 2》是运行在 Steam 上的原生实时游戏无法用普通 CLI 子进程方式包裹。因此该项目换了一条技术路线让一个名为STS2_Bridge的.NET模组Mod跑在游戏进程内部直接读取游戏的内部状态、执行游戏的动作 API并在本机暴露一个 HTTP 服务CLI 侧则通过该 HTTP 服务读写状态与下发动作。整体数据流如下摘自 STS2.md 的架构图┌────────────────────────────────────────────┐ │ Slay the Spire 2 (Steam) │ │ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ │ │ Combat │ │ Map │ │ Menu │ │ │ └─────┬────┘ └────┬─────┘ └────┬────┘ │ │ │ │ │ │ │ ┌─────┴─────────────┴─────────────┴─────┐ │ │ │ STS2_Bridge (.NET mod) │ │ │ │ Reads game state, executes actions │ │ │ └──────────────────┬────────────────────┘ │ │ │ │ │ http://localhost:15526 │ └─────────────────────┼──────────────────────┘ │ ┌─────────────┴────────────────┐ │ cli-anything-sts2 │ │ state · play-card · rest … │ └──────────────────────────────┘从源码结构看这套体系分为两大部分进程内桥接插件源码位于 slay_the_spire_ii/agent-harness/bridge/plugin/含BridgeMod.cs、BridgeMod.StateBuilder.cs、BridgeMod.Actions.cs、BridgeMod.Helpers.cs等.NET 9源文件构建产物安装包位于 slay_the_spire_ii/agent-harness/bridge/install/bridge_plugin/。CLI 适配层Python 实现位于 slay_the_spire_ii/agent-harness/cli_anything/slay_the_spire_ii/。这样设计的关键收益是低转换间隙桥接 Mod 直接接触游戏内部状态与动作 APICLI 只需把 HTTP 调用翻译成游戏指令不需要图像识别、窗口自动化这类脆弱且易碎的手段。二、CLI 策略HTTP 桥接 规范化状态CLI 与桥接 Mod 之间通过http://localhost:15526/api/v1/singleplayer通信CLI 从该端点读取规范化后的 JSON 状态也通过同一端点回传动作命令。2.1 核心领域模块DomainModuleKey OperationsStatecore/state_adapter.py将原始桥接 JSON 规范化为面向决策的状态Actionscore/action_adapter.py为每个游戏命令构造类型化动作载荷Backendutils/sts2_backend.py封装 GET/POST 桥接 API 的 HTTP 客户端Typescore/types.pyJsonDict类型别名、PlannedActiondataclass其中types.py中的PlannedAction是一个slotsTrue的 dataclass包含三个字段action动作名、payloadJsonDict载荷、reason决策理由。这个结构是为 AI Agent 预留的计划-执行接口Agent 先产出动作意图与理由再交给底层执行。2.2 15 种决策状态Decision States桥接层把所有游戏画面归一化为以下 15 种决策类型decision字段menu·combat_play·hand_select·map_select·game_over·combat_rewards·card_reward·event_choice·rest_site·shop·card_select·relic_select·treasure·overlay·unknown每种决策状态对应一组典型下一步命令。例如combat_play时用play-card/use-potion/end-turncard_reward时用pick-card-reward/skip-card-reward。完整的决策 → 命令路由表见 skills/SKILL.md。2.3 角色CharactersIRONCLAD · SILENT · DEFECT · NECROBINDER · REGENT启动新游戏时通过--character指定角色、--ascension指定进阶等级默认 0。三、后端实现低转换间隙的 HTTP 客户端STS2.md 强调桥接 Mod 能直接访问游戏内部状态与动作 API因此 CLI 到 HTTP 调用的翻译非常干净。唯一的运行前提是游戏必须正在运行、STS2_BridgeMod 已启用并监听localhost:15526。3.1 Sts2RawClientGET 状态 / POST 动作utils/sts2_backend.py 中Sts2RawClient的两个核心方法get_state(*, formatjson)向/api/v1/singleplayer?formatjson发起 GET返回解析后的 JSON 字典也支持formatmarkdown时返回文本。post_action(action, **payload)构造{**payload, action: action}的 JSON 体 POST 到/api/v1/singleplayer。注意若payload中重复传入action会抛ValueError避免动作名被覆盖。错误处理方面HTTP 错误与连接失败都会被包装为ApiError。特别地当游戏未运行或 Mod 未启用导致连接失败时错误信息会明确提示 Is the game running with the bridge mod enabled?方便排查。默认超时 10 秒可通过--timeout调整。3.2 桥接插件的原始 API 面桥接插件源码bridge/plugin/暴露两个互斥端点详见 bridge/plugin/docs/raw_api.mdGET/POST http://localhost:15526/api/v1/singleplayer—— 单机局GET/POST http://localhost:15526/api/v1/multiplayer—— 多人合作局与单机端点互斥混用返回 HTTP 409GET 请求的state_type字段与 CLI 侧的决策状态一一对应包括monster/elite/boss战斗中、hand_select战斗中的手牌选择提示如消耗/弃牌、combat_rewards战利品、card_reward卡牌奖励、map带完整 DAG 的地图导航、rest_site篝火、shop商店全库存、event事件/远古、card_select卡牌转换/升级/移除等、relic_select遗物选择、treasure宝箱房、overlay未处理覆盖层的兜底防止卡死、menu无进行中的对局。各状态还附带丰富细节战斗状态含玩家 HP、格挡、能量、星力Regent 专属、手牌含星力费用、抽牌/弃牌/消耗堆计数与内容、遗物、药水、敌方意图intent 的 title/label/description、实体关键词等地图状态含当前坐标、已访问路径、next_options下一层节点类型前瞻1 层 lookahead以及完整 DAG。安全注意这些端点专为本地使用设计没有任何鉴权或安全措施不应暴露到公网raw_api.md 原文档亦有此提醒。四、状态规范化器从原始 JSON 到决策状态core/state_adapter.py 的normalize_state()是状态管线的核心。它根据原始状态的state_type分发到各_normalize_*函数并为所有输出统一附带contextact/floor/ascension与run字段。各分支要点战斗类monster/elite/boss→decisioncombat_play输出回合round、当前回合turn、是否出牌阶段is_play_phase、能量/最大能量、手牌、敌人列表、抽牌/弃牌/消耗堆计数以及完整的player与battle原始副本。hand_select→ 战斗中的选择提示modesimple_select消耗/弃牌或upgrade_select战斗中升级、prompt提示文本、可选卡片、已选卡片、can_confirm确认按钮状态。card_reward→ 卡牌奖励候选卡cards、can_skip是否可跳过。combat_rewards→ 战后奖励items、can_proceed。map→ 地图choices取自next_options、current_position、visited、全部nodes、boss。event→ 事件event_name、event_id、描述body、options、in_dialogue是否处于对话阶段、is_ancient是否远古事件。rest_site→ 篝火选项options与can_proceed。shop→ 商店items会按category自动分组为cards/relics/potions/card_removal方便 Agent 直接读取买什么。card_select→screen_typetransform/upgrade/select/simple_select/choose、preview_showing、can_skip/can_confirm/can_cancel。relic_select→relics、can_skip。treasure→ 宝箱房遗物relics、can_proceed、message。game_over→screen_type、can_return_to_main_menu、can_continue、can_view_run、options。menu→ 主菜单screen、can_continue_game、can_start_new_game、can_abandon_game、可选characters、ascension。overlay→ 兜底原样透出overlay字典。其余未知类型→decisionunknown同时保留raw_state_type、message与完整raw原始状态确保未知画面不会导致 Agent 无法决策。单元测试 tests/test_core.py 对上述行为逐项验证例如战斗状态归一化后decisioncombat_play、商店状态按类别正确分组、菜单状态解析can_continue_game、未知状态保留原始载荷等。五、动作适配器24 个类型化动作工厂core/action_adapter.py 为每个游戏命令提供类型化工厂函数全部返回JsonDict载荷。核心动作包括动作名载荷示例说明play_card{action:play_card,card_index:0,target:jaw_worm_0}打出手牌target为敌方entity_id对AnyEnemy卡必需、对自我/全体卡可省略use_potion{action:use_potion,slot:0,target:...}使用药水按槽位索引end_turn{action:end_turn}结束回合choose_map_node{action:choose_map_node,index:0}选择地图节点索引取自next_optionschoose_event_option{action:choose_event_option,index:0}选择事件选项advance_dialogue{action:advance_dialogue}推进远古事件对话需重复调用直到in_dialoguefalsechoose_rest_option{action:choose_rest_option,index:0}篝火动作休息/锻造等shop_purchase{action:shop_purchase,index:0}购买商店物品要求有货且买得起claim_reward{action:claim_reward,index:0}领取战斗奖励金/药水/遗物立即领取卡牌进入card_reward阶段select_card_reward/skip_card_reward—选择/跳过卡牌奖励proceed{action:proceed}离开当前房间奖励、篝火、商店、宝箱房可用事件不可用需用事件选项中的 Proceed 项select_card/confirm_selection/cancel_selection—卡牌选择覆盖层三件套combat_select_card/combat_confirm_selection—战斗中的手牌选择如选择一张牌消耗与确认select_relic/skip_relic_selection—遗物选择Boss 遗物立即生效/ 跳过claim_treasure_relic—领取宝箱房已揭示的遗物continue_game/start_new_game/abandon_game/return_to_main_menu—主菜单/对局生命周期管理start_new_game携带character与ascension参数所有工厂通过from_name(name, **kwargs)统一分发未知动作名抛出ValueError(Unknown action name: ...)。测试 tests/test_core.py 验证了无target时play_card不输出 target 字段、start_new_game(REGENT, 12)正确保留角色与进阶参数、未知动作名被拒绝等行为。六、CLI 命令全量参考入口文件 slay_the_spire_ii_cli.py 基于 Click 实现包名cli-anything-sts2。不带子命令时默认进入交互式 REPLrepl子命令仍保留。6.1 状态检查CommandDescriptionstate打印带decision字段的规范化状态raw-state打印桥接插件的原始 JSON6.2 主菜单CommandDescriptioncontinue-game继续已保存的对局start-game --character IRONCLAD --ascension 0开新局abandon-game放弃当前存档return-to-main-menu从任意界面返回主菜单6.3 战斗CommandDescriptionplay-card index [--target enemy_id]按手牌索引出牌use-potion slot [--target enemy_id]按槽位用药水end-turn结束回合6.4 地图与房间流转CommandDescriptionchoose-map index选择地图节点proceed离开当前房间6.5 奖励CommandDescriptionclaim-reward index领取战斗奖励pick-card-reward index选择卡牌奖励skip-card-reward跳过卡牌奖励claim-treasure-relic index领取宝箱房遗物select-relic index选择遗物skip-relic-selection跳过遗物选择6.6 事件与篝火CommandDescriptionevent index选择事件选项advance-dialogue推进纯对话事件rest index篝火动作6.7 商店CommandDescriptionshop-buy index购买商店物品6.8 卡牌/遗物选择覆盖层CommandDescriptionselect-card index覆盖层中选卡confirm-selection确认当前选择cancel-selection取消当前选择combat-select-card index战斗覆盖层选卡combat-confirm-selection确认战斗选卡6.9 原始动作CommandDescriptionaction name --kv keyvalue按名称发送原始动作并附加keyvalue载荷--kv可多次使用值支持整数与布尔自动转换_coerce_value逻辑6.10 配置项OptionDefaultDescription--base-urlhttp://localhost:15526桥接 API 地址--timeout10.0HTTP 超时秒七、实战流程示例以下序列覆盖开新局 → 战斗 → 地图 → 事件 → 篝火的典型回合闭环命令来自 cli_anything/slay_the_spire_ii/README.md# 1. 开新局并确认状态 cli-anything-sts2 start-game --character IRONCLAD --ascension 0 cli-anything-sts2 state # 2. 战斗先读状态再出牌出牌后重新读状态最后结束回合 cli-anything-sts2 state # decisioncombat_play记录手牌与能量 cli-anything-sts2 play-card 0 --target jaw_worm_0 # 打第一张牌 cli-anything-sts2 state # 出牌后手牌索引与能量已变化必须重读 cli-anything-sts2 end-turn # 3. 地图与事件 cli-anything-sts2 choose-map 0 # 选择地图节点 cli-anything-sts2 event 1 # 选择事件选项 cli-anything-sts2 rest 0 # 篝火休息/锻造交互式 REPL 会话示例默认入口cli-anything-sts2 # slay_the_spire_ii [http://localhost:15526] ❯ state # slay_the_spire_ii [http://localhost:15526] ❯ play-card 0 --target jaw_worm_0 # slay_the_spire_ii [http://localhost:15526] ❯ end-turn # slay_the_spire_ii [http://localhost:15526] ❯ exit八、安装与运行前提安装 CLI在slay_the_spire_ii/agent-harness/下执行pip install -e .PyPI 包名为cli-anything-slay-the-spire-ii要求 Python 3.10。构建桥接 Mod在 bridge/plugin/ 下执行./build.sh需要.NET 9 SDK与本地 Steam 版《Slay the Spire 2》若自动探测游戏数据目录失败可显式传入游戏数据目录参数或设置STS2_GAME_DATA_DIR环境变量详见 bridge/plugin/README.md。安装 Mod 到游戏在 bridge/install/ 下执行./install_bridge.sh将STS2_Bridge.dll与STS2_Bridge.json复制到游戏mods/STS2_Bridge/目录。启动游戏并启用 Mod然后执行cli-anything-sts2 state若返回 JSON 即代表桥接成功。九、验证体系单元测试与端到端测试单元测试tests/test_core.py直接对normalize_state与action_adapter各函数做纯逻辑验证无需真实游戏。端到端子进程测试tests/test_full_e2e.py在测试内启动一个假的桥接 HTTP 服务器ThreadingHTTPServer验证cli-anything-sts2子进程的--help、raw-state、state、action --kv、continue-game等命令行为包括 HTTP 请求体是否与action_adapter生成的载荷一致。这证明了CLI 层与 HTTP 协议解耦、可离线测试的设计。十、给 AI Agent 的使用要点skills/SKILL.md 与 README 为 Agent 明确了操作纪律先读state任何决策前必须先拿到当前的decision字段据此路由下一步命令每个动作后重读状态战斗过程中手牌索引与能量实时变化陈旧索引会导致动作失败检查返回码0 表示成功非 0 表示错误解析 stdout 的 JSON所有命令输出均为标准 JSON善用raw-state排查当规范化状态异常时可直接查看桥接插件原始 JSON 定位问题。这套游戏内桥接 本地 HTTP 状态规范化 动作工厂的模式把一款原生 Steam 游戏变成了真正可被 Agent 编程操控的状态机也构成了 CLI-Anything 生态中让一切软件 Agent-Native理念的一个完整落地案例。【免费下载链接】CLI-AnythingCLI-Anything: Making ALL Software Agent-Native -- CLI-Hub: https://clianything.cc/项目地址: https://gitcode.com/GitHub_Trending/cl/CLI-Anything创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表