Skip to content

feat: PiCLI 支持 PI v2.5 协议#1227

Merged
MistEO merged 3 commits intomainfrom
feat/picli
Mar 26, 2026
Merged

feat: PiCLI 支持 PI v2.5 协议#1227
MistEO merged 3 commits intomainfrom
feat/picli

Conversation

@MistEO
Copy link
Copy Markdown
Member

@MistEO MistEO commented Mar 25, 2026

Summary by Sourcery

在 MaaPiCli 中增加对更新版本 ProjectInterface 协议的支持,包括全局/资源/控制器级选项、复选框和分组选项、预设,以及为代理提供的 PI_* 环境变量。

新功能:

  • 在 CLI 中支持全局、资源和控制器级选项,并按定义的优先级将这些选项传递到运行时任务配置中。
  • 引入复选框类型选项以及多选输入处理,覆盖接口解析、配置与运行时生成的完整流程。
  • 添加任务分组以及在 CLI 中的分组任务展示,并新增预设定义,用于应用预定义的任务集合和选项。
  • 通过环境变量将 PI_* 元数据(接口版本、客户端信息、控制器/资源描述符)暴露给代理子进程。
  • 扩展接口与配置模式(schema),支持控制器/资源作用域选项、任务分组、预设,以及额外的选项字段。

增强:

  • 改进 CLI 配置打印,展示所有层级的选项值,并在存在分组元数据时以分组方式渲染任务。
  • 在 CLI 交互和运行时生成时,根据适用的控制器/资源过滤选项,以避免无效选项被应用。
  • 根据已解析接口校验并清理配置中的选项列表,移除未知选项。
  • 重构 Configurator,将选项适用性检查与运行时任务的选项覆盖合并逻辑集中处理。
  • 在新的 README 中记录 MaaPiCli 的功能以及对 PI 协议的支持级别,包括已知的 CLI 限制。
Original summary in English

Summary by Sourcery

Add support in MaaPiCli for newer ProjectInterface protocol versions, including global/resource/controller options, checkbox and grouped options, presets, and PI_* environment variables for agents.

New Features:

  • Support global, resource, and controller level options in the CLI and propagate them into runtime task configuration with defined precedence.
  • Introduce checkbox-type options and multi-select input handling across interface parsing, configuration, and runtime generation.
  • Add task grouping and grouped task display in the CLI, along with preset definitions that can apply predefined task sets and options.
  • Expose PI_* metadata (interface version, client info, controller/resource descriptors) to agent subprocesses via environment variables.
  • Extend interface and configuration schemas with controller/resource-scoped options, task groups, presets, and additional option fields.

Enhancements:

  • Improve CLI configuration printing to show option values for all levels and render tasks grouped when group metadata is present.
  • Filter options by applicable controller/resource both when interacting in the CLI and when generating runtime to avoid invalid option application.
  • Validate and clean configuration option lists against the parsed interface, removing unknown options.
  • Refactor Configurator to centralize option applicability checks and option override merging for runtime tasks.
  • Document MaaPiCli capabilities and PI protocol support levels, including known CLI limitations, in a new README.

Copilot AI review requested due to automatic review settings March 25, 2026 08:33
@MistEO MistEO requested review from Windsland52 and neko-para March 25, 2026 08:34
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.

嗨——我已经审阅了你的改动,一切看起来都很棒!


Sourcery 对开源项目是免费的——如果你喜欢我们的评审,请考虑分享给他人 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English

Hey - I've reviewed your changes and they look great!


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 为 MaaPiCli(ProjectInterface CLI Client)补齐对 PI v2.5.0 的协议支持,涵盖 v2.3.0~v2.5.0 的多项新增字段与行为(多级 option、checkbox、preset、group、以及 Agent 子进程 PI_* 环境变量)。

Changes:

  • 扩展 PI 数据结构:新增 controller/resource 级 option、task.group、option.checkbox/default_case 变体、preset/group/global_option 等字段,并同步扩展配置结构以支持多级 option 与 checkbox 值。
  • CLI 交互增强:展示/编辑全局、资源、控制器级 options;支持按 group 展示任务;新增 preset 一键应用;支持 checkbox 选项交互。
  • 运行时增强:生成并传递 PI_* 环境变量给 Agent 子进程;解析 import 时合并 preset;合并 option override 按优先级生效。

Reviewed changes

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

Show a summary per file
File Description
source/include/ProjectInterface/Types.h 扩展 PI/配置/运行时参数结构以支持 v2.3~v2.5 新字段(checkbox、group、preset、多级 option、env_vars 等)
source/include/ProjectInterface/Configurator.h 新增 option 适用性判断与多级 option 合并的私有辅助函数声明
source/MaaPiCli/README.md 新增 MaaPiCli 说明与 PI 支持版本/CLI 局限文档
source/MaaPiCli/Impl/Runner.cpp 启动 Agent 子进程时注入 PI_* 环境变量
source/MaaPiCli/Impl/Parser.cpp import 合并 preset;配置校验中增加多级 option 列表的清理与 checkbox 校验
source/MaaPiCli/Impl/Configurator.cpp 生成 PI_* env vars;按优先级合并 global/resource/controller/task 四级 option overrides;支持 checkbox overrides
source/MaaPiCli/CLI/interactor.h 增加 preset 应用与多级 option 处理接口声明
source/MaaPiCli/CLI/interactor.cpp CLI 展示/录入多级 option、checkbox;按 group 输出任务;支持 preset 应用
Comments suppressed due to low confidence (1)

