HagiCode.Libs.Providers
0.3.3-dev.117.1
See the version list below for details.
dotnet add package HagiCode.Libs.Providers --version 0.3.3-dev.117.1
NuGet\Install-Package HagiCode.Libs.Providers -Version 0.3.3-dev.117.1
<PackageReference Include="HagiCode.Libs.Providers" Version="0.3.3-dev.117.1" />
<PackageVersion Include="HagiCode.Libs.Providers" Version="0.3.3-dev.117.1" />
<PackageReference Include="HagiCode.Libs.Providers" />
paket add HagiCode.Libs.Providers --version 0.3.3-dev.117.1
#r "nuget: HagiCode.Libs.Providers, 0.3.3-dev.117.1"
#:package HagiCode.Libs.Providers@0.3.3-dev.117.1
#addin nuget:?package=HagiCode.Libs.Providers&version=0.3.3-dev.117.1&prerelease
#tool nuget:?package=HagiCode.Libs.Providers&version=0.3.3-dev.117.1&prerelease
HagiCode.Libs.Providers
HagiCode.Libs.Providers builds on HagiCode.Libs.Core and adds reusable provider abstractions plus built-in integrations for Claude Code, Copilot, Codex, DeepAgents, CodeBuddy, Gemini, Junie, Hermes, Dsh, Kimi, Kiro, OpenCode, Pi, OMP, QoderCLI, and Reasonix.
What is included
- The
ICliProviderandICliProvider<TOptions>contracts for provider-oriented integrations - Built-in provider implementations for the supported HagiCode CLI backends
AddHagiCodeLibs()for dependency injection registration- A provider registry for resolving providers by name or alias
- Registration of the shared
ICliExecutionFacadefor provider-side probes or adapters - Registration of the shared
CliProviderPoolCoordinator, Hermes pool defaults, and ACP/runtime reuse backends - Single-attempt provider primitives that preserve native thread or session context for upstream retry orchestration
Install
dotnet add package HagiCode.Libs.Providers
If your application uses dependency injection, also reference Microsoft.Extensions.DependencyInjection.
Dependency injection entry point
using HagiCode.Libs.Core.Execution;
using HagiCode.Libs.Providers;
using HagiCode.Libs.Providers.Codebuddy;
using HagiCode.Libs.Providers.Copilot;
using HagiCode.Libs.Providers.Codex;
using HagiCode.Libs.Providers.DeepAgents;
using HagiCode.Libs.Providers.Dsh;
using HagiCode.Libs.Providers.Gemini;
using HagiCode.Libs.Providers.Junie;
using HagiCode.Libs.Providers.Hermes;
using HagiCode.Libs.Providers.Kimi;
using HagiCode.Libs.Providers.Kiro;
using HagiCode.Libs.Providers.OpenCode;
using HagiCode.Libs.Providers.Omp;
using HagiCode.Libs.Providers.Pi;
using HagiCode.Libs.Providers.Reasonix;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddHagiCodeLibs();
await using var serviceProvider = services.BuildServiceProvider();
var executionFacade = serviceProvider.GetRequiredService<ICliExecutionFacade>();
var codebuddy = serviceProvider.GetRequiredService<ICliProvider<CodebuddyOptions>>();
var copilot = serviceProvider.GetRequiredService<ICliProvider<CopilotOptions>>();
var codex = serviceProvider.GetRequiredService<ICodexProvider>();
var deepAgents = serviceProvider.GetRequiredService<ICliProvider<DeepAgentsOptions>>();
var dsh = serviceProvider.GetRequiredService<ICliProvider<DshOptions>>();
var gemini = serviceProvider.GetRequiredService<ICliProvider<GeminiOptions>>();
var junie = serviceProvider.GetRequiredService<ICliProvider<JunieOptions>>();
var hermes = serviceProvider.GetRequiredService<ICliProvider<HermesOptions>>();
var kimi = serviceProvider.GetRequiredService<ICliProvider<KimiOptions>>();
var kiro = serviceProvider.GetRequiredService<ICliProvider<KiroOptions>>();
var openCode = serviceProvider.GetRequiredService<ICliProvider<OpenCodeOptions>>();
var pi = serviceProvider.GetRequiredService<ICliProvider<PiOptions>>();
var omp = serviceProvider.GetRequiredService<ICliProvider<OmpOptions>>();
var reasonix = serviceProvider.GetRequiredService<ICliProvider<ReasonixOptions>>();
The same DI graph also exposes the shared pool services for Hermes diagnostics or explicit cleanup:
using HagiCode.Libs.Providers.Pooling;
var poolCoordinator = serviceProvider.GetRequiredService<CliProviderPoolCoordinator>();
var poolDefaults = serviceProvider.GetRequiredService<CliProviderPoolConfigurationRegistry>();
Shared adapter parity
Claude Code、CodeBuddy、Hermes 现在与 hagicode-core 的对应 provider 薄适配层共享同一套 libs-backed 实现。重点是:
Claude Code继续保留 raw stream / resume 语义,但ClaudeCodeProvider现在固定按次启动并回收本地 CLI 进程,不再做 warm transport reuseClaudeCodeOptions.UserInputHandler(默认null,此时行为不变)让代理在运行中向用户提问:设置后 provider 会给 CLI 追加--permission-prompt-tool stdio,CLI 因此注册AskUserQuestion并把权限询问以control_request发给宿主。AskUserQuestion请求(ClaudeUserInputRequest)在后台任务里交给 handler,等待回答期间流不会被阻塞;handler 返回每个问题文本对应的选项 label 或自由文本,provider 写回control_response(allow+updatedInput= 原输入加answers,多选用逗号加空格拼成一个字符串)。handler 返回null、抛异常、超过QuestionTimeout(默认 30 分钟)都会以deny加说明回复,CLI 把该调用记入permission_denials,运行仍正常结束;调用方取消则尽力发送deny后以OperationCanceledException结束。提问挂起期间,PromptStartTimeout、SubagentBackgroundWorkTimeout与监视器截止时间加BackgroundWorkGracePeriod不会结束运行,问题解决后重新生效。其他can_use_tool请求不经过 handler,立即以固定文案deny,与 CLI 不批准该工具时的结果一致;CLI 对宿主control_response的回显会被丢弃。提问按工具名识别(CLI 2.1.159 不带requires_user_interaction,2.1.292 带)。交互请求同时以control_request流消息、按到达位置交给调用方(ClaudeUserInputRequest.TryFromCliMessage可读回),与agent_work_snapshot一样,持久化或解析整条流的调用方必须识别并跳过或处理它;provider 自行回复的请求不会向外传递- 调用方取消(
CancellationToken)会以OperationCanceledException结束流,不会被当作正常的流结束;只有子代理等待计时器触发的静默停止会被吞掉。取消后 transport 会被释放,进程随之回收 CodeBuddy的 tool update 归一化与 permission-mode 映射统一落在CodebuddyProviderHermes的 ACP session reuse、fallback 文本聚合与 lifecycle 诊断统一落在HermesProviderHagiCode.Libs.Providers只负责单次执行并保留 provider-native 会话上下文;如果上层需要重试,必须在 provider 调用边界之外显式编排
ProviderRegistry 的规范名称与兼容别名也已统一:
claude-code→claude,claudecode,anthropic-claudecodebuddy→codebuddy-clihermes→hermes-clipi→pi-cli
Provider usage
using HagiCode.Libs.Providers.Copilot;
using HagiCode.Libs.Providers.Codex;
using HagiCode.Libs.Providers.Codebuddy;
using HagiCode.Libs.Providers.DeepAgents;
using HagiCode.Libs.Providers.Hermes;
using HagiCode.Libs.Providers.Kimi;
using HagiCode.Libs.Providers.Kiro;
using HagiCode.Libs.Providers.Omp;
using HagiCode.Libs.Providers.Pi;
using HagiCode.Libs.Providers.Reasonix;
var codebuddyOptions = new CodebuddyOptions
{
WorkingDirectory = "/path/to/repo",
SessionId = "codebuddy-session-123",
ModeId = "plan",
Model = "glm-4.7"
};
await foreach (var message in codebuddy.ExecuteAsync(codebuddyOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
var hermesOptions = new HermesOptions
{
WorkingDirectory = "/path/to/repo",
SessionId = "hermes-session-123",
ModeId = "bypassPermissions",
Model = "hermes/default",
Arguments = ["acp"]
};
await foreach (var message in hermes.ExecuteAsync(hermesOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
var copilotOptions = new CopilotOptions
{
WorkingDirectory = "/path/to/repo",
Model = "claude-sonnet-4.5",
SessionId = "copilot-session-123",
Permissions = new CopilotPermissionOptions
{
AllowAllTools = true,
AllowedPaths = ["/path/to/repo"]
},
AdditionalArgs = ["--config-dir", "/path/to/.copilot"]
};
await foreach (var message in copilot.ExecuteAsync(copilotOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
// Copilot tool-call turns always terminate with either a "result" or "error"
// message so upstream Orleans/session UIs can leave the running state deterministically.
// Reuse a persisted provider-native Copilot conversation on the next call.
var resumedOptions = copilotOptions with { SessionId = "copilot-session-123" };
// Without SessionId, Copilot requests stay anonymous; WorkingDirectory and permission
// flags only shape the compatibility fingerprint and do not preserve prior runtime state on their own.
var codexOptions = new CodexSessionOptions
{
ThreadOptions = new ThreadOptions
{
WorkingDirectory = "/path/to/repo",
Model = "gpt-5-codex",
SandboxMode = SandboxMode.WorkspaceWrite,
ApprovalPolicy = ApprovalMode.Never,
AdditionalDirectories = ["/path/to/repo"],
SkipGitRepoCheck = true,
}
};
await using var codexSession = await codex.CreateSessionAsync(codexOptions);
var codexResult = await codexSession.Thread.RunAsync("Reply with exactly the word 'pong'");
Console.WriteLine(codexResult.FinalResponse);
var deepAgentsOptions = new DeepAgentsOptions
{
Model = "glm-5.1",
WorkspaceRoot = "/path/to/repo",
ModeId = "bypassPermissions",
AgentName = "coding-assistant",
AgentDescription = "Repo-aware DeepAgents ACP runner",
SkillsDirectories = ["/path/to/skills"],
ExtraArguments = ["--debug"]
};
await foreach (var message in deepAgents.ExecuteAsync(deepAgentsOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
// ModeId is the authoritative ACP session-mode contract for DeepAgents.
// Compatibility flags such as --auto-approve may still be forwarded, but cross-call
// resume depends on provider-native session/load support.
// Reuse the same Codex thread id to continue a previous conversation by setting
// CodexSessionOptions.ThreadId before calling CreateSessionAsync.
var kimiOptions = new KimiOptions
{
WorkingDirectory = "/path/to/repo",
Model = "kimi-k2.5",
AuthenticationMethod = "token",
AuthenticationToken = "<token>",
ExtraArguments = ["--profile", "smoke"]
};
await foreach (var message in kimi.ExecuteAsync(kimiOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
var kiroOptions = new KiroOptions
{
WorkingDirectory = "/path/to/repo",
Model = "kiro-default",
AuthenticationMethod = "token",
AuthenticationToken = "<token>",
ExtraArguments = ["--profile", "smoke"]
};
await foreach (var message in kiro.ExecuteAsync(kiroOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
var piOptions = new PiOptions
{
WorkingDirectory = "/path/to/repo",
Provider = "omniroute",
Model = "glm/glm-4.7",
DisableAllTools = true,
NoSession = true,
EnvironmentVariables = new Dictionary<string, string?>
{
["PI_OFFLINE"] = "1"
}
};
await foreach (var message in pi.ExecuteAsync(piOptions, "Plan a two-day Chongqing trip in three short bullet points."))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
var reasonixOptions = new ReasonixOptions
{
WorkingDirectory = "/path/to/repo",
Model = "deepseek-flash",
SessionId = "reasonix-session-123"
};
await foreach (var message in reasonix.ExecuteAsync(reasonixOptions, "Reply with exactly the word 'pong'"))
{
Console.WriteLine($"{message.Type}: {message.Content}");
}
Vendored Codex SDK notice
The Codex integration vendors source from ManagedCode.CodexSharpSDK under Codex/Vendored/.
The upstream MIT license is preserved in source control at Codex/Vendored/LICENSE.ManagedCode.CodexSharpSDK.txt and is included in the NuGet package under vendor/codex/.
Hermes pool controls
Hermes is the only built-in provider that still exposes PoolSettings:
var hermesPoolOptions = new HermesOptions
{
SessionId = "demo-session",
WorkingDirectory = "/path/to/repo",
PoolSettings = new CliPoolSettings
{
Enabled = true,
IdleTimeout = TimeSpan.FromMinutes(10),
MaxActiveSessions = 50,
KeepAnonymousSessions = false
}
};
Practical boundaries:
Hermespools live ACP sessions.HermesincludesModeIdin its reuse fingerprint and re-applies it aftersession/newor warm reuse.- Setting
HermesOptions.PoolSettings.Enabled = falsefalls back to the one-shot path without changing message semantics. - Non-Hermes providers now execute as one-shot transports or processes.
SessionIdremains a provider-native continuity hint only where that backend supports it. - Idle eviction is lazy and deterministic; if a lease faults, the coordinator disposes that entry immediately rather than returning it to the warm set.
Adoption boundaries
- Interactive provider transports still use
CliProcessManagerdirectly because they need open stdio sessions. - The new execution facade is intended for provider-facing adapters, diagnostics, and one-shot probes such as version checks.
- Provider callers should continue passing structured option models; the new facade is additive and does not replace provider-specific option records.
geminiis the canonical built-in provider name;ProviderRegistryand the dedicated console also acceptgemini-clias an alias.junieis the canonical built-in provider name;ProviderRegistryalso acceptsjunie-clias an alias and boots ACP throughjunie --acp=true.dshis the canonical built-in provider name;ProviderRegistryalso acceptsdsh-clias an alias and boots ACP throughdsh --profile acp. Caller-supplied--profilearguments are rejected. Before any ACP start, thedsh --helpbanner (DeepSeek Harness) is checked so an unrelated distributed-shelldshis not driven as an agent.deepagentsis the canonical built-in provider name, and the managed runtime boots ACP throughdeepagents --acp.kimiis the canonical built-in provider name;ProviderRegistryand the dedicated console also acceptkimi-clias an alias.kiro-cliis the canonical built-in provider name across the shared provider registry and the dedicated console.piis the canonical built-in provider name;ProviderRegistryalso acceptspi-clias a compatibility alias and the built-in provider runs Pi through--mode json --printone-shot execution.ompis the canonical built-in provider name;ProviderRegistryalso acceptsomp-clias a compatibility alias and the built-in provider runs OMP through--mode json --printone-shot execution.reasonixis the canonical built-in provider name. Reasonix 1.x ACP now only accepts the startup-time-modelselector; working directory and session resume flow through ACPsession/new/session/load, while permissions, MCP plugins, proxying, and similar policy are expected to live inreasonix.tomlinstead of CLI bootstrap flags.- Kiro discovery is strict: the shared provider only supports
kiro-cliexecutables. Generickirolaunchers are not accepted for implicit discovery, explicitExecutablePath, or readiness checks. CliInstallRegistrynow treats DeepAgents as local-only validation metadata because the managed runtime expects adeepagentsexecutable (oruvx --from deepagents-cli deepagents --acp) rather than the legacydeepagents-acpnpm package.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- GitHub.Copilot.SDK (>= 1.0.0-beta.10)
- HagiCode.Libs.Core (>= 0.3.3-dev.117.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.2)
- Microsoft.Extensions.Options (>= 10.0.2)
- Nerdbank.MessagePack (>= 1.1.78)
- StreamJsonRpc (>= 2.24.92)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.4.1-dev.124.1 | 0 | 10/14/2026 |
| 0.4.0 | 29 | 10/14/2026 |
| 0.3.3-dev.122.1 | 22 | 10/14/2026 |
| 0.3.3-dev.121.1 | 26 | 10/14/2026 |
| 0.3.3-dev.120.1 | 33 | 10/13/2026 |
| 0.3.3-dev.119.1 | 45 | 10/12/2026 |
| 0.3.3-dev.118.1 | 46 | 10/12/2026 |
| 0.3.3-dev.117.1 | 53 | 10/12/2026 |
| 0.3.3-dev.116.1 | 43 | 10/12/2026 |
| 0.3.3-dev.115.1 | 45 | 10/11/2026 |
| 0.3.3-dev.114.1 | 43 | 10/11/2026 |
| 0.3.3-dev.113.1 | 44 | 10/11/2026 |
| 0.3.3-dev.112.1 | 47 | 10/11/2026 |
| 0.3.3-dev.111.1 | 43 | 10/9/2026 |
| 0.3.3-dev.110.1 | 51 | 10/8/2026 |
| 0.3.2 | 61 | 10/8/2026 |
| 0.3.2-dev.108.1 | 49 | 10/7/2026 |
| 0.3.2-dev.107.1 | 52 | 10/7/2026 |
| 0.3.2-dev.106.1 | 46 | 10/7/2026 |
| 0.3.2-dev.105.1 | 56 | 10/1/2026 |