Compare commits

..
3 Commits
Author SHA1 Message Date
David Kaya 36b8dd0c12 chore: bump version to 0.0.23 2026-04-07 19:15:40 +02:00
David KayaandCopilot 7a7b3fcdca fix: defer Copilot CLI resolution until agent nodes exist
CopilotAgentBundle.CreateAsync unconditionally resolved the Copilot CLI
path and started a CopilotClient, even for workflows with no agent
nodes (e.g. request-port-only workflows). This caused a hard failure
in CI where the copilot binary is not on PATH.

Move CLI path resolution, client creation, and agent setup inside a
guard that checks whether the workflow actually contains agent nodes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-07 19:14:56 +02:00
David KayaandCopilot 794794afe4 fix(ci): update .NET SDK version to 10.0.x to match sidecar target framework
The sidecar projects were updated to target net10.0 but the CI
workflow still installed dotnet-version 9.0.x, causing all validate
jobs to fail at the sidecar test step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-07 18:54:03 +02:00
3 changed files with 38 additions and 33 deletions
+2 -2
View File
@@ -40,7 +40,7 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
dotnet-version: 10.0.x
- name: Install Linux native dependencies
if: runner.os == 'Linux'
@@ -115,7 +115,7 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
dotnet-version: 10.0.x
- name: Install Linux native dependencies
if: runner.os == 'Linux'
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "aryx",
"version": "0.0.22",
"version": "0.0.23",
"description": "Orchestrator for Copilot-powered agent workflows across multiple projects.",
"private": true,
"main": "dist-electron/main/index.js",
@@ -38,7 +38,6 @@ internal sealed class CopilotAgentBundle : IAsyncDisposable
{
List<IAsyncDisposable> disposables = [];
List<AIAgent> agents = [];
CopilotClientOptions clientOptions = CopilotCliPathResolver.CreateClientOptions();
ResolvedHookSet configuredHooks = await HookConfigLoader.LoadAsync(command.ProjectPath, cancellationToken)
.ConfigureAwait(false);
IHookCommandRunner hookCommandRunner = HookCommandRunner.Instance;
@@ -52,42 +51,48 @@ internal sealed class CopilotAgentBundle : IAsyncDisposable
disposables.Add(toolingBundle);
}
// Share a single CopilotClient across all agents to avoid spawning
// multiple CLI processes that race on token refresh during auto-login.
CopilotClient sharedClient = new(clientOptions);
await sharedClient.StartAsync(cancellationToken).ConfigureAwait(false);
IReadOnlyList<WorkflowNodeDto> agentNodes = command.Workflow.GetAllAgentNodes(command.WorkflowLibrary);
foreach ((WorkflowNodeDto definition, int agentIndex) in agentNodes.Select((definition, index) => (definition, index)))
if (agentNodes.Count > 0)
{
SessionConfig sessionConfig = CreateSessionConfig(
command,
definition,
agentIndex,
(request, invocation) => onPermissionRequest(definition, request, invocation),
(request, invocation) => onUserInputRequest(definition, request, invocation),
evt => onSessionEvent?.Invoke(definition, evt),
configuredHooks,
hookCommandRunner);
CopilotClientOptions clientOptions = CopilotCliPathResolver.CreateClientOptions();
ApplySessionTooling(sessionConfig, toolingBundle?.McpServers, toolingBundle?.Tools);
ApplyPromptInvocation(sessionConfig, command.PromptInvocation);
// Share a single CopilotClient across all agents to avoid spawning
// multiple CLI processes that race on token refresh during auto-login.
CopilotClient sharedClient = new(clientOptions);
await sharedClient.StartAsync(cancellationToken).ConfigureAwait(false);
AryxCopilotAgent agent = new(
sharedClient,
sessionConfig,
ownsClient: false,
id: definition.GetAgentId(),
name: definition.GetAgentName(),
description: NormalizeOptionalString(definition.Config.Description));
foreach ((WorkflowNodeDto definition, int agentIndex) in agentNodes.Select((definition, index) => (definition, index)))
{
SessionConfig sessionConfig = CreateSessionConfig(
command,
definition,
agentIndex,
(request, invocation) => onPermissionRequest(definition, request, invocation),
(request, invocation) => onUserInputRequest(definition, request, invocation),
evt => onSessionEvent?.Invoke(definition, evt),
configuredHooks,
hookCommandRunner);
agents.Add(agent);
disposables.Add(agent);
ApplySessionTooling(sessionConfig, toolingBundle?.McpServers, toolingBundle?.Tools);
ApplyPromptInvocation(sessionConfig, command.PromptInvocation);
AryxCopilotAgent agent = new(
sharedClient,
sessionConfig,
ownsClient: false,
id: definition.GetAgentId(),
name: definition.GetAgentName(),
description: NormalizeOptionalString(definition.Config.Description));
agents.Add(agent);
disposables.Add(agent);
}
// The bundle owns the shared client — disposed after all agents.
disposables.Add(sharedClient);
}
// The bundle owns the shared client — disposed after all agents.
disposables.Add(sharedClient);
CopilotAgentBundle bundle = new(agents, hasConfiguredHooks: !configuredHooks.IsEmpty);
bundle._disposables.AddRange(disposables);
return bundle;