Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/CodexSdk.MAF/CodexAIAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ protected override async Task<AgentResponse> RunCoreAsync(
break;
}

var update = threadEvent.ToAgentResponseUpdate();
var update = threadEvent.ToAgentResponseUpdate(_options.ThreadOptions.Model);
if (update?.ShouldReturnAsResponseMessage() == true)
{
responseMessages.Add(update.ToChatMessage());
Expand Down Expand Up @@ -174,7 +174,7 @@ protected override async IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingA
cancellationToken);
}

var update = threadEvent.ToAgentResponseUpdate();
var update = threadEvent.ToAgentResponseUpdate(_options.ThreadOptions.Model);
if (update is null)
{
continue;
Expand Down
2 changes: 1 addition & 1 deletion src/CodexSdk.MAF/Internal/AgentResponseUpdateExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static ChatMessage ToChatMessage([NotNull] this AgentResponseUpdate updat
return new ChatMessage
{
AdditionalProperties = update.AdditionalProperties,
AuthorName = update.AuthorName,
AuthorName = ThreadEventExtensions.AgentName,
Contents = update.Contents,
CreatedAt = update.CreatedAt,
MessageId = update.MessageId,
Expand Down
21 changes: 11 additions & 10 deletions src/CodexSdk.MAF/Internal/ThreadEventExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ namespace OpenAI.CodexSdk.MAF.Internal;

internal static class ThreadEventExtensions
{
private const string AgentName = "codex";
internal const string AgentName = "codex";
private const string ModelNamePropertyName = "modelName";
private const string CommandExecutionFunctionName = "command_execution";

public static AgentResponseUpdate? ToAgentResponseUpdate(this ThreadEvent threadEvent)
public static AgentResponseUpdate? ToAgentResponseUpdate(
this ThreadEvent threadEvent,
string? modelName = null)
{
var update = threadEvent switch
{
Expand All @@ -26,15 +29,17 @@ internal static class ThreadEventExtensions

if (update is not null)
{
if (string.IsNullOrWhiteSpace(update.AuthorName))
{
update.AuthorName = AgentName;
}
update.AuthorName = AgentName;
update.AdditionalProperties ??= [];
update.AdditionalProperties[ModelNamePropertyName] = NormalizeModelName(modelName);
}

return update;
}

private static string NormalizeModelName(string? modelName) =>
string.IsNullOrWhiteSpace(modelName) ? string.Empty : modelName.Trim();

public static UsageDetails ToUsageDetails(this Usage usage)
{
return new UsageDetails
Expand All @@ -54,7 +59,6 @@ private static AgentResponseUpdate CreateLifecycleUpdate(string eventType)
Role = ChatRole.System,
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "agentName", AgentName },
{ "type", eventType },
},
Contents = [new TextContent(eventType)],
Expand All @@ -68,7 +72,6 @@ private static AgentResponseUpdate CreateUsageUpdate(Usage usage)
Role = ChatRole.System,
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "agentName", AgentName },
{ "type", "turn.completed" },
},
Contents =
Expand All @@ -85,7 +88,6 @@ private static AgentResponseUpdate CreateErrorUpdate(string message, string even
Role = ChatRole.System,
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "agentName", AgentName },
{ "type", eventType },
},
Contents = [CreateErrorContent(message, terminal)],
Expand All @@ -101,7 +103,6 @@ private static AgentResponseUpdate CreateItemUpdate(string eventType, ThreadItem
Role = role,
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "agentName", AgentName },
{ "type", eventType },
{ "itemType", item.GetType().Name },
},
Expand Down
59 changes: 56 additions & 3 deletions tests/CodexSdk.MAF.Tests/ThreadEventExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.CodexSdk;
using OpenAI.CodexSdk.MAF.Internal;
Expand Down Expand Up @@ -71,6 +72,9 @@ public void ToAgentResponseUpdate_WhenCommandExecutionStartedEvent_ReturnsFuncti
Assert.NotNull(update);
Assert.Equal("item_3", update.MessageId);
Assert.Equal(ChatRole.Assistant, update.Role);
Assert.Equal("codex", update.AuthorName);
Assert.False(update.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal(string.Empty, update.AdditionalProperties["modelName"]);
var content = Assert.IsType<FunctionCallContent>(Assert.Single(update.Contents));
Assert.Equal("item_3", content.CallId);
Assert.Equal("command_execution", content.Name);
Expand All @@ -81,17 +85,60 @@ public void ToAgentResponseUpdate_WhenCommandExecutionStartedEvent_ReturnsFuncti
[Fact]
public void ToAgentResponseUpdate_WhenTurnStarts_ReturnsVisibleSystemContent()
{
var update = new TurnStartedEvent().ToAgentResponseUpdate();
var update = new TurnStartedEvent().ToAgentResponseUpdate("gpt-5.6-sol");

Assert.NotNull(update);
Assert.Equal(ChatRole.System, update.Role);
Assert.Equal("codex", update.AuthorName);
Assert.False(update.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal("gpt-5.6-sol", update.AdditionalProperties["modelName"]);
Assert.Equal("turn.started", update.AdditionalProperties!["type"]);
Assert.Equal("turn.started", Assert.IsType<TextContent>(Assert.Single(update.Contents)).Text);
Assert.True(update.ShouldReturnAsResponseMessage());
Assert.False(update.ShouldSaveAsResponseMessage());
}

[Theory]
[InlineData(" gpt-5.6-sol ", "gpt-5.6-sol")]
[InlineData(null, "")]
[InlineData(" ", "")]
public void ToAgentResponseUpdate_WhenAssistantItem_MapsConfiguredModelName(
string? configuredModel,
string expectedModelName)
{
// Arrange
var threadEvent = new ItemCompletedEvent
{
Item = new AgentMessageItem { Id = "message-1", Text = "done" },
};

// Act
var update = threadEvent.ToAgentResponseUpdate(configuredModel);
var persisted = update!.ToChatMessage();

// Assert
Assert.Equal(ChatRole.Assistant, update.Role);
Assert.Equal("codex", update.AuthorName);
Assert.False(update.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal(expectedModelName, update.AdditionalProperties["modelName"]);
Assert.Equal("codex", persisted.AuthorName);
Assert.False(persisted.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal(expectedModelName, persisted.AdditionalProperties!["modelName"]);
}

[Fact]
public void ToChatMessage_WhenUpdateAuthorIsMissing_UsesAgentName()
{
// Arrange
var update = new AgentResponseUpdate(ChatRole.Assistant, "done");

// Act
var message = update.ToChatMessage();

// Assert
Assert.Equal("codex", message.AuthorName);
}

[Fact]
public void ToAgentResponseUpdate_WhenTurnCompletes_MapsCompleteUsage()
{
Expand All @@ -108,10 +155,13 @@ public void ToAgentResponseUpdate_WhenTurnCompletes_MapsCompleteUsage()
};

// Act
var update = threadEvent.ToAgentResponseUpdate();
var update = threadEvent.ToAgentResponseUpdate("gpt-5.6-sol");

// Assert
Assert.NotNull(update);
Assert.Equal("codex", update.AuthorName);
Assert.False(update.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal("gpt-5.6-sol", update.AdditionalProperties["modelName"]);
var usage = Assert.IsType<UsageContent>(Assert.Single(update.Contents)).Details;
Assert.Equal(100L, usage.InputTokenCount);
Assert.Equal(60L, usage.CachedInputTokenCount);
Expand All @@ -136,11 +186,14 @@ public void ToAgentResponseUpdate_WhenCommandExecutionCompletedEvent_ReturnsFunc
},
};

var update = threadEvent.ToAgentResponseUpdate();
var update = threadEvent.ToAgentResponseUpdate("gpt-5.6-sol");

Assert.NotNull(update);
Assert.Equal("item_3", update.MessageId);
Assert.Equal(ChatRole.Tool, update.Role);
Assert.Equal("codex", update.AuthorName);
Assert.False(update.AdditionalProperties!.ContainsKey("agentName"));
Assert.Equal("gpt-5.6-sol", update.AdditionalProperties["modelName"]);
var content = Assert.IsType<FunctionResultContent>(Assert.Single(update.Contents));
Assert.Equal("item_3", content.CallId);
var result = Assert.IsType<Dictionary<string, object?>>(content.Result);
Expand Down