mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-27 13:23:57 +02:00
refactor: decouple turn execution state from Copilot SDK events
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
|||||||
|
namespace Aryx.AgentHost.Contracts;
|
||||||
|
|
||||||
|
internal abstract record ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderAssistantMessageDeltaEvent(string MessageId) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderAssistantMessageEvent(
|
||||||
|
string MessageId,
|
||||||
|
bool HasToolRequests) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderToolExecutionStartEvent(
|
||||||
|
string ToolCallId,
|
||||||
|
string ToolName,
|
||||||
|
IReadOnlyDictionary<string, object?>? ToolArguments) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderAssistantIntentEvent(string? Intent) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderAssistantReasoningDeltaEvent(
|
||||||
|
string? ReasoningId,
|
||||||
|
string? DeltaContent) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSubagentStartedEvent(
|
||||||
|
string? ToolCallId,
|
||||||
|
string? AgentName,
|
||||||
|
string? AgentDisplayName,
|
||||||
|
string? AgentDescription) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSubagentCompletedEvent(
|
||||||
|
string? ToolCallId,
|
||||||
|
string? AgentName,
|
||||||
|
string? AgentDisplayName) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSubagentFailedEvent(
|
||||||
|
string? ToolCallId,
|
||||||
|
string? AgentName,
|
||||||
|
string? AgentDisplayName,
|
||||||
|
string? Error) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSubagentSelectedEvent(
|
||||||
|
string? AgentName,
|
||||||
|
string? AgentDisplayName,
|
||||||
|
IReadOnlyList<string>? Tools) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSubagentDeselectedEvent() : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSkillInvokedEvent(
|
||||||
|
string SkillName,
|
||||||
|
string Path,
|
||||||
|
string Content,
|
||||||
|
IReadOnlyList<string>? AllowedTools,
|
||||||
|
string? PluginName,
|
||||||
|
string? PluginVersion) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderHookStartEvent(
|
||||||
|
string HookInvocationId,
|
||||||
|
string HookType,
|
||||||
|
object? Input) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderHookEndEvent(
|
||||||
|
string HookInvocationId,
|
||||||
|
string HookType,
|
||||||
|
bool? Success,
|
||||||
|
object? Output,
|
||||||
|
string? Error) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderAssistantUsageEvent(
|
||||||
|
string Model,
|
||||||
|
double? InputTokens,
|
||||||
|
double? OutputTokens,
|
||||||
|
double? CacheReadTokens,
|
||||||
|
double? CacheWriteTokens,
|
||||||
|
double? Cost,
|
||||||
|
double? Duration,
|
||||||
|
double? TotalNanoAiu,
|
||||||
|
Dictionary<string, QuotaSnapshotDto>? QuotaSnapshots) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSessionUsageEvent(
|
||||||
|
double TokenLimit,
|
||||||
|
double CurrentTokens,
|
||||||
|
double MessagesLength,
|
||||||
|
double? SystemTokens,
|
||||||
|
double? ConversationTokens,
|
||||||
|
double? ToolDefinitionsTokens,
|
||||||
|
bool? IsInitial) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSessionCompactionStartEvent(
|
||||||
|
double? SystemTokens,
|
||||||
|
double? ConversationTokens,
|
||||||
|
double? ToolDefinitionsTokens) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderSessionCompactionCompleteEvent(
|
||||||
|
bool? Success,
|
||||||
|
string? Error,
|
||||||
|
double? SystemTokens,
|
||||||
|
double? ConversationTokens,
|
||||||
|
double? ToolDefinitionsTokens,
|
||||||
|
double? PreCompactionTokens,
|
||||||
|
double? PostCompactionTokens,
|
||||||
|
double? PreCompactionMessagesLength,
|
||||||
|
double? MessagesRemoved,
|
||||||
|
double? TokensRemoved,
|
||||||
|
string? SummaryContent,
|
||||||
|
double? CheckpointNumber,
|
||||||
|
string? CheckpointPath) : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderPendingMessagesModifiedEvent() : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderMcpOauthRequiredEvent() : ProviderSessionEvent;
|
||||||
|
|
||||||
|
internal sealed record ProviderExitPlanModeRequestedEvent() : ProviderSessionEvent;
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
using Aryx.AgentHost.Contracts;
|
||||||
|
using GitHub.Copilot.SDK;
|
||||||
|
|
||||||
|
namespace Aryx.AgentHost.Services;
|
||||||
|
|
||||||
|
internal sealed class CopilotEventAdapter : IProviderEventAdapter
|
||||||
|
{
|
||||||
|
public ProviderSessionEvent? TryAdapt(object rawEvent)
|
||||||
|
{
|
||||||
|
return rawEvent switch
|
||||||
|
{
|
||||||
|
AssistantMessageDeltaEvent messageDelta
|
||||||
|
when NormalizeRequiredString(messageDelta.Data?.MessageId) is { } messageId =>
|
||||||
|
new ProviderAssistantMessageDeltaEvent(messageId),
|
||||||
|
|
||||||
|
AssistantMessageEvent assistantMessage
|
||||||
|
when NormalizeRequiredString(assistantMessage.Data?.MessageId) is { } messageId =>
|
||||||
|
new ProviderAssistantMessageEvent(
|
||||||
|
messageId,
|
||||||
|
assistantMessage.Data?.ToolRequests is { Length: > 0 }),
|
||||||
|
|
||||||
|
ToolExecutionStartEvent toolExecutionStart
|
||||||
|
when NormalizeRequiredString(toolExecutionStart.Data?.ToolCallId) is { } toolCallId
|
||||||
|
&& NormalizeRequiredString(toolExecutionStart.Data?.ToolName) is { } toolName =>
|
||||||
|
new ProviderToolExecutionStartEvent(
|
||||||
|
toolCallId,
|
||||||
|
toolName,
|
||||||
|
WorkflowRequestInfoInterpreter.NormalizeRawToolArguments(toolExecutionStart.Data?.Arguments)),
|
||||||
|
|
||||||
|
AssistantIntentEvent intentEvent =>
|
||||||
|
new ProviderAssistantIntentEvent(NormalizeOptionalString(intentEvent.Data?.Intent)),
|
||||||
|
|
||||||
|
AssistantReasoningDeltaEvent reasoningDelta =>
|
||||||
|
new ProviderAssistantReasoningDeltaEvent(
|
||||||
|
NormalizeOptionalString(reasoningDelta.Data?.ReasoningId),
|
||||||
|
reasoningDelta.Data?.DeltaContent),
|
||||||
|
|
||||||
|
SubagentStartedEvent started =>
|
||||||
|
new ProviderSubagentStartedEvent(
|
||||||
|
started.Data?.ToolCallId,
|
||||||
|
started.Data?.AgentName,
|
||||||
|
started.Data?.AgentDisplayName,
|
||||||
|
started.Data?.AgentDescription),
|
||||||
|
|
||||||
|
SubagentCompletedEvent completed =>
|
||||||
|
new ProviderSubagentCompletedEvent(
|
||||||
|
completed.Data?.ToolCallId,
|
||||||
|
completed.Data?.AgentName,
|
||||||
|
completed.Data?.AgentDisplayName),
|
||||||
|
|
||||||
|
SubagentFailedEvent failed =>
|
||||||
|
new ProviderSubagentFailedEvent(
|
||||||
|
failed.Data?.ToolCallId,
|
||||||
|
failed.Data?.AgentName,
|
||||||
|
failed.Data?.AgentDisplayName,
|
||||||
|
failed.Data?.Error),
|
||||||
|
|
||||||
|
SubagentSelectedEvent selected =>
|
||||||
|
new ProviderSubagentSelectedEvent(
|
||||||
|
selected.Data?.AgentName,
|
||||||
|
selected.Data?.AgentDisplayName,
|
||||||
|
selected.Data?.Tools),
|
||||||
|
|
||||||
|
SubagentDeselectedEvent =>
|
||||||
|
new ProviderSubagentDeselectedEvent(),
|
||||||
|
|
||||||
|
SkillInvokedEvent skillInvoked =>
|
||||||
|
new ProviderSkillInvokedEvent(
|
||||||
|
skillInvoked.Data?.Name ?? string.Empty,
|
||||||
|
skillInvoked.Data?.Path ?? string.Empty,
|
||||||
|
skillInvoked.Data?.Content ?? string.Empty,
|
||||||
|
skillInvoked.Data?.AllowedTools,
|
||||||
|
skillInvoked.Data?.PluginName,
|
||||||
|
skillInvoked.Data?.PluginVersion),
|
||||||
|
|
||||||
|
HookStartEvent hookStart =>
|
||||||
|
new ProviderHookStartEvent(
|
||||||
|
hookStart.Data?.HookInvocationId ?? string.Empty,
|
||||||
|
hookStart.Data?.HookType ?? string.Empty,
|
||||||
|
hookStart.Data?.Input),
|
||||||
|
|
||||||
|
HookEndEvent hookEnd =>
|
||||||
|
new ProviderHookEndEvent(
|
||||||
|
hookEnd.Data?.HookInvocationId ?? string.Empty,
|
||||||
|
hookEnd.Data?.HookType ?? string.Empty,
|
||||||
|
hookEnd.Data?.Success,
|
||||||
|
hookEnd.Data?.Output,
|
||||||
|
hookEnd.Data?.Error?.Message),
|
||||||
|
|
||||||
|
AssistantUsageEvent assistantUsage =>
|
||||||
|
new ProviderAssistantUsageEvent(
|
||||||
|
assistantUsage.Data?.Model ?? string.Empty,
|
||||||
|
assistantUsage.Data?.InputTokens,
|
||||||
|
assistantUsage.Data?.OutputTokens,
|
||||||
|
assistantUsage.Data?.CacheReadTokens,
|
||||||
|
assistantUsage.Data?.CacheWriteTokens,
|
||||||
|
assistantUsage.Data?.Cost,
|
||||||
|
assistantUsage.Data?.Duration,
|
||||||
|
assistantUsage.Data?.CopilotUsage?.TotalNanoAiu,
|
||||||
|
QuotaSnapshotMapper.MapOrNull(assistantUsage.Data?.QuotaSnapshots)),
|
||||||
|
|
||||||
|
SessionUsageInfoEvent usageInfo =>
|
||||||
|
new ProviderSessionUsageEvent(
|
||||||
|
usageInfo.Data?.TokenLimit ?? 0,
|
||||||
|
usageInfo.Data?.CurrentTokens ?? 0,
|
||||||
|
usageInfo.Data?.MessagesLength ?? 0,
|
||||||
|
usageInfo.Data?.SystemTokens,
|
||||||
|
usageInfo.Data?.ConversationTokens,
|
||||||
|
usageInfo.Data?.ToolDefinitionsTokens,
|
||||||
|
usageInfo.Data?.IsInitial),
|
||||||
|
|
||||||
|
SessionCompactionStartEvent compactionStart =>
|
||||||
|
new ProviderSessionCompactionStartEvent(
|
||||||
|
compactionStart.Data?.SystemTokens,
|
||||||
|
compactionStart.Data?.ConversationTokens,
|
||||||
|
compactionStart.Data?.ToolDefinitionsTokens),
|
||||||
|
|
||||||
|
SessionCompactionCompleteEvent compactionComplete =>
|
||||||
|
new ProviderSessionCompactionCompleteEvent(
|
||||||
|
compactionComplete.Data?.Success,
|
||||||
|
compactionComplete.Data?.Error,
|
||||||
|
compactionComplete.Data?.SystemTokens,
|
||||||
|
compactionComplete.Data?.ConversationTokens,
|
||||||
|
compactionComplete.Data?.ToolDefinitionsTokens,
|
||||||
|
compactionComplete.Data?.PreCompactionTokens,
|
||||||
|
compactionComplete.Data?.PostCompactionTokens,
|
||||||
|
compactionComplete.Data?.PreCompactionMessagesLength,
|
||||||
|
compactionComplete.Data?.MessagesRemoved,
|
||||||
|
compactionComplete.Data?.TokensRemoved,
|
||||||
|
compactionComplete.Data?.SummaryContent,
|
||||||
|
compactionComplete.Data?.CheckpointNumber,
|
||||||
|
compactionComplete.Data?.CheckpointPath),
|
||||||
|
|
||||||
|
PendingMessagesModifiedEvent =>
|
||||||
|
new ProviderPendingMessagesModifiedEvent(),
|
||||||
|
|
||||||
|
McpOauthRequiredEvent =>
|
||||||
|
new ProviderMcpOauthRequiredEvent(),
|
||||||
|
|
||||||
|
ExitPlanModeRequestedEvent =>
|
||||||
|
new ProviderExitPlanModeRequestedEvent(),
|
||||||
|
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? NormalizeRequiredString(string? value)
|
||||||
|
{
|
||||||
|
string? normalized = NormalizeOptionalString(value);
|
||||||
|
return string.IsNullOrWhiteSpace(normalized) ? null : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? NormalizeOptionalString(string? value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using Aryx.AgentHost.Contracts;
|
using Aryx.AgentHost.Contracts;
|
||||||
using GitHub.Copilot.SDK;
|
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
namespace Aryx.AgentHost.Services;
|
namespace Aryx.AgentHost.Services;
|
||||||
@@ -70,7 +69,7 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ObserveSessionEvent(WorkflowNodeDto agentDefinition, SessionEvent sessionEvent)
|
public void ObserveSessionEvent(WorkflowNodeDto agentDefinition, ProviderSessionEvent sessionEvent)
|
||||||
{
|
{
|
||||||
AgentIdentity agent = AgentIdentityResolver.ResolveAgentIdentity(
|
AgentIdentity agent = AgentIdentityResolver.ResolveAgentIdentity(
|
||||||
_command.Workflow,
|
_command.Workflow,
|
||||||
@@ -79,27 +78,25 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
|
|
||||||
switch (sessionEvent)
|
switch (sessionEvent)
|
||||||
{
|
{
|
||||||
case AssistantMessageDeltaEvent messageDelta when !string.IsNullOrWhiteSpace(messageDelta.Data?.MessageId):
|
case ProviderAssistantMessageDeltaEvent messageDelta:
|
||||||
RecordObservedAgentForMessage(agent, messageDelta.Data!.MessageId);
|
RecordObservedAgentForMessage(agent, messageDelta.MessageId);
|
||||||
QueueThinkingIfNeeded(agent);
|
QueueThinkingIfNeeded(agent);
|
||||||
break;
|
break;
|
||||||
case AssistantMessageEvent assistantMessage when !string.IsNullOrWhiteSpace(assistantMessage.Data?.MessageId):
|
case ProviderAssistantMessageEvent assistantMessage:
|
||||||
RecordObservedAgentForMessage(agent, assistantMessage.Data!.MessageId);
|
RecordObservedAgentForMessage(agent, assistantMessage.MessageId);
|
||||||
QueueThinkingIfNeeded(agent);
|
QueueThinkingIfNeeded(agent);
|
||||||
if (assistantMessage.Data?.ToolRequests is { Length: > 0 })
|
if (assistantMessage.HasToolRequests)
|
||||||
{
|
{
|
||||||
QueueMessageReclassifiedIfNeeded(assistantMessage.Data.MessageId);
|
QueueMessageReclassifiedIfNeeded(assistantMessage.MessageId);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ToolExecutionStartEvent toolExecutionStart
|
case ProviderToolExecutionStartEvent toolExecutionStart:
|
||||||
when !string.IsNullOrWhiteSpace(toolExecutionStart.Data?.ToolCallId)
|
string toolCallId = toolExecutionStart.ToolCallId;
|
||||||
&& !string.IsNullOrWhiteSpace(toolExecutionStart.Data?.ToolName):
|
string toolName = toolExecutionStart.ToolName;
|
||||||
string toolCallId = toolExecutionStart.Data.ToolCallId.Trim();
|
|
||||||
string toolName = toolExecutionStart.Data.ToolName.Trim();
|
|
||||||
ToolNamesByCallId[toolCallId] = toolName;
|
ToolNamesByCallId[toolCallId] = toolName;
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
AgentActivityEventDto? toolActivity = CreateToolCallingActivity(
|
AgentActivityEventDto? toolActivity = CreateToolCallingActivity(
|
||||||
agent, toolName, toolCallId, toolExecutionStart.Data.Arguments);
|
agent, toolName, toolCallId, toolExecutionStart.ToolArguments);
|
||||||
if (toolActivity is not null)
|
if (toolActivity is not null)
|
||||||
{
|
{
|
||||||
_pendingEvents.Enqueue(toolActivity);
|
_pendingEvents.Enqueue(toolActivity);
|
||||||
@@ -107,86 +104,101 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
|
|
||||||
QueueMessageReclassifiedIfNeeded(_lastObservedMessageId);
|
QueueMessageReclassifiedIfNeeded(_lastObservedMessageId);
|
||||||
break;
|
break;
|
||||||
case AssistantIntentEvent intentEvent:
|
case ProviderAssistantIntentEvent intentEvent:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
QueueThinkingIfNeeded(agent);
|
QueueThinkingIfNeeded(agent);
|
||||||
AssistantIntentEventDto? assistantIntent = CreateAssistantIntentEvent(agent, intentEvent.Data);
|
AssistantIntentEventDto? assistantIntent = CreateAssistantIntentEvent(agent, intentEvent.Intent);
|
||||||
if (assistantIntent is not null)
|
if (assistantIntent is not null)
|
||||||
{
|
{
|
||||||
_pendingEvents.Enqueue(assistantIntent);
|
_pendingEvents.Enqueue(assistantIntent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AssistantReasoningDeltaEvent reasoningDelta:
|
case ProviderAssistantReasoningDeltaEvent reasoningDelta:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
QueueThinkingIfNeeded(agent);
|
QueueThinkingIfNeeded(agent);
|
||||||
ReasoningDeltaEventDto? reasoningDeltaEvent = CreateReasoningDeltaEvent(agent, reasoningDelta.Data);
|
ReasoningDeltaEventDto? reasoningDeltaEvent = CreateReasoningDeltaEvent(
|
||||||
|
agent,
|
||||||
|
reasoningDelta.ReasoningId,
|
||||||
|
reasoningDelta.DeltaContent);
|
||||||
if (reasoningDeltaEvent is not null)
|
if (reasoningDeltaEvent is not null)
|
||||||
{
|
{
|
||||||
_pendingEvents.Enqueue(reasoningDeltaEvent);
|
_pendingEvents.Enqueue(reasoningDeltaEvent);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SubagentStartedEvent started:
|
case ProviderSubagentStartedEvent started:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSubagentEvent(agent, "started", started.Data));
|
_pendingEvents.Enqueue(CreateSubagentStartedEvent(agent, started));
|
||||||
break;
|
break;
|
||||||
case SubagentCompletedEvent completed:
|
case ProviderSubagentCompletedEvent completed:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSubagentCompletedEvent(agent, completed.Data));
|
_pendingEvents.Enqueue(CreateSubagentCompletedEvent(agent, completed));
|
||||||
break;
|
break;
|
||||||
case SubagentFailedEvent failed:
|
case ProviderSubagentFailedEvent failed:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSubagentFailedEvent(agent, failed.Data));
|
_pendingEvents.Enqueue(CreateSubagentFailedEvent(agent, failed));
|
||||||
break;
|
break;
|
||||||
case SubagentSelectedEvent selected:
|
case ProviderSubagentSelectedEvent selected:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSubagentSelectedEvent(agent, selected.Data));
|
_pendingEvents.Enqueue(CreateSubagentSelectedEvent(agent, selected));
|
||||||
break;
|
break;
|
||||||
case SubagentDeselectedEvent:
|
case ProviderSubagentDeselectedEvent:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSubagentDeselectedEvent(agent));
|
_pendingEvents.Enqueue(CreateSubagentDeselectedEvent(agent));
|
||||||
break;
|
break;
|
||||||
case SkillInvokedEvent skillInvoked:
|
case ProviderSkillInvokedEvent skillInvoked:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateSkillInvokedEvent(agent, skillInvoked.Data));
|
_pendingEvents.Enqueue(CreateSkillInvokedEvent(agent, skillInvoked));
|
||||||
break;
|
break;
|
||||||
case HookStartEvent hookStart:
|
case ProviderHookStartEvent hookStart:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
if (!SuppressHookLifecycleEvents)
|
if (!SuppressHookLifecycleEvents)
|
||||||
{
|
{
|
||||||
_pendingEvents.Enqueue(CreateHookLifecycleEvent(agent, "start", hookStart.Data));
|
_pendingEvents.Enqueue(CreateHookLifecycleEvent(
|
||||||
|
agent,
|
||||||
|
"start",
|
||||||
|
hookStart.HookInvocationId,
|
||||||
|
hookStart.HookType,
|
||||||
|
input: hookStart.Input));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HookEndEvent hookEnd:
|
case ProviderHookEndEvent hookEnd:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
if (!SuppressHookLifecycleEvents)
|
if (!SuppressHookLifecycleEvents)
|
||||||
{
|
{
|
||||||
_pendingEvents.Enqueue(CreateHookLifecycleEvent(agent, "end", hookEnd.Data));
|
_pendingEvents.Enqueue(CreateHookLifecycleEvent(
|
||||||
|
agent,
|
||||||
|
"end",
|
||||||
|
hookEnd.HookInvocationId,
|
||||||
|
hookEnd.HookType,
|
||||||
|
success: hookEnd.Success,
|
||||||
|
output: hookEnd.Output,
|
||||||
|
error: hookEnd.Error));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AssistantUsageEvent assistantUsage:
|
case ProviderAssistantUsageEvent assistantUsage:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateAssistantUsageEvent(agent, assistantUsage.Data));
|
_pendingEvents.Enqueue(CreateAssistantUsageEvent(agent, assistantUsage));
|
||||||
break;
|
break;
|
||||||
case SessionUsageInfoEvent usageInfo:
|
case ProviderSessionUsageEvent usageInfo:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateUsageEvent(agent, usageInfo.Data));
|
_pendingEvents.Enqueue(CreateUsageEvent(agent, usageInfo));
|
||||||
break;
|
break;
|
||||||
case SessionCompactionStartEvent compactionStart:
|
case ProviderSessionCompactionStartEvent compactionStart:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateCompactionStartEvent(agent, compactionStart.Data));
|
_pendingEvents.Enqueue(CreateCompactionStartEvent(agent, compactionStart));
|
||||||
break;
|
break;
|
||||||
case SessionCompactionCompleteEvent compactionComplete:
|
case ProviderSessionCompactionCompleteEvent compactionComplete:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreateCompactionCompleteEvent(agent, compactionComplete.Data));
|
_pendingEvents.Enqueue(CreateCompactionCompleteEvent(agent, compactionComplete));
|
||||||
break;
|
break;
|
||||||
case PendingMessagesModifiedEvent:
|
case ProviderPendingMessagesModifiedEvent:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
_pendingEvents.Enqueue(CreatePendingMessagesModifiedEvent(agent));
|
_pendingEvents.Enqueue(CreatePendingMessagesModifiedEvent(agent));
|
||||||
break;
|
break;
|
||||||
case McpOauthRequiredEvent:
|
case ProviderMcpOauthRequiredEvent:
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
break;
|
break;
|
||||||
case ExitPlanModeRequestedEvent:
|
case ProviderExitPlanModeRequestedEvent:
|
||||||
HasPendingExitPlanModeRequest = true;
|
HasPendingExitPlanModeRequest = true;
|
||||||
ActiveAgent = agent;
|
ActiveAgent = agent;
|
||||||
break;
|
break;
|
||||||
@@ -297,7 +309,7 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
string toolName,
|
string toolName,
|
||||||
string toolCallId,
|
string toolCallId,
|
||||||
object? rawArguments = null)
|
IReadOnlyDictionary<string, object?>? toolArguments = null)
|
||||||
{
|
{
|
||||||
if (toolName.StartsWith("handoff_to_", StringComparison.Ordinal))
|
if (toolName.StartsWith("handoff_to_", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
@@ -314,7 +326,7 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
ToolName = toolName,
|
ToolName = toolName,
|
||||||
ToolCallId = toolCallId,
|
ToolCallId = toolCallId,
|
||||||
ToolArguments = WorkflowRequestInfoInterpreter.NormalizeRawToolArguments(rawArguments),
|
ToolArguments = toolArguments,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,29 +389,28 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
return CompletedMessages;
|
return CompletedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubagentEventDto CreateSubagentEvent(
|
private SubagentEventDto CreateSubagentStartedEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
string eventKind,
|
ProviderSubagentStartedEvent data)
|
||||||
SubagentStartedData? data)
|
|
||||||
{
|
{
|
||||||
return new SubagentEventDto
|
return new SubagentEventDto
|
||||||
{
|
{
|
||||||
Type = "subagent-event",
|
Type = "subagent-event",
|
||||||
RequestId = _command.RequestId,
|
RequestId = _command.RequestId,
|
||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
EventKind = eventKind,
|
EventKind = "started",
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
ToolCallId = data?.ToolCallId,
|
ToolCallId = data.ToolCallId,
|
||||||
CustomAgentName = data?.AgentName,
|
CustomAgentName = data.AgentName,
|
||||||
CustomAgentDisplayName = data?.AgentDisplayName,
|
CustomAgentDisplayName = data.AgentDisplayName,
|
||||||
CustomAgentDescription = data?.AgentDescription,
|
CustomAgentDescription = data.AgentDescription,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubagentEventDto CreateSubagentCompletedEvent(
|
private SubagentEventDto CreateSubagentCompletedEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SubagentCompletedData? data)
|
ProviderSubagentCompletedEvent data)
|
||||||
{
|
{
|
||||||
return new SubagentEventDto
|
return new SubagentEventDto
|
||||||
{
|
{
|
||||||
@@ -409,15 +420,15 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
EventKind = "completed",
|
EventKind = "completed",
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
ToolCallId = data?.ToolCallId,
|
ToolCallId = data.ToolCallId,
|
||||||
CustomAgentName = data?.AgentName,
|
CustomAgentName = data.AgentName,
|
||||||
CustomAgentDisplayName = data?.AgentDisplayName,
|
CustomAgentDisplayName = data.AgentDisplayName,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubagentEventDto CreateSubagentFailedEvent(
|
private SubagentEventDto CreateSubagentFailedEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SubagentFailedData? data)
|
ProviderSubagentFailedEvent data)
|
||||||
{
|
{
|
||||||
return new SubagentEventDto
|
return new SubagentEventDto
|
||||||
{
|
{
|
||||||
@@ -427,16 +438,16 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
EventKind = "failed",
|
EventKind = "failed",
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
ToolCallId = data?.ToolCallId,
|
ToolCallId = data.ToolCallId,
|
||||||
CustomAgentName = data?.AgentName,
|
CustomAgentName = data.AgentName,
|
||||||
CustomAgentDisplayName = data?.AgentDisplayName,
|
CustomAgentDisplayName = data.AgentDisplayName,
|
||||||
Error = data?.Error,
|
Error = data.Error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubagentEventDto CreateSubagentSelectedEvent(
|
private SubagentEventDto CreateSubagentSelectedEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SubagentSelectedData? data)
|
ProviderSubagentSelectedEvent data)
|
||||||
{
|
{
|
||||||
return new SubagentEventDto
|
return new SubagentEventDto
|
||||||
{
|
{
|
||||||
@@ -446,9 +457,9 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
EventKind = "selected",
|
EventKind = "selected",
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
CustomAgentName = data?.AgentName,
|
CustomAgentName = data.AgentName,
|
||||||
CustomAgentDisplayName = data?.AgentDisplayName,
|
CustomAgentDisplayName = data.AgentDisplayName,
|
||||||
Tools = data?.Tools,
|
Tools = data.Tools,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,10 +478,10 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
|
|
||||||
private AssistantIntentEventDto? CreateAssistantIntentEvent(
|
private AssistantIntentEventDto? CreateAssistantIntentEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
AssistantIntentData? data)
|
string? intent)
|
||||||
{
|
{
|
||||||
string? intent = data?.Intent?.Trim();
|
string? normalizedIntent = intent?.Trim();
|
||||||
if (string.IsNullOrWhiteSpace(intent))
|
if (string.IsNullOrWhiteSpace(normalizedIntent))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -482,17 +493,17 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
Intent = intent,
|
Intent = normalizedIntent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReasoningDeltaEventDto? CreateReasoningDeltaEvent(
|
private ReasoningDeltaEventDto? CreateReasoningDeltaEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
AssistantReasoningDeltaData? data)
|
string? reasoningId,
|
||||||
|
string? deltaContent)
|
||||||
{
|
{
|
||||||
if (data is null
|
if (string.IsNullOrWhiteSpace(reasoningId)
|
||||||
|| string.IsNullOrWhiteSpace(data.ReasoningId)
|
|| string.IsNullOrEmpty(deltaContent))
|
||||||
|| string.IsNullOrEmpty(data.DeltaContent))
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -504,14 +515,14 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
ReasoningId = data.ReasoningId,
|
ReasoningId = reasoningId,
|
||||||
ContentDelta = data.DeltaContent,
|
ContentDelta = deltaContent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkillInvokedEventDto CreateSkillInvokedEvent(
|
private SkillInvokedEventDto CreateSkillInvokedEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SkillInvokedData? data)
|
ProviderSkillInvokedEvent data)
|
||||||
{
|
{
|
||||||
return new SkillInvokedEventDto
|
return new SkillInvokedEventDto
|
||||||
{
|
{
|
||||||
@@ -520,19 +531,24 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
SkillName = data?.Name ?? string.Empty,
|
SkillName = data.SkillName,
|
||||||
Path = data?.Path ?? string.Empty,
|
Path = data.Path,
|
||||||
Content = data?.Content ?? string.Empty,
|
Content = data.Content,
|
||||||
AllowedTools = data?.AllowedTools,
|
AllowedTools = data.AllowedTools,
|
||||||
PluginName = data?.PluginName,
|
PluginName = data.PluginName,
|
||||||
PluginVersion = data?.PluginVersion,
|
PluginVersion = data.PluginVersion,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private HookLifecycleEventDto CreateHookLifecycleEvent(
|
private HookLifecycleEventDto CreateHookLifecycleEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
string phase,
|
string phase,
|
||||||
HookStartData? data)
|
string hookInvocationId,
|
||||||
|
string hookType,
|
||||||
|
object? input = null,
|
||||||
|
bool? success = null,
|
||||||
|
object? output = null,
|
||||||
|
string? error = null)
|
||||||
{
|
{
|
||||||
return new HookLifecycleEventDto
|
return new HookLifecycleEventDto
|
||||||
{
|
{
|
||||||
@@ -541,37 +557,19 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
HookInvocationId = data?.HookInvocationId ?? string.Empty,
|
HookInvocationId = hookInvocationId,
|
||||||
HookType = data?.HookType ?? string.Empty,
|
HookType = hookType,
|
||||||
Phase = phase,
|
Phase = phase,
|
||||||
Input = data?.Input,
|
Input = input,
|
||||||
};
|
Success = success,
|
||||||
}
|
Output = output,
|
||||||
|
Error = error,
|
||||||
private HookLifecycleEventDto CreateHookLifecycleEvent(
|
|
||||||
AgentIdentity agent,
|
|
||||||
string phase,
|
|
||||||
HookEndData? data)
|
|
||||||
{
|
|
||||||
return new HookLifecycleEventDto
|
|
||||||
{
|
|
||||||
Type = "hook-lifecycle",
|
|
||||||
RequestId = _command.RequestId,
|
|
||||||
SessionId = _command.SessionId,
|
|
||||||
AgentId = agent.AgentId,
|
|
||||||
AgentName = agent.AgentName,
|
|
||||||
HookInvocationId = data?.HookInvocationId ?? string.Empty,
|
|
||||||
HookType = data?.HookType ?? string.Empty,
|
|
||||||
Phase = phase,
|
|
||||||
Success = data?.Success,
|
|
||||||
Output = data?.Output,
|
|
||||||
Error = data?.Error?.Message,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssistantUsageEventDto CreateAssistantUsageEvent(
|
private AssistantUsageEventDto CreateAssistantUsageEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
AssistantUsageData? data)
|
ProviderAssistantUsageEvent data)
|
||||||
{
|
{
|
||||||
return new AssistantUsageEventDto
|
return new AssistantUsageEventDto
|
||||||
{
|
{
|
||||||
@@ -580,19 +578,19 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
Model = data?.Model ?? string.Empty,
|
Model = data.Model,
|
||||||
InputTokens = data?.InputTokens,
|
InputTokens = data.InputTokens,
|
||||||
OutputTokens = data?.OutputTokens,
|
OutputTokens = data.OutputTokens,
|
||||||
CacheReadTokens = data?.CacheReadTokens,
|
CacheReadTokens = data.CacheReadTokens,
|
||||||
CacheWriteTokens = data?.CacheWriteTokens,
|
CacheWriteTokens = data.CacheWriteTokens,
|
||||||
Cost = data?.Cost,
|
Cost = data.Cost,
|
||||||
Duration = data?.Duration,
|
Duration = data.Duration,
|
||||||
TotalNanoAiu = data?.CopilotUsage?.TotalNanoAiu,
|
TotalNanoAiu = data.TotalNanoAiu,
|
||||||
QuotaSnapshots = QuotaSnapshotMapper.MapOrNull(data?.QuotaSnapshots),
|
QuotaSnapshots = data.QuotaSnapshots,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SessionUsageEventDto CreateUsageEvent(AgentIdentity agent, SessionUsageInfoData? data)
|
private SessionUsageEventDto CreateUsageEvent(AgentIdentity agent, ProviderSessionUsageEvent data)
|
||||||
{
|
{
|
||||||
return new SessionUsageEventDto
|
return new SessionUsageEventDto
|
||||||
{
|
{
|
||||||
@@ -601,19 +599,19 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
SessionId = _command.SessionId,
|
SessionId = _command.SessionId,
|
||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
TokenLimit = data?.TokenLimit ?? 0,
|
TokenLimit = data.TokenLimit,
|
||||||
CurrentTokens = data?.CurrentTokens ?? 0,
|
CurrentTokens = data.CurrentTokens,
|
||||||
MessagesLength = data?.MessagesLength ?? 0,
|
MessagesLength = data.MessagesLength,
|
||||||
SystemTokens = data?.SystemTokens,
|
SystemTokens = data.SystemTokens,
|
||||||
ConversationTokens = data?.ConversationTokens,
|
ConversationTokens = data.ConversationTokens,
|
||||||
ToolDefinitionsTokens = data?.ToolDefinitionsTokens,
|
ToolDefinitionsTokens = data.ToolDefinitionsTokens,
|
||||||
IsInitial = data?.IsInitial,
|
IsInitial = data.IsInitial,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SessionCompactionEventDto CreateCompactionStartEvent(
|
private SessionCompactionEventDto CreateCompactionStartEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SessionCompactionStartData? data)
|
ProviderSessionCompactionStartEvent data)
|
||||||
{
|
{
|
||||||
return new SessionCompactionEventDto
|
return new SessionCompactionEventDto
|
||||||
{
|
{
|
||||||
@@ -623,15 +621,15 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
Phase = "start",
|
Phase = "start",
|
||||||
SystemTokens = data?.SystemTokens,
|
SystemTokens = data.SystemTokens,
|
||||||
ConversationTokens = data?.ConversationTokens,
|
ConversationTokens = data.ConversationTokens,
|
||||||
ToolDefinitionsTokens = data?.ToolDefinitionsTokens,
|
ToolDefinitionsTokens = data.ToolDefinitionsTokens,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private SessionCompactionEventDto CreateCompactionCompleteEvent(
|
private SessionCompactionEventDto CreateCompactionCompleteEvent(
|
||||||
AgentIdentity agent,
|
AgentIdentity agent,
|
||||||
SessionCompactionCompleteData? data)
|
ProviderSessionCompactionCompleteEvent data)
|
||||||
{
|
{
|
||||||
return new SessionCompactionEventDto
|
return new SessionCompactionEventDto
|
||||||
{
|
{
|
||||||
@@ -641,19 +639,19 @@ internal sealed class CopilotTurnExecutionState
|
|||||||
AgentId = agent.AgentId,
|
AgentId = agent.AgentId,
|
||||||
AgentName = agent.AgentName,
|
AgentName = agent.AgentName,
|
||||||
Phase = "complete",
|
Phase = "complete",
|
||||||
Success = data?.Success,
|
Success = data.Success,
|
||||||
Error = data?.Error,
|
Error = data.Error,
|
||||||
SystemTokens = data?.SystemTokens,
|
SystemTokens = data.SystemTokens,
|
||||||
ConversationTokens = data?.ConversationTokens,
|
ConversationTokens = data.ConversationTokens,
|
||||||
ToolDefinitionsTokens = data?.ToolDefinitionsTokens,
|
ToolDefinitionsTokens = data.ToolDefinitionsTokens,
|
||||||
PreCompactionTokens = data?.PreCompactionTokens,
|
PreCompactionTokens = data.PreCompactionTokens,
|
||||||
PostCompactionTokens = data?.PostCompactionTokens,
|
PostCompactionTokens = data.PostCompactionTokens,
|
||||||
PreCompactionMessagesLength = data?.PreCompactionMessagesLength,
|
PreCompactionMessagesLength = data.PreCompactionMessagesLength,
|
||||||
MessagesRemoved = data?.MessagesRemoved,
|
MessagesRemoved = data.MessagesRemoved,
|
||||||
TokensRemoved = data?.TokensRemoved,
|
TokensRemoved = data.TokensRemoved,
|
||||||
SummaryContent = data?.SummaryContent,
|
SummaryContent = data.SummaryContent,
|
||||||
CheckpointNumber = data?.CheckpointNumber,
|
CheckpointNumber = data.CheckpointNumber,
|
||||||
CheckpointPath = data?.CheckpointPath,
|
CheckpointPath = data.CheckpointPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public sealed class CopilotWorkflowRunner : ITurnWorkflowRunner
|
|||||||
throw new InvalidOperationException(validationError);
|
throw new InvalidOperationException(validationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IProviderEventAdapter providerEventAdapter = new CopilotEventAdapter();
|
||||||
CopilotTurnExecutionState state = new(command);
|
CopilotTurnExecutionState state = new(command);
|
||||||
using CancellationTokenSource runCancellation =
|
using CancellationTokenSource runCancellation =
|
||||||
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||||
@@ -70,7 +71,11 @@ public sealed class CopilotWorkflowRunner : ITurnWorkflowRunner
|
|||||||
runCancellation.Token),
|
runCancellation.Token),
|
||||||
(agent, sessionEvent) =>
|
(agent, sessionEvent) =>
|
||||||
{
|
{
|
||||||
state.ObserveSessionEvent(agent, sessionEvent);
|
if (providerEventAdapter.TryAdapt(sessionEvent) is { } providerEvent)
|
||||||
|
{
|
||||||
|
state.ObserveSessionEvent(agent, providerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionEvent is McpOauthRequiredEvent mcpOauthRequired)
|
if (sessionEvent is McpOauthRequiredEvent mcpOauthRequired)
|
||||||
{
|
{
|
||||||
state.EnqueuePendingMcpOauthRequest(
|
state.EnqueuePendingMcpOauthRequest(
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Aryx.AgentHost.Contracts;
|
||||||
|
|
||||||
|
namespace Aryx.AgentHost.Services;
|
||||||
|
|
||||||
|
internal interface IProviderEventAdapter
|
||||||
|
{
|
||||||
|
ProviderSessionEvent? TryAdapt(object rawEvent);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Aryx.AgentHost.Contracts;
|
||||||
|
using Aryx.AgentHost.Services;
|
||||||
|
using GitHub.Copilot.SDK;
|
||||||
|
|
||||||
|
namespace Aryx.AgentHost.Tests;
|
||||||
|
|
||||||
|
internal static class SessionEventTestExtensions
|
||||||
|
{
|
||||||
|
private static readonly IProviderEventAdapter ProviderEventAdapter = new CopilotEventAdapter();
|
||||||
|
|
||||||
|
public static void ObserveSessionEvent(
|
||||||
|
this CopilotTurnExecutionState state,
|
||||||
|
WorkflowNodeDto agentDefinition,
|
||||||
|
SessionEvent sessionEvent)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(state);
|
||||||
|
ArgumentNullException.ThrowIfNull(agentDefinition);
|
||||||
|
ArgumentNullException.ThrowIfNull(sessionEvent);
|
||||||
|
|
||||||
|
ProviderSessionEvent providerEvent = Assert.IsAssignableFrom<ProviderSessionEvent>(
|
||||||
|
ProviderEventAdapter.TryAdapt(sessionEvent));
|
||||||
|
|
||||||
|
state.ObserveSessionEvent(agentDefinition, providerEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user