source/MaaPiCli/CLI/interactor.cpp:1356

  • opt.default_case is now a variant<string, vector<string>>, but the Select branch treats any non-empty variant as “has default” and then only reads the string alternative. If default_case is (incorrectly) an array, has_default becomes true while config_opt.value stays empty, which skips prompting and produces an invalid config entry. Consider making “has default” conditional on get_if<string> and also fall back to interactive selection when the default string is empty or not found in opt.cases.
        auto has_default = std::visit([](const auto& v) { return !v.empty(); }, opt.default_case);
        if (has_default) {
            if (auto* str = std::get_if<std::string>(&opt.default_case)) {
                config_opt.value = *str;
            }
            auto case_iter = std::ranges::find(opt.cases, config_opt.value, std::mem_fn(&InterfaceData::Option::Case::name));
            if (case_iter != opt.cases.end()) {
                selected_case = &(*case_iter);
            }
        }

Comment on lines +1444 to +1448
auto has_default = std::visit([](const auto& v) { return !v.empty(); }, opt.default_case);
if (has_default) {
if (auto* vec = std::get_if<std::vector<std::string>>(&opt.default_case)) {
config_opt.values = *vec;
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Checkbox default handling has the same variant issue: has_default becomes true for a non-empty string default_case, but the code only reads the vector alternative, so it will skip prompting and leave config_opt.values empty. Consider treating a default as present only when the variant holds a non-empty vector<string> and otherwise falling back to prompting (or logging an error).

Suggested change
auto has_default = std::visit([](const auto& v) { return !v.empty(); }, opt.default_case);
if (has_default) {
if (auto* vec = std::get_if<std::vector<std::string>>(&opt.default_case)) {
config_opt.values = *vec;
}
if (auto* vec = std::get_if<std::vector<std::string>>(&opt.default_case); vec && !vec->empty()) {
config_opt.values = *vec;

Copilot uses AI. Check for mistakes.
for (int idx : indexes) {
config_opt.values.emplace_back(opt.cases[idx - 1].name);
}
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

For checkbox options, sub-options (case.option) are never processed: selected_case remains nullptr, so the nested sub-option recursion at the end of process_option() is skipped. Per PI spec, each selected checkbox case may have its own option list that should be applied; consider iterating over all selected cases (from defaults or user input) and calling process_option() for each case’s sub-options.

Suggested change
}
}
// Ensure that at least one selected checkbox case is available for
// sub-option processing later in process_option().
if (!config_opt.values.empty()) {
for (const auto& value : config_opt.values) {
auto it = std::find_if(
opt.cases.begin(), opt.cases.end(),
[&](const auto& case_item) {
return case_item.name == value;
});
if (it != opt.cases.end()) {
selected_case = &(*it);
break;
}
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +187
auto check_option_list = [&](std::vector<Configuration::Option>& opts) {
for (auto it = opts.begin(); it != opts.end();) {
if (!data.option.contains(it->name)) {
LogWarn << "Option not found in config, removing" << VAR(it->name);
it = opts.erase(it);
erased = true;
}
else {
++it;
}
}
};
check_option_list(config.global_option);
check_option_list(config.resource_option);
check_option_list(config.controller_option);

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Parser::check_configuration() now prunes unknown options from global_option/resource_option/controller_option, but it does not validate the option values against the option definition (e.g., select/switch value exists in cases, checkbox values all exist). This can leave an incompatible config that later silently does nothing at runtime. Consider reusing the same per-type validation logic as check_task() for these level-option lists (and prune invalid entries similarly).

Copilot uses AI. Check for mistakes.
auto check_option_list = [&](std::vector<Configuration::Option>& opts) {
for (auto it = opts.begin(); it != opts.end();) {
if (!data.option.contains(it->name)) {
LogWarn << "Option not found in config, removing" << VAR(it->name);
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Log message wording is misleading: here you’re checking whether the option exists in the interface data (data.option.contains(...)), but the message says "Option not found in config". Consider changing it to something like "Option not found in interface, removing from config" to reflect what happened.

Suggested change
LogWarn << "Option not found in config, removing" << VAR(it->name);
LogWarn << "Option not found in interface, removing from config" << VAR(it->name);

Copilot uses AI. Check for mistakes.
@MistEO MistEO merged commit 2a56c42 into main Mar 26, 2026
24 of 25 checks passed
@MistEO MistEO deleted the feat/picli branch March 26, 2026 08:04
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.

2 participants