从零开始:如何将 Reasonix CLI 集成到 HagiCode 系统中 从零开始如何将 Reasonix CLI 集成到 HagiCode 系统中本文分享了将 Reasonix CLI 作为一等 Agent Provider 集成到 HagiCode 系统的完整技术实践涵盖三层架构设计、关键技术决策和前后端实现细节。背景Reasonix CLI说起来也是个挺有意思的东西。它是一个基于 ACPAgent Communication Protocol的 AI 代码助手工具提供了强大的流式传输和会话管理能力。其实在 HagiCode.Libs 层我们已经把它的底层实现都搞定了只是这些组件还处在孤立的状态就像一个个漂亮的珍珠还没串成项链。用户无法通过 Hero 职业选择、会话执行链路或监控面板来使用它这多少有点可惜。我们面临的问题是如何将 Reasonix 提升为与 Codex、Hermes 等同等级的一等 Agent Provider实现完整的后端路由和前端展示这可不是简单地注册一个枚举值就能了事的而是需要构建从底层抽象到用户界面的完整链路。就像盖房子不能只打个地基就完事了总得把墙砌起来屋顶盖上去。这个集成的挑战在于Reasonix 作为一个本地 CLI 工具有自己的性格和脾气。比如它不需要连接字符串所有参数都是用户运行时配置它可能根本没有安装需要优雅降级处理它兼容 anthropic 系列模型但又有自己的 effort、budget 等 ACP 特有参数。这就像一个人有自己独特的处事方式不能硬来。经过仔细的架构设计和多轮讨论我们最终采用了一套清晰的三层架构方案将 Reasonix 成功集成到系统中。这套方案不仅解决了眼前的问题也为后续类似 CLI Provider 的集成提供了可复用的模式。其实很多事情就是这样一旦找到了正确的方法后面的路就好走多了。关于 HagiCode本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个开源的 AI 代码助手项目致力于为开发者提供强大的代码生成、重构和优化能力。在开发过程中我们遇到了各种各样的技术挑战将 Reasonix 集成为一等 Agent Provider 就是其中之一。如果你觉得本文分享的方案有价值说明我们的工程实践还不错那么 HagiCode 本身也值得关注一下。核心内容技术架构设计系统采用了清晰的三层架构来分离关注点每层都有明确的职责边界HagiCode.Libs 层这一层已经完成提供了 CLI provider 的抽象和具体实现。它定义了ICliProviderReasonixOptions接口实现了ReasonixProvider来处理 ACP 流式传输和会话管理同时支持 effort、budget、yolo、transcript 等参数。这一层的职责是提供稳定、可复用的底层能力不涉及任何业务逻辑。就像房子的地基虽然看不见但很重要。hagicode-core 层这是我们本次集成的重点。它负责将底层抽象桥接到系统的统一接口上。具体工作包括注册AIProviderType.ReasonixCli 12枚举值创建ReasonixCliProvider作为 thin adapter 桥接 Libs 层实现ReasonixGrain处理会话状态和执行流以及集成 Hero 系统进行参数映射和配置管理。这一层的核心是协调各组件构建完整的业务链路。就像房子的承重墙把各个部分连接起来。web 层负责向用户展示和收集配置。我们需要重新生成 OpenAPI 类型以支持新枚举值实现视觉类型映射让 Reasonix 有自己的图标和显示名称创建 CLI 参数配置表单让用户可以配置各个参数以及添加多语言支持。这一层的重点是用户体验和交互设计。就像房子的装修做得好不好直接影响住得舒不舒服。这样的分层设计让每一层都专注于自己的职责降低了系统的复杂度也便于后续维护和扩展。其实很多时候把事情分清楚反而会更简单。关键技术决策在实现过程中我们做了几个关键的技术决策这些决策对最终的架构和用户体验都有重要影响。决策一使用专用 Grain我们创建了独立的ReasonixGrain : IReasonixGrain, IExecutorStreamGrain而不是尝试复用某个共享的 Grain。这个决策遵循了系统现有的 11 个 provider 的既定模式。虽然看起来可能会有些代码重复但专用 Grain 让我们可以针对 Reasonix 的特性做精细化的控制比如它特有的会话绑定机制和 ACP 消息映射。我们还定义了一个空的响应 DTOReasonixResponse作为类型区分符虽然它不包含实际数据但在类型系统中起到了重要的作用。就像每个人都有自己的房间哪怕空着也是自己的空间。决策二不创建专用 Settings 类与某些需要连接字符串的 Provider 不同Reasonix 的所有配置都是用户运行时设置的不需要启动时验证。因此我们没有创建专用的 Settings 类而是将所有配置存储在AIProviderOptions.Providers[ReasonixCli].Settings字典中。这种模式与 Qoder、Kiro、Kimi 等其他本地 CLI Provider 保持一致简化了代码结构也避免了不必要的抽象层。支持的设置键包括effort、budgetUsd、transcriptPath、enableYolo、arguments、startupTimeoutMs、reasoning。有时候简单点反而更好。决策三Provider 策略健康监控Reasonix 是用户本地安装的 CLI可能根本没有安装或者不在系统 PATH 中。这种情况下我们不应该直接报错而是应该优雅地降级处理。我们使用了Provider策略通过CommandUtil.TryResolveExecutablePath来检查 CLI 是否可用。如果检查失败UI 会显示为不可用但不会影响系统的其他部分。这种设计让系统更加健壮也给用户清晰的反馈。毕竟谁也不会希望因为一个小问题整个系统都挂了。决策四经济系统分类在 HagiCode 系统中不同的 Provider 有不同的经济系统分类。我们决定让 Reasonix 默认使用claude经济系统分类因为 Reasonix 本身兼容 anthropic 系列模型。目前只有 Codex 和 Copilot 有专用的经济系统分类其他 Provider 都是复用现有的分类。这样既保持了系统的简洁性又能正确处理计费和成本统计。复用也是个智慧不需要什么都从头来。决策五模型兼容性Reasonix 通过--model标志支持多种模型特别是 anthropic 系列。我们在secondary-professions.index.json中添加了兼容性映射让用户可以在 Reasonix 中选择这些模型。这种设计既尊重了 Reasonix 的能力又保持了系统的一致性用户无需理解底层的区别就能顺畅地使用各种模型。用户也不容易还是让他们简单点好。后端实现细节后端实现分为几个关键部分每部分都有其独特的技术要点。枚举和类型注册首先我们需要在系统中注册新的 Provider 类型// AIProviderType.cspublicenumAIProviderType{// ... 其他 providerReasonixCli12,}// AIProviderTypeExtensions.csprivatestaticreadonlyDictionarystring,AIProviderType_typeMapnew(){// ... 其他映射[Reasonix]AIProviderType.ReasonixCli,[reasonix]AIProviderType.ReasonixCli,[reasonix-cli]AIProviderType.ReasonixCli,[ReasonixCli]AIProviderType.ReasonixCli,};这个枚举值需要与其他并发变更协调避免冲突。我们选择了 12 这个值因为它是下一个可用的编号。就像排队一样总得有个先后顺序。Thin Adapter 实现ReasonixCliProvider是连接 Libs 层和系统统一接口的关键组件publicsealedclassReasonixCliProvider:IAIProvider,IVersionedAIProvider,IAsyncDisposable{privatestaticreadonlyIReadOnlyListstringSupportedSettingKeys[effort,budgetUsd,transcriptPath,enableYolo,arguments,startupTimeoutMs,reasoning];privatereadonlyICliProviderReasonixOptions_provider;privatereadonlyConcurrentDictionarystring,string_sessionBindingsnew(StringComparer.Ordinal);publicasyncIAsyncEnumerableAIStreamingChunkStreamCoreAsync(AIRequestrequest,string?sessionIdnull,[EnumeratorCancellation]CancellationTokencancellationTokendefault){varoptionsBuildOptions(request,sessionId);awaitforeach(varmessagein_provider.StreamAsync(options,cancellationToken)){yieldreturnMapToStreamingChunk(message);}}privateReasonixOptionsBuildOptions(AIRequestrequest,string?sessionId){returnnewReasonixOptions{ExecutablePathGetExecutablePath(),WorkingDirectoryGetWorkingDirectory(),Model_config.Model,Effort_config.Settings.GetValueOrDefault(effort,medium),Budget_config.Settings.GetValueOrDefault(budgetUsd,10.0),Yolo_config.Settings.GetValueOrDefault(enableYolo,false),TranscriptPath_config.Settings.GetValueOrDefault(transcriptPath),Arguments_config.Settings.GetValueOrDefault(arguments,),StartupTimeoutGetStartupTimeout(),EnvironmentVariables_environmentVariables,CessionIdsessionId??GetCessionId()};}}这个 adapter 的关键职责是验证配置参数拒绝不支持的设置键维护会话绑定关系支持会话恢复将 ACP 消息映射到系统的统一格式使用ProviderErrorAutoRetryCoordinator实现自动重试就像一个翻译官把一种语言翻译成另一种语言还得保证意思准确无误。Orleans Grain 实现ReasonixGrain负责处理会话状态和执行流publicclassReasonixGrain:Grain,IReasonixGrain,IExecutorStreamGrain{privatereadonlyDictionarystring,ExecutorToolLifecycleStatus_toolLifecycleStatenew(StringComparer.Ordinal);publicIAsyncEnumerableReasonixResponseExecuteCommandStreamAsync(stringcommand,string?heroIdnull,CancellationTokentokendefault,string?executionMessageIdnull,string?systemMessagenull,Dictionarystring,string?requestSettingsnull){varrequestBuildRequest(command,isEdit:false,heroId,executionMessageId,systemMessage,requestSettings);returnSendAsync(request,heroId,token);}privateasyncIAsyncEnumerableReasonixResponseSendAsync(AIRequestrequest,string?heroId,[EnumeratorCancellation]CancellationTokentoken){_cancellationTokenSourcenewCancellationTokenSource();varlinkedTokenCancellationTokenSource.CreateLinkedTokenSource(token,_cancellationTokenSource.Token);varproviderawaitResolveReasonixProviderAsync(heroId);awaitforeach(varchunkinprovider.StreamAsync(request,linkedToken.Token)){varresponseBuildChunkResponse(chunk);yieldreturnresponse;}}privateasyncTaskIAIProviderResolveReasonixProviderAsync(string?heroId){// Hero 感知的配置回退逻辑varconfigawaitHeroProviderResolver.ResolveAsync(AIProviderType.ReasonixCli,heroId);return_aiProviderFactory.CreateProvider(AIProviderType.ReasonixCli,config);}}Grain 的核心功能包括使用[PersistentState(reasonix-interop)]维护会话状态实现 Hero 感知的配置回退逻辑追踪工具生命周期状态支持取消令牌链确保执行可以及时中断这就像一个管家把事情安排得井井有条。Hero 系统集成Hero 系统是 HagiCode 的职业配置系统我们需要将 Reasonix 集成到这个体系中// HeroAppService.cs// Family 推断AIProviderType.ReasonixClireasonix// 托管的 CLI 参数ManagedCliParameterKeysByProvider[AIProviderType.ReasonixCli][binary,effort,budgetUsd,transcriptPath,enableYolo,arguments,startupTimeoutMs];// 托管的模型参数ManagedModelParameterKeysByProvider[AIProviderType.ReasonixCli][model,reasoning];在职业目录配置文件main-professions.yaml中-Id:profession-reasonixName:ReasonixFamily:reasonixSummary:hero.professionCopy.primary.reasonix.summaryIcon:executor-avatar:ReasonixSourceLabel:hero.professionCopy.sources.aiProvidersReasonixCliProviderType:ReasonixCliSortOrder:130DefaultEnabled:trueDefaultParameters:binary:reasonixeffort:mediumenableYolo:falsestartupTimeoutMs:15000这样配置后用户就可以在 Hero 配置界面看到 Reasonix 选项并进行个性化设置。就像给一个人登记户口有了身份才能在这个社会里正常生活。前端实现细节前端实现主要负责用户交互和展示同样分为几个关键部分。类型生成和视觉映射首先需要重新生成 OpenAPI 类型npmrun generate:api:once这会生成包含REASONIX_CLI ReasonixCli的类型定义。然后在视觉映射中// executorTypeAdapter.tsexporttypeExecutorVisualTypeClaude|Codex|Copilot|Reasonix|...;exportconstresolveExecutorVisualTypeFromProviderType(providerType:PCode_Models_AIProviderType):ExecutorVisualType{switch(providerType){// ... 其他 casecasePCode_Models_AIProviderType.REASONIX_CLI:returnReasonix;}};这样 Reasonix 就有自己的视觉类型可以显示对应的图标和样式。就像每个人都有自己的身份证照片。配置表单实现在HeroCliEquipmentForm.tsx中我们为 Reasonix 添加了专门的配置表单casePCode_Models_AIProviderType.REASONIX_CLI:return(Form.Item namebinaryInput//Form.ItemForm.Item nameeffortSelectSelect.Option valuenoneNone/Select.OptionSelect.Option valuelowLow/Select.OptionSelect.Option valuemediumMedium/Select.OptionSelect.Option valuehighHigh/Select.Option/Select/Form.ItemForm.Item namebudgetUsdInputNumber//Form.ItemForm.Item nametranscriptPathInput//Form.ItemForm.Item nameenableYoloSwitch//Form.ItemForm.Item nameargumentsInput//Form.ItemForm.Item namestartupTimeoutMsInputNumber//Form.Item/);这个表单涵盖了所有 Reasonix 支持的参数用户可以根据自己的需求进行配置。就像给一个人量身定做衣服合身最重要。多语言支持为了让国际用户也能使用我们添加了多语言支持# locales/*/common/hero.ymlprofession:primary:reasonix:name:Reasonixsummary:基于 ACP 的 AI 代码助手parameters:effort:计算力投入budgetUsd:预算 (USD)transcriptPath:转录文件路径enableYolo:启用 YOLO 模式毕竟语言不通再好的东西也没法用。健康监控映射前端还需要展示 Reasonix 的健康状态// healthApi.tsexportconstMONITORING_CHANNEL_FALLBACKS{// ... 其他 providerreasonix:{displayName:Reasonix,icon:executor-avatar:Reasonix}};exportconstmapProviderTypeToMonitoringCliId(providerType:PCode_Models_AIProviderType):string{switch(providerType){// ... 其他 casecasePCode_Models_AIProviderType.REASONIX_CLI:returnreasonix;}};这样用户可以在监控面板中看到 Reasonix 的状态如果 CLI 未安装或不可用会得到清晰的提示。就像医生给病人检查有问题早发现早治疗。最佳实践和注意事项在实现过程中我们总结了一些最佳实践和需要注意的地方。参数验证ReasonixCliProvider 必须严格验证配置参数拒绝不支持的设置键publicvoidValidateConfigurationOverrides(Dictionarystring,string?overrides){foreach(varkeyinoverrides.Keys){if(!SupportedSettingKeys.Contains(key)){thrownewHeroProviderConfigurationException($Unsupported setting key {key} for Reasonix provider);}}}这样可以防止用户配置错误的参数避免运行时错误。就像守门员不能让不该进的东西混进来。会话绑定管理使用ConcurrentDictionary管理会话绑定支持会话恢复_sessionBindings[cessionId]sessionId;// 在后续请求中绑定已存在的会话if(_sessionBindings.TryGetValue(cessionId,outvarboundSessionId)){options.SessionIdboundSessionId;}这种设计让用户可以在中断后恢复之前的会话提供更好的体验。就像把一个故事记住下次还能继续讲。优雅降级处理前端应该检查 CLI 可用性并给出友好的提示constreasonixAvailableawaithealthApi.checkCliAvailable(reasonix);if(!reasonixAvailable){showMessage(Reasonix CLI 未安装请在系统 PATH 中配置);}不要让用户遇到莫名其妙的错误提前检查并给出明确的指导。毕竟谁也不愿意莫名其妙地被卡住。测试覆盖完善的测试是质量保证的关键[Fact]publicasyncTaskExecuteCommandStreamAsync_WithValidCommand_StreamsReasonixResponse(){// Arrangevargrain_grainFactory.GetGrainIReasonixGrain(test-cession);varresponsesnewListReasonixResponse();// Actawaitforeach(varresponseingrain.ExecuteCommandStreamAsync(help)){responses.Add(response);}// Assertresponses.Should().NotBeEmpty();responses.All(rr.KindExecutorResponseKind.Content).Should().BeTrue();}这样的单元测试可以验证核心功能是否正常工作防止回归错误。就像考试前做练习题总得确保自己真的掌握了。总结通过这次 Reasonix 的集成实践我们成功地将一个本地 CLI 工具提升为系统的一等 Agent Provider。整个过程中我们遵循了既定的架构模式做出了合理的技术决策最终实现了一个功能完整、用户体验良好的集成方案。这套方案的核心价值在于清晰的三层架构分离了关注点降低了复杂度专用 Grain 和 thin adapter 的设计保持了灵活性优雅降级和健康监控提升了用户体验完善的参数验证和会话管理保证了可靠性对于其他类似 CLI Provider 的集成这套方案提供了可复用的模式。我们希望这次实践能够帮助到其他开发者也欢迎大家到 HagiCode 项目中交流经验。其实很多事情都是这样一开始看着难但只要方法对了一步一步来总能解决的。就像登山看着山顶很远但只要不放弃总能爬上去。总结回到“从零开始如何将 Reasonix CLI 集成到 HagiCode 系统中”这个主题真正值得反复确认的不是零散技巧而是约束条件、实现边界和工程取舍是否已经看清。只要把文中的判断依据沉淀成稳定的检查项后续面对类似问题时就能更快做出可靠决策。原文与版权说明感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。本内容采用人工智能辅助协作,最终内容由作者审核并确认。本文作者: newbe36524原文链接: https://docs.hagicode.com/go?platformcsdntarget%2Fblog%2F2026-06-09-integrating-reasonix-cli-into-hagicode%2F版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!