mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-24 05:28:46 +02:00
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>
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user