Repository: microsoft/semantic-kernel
File: dotnet/src/Agents/OpenAI/OpenAIResponseAgent.cs (C#)

Code before:
            {
                if (this.StoreEnabled)
                {
                    this.UpdateResponseId(agentThread, responseCompletedUpdate.Response.Id);
                }
                foreach (var item in responseCompletedUpdate.Response.OutputItems)
                {
                    history.Add(item.ToChatMessageContent());
                }
            }
        }
    }

    private ChatHistory GetChatHistory(AgentThread agentThread)
    {
        if (agentThread is ChatHistoryAgentThread chatHistoryAgentThread)
        {
            return chatHistoryAgentThread.ChatHistory;
        }

        throw new InvalidOperationException("The agent thread is not a ChatHistoryAgentThread.");
    }

    private void UpdateResponseId(AgentThread agentThread, string id)
    {
        if (agentThread is OpenAIResponseAgentThread openAIResponseAgentThread)
        {
            openAIResponseAgentThread.ResponseId = id;
            return;
        }

        throw new InvalidOperationException("The agent thread is not an OpenAIResponseAgentThread.");
    }
    #endregion
}


Review comment (suggestion):
Here, we should also invoke the OnIntermediateMessage callback on options if it is not null, so that users can also receive fully formed messages without having to assemble them manually from the streaming parts.

Code after:
        var creationOptions = new ResponseCreationOptions()
        {
            EndUserId = this.GetDisplayName(),
            Instructions = $"{this.Instructions}\n{options?.AdditionalInstructions}",
            StoredOutputEnabled = this.StoreEnabled,
        };
        if (this.StoreEnabled && agentThread.Id != null)
        {
            creationOptions.PreviousResponseId = agentThread.Id;
        }

        await foreach (StreamingResponseUpdate update in this.Client.CreateResponseStreamingAsync(inputItems, creationOptions, cancellationToken).ConfigureAwait(false))
        {
            if (update is StreamingResponseOutputTextDeltaUpdate outputTextUpdate)
            {
                yield return outputTextUpdate.ToStreamingChatMessageContent();
            }
            else if (update is StreamingResponseCompletedUpdate responseCompletedUpdate)
            {
                if (this.StoreEnabled)
                {
                    this.UpdateResponseId(agentThread, responseCompletedUpdate.Response.Id);
                }
                foreach (var item in responseCompletedUpdate.Response.OutputItems)
                {
                    history.Add(item.ToChatMessageContent());
                }
            }
        }
    }

    private ChatHistory GetChatHistory(AgentThread agentThread)
    {
        if (agentThread is ChatHistoryAgentThread chatHistoryAgentThread)
        {
            return chatHistoryAgentThread.ChatHistory;
        }

        throw new InvalidOperationException("The agent thread is not a ChatHistoryAgentThread.");
    }

    private void UpdateResponseId(AgentThread agentThread, string id)
    {
        if (agentThread is OpenAIResponseAgentThread openAIResponseAgentThread)
        {
            openAIResponseAgentThread.ResponseId = id;
            return;
        }

        throw new InvalidOperationException("The agent thread is not an OpenAIResponseAgentThread.");
    }