-
Notifications
You must be signed in to change notification settings - Fork 846
Add support for custom headers in HostedMcpServerTool #7053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add support for custom headers in HostedMcpServerTool #7053
Conversation
Introduces a Headers property to HostedMcpServerTool for specifying additional request headers. Updates OpenAIResponsesChatClient to pass these headers when creating MCP tools and adds unit tests to verify header roundtripping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for custom HTTP headers in HostedMcpServerTool, enabling users to specify additional request headers when communicating with remote MCP servers.
- Introduces a
Headersproperty of typeIDictionary<string, string>?to theHostedMcpServerToolclass - Updates
OpenAIResponsesChatClientto pass these headers to both variants ofResponseTool.CreateMcpTool() - Adds roundtrip tests to verify the Headers property can be set, retrieved, and cleared
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs | Adds the nullable Headers property with XML documentation |
| src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIResponsesChatClient.cs | Passes mcpTool.Headers parameter to both CreateMcpTool overloads (URI-based and connector ID-based) |
| test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Tools/HostedMcpServerToolTests.cs | Adds assertions to verify Headers can be set to a dictionary, retrieved, and reset to null |
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Tools/HostedMcpServerToolTests.cs
Show resolved
Hide resolved
|
@stephentoub any chance I can get an assignee on this one to help with getting it through? This is #7049 with the reverts. |
|
Thanks for your PR @echapmanFromBunnings. We originally pursued this API shape because OpenAI supported headers in the request, while Anthropic only supported passing an auth token. I initially took the broader approach and used a dictionary in Later, OpenAI added support for passing the token in the same way Anthropic does, which suggested to me that there might not be many use cases for headers beyond auth and that we don't need a headers dictionary in the class. For the sake of doing an informed decision, could you share more about what kinds of headers you need to pass to your MCP server? If we bring the headers dictionary back, we need to reconsider if we want to keep |
|
Hi @jozkee Since the MCP server essentially operates as an HTTP client, couldn’t we simply allow these headers to leverage the underlying protocol? In this context, headers are not being used for authentication, so encountering a header should not imply it is solely for that purpose. These are two distinct concerns and should be treated as such. |
| public HostedMcpServerToolApprovalMode? ApprovalMode { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets additional headers to include in requests to the remote MCP server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the previous version of this:
| /// Gets or sets additional headers to include in requests to the remote MCP server. | |
| /// Gets or sets the HTTP headers that the AI service should use when calling the remote MCP server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to add <remarks> mentioning that some providers may return an error if both AuthorizationToken and an "authorization" header are specified? This is the case for OpenAI.
$ curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"tools": [
{
"type": "mcp",
"server_label": "gh",
"server_url": "https://api.githubcopilot.com/mcp",
"authorization": "github_pat_123",
"headers": { "Authorization": "Bearer github_pat_123" }
}
],
"input": "What tools are available?"
}'{
"error": {
"message": "Cannot specify both 'authorization' parameter and 'Authorization' header.",
"type": "invalid_request_error",
"param": "headers",
"code": null
}
}| url, | ||
| mcpTool.AuthorizationToken, | ||
| mcpTool.ServerDescription) : | ||
| mcpTool.ServerDescription, mcpTool.Headers) : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| mcpTool.ServerDescription, mcpTool.Headers) : | |
| mcpTool.ServerDescription, | |
| mcpTool.Headers) : |
| new McpToolConnectorId(mcpTool.ServerAddress), | ||
| mcpTool.AuthorizationToken, | ||
| mcpTool.ServerDescription); | ||
| mcpTool.ServerDescription, mcpTool.Headers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| mcpTool.ServerDescription, mcpTool.Headers); | |
| mcpTool.ServerDescription, | |
| mcpTool.Headers); |
|
CI errors are about CompatibilitySuppression.xml since we are bringing the property back. I suspect we need to remove them from: extensions/src/Libraries/Microsoft.Extensions.AI.Abstractions/CompatibilitySuppressions.xml Lines 25 to 45 in 1ab483a
cc @joperezr |
Deleted baseline suppressions for the Headers property and its setter in HostedMcpServerTool from CompatibilitySuppressions.xml.
Expanded XML documentation for the Headers property in HostedMcpServerTool to clarify usage and behavior. Minor formatting adjustments in OpenAIResponsesChatClient for MCP tool creation calls.
|
Addressed all PR comments, and added extensive documents on that headers prop @jozkee |
Deleted baseline suppressions for get_Headers and set_Headers members of HostedMcpServerTool across net8.0, net9.0, and netstandard2.0. This likely reflects removal or resolution of related compatibility issues.
…manFromBunnings/extensions into AddHeaderToMcpToolCreation
src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs
Show resolved
Hide resolved
| /// <para> | ||
| /// The underlying provider may respond with an error if <see cref="AuthorizationToken"/> is set and an Authorization header is included. | ||
| /// </para> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a provider would have problems with that, wouldn't it be better for it to just not send the auth header? Basically say that if AuthorizationToken is set, any Authorization header in Headers may be ignored, or alternatively say that AuthorizationToken may be ignored if Headers contains an Authorization header?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, what's the benefit of having both? If we only had Headers, is that not sufficient? The token can be extracted from an auth header.
It feels awkward having both, like there are two possible sources of truth. (At the same time I understand that for the common case, having the simple AuthorizationToken property is simpler.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we only had Headers, is that not sufficient?
It is sufficient but it still creates friction with Claude and OpenAI Connectors that only support Authorization Tokens. Converting the Authorization HTTP Header implies trimming the "Bearer " prefix.
If a provider would have problems with that, wouldn't it be better for it to just not send the auth header? Basically say that if AuthorizationToken is set, any Authorization header in Headers may be ignored, or alternatively say that AuthorizationToken may be ignored if Headers contains an Authorization header?
That would mean us (MEAI) deciding for users and providers in this behavior. My thinking was that is better to simply rely what was given to us to the provider. If we are going to decide how to handle this in MEAI.OpenAI I would rather choose throwing to signal there's a bug, which aligns with OpenAI's current behavior.
| public HostedMcpServerToolApprovalMode? ApprovalMode { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the HTTP headers that the AI service could use when calling the remote MCP server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// Gets or sets the HTTP headers that the AI service could use when calling the remote MCP server. | |
| /// Gets or sets HTTP headers to include when calling the remote MCP server. |
| mcpTool.AuthorizationToken, | ||
| mcpTool.ServerDescription); | ||
| mcpTool.ServerDescription, | ||
| mcpTool.Headers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be validating these with unit tests, ala
extensions/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientTests.cs
Lines 1190 to 2140 in e9b33a7
| [Theory] | |
| [InlineData("user")] | |
| [InlineData("tool")] | |
| public async Task McpToolCall_ApprovalRequired_NonStreaming(string role) | |
| { | |
| string input = """ | |
| { | |
| "model": "gpt-4o-mini", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/mcp" | |
| } | |
| ], | |
| "tool_choice": "auto", | |
| "input": [ | |
| { | |
| "type": "message", | |
| "role": "user", | |
| "content": [ | |
| { | |
| "type": "input_text", | |
| "text": "Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| """; | |
| string output = """ | |
| { | |
| "id": "resp_04e29d5bdd80bd9f0068e6b01f786081a29148febb92892aee", | |
| "object": "response", | |
| "created_at": 1759948831, | |
| "status": "completed", | |
| "background": false, | |
| "error": null, | |
| "incomplete_details": null, | |
| "instructions": null, | |
| "max_output_tokens": null, | |
| "max_tool_calls": null, | |
| "model": "gpt-4o-mini-2024-07-18", | |
| "output": [ | |
| { | |
| "id": "mcpr_04e29d5bdd80bd9f0068e6b022a9c081a2ae898104b7a75051", | |
| "type": "mcp_approval_request", | |
| "arguments": "{\"repoName\":\"dotnet/extensions\"}", | |
| "name": "ask_question", | |
| "server_label": "deepwiki" | |
| } | |
| ], | |
| "parallel_tool_calls": true, | |
| "previous_response_id": null, | |
| "prompt_cache_key": null, | |
| "reasoning": { | |
| "effort": null, | |
| "summary": null | |
| }, | |
| "safety_identifier": null, | |
| "service_tier": "default", | |
| "store": true, | |
| "temperature": 1.0, | |
| "text": { | |
| "format": { | |
| "type": "text" | |
| }, | |
| "verbosity": "medium" | |
| }, | |
| "tool_choice": "auto", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "allowed_tools": null, | |
| "headers": null, | |
| "require_approval": "always", | |
| "server_description": null, | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/<redacted>" | |
| } | |
| ], | |
| "top_logprobs": 0, | |
| "top_p": 1.0, | |
| "truncation": "disabled", | |
| "usage": { | |
| "input_tokens": 193, | |
| "input_tokens_details": { | |
| "cached_tokens": 0 | |
| }, | |
| "output_tokens": 23, | |
| "output_tokens_details": { | |
| "reasoning_tokens": 0 | |
| }, | |
| "total_tokens": 216 | |
| }, | |
| "user": null, | |
| "metadata": {} | |
| } | |
| """; | |
| var chatOptions = new ChatOptions | |
| { | |
| Tools = [new HostedMcpServerTool("deepwiki", new Uri("https://mcp.deepwiki.com/mcp"))] | |
| }; | |
| McpServerToolApprovalRequestContent approvalRequest; | |
| using (VerbatimHttpHandler handler = new(input, output)) | |
| using (HttpClient httpClient = new(handler)) | |
| using (IChatClient client = CreateResponseClient(httpClient, "gpt-4o-mini")) | |
| { | |
| var response = await client.GetResponseAsync( | |
| "Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository", | |
| chatOptions); | |
| approvalRequest = Assert.Single(response.Messages.SelectMany(m => m.Contents).OfType<McpServerToolApprovalRequestContent>()); | |
| chatOptions.ConversationId = response.ConversationId; | |
| } | |
| input = $$""" | |
| { | |
| "previous_response_id": "resp_04e29d5bdd80bd9f0068e6b01f786081a29148febb92892aee", | |
| "model": "gpt-4o-mini", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/mcp" | |
| } | |
| ], | |
| "tool_choice": "auto", | |
| "input": [ | |
| { | |
| "type": "mcp_approval_response", | |
| "approval_request_id": "mcpr_04e29d5bdd80bd9f0068e6b022a9c081a2ae898104b7a75051", | |
| "approve": true | |
| } | |
| ] | |
| } | |
| """; | |
| output = """ | |
| { | |
| "id": "resp_06ee3b1962eeb8470068e6b21c377081a3a20dbf60eee7a736", | |
| "object": "response", | |
| "created_at": 1759949340, | |
| "status": "completed", | |
| "background": false, | |
| "error": null, | |
| "incomplete_details": null, | |
| "instructions": null, | |
| "max_output_tokens": null, | |
| "max_tool_calls": null, | |
| "model": "gpt-4o-mini-2024-07-18", | |
| "output": [ | |
| { | |
| "id": "mcp_06ee3b1962eeb8470068e6b21cbaa081a3b5aa2a6c989f4c6f", | |
| "type": "mcp_call", | |
| "status": "completed", | |
| "approval_request_id": "mcpr_06ee3b1962eeb8470068e6b192985c81a383a16059ecd8230e", | |
| "arguments": "{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}", | |
| "error": null, | |
| "name": "ask_question", | |
| "output": "The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` within the `dotnet/extensions` repository. This file provides an overview of the package, including installation instructions and usage examples for its core interfaces like `IChatClient` and `IEmbeddingGenerator`. \n\n## Path to README.md\n\nThe specific path to the `README.md` file for the `Microsoft.Extensions.AI.Abstractions` project is `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md`. This path is also referenced in the `AI Extensions Framework` wiki page as a relevant source file. \n\n## Notes\n\nThe `Packaging.targets` file in the `eng/MSBuild` directory indicates that `README.md` files are included in packages when `IsPackable` and `IsShipping` properties are true. This suggests that the `README.md` file located at `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` is intended to be part of the distributed NuGet package for `Microsoft.Extensions.AI.Abstractions`. \n\nWiki pages you might want to explore:\n- [AI Extensions Framework (dotnet/extensions)](/wiki/dotnet/extensions#3)\n- [Chat Completion (dotnet/extensions)](/wiki/dotnet/extensions#3.3)\n\nView this search on DeepWiki: https://deepwiki.com/search/what-is-the-path-to-the-readme_315595bd-9b39-4f04-9fa3-42dc778fa9f3\n", | |
| "server_label": "deepwiki" | |
| }, | |
| { | |
| "id": "msg_06ee3b1962eeb8470068e6b226ab0081a39fccce9aa47aedbc", | |
| "type": "message", | |
| "status": "completed", | |
| "content": [ | |
| { | |
| "type": "output_text", | |
| "annotations": [], | |
| "logprobs": [], | |
| "text": "The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the `Microsoft.Extensions.AI.Abstractions` package, including installation instructions and usage examples for its core interfaces like `IChatClient` and `IEmbeddingGenerator`." | |
| } | |
| ], | |
| "role": "assistant" | |
| } | |
| ], | |
| "parallel_tool_calls": true, | |
| "previous_response_id": "resp_06ee3b1962eeb8470068e6b18e0db881a3bdfd255a60327cdc", | |
| "prompt_cache_key": null, | |
| "reasoning": { | |
| "effort": null, | |
| "summary": null | |
| }, | |
| "safety_identifier": null, | |
| "service_tier": "default", | |
| "store": true, | |
| "temperature": 1.0, | |
| "text": { | |
| "format": { | |
| "type": "text" | |
| }, | |
| "verbosity": "medium" | |
| }, | |
| "tool_choice": "auto", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "allowed_tools": null, | |
| "headers": null, | |
| "require_approval": "always", | |
| "server_description": null, | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/<redacted>" | |
| } | |
| ], | |
| "top_logprobs": 0, | |
| "top_p": 1.0, | |
| "truncation": "disabled", | |
| "usage": { | |
| "input_tokens": 542, | |
| "input_tokens_details": { | |
| "cached_tokens": 0 | |
| }, | |
| "output_tokens": 72, | |
| "output_tokens_details": { | |
| "reasoning_tokens": 0 | |
| }, | |
| "total_tokens": 614 | |
| }, | |
| "user": null, | |
| "metadata": {} | |
| } | |
| """; | |
| using (VerbatimHttpHandler handler = new(input, output)) | |
| using (HttpClient httpClient = new(handler)) | |
| using (IChatClient client = CreateResponseClient(httpClient, "gpt-4o-mini")) | |
| { | |
| var response = await client.GetResponseAsync( | |
| new ChatMessage(new ChatRole(role), [approvalRequest.CreateResponse(true)]), chatOptions); | |
| Assert.NotNull(response); | |
| Assert.Equal("resp_06ee3b1962eeb8470068e6b21c377081a3a20dbf60eee7a736", response.ResponseId); | |
| Assert.Equal("resp_06ee3b1962eeb8470068e6b21c377081a3a20dbf60eee7a736", response.ConversationId); | |
| Assert.Equal("gpt-4o-mini-2024-07-18", response.ModelId); | |
| Assert.Equal(DateTimeOffset.FromUnixTimeSeconds(1_759_949_340), response.CreatedAt); | |
| Assert.Null(response.FinishReason); | |
| var message = Assert.Single(response.Messages); | |
| Assert.Equal(ChatRole.Assistant, response.Messages[0].Role); | |
| Assert.Equal("The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the `Microsoft.Extensions.AI.Abstractions` package, including installation instructions and usage examples for its core interfaces like `IChatClient` and `IEmbeddingGenerator`.", response.Messages[0].Text); | |
| Assert.Equal(3, message.Contents.Count); | |
| var call = Assert.IsType<McpServerToolCallContent>(message.Contents[0]); | |
| Assert.Equal("mcp_06ee3b1962eeb8470068e6b21cbaa081a3b5aa2a6c989f4c6f", call.CallId); | |
| Assert.Equal("deepwiki", call.ServerName); | |
| Assert.Equal("ask_question", call.ToolName); | |
| Assert.NotNull(call.Arguments); | |
| Assert.Equal(2, call.Arguments.Count); | |
| Assert.Equal("dotnet/extensions", ((JsonElement)call.Arguments["repoName"]!).GetString()); | |
| Assert.Equal("What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?", ((JsonElement)call.Arguments["question"]!).GetString()); | |
| var result = Assert.IsType<McpServerToolResultContent>(message.Contents[1]); | |
| Assert.Equal("mcp_06ee3b1962eeb8470068e6b21cbaa081a3b5aa2a6c989f4c6f", result.CallId); | |
| Assert.NotNull(result.Output); | |
| Assert.StartsWith("The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at", Assert.IsType<TextContent>(Assert.Single(result.Output)).Text); | |
| Assert.NotNull(response.Usage); | |
| Assert.Equal(542, response.Usage.InputTokenCount); | |
| Assert.Equal(72, response.Usage.OutputTokenCount); | |
| Assert.Equal(614, response.Usage.TotalTokenCount); | |
| } | |
| } | |
| [Theory] | |
| [InlineData(false)] | |
| [InlineData(true)] | |
| public async Task McpToolCall_ApprovalNotRequired_NonStreaming(bool rawTool) | |
| { | |
| const string Input = """ | |
| { | |
| "model": "gpt-4o-mini", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/mcp", | |
| "require_approval": "never" | |
| } | |
| ], | |
| "tool_choice": "auto", | |
| "input": [ | |
| { | |
| "type": "message", | |
| "role": "user", | |
| "content": [ | |
| { | |
| "type": "input_text", | |
| "text": "Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| """; | |
| const string Output = """ | |
| { | |
| "id": "resp_68be416397ec81918c48ef286530b8140384f747588fc3f5", | |
| "object": "response", | |
| "created_at": 1757299043, | |
| "status": "completed", | |
| "background": false, | |
| "error": null, | |
| "incomplete_details": null, | |
| "instructions": null, | |
| "max_output_tokens": null, | |
| "max_tool_calls": null, | |
| "model": "gpt-4o-mini-2024-07-18", | |
| "output": [ | |
| { | |
| "id": "mcpl_68be4163aa80819185e792abdcde71670384f747588fc3f5", | |
| "type": "mcp_list_tools", | |
| "server_label": "deepwiki", | |
| "tools": [ | |
| { | |
| "annotations": { | |
| "read_only": false | |
| }, | |
| "description": "Get a list of documentation topics for a GitHub repository", | |
| "input_schema": { | |
| "type": "object", | |
| "properties": { | |
| "repoName": { | |
| "type": "string", | |
| "description": "GitHub repository: owner/repo (e.g. \"facebook/react\")" | |
| } | |
| }, | |
| "required": [ | |
| "repoName" | |
| ], | |
| "additionalProperties": false, | |
| "$schema": "http://json-schema.org/draft-07/schema#" | |
| }, | |
| "name": "read_wiki_structure" | |
| }, | |
| { | |
| "annotations": { | |
| "read_only": false | |
| }, | |
| "description": "View documentation about a GitHub repository", | |
| "input_schema": { | |
| "type": "object", | |
| "properties": { | |
| "repoName": { | |
| "type": "string", | |
| "description": "GitHub repository: owner/repo (e.g. \"facebook/react\")" | |
| } | |
| }, | |
| "required": [ | |
| "repoName" | |
| ], | |
| "additionalProperties": false, | |
| "$schema": "http://json-schema.org/draft-07/schema#" | |
| }, | |
| "name": "read_wiki_contents" | |
| }, | |
| { | |
| "annotations": { | |
| "read_only": false | |
| }, | |
| "description": "Ask any question about a GitHub repository", | |
| "input_schema": { | |
| "type": "object", | |
| "properties": { | |
| "repoName": { | |
| "type": "string", | |
| "description": "GitHub repository: owner/repo (e.g. \"facebook/react\")" | |
| }, | |
| "question": { | |
| "type": "string", | |
| "description": "The question to ask about the repository" | |
| } | |
| }, | |
| "required": [ | |
| "repoName", | |
| "question" | |
| ], | |
| "additionalProperties": false, | |
| "$schema": "http://json-schema.org/draft-07/schema#" | |
| }, | |
| "name": "ask_question" | |
| } | |
| ] | |
| }, | |
| { | |
| "id": "mcp_68be4166acfc8191bc5e0a751eed358b0384f747588fc3f5", | |
| "type": "mcp_call", | |
| "approval_request_id": null, | |
| "arguments": "{\"repoName\":\"dotnet/extensions\"}", | |
| "error": null, | |
| "name": "read_wiki_structure", | |
| "output": "Available pages for dotnet/extensions:\n\n- 1 Overview\n- 2 Build System and CI/CD\n- 3 AI Extensions Framework\n - 3.1 Core Abstractions\n - 3.2 AI Function System\n - 3.3 Chat Completion\n - 3.4 Caching System\n - 3.5 Evaluation and Reporting\n- 4 HTTP Resilience and Diagnostics\n - 4.1 Standard Resilience\n - 4.2 Hedging Strategies\n- 5 Telemetry and Compliance\n- 6 Testing Infrastructure\n - 6.1 AI Service Integration Testing\n - 6.2 Time Provider Testing", | |
| "server_label": "deepwiki" | |
| }, | |
| { | |
| "id": "mcp_68be416900f88191837ae0718339a4ce0384f747588fc3f5", | |
| "type": "mcp_call", | |
| "approval_request_id": null, | |
| "arguments": "{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}", | |
| "error": null, | |
| "name": "ask_question", | |
| "output": "The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` within the `dotnet/extensions` repository. This file provides an overview of the `Microsoft.Extensions.AI.Abstractions` package, including installation instructions and usage examples for its core interfaces like `IChatClient` and `IEmbeddingGenerator`. \n\n## Path to README.md\n\nThe specific path to the `README.md` file for the `Microsoft.Extensions.AI.Abstractions` project is `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md`. This path is also referenced in the `AI Extensions Framework` wiki page as a relevant source file. \n\n## Notes\n\nThe `Packaging.targets` file in the `eng/MSBuild` directory indicates that `README.md` files are included in packages when `IsPackable` and `IsShipping` properties are true. This suggests that the `README.md` file located at `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` is intended to be part of the distributed NuGet package for `Microsoft.Extensions.AI.Abstractions`. \n\nWiki pages you might want to explore:\n- [AI Extensions Framework (dotnet/extensions)](/wiki/dotnet/extensions#3)\n- [Chat Completion (dotnet/extensions)](/wiki/dotnet/extensions#3.3)\n\nView this search on DeepWiki: https://deepwiki.com/search/what-is-the-path-to-the-readme_315595bd-9b39-4f04-9fa3-42dc778fa9f3\n", | |
| "server_label": "deepwiki" | |
| }, | |
| { | |
| "id": "msg_68be416fb43c819194a1d4ace2643a7e0384f747588fc3f5", | |
| "type": "message", | |
| "status": "completed", | |
| "content": [ | |
| { | |
| "type": "output_text", | |
| "annotations": [], | |
| "logprobs": [], | |
| "text": "The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file includes an overview, installation instructions, and usage examples related to the package." | |
| } | |
| ], | |
| "role": "assistant" | |
| } | |
| ], | |
| "parallel_tool_calls": true, | |
| "previous_response_id": null, | |
| "prompt_cache_key": null, | |
| "reasoning": { | |
| "effort": null, | |
| "summary": null | |
| }, | |
| "safety_identifier": null, | |
| "service_tier": "default", | |
| "store": true, | |
| "temperature": 1, | |
| "text": { | |
| "format": { | |
| "type": "text" | |
| }, | |
| "verbosity": "medium" | |
| }, | |
| "tool_choice": "auto", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "allowed_tools": null, | |
| "headers": null, | |
| "require_approval": "never", | |
| "server_description": null, | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/<redacted>" | |
| } | |
| ], | |
| "top_logprobs": 0, | |
| "top_p": 1, | |
| "truncation": "disabled", | |
| "usage": { | |
| "input_tokens": 1329, | |
| "input_tokens_details": { | |
| "cached_tokens": 0 | |
| }, | |
| "output_tokens": 123, | |
| "output_tokens_details": { | |
| "reasoning_tokens": 0 | |
| }, | |
| "total_tokens": 1452 | |
| }, | |
| "user": null, | |
| "metadata": {} | |
| } | |
| """; | |
| using VerbatimHttpHandler handler = new(Input, Output); | |
| using HttpClient httpClient = new(handler); | |
| using IChatClient client = CreateResponseClient(httpClient, "gpt-4o-mini"); | |
| AITool mcpTool = rawTool ? | |
| ResponseTool.CreateMcpTool("deepwiki", serverUri: new("https://mcp.deepwiki.com/mcp"), toolCallApprovalPolicy: new McpToolCallApprovalPolicy(GlobalMcpToolCallApprovalPolicy.NeverRequireApproval)).AsAITool() : | |
| new HostedMcpServerTool("deepwiki", new Uri("https://mcp.deepwiki.com/mcp")) | |
| { | |
| ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire, | |
| }; | |
| ChatOptions chatOptions = new() | |
| { | |
| Tools = [mcpTool], | |
| }; | |
| var response = await client.GetResponseAsync("Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository", chatOptions); | |
| Assert.NotNull(response); | |
| Assert.Equal("resp_68be416397ec81918c48ef286530b8140384f747588fc3f5", response.ResponseId); | |
| Assert.Equal("resp_68be416397ec81918c48ef286530b8140384f747588fc3f5", response.ConversationId); | |
| Assert.Equal("gpt-4o-mini-2024-07-18", response.ModelId); | |
| Assert.Equal(DateTimeOffset.FromUnixTimeSeconds(1_757_299_043), response.CreatedAt); | |
| Assert.Null(response.FinishReason); | |
| var message = Assert.Single(response.Messages); | |
| Assert.Equal(ChatRole.Assistant, response.Messages[0].Role); | |
| Assert.Equal("The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file includes an overview, installation instructions, and usage examples related to the package.", response.Messages[0].Text); | |
| Assert.Equal(6, message.Contents.Count); | |
| var firstCall = Assert.IsType<McpServerToolCallContent>(message.Contents[1]); | |
| Assert.Equal("mcp_68be4166acfc8191bc5e0a751eed358b0384f747588fc3f5", firstCall.CallId); | |
| Assert.Equal("deepwiki", firstCall.ServerName); | |
| Assert.Equal("read_wiki_structure", firstCall.ToolName); | |
| Assert.NotNull(firstCall.Arguments); | |
| Assert.Single(firstCall.Arguments); | |
| Assert.Equal("dotnet/extensions", ((JsonElement)firstCall.Arguments["repoName"]!).GetString()); | |
| var firstResult = Assert.IsType<McpServerToolResultContent>(message.Contents[2]); | |
| Assert.Equal("mcp_68be4166acfc8191bc5e0a751eed358b0384f747588fc3f5", firstResult.CallId); | |
| Assert.NotNull(firstResult.Output); | |
| Assert.StartsWith("Available pages for dotnet/extensions", Assert.IsType<TextContent>(Assert.Single(firstResult.Output)).Text); | |
| var secondCall = Assert.IsType<McpServerToolCallContent>(message.Contents[3]); | |
| Assert.Equal("mcp_68be416900f88191837ae0718339a4ce0384f747588fc3f5", secondCall.CallId); | |
| Assert.Equal("deepwiki", secondCall.ServerName); | |
| Assert.Equal("ask_question", secondCall.ToolName); | |
| Assert.NotNull(secondCall.Arguments); | |
| Assert.Equal("dotnet/extensions", ((JsonElement)secondCall.Arguments["repoName"]!).GetString()); | |
| Assert.Equal("What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?", ((JsonElement)secondCall.Arguments["question"]!).GetString()); | |
| var secondResult = Assert.IsType<McpServerToolResultContent>(message.Contents[4]); | |
| Assert.Equal("mcp_68be416900f88191837ae0718339a4ce0384f747588fc3f5", secondResult.CallId); | |
| Assert.NotNull(secondResult.Output); | |
| Assert.StartsWith("The `README.md` file for `Microsoft.Extensions.AI.Abstractions` is located at", Assert.IsType<TextContent>(Assert.Single(secondResult.Output)).Text); | |
| Assert.NotNull(response.Usage); | |
| Assert.Equal(1329, response.Usage.InputTokenCount); | |
| Assert.Equal(123, response.Usage.OutputTokenCount); | |
| Assert.Equal(1452, response.Usage.TotalTokenCount); | |
| } | |
| [Fact] | |
| public async Task McpToolCall_ApprovalNotRequired_Streaming() | |
| { | |
| const string Input = """ | |
| { | |
| "model": "gpt-4o-mini", | |
| "tools": [ | |
| { | |
| "type": "mcp", | |
| "server_label": "deepwiki", | |
| "server_url": "https://mcp.deepwiki.com/mcp", | |
| "require_approval": "never" | |
| } | |
| ], | |
| "tool_choice": "auto", | |
| "input": [ | |
| { | |
| "type": "message", | |
| "role": "user", | |
| "content": [ | |
| { | |
| "type": "input_text", | |
| "text": "Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository" | |
| } | |
| ] | |
| } | |
| ], | |
| "stream": true | |
| } | |
| """; | |
| const string Output = """ | |
| event: response.created | |
| data: {"type":"response.created","sequence_number":0,"response":{"id":"resp_68be44fd7298819e82fd82c8516e970d03a2537be0e84a54","object":"response","created_at":1757299965,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"mcp","allowed_tools":null,"headers":null,"require_approval":"never","server_description":null,"server_label":"deepwiki","server_url":"https://mcp.deepwiki.com/<redacted>"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} | |
| event: response.in_progress | |
| data: {"type":"response.in_progress","sequence_number":1,"response":{"id":"resp_68be44fd7298819e82fd82c8516e970d03a2537be0e84a54","object":"response","created_at":1757299965,"status":"in_progress","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"mcp","allowed_tools":null,"headers":null,"require_approval":"never","server_description":null,"server_label":"deepwiki","server_url":"https://mcp.deepwiki.com/<redacted>"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}} | |
| event: response.output_item.added | |
| data: {"type":"response.output_item.added","sequence_number":2,"output_index":0,"item":{"id":"mcpl_68be44fd8f68819eba7a74a2f6d27a5a03a2537be0e84a54","type":"mcp_list_tools","server_label":"deepwiki","tools":[]}} | |
| event: response.mcp_list_tools.in_progress | |
| data: {"type":"response.mcp_list_tools.in_progress","sequence_number":3,"output_index":0,"item_id":"mcpl_68be44fd8f68819eba7a74a2f6d27a5a03a2537be0e84a54"} | |
| event: response.mcp_list_tools.completed | |
| data: {"type":"response.mcp_list_tools.completed","sequence_number":4,"output_index":0,"item_id":"mcpl_68be44fd8f68819eba7a74a2f6d27a5a03a2537be0e84a54"} | |
| event: response.output_item.done | |
| data: {"type":"response.output_item.done","sequence_number":5,"output_index":0,"item":{"id":"mcpl_68be44fd8f68819eba7a74a2f6d27a5a03a2537be0e84a54","type":"mcp_list_tools","server_label":"deepwiki","tools":[{"annotations":{"read_only":false},"description":"Get a list of documentation topics for a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"}},"required":["repoName"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"read_wiki_structure"},{"annotations":{"read_only":false},"description":"View documentation about a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"}},"required":["repoName"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"read_wiki_contents"},{"annotations":{"read_only":false},"description":"Ask any question about a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"},"question":{"type":"string","description":"The question to ask about the repository"}},"required":["repoName","question"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"ask_question"}]}} | |
| event: response.output_item.added | |
| data: {"type":"response.output_item.added","sequence_number":6,"output_index":1,"item":{"id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"","error":null,"name":"read_wiki_structure","output":null,"server_label":"deepwiki"}} | |
| event: response.mcp_call.in_progress | |
| data: {"type":"response.mcp_call.in_progress","sequence_number":7,"output_index":1,"item_id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54"} | |
| event: response.mcp_call_arguments.delta | |
| data: {"type":"response.mcp_call_arguments.delta","sequence_number":8,"output_index":1,"item_id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54","delta":"{\"repoName\":\"dotnet/extensions\"}","obfuscation":""} | |
| event: response.mcp_call_arguments.done | |
| data: {"type":"response.mcp_call_arguments.done","sequence_number":9,"output_index":1,"item_id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54","arguments":"{\"repoName\":\"dotnet/extensions\"}"} | |
| event: response.mcp_call.completed | |
| data: {"type":"response.mcp_call.completed","sequence_number":10,"output_index":1,"item_id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54"} | |
| event: response.output_item.done | |
| data: {"type":"response.output_item.done","sequence_number":11,"output_index":1,"item":{"id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"{\"repoName\":\"dotnet/extensions\"}","error":null,"name":"read_wiki_structure","output":"Available pages for dotnet/extensions:\n\n- 1 Overview\n- 2 Build System and CI/CD\n- 3 AI Extensions Framework\n - 3.1 Core Abstractions\n - 3.2 AI Function System\n - 3.3 Chat Completion\n - 3.4 Caching System\n - 3.5 Evaluation and Reporting\n- 4 HTTP Resilience and Diagnostics\n - 4.1 Standard Resilience\n - 4.2 Hedging Strategies\n- 5 Telemetry and Compliance\n- 6 Testing Infrastructure\n - 6.1 AI Service Integration Testing\n - 6.2 Time Provider Testing","server_label":"deepwiki"}} | |
| event: response.output_item.added | |
| data: {"type":"response.output_item.added","sequence_number":12,"output_index":2,"item":{"id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"","error":null,"name":"ask_question","output":null,"server_label":"deepwiki"}} | |
| event: response.mcp_call.in_progress | |
| data: {"type":"response.mcp_call.in_progress","sequence_number":13,"output_index":2,"item_id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54"} | |
| event: response.mcp_call_arguments.delta | |
| data: {"type":"response.mcp_call_arguments.delta","sequence_number":14,"output_index":2,"item_id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54","delta":"{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}","obfuscation":"IT"} | |
| event: response.mcp_call_arguments.done | |
| data: {"type":"response.mcp_call_arguments.done","sequence_number":15,"output_index":2,"item_id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54","arguments":"{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}"} | |
| event: response.mcp_call.completed | |
| data: {"type":"response.mcp_call.completed","sequence_number":16,"output_index":2,"item_id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54"} | |
| event: response.output_item.done | |
| data: {"type":"response.output_item.done","sequence_number":17,"output_index":2,"item":{"id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}","error":null,"name":"ask_question","output":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` is `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` . This file provides an overview of the `Microsoft.Extensions.AI.Abstractions` library, including installation instructions and usage examples for its core components like `IChatClient` and `IEmbeddingGenerator` .\n\n## README.md Content Overview\nThe `README.md` file for `Microsoft.Extensions.AI.Abstractions` details the purpose of the library, which is to provide abstractions for generative AI components . It includes instructions on how to install the NuGet package `Microsoft.Extensions.AI.Abstractions` .\n\nThe document also provides usage examples for the `IChatClient` interface, which defines methods for interacting with AI services that offer \"chat\" capabilities . This includes examples for requesting both complete and streaming chat responses .\n\nFurthermore, the `README.md` explains the `IEmbeddingGenerator` interface, which is used for generating vector embeddings from input values . It demonstrates how to use `GenerateAsync` to create embeddings . The file also discusses how both `IChatClient` and `IEmbeddingGenerator` implementations can be layered to create pipelines of functionality, incorporating features like caching and telemetry .\n\nNotes:\nThe user's query specifically asked for the path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions`. The provided codebase context, particularly the wiki page for \"AI Extensions Framework\", directly lists this file as a relevant source file . The content of the `README.md` file itself further confirms its relevance to the `Microsoft.Extensions.AI.Abstractions` library.\n\nWiki pages you might want to explore:\n- [AI Extensions Framework (dotnet/extensions)](/wiki/dotnet/extensions#3)\n- [Chat Completion (dotnet/extensions)](/wiki/dotnet/extensions#3.3)\n\nView this search on DeepWiki: https://deepwiki.com/search/what-is-the-path-to-the-readme_bb6bee43-3136-4b21-bc5d-02ca1611d857\n","server_label":"deepwiki"}} | |
| event: response.output_item.added | |
| data: {"type":"response.output_item.added","sequence_number":18,"output_index":3,"item":{"id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","type":"message","status":"in_progress","content":[],"role":"assistant"}} | |
| event: response.content_part.added | |
| data: {"type":"response.content_part.added","sequence_number":19,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""}} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":20,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"The","logprobs":[],"obfuscation":"a5sNdjeWpJXIK"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":21,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" path","logprobs":[],"obfuscation":"2oWbALsHrtv"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":22,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"K8lRBCaiusvjP"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":23,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"LP7Xp4jDWA5w"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":24,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" `","logprobs":[],"obfuscation":"2rUNEj0h3wLlee"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":25,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"README","logprobs":[],"obfuscation":"PSbOrCj8y6"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":26,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".md","logprobs":[],"obfuscation":"Do0BCY4kJ6wQW"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":27,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"`","logprobs":[],"obfuscation":"3fTPkjHu1Oq83DT"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":28,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" file","logprobs":[],"obfuscation":"CI9PXx3sH06"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":29,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"fJuaoSPsMge8"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":30,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" `","logprobs":[],"obfuscation":"O1h4Q0T72OM4e7"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":31,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"Microsoft","logprobs":[],"obfuscation":"E2YPgfE"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":32,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".Extensions","logprobs":[],"obfuscation":"vfVX8"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":33,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".A","logprobs":[],"obfuscation":"EwDmSMHqymBRl1"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":34,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"I","logprobs":[],"obfuscation":"QQfjze1z7QhvcJE"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":35,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".A","logprobs":[],"obfuscation":"7fLbFXKbxOMkBi"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":36,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"bst","logprobs":[],"obfuscation":"3p1svK7Jd1N7C"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":37,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"ractions","logprobs":[],"obfuscation":"Cl2xCwTC"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":38,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"`","logprobs":[],"obfuscation":"ObDOKE72QOlXSx9"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":39,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" in","logprobs":[],"obfuscation":"FJwPbDYgh4XjL"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":40,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"e8cV5qt7hEsz"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":41,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" `","logprobs":[],"obfuscation":"Hf8ZQDFLfImh3e"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":42,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"dot","logprobs":[],"obfuscation":"0lh2vLiYye2JI"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":43,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"net","logprobs":[],"obfuscation":"g5fzb2qtk4Piz"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":44,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"/extensions","logprobs":[],"obfuscation":"egpos"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":45,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"`","logprobs":[],"obfuscation":"gXw3bKveEVIKXux"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":46,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" repository","logprobs":[],"obfuscation":"rqhlC"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":47,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" is","logprobs":[],"obfuscation":"YZq9zsRja0g2M"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":48,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":":\n\n","logprobs":[],"obfuscation":"mhDAmaHJUvLGl"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":49,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"``","logprobs":[],"obfuscation":"3XmO5YTsWjzHHf"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":50,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"`\n","logprobs":[],"obfuscation":"4fmXZmdkPxNn8K"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":51,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"src","logprobs":[],"obfuscation":"ifGf4yLEg5pMZ"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":52,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"/L","logprobs":[],"obfuscation":"C1k1toBElpgxyW"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":53,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"ibraries","logprobs":[],"obfuscation":"fdOTYTyp"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":54,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"/M","logprobs":[],"obfuscation":"DyscJIQYaPJugC"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":55,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"icrosoft","logprobs":[],"obfuscation":"PQxU7muP"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":56,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".Extensions","logprobs":[],"obfuscation":"RCJB8"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":57,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".A","logprobs":[],"obfuscation":"i92CWxnAkwS4C9"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":58,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"I","logprobs":[],"obfuscation":"qfH8wVJN74vCfBM"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":59,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".A","logprobs":[],"obfuscation":"LcuBP89lZVCCH9"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":60,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"bst","logprobs":[],"obfuscation":"I8rKDbKN0zylv"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":61,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"ractions","logprobs":[],"obfuscation":"tOgiCPs5"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":62,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"/","logprobs":[],"obfuscation":"jgJjLruTbFJGDhU"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":63,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"README","logprobs":[],"obfuscation":"D5VSEFNde7"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":64,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".md","logprobs":[],"obfuscation":"7ZGJO5sZOTPBs"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":65,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"\n","logprobs":[],"obfuscation":"7Sv80haKTTwfEWj"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":66,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"``","logprobs":[],"obfuscation":"m1JSvZ8rrpJnH5"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":67,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"`\n\n","logprobs":[],"obfuscation":"U93PMKtCB5Pb5"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":68,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"This","logprobs":[],"obfuscation":"f5veTGedo9nM"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":69,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" file","logprobs":[],"obfuscation":"oEBwvP5FnPK"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":70,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" provides","logprobs":[],"obfuscation":"IVNCYwr"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":71,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" an","logprobs":[],"obfuscation":"3x6WquURIJ3ld"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":72,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" overview","logprobs":[],"obfuscation":"VR9yeiD"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":73,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" of","logprobs":[],"obfuscation":"z46dC1o2FC8Rs"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":74,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" the","logprobs":[],"obfuscation":"YfZGabvmgyoI"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":75,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" library","logprobs":[],"obfuscation":"TamElgEp"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":76,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"VfVfqbnHAfsJyJn"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":77,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" installation","logprobs":[],"obfuscation":"CGR"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":78,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" instructions","logprobs":[],"obfuscation":"xst"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":79,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"3u5wqRA2RXh2QP8"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":80,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" and","logprobs":[],"obfuscation":"tD4WZmOhepzQ"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":81,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" usage","logprobs":[],"obfuscation":"SadOK826mZ"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":82,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" examples","logprobs":[],"obfuscation":"5VpLKav"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":83,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" for","logprobs":[],"obfuscation":"xPvtjDSUic9E"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":84,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" its","logprobs":[],"obfuscation":"6duK61DX14vx"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":85,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" core","logprobs":[],"obfuscation":"Cz8trPLsCWu"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":86,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" components","logprobs":[],"obfuscation":"Gexuy"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":87,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":".","logprobs":[],"obfuscation":"HVeWkHoX1cc6hVh"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":88,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" If","logprobs":[],"obfuscation":"G1TOxxwvSEq4L"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":89,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" you","logprobs":[],"obfuscation":"xQlKeOixd1hv"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":90,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" have","logprobs":[],"obfuscation":"bX6P0qgFPnR"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":91,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" any","logprobs":[],"obfuscation":"KxH8EiMzXa1N"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":92,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" more","logprobs":[],"obfuscation":"kA0kxRPPqru"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":93,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" questions","logprobs":[],"obfuscation":"9HRCyD"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":94,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" about","logprobs":[],"obfuscation":"yYFZhtsSfc"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":95,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" it","logprobs":[],"obfuscation":"zpyEAwPWl8Ozh"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":96,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":",","logprobs":[],"obfuscation":"ivjn00lbmzDHiFU"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":97,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" feel","logprobs":[],"obfuscation":"O2edXDmkBqt"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":98,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" free","logprobs":[],"obfuscation":"MlpWh7p0P1F"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":99,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" to","logprobs":[],"obfuscation":"uMNfozGkKe6xW"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":100,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":" ask","logprobs":[],"obfuscation":"6rMOxwXhR8RY"} | |
| event: response.output_text.delta | |
| data: {"type":"response.output_text.delta","sequence_number":101,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"delta":"!","logprobs":[],"obfuscation":"QPZMdhS0e5vYuRl"} | |
| event: response.output_text.done | |
| data: {"type":"response.output_text.done","sequence_number":102,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"text":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` in the `dotnet/extensions` repository is:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the library, installation instructions, and usage examples for its core components. If you have any more questions about it, feel free to ask!","logprobs":[]} | |
| event: response.content_part.done | |
| data: {"type":"response.content_part.done","sequence_number":103,"item_id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","output_index":3,"content_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` in the `dotnet/extensions` repository is:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the library, installation instructions, and usage examples for its core components. If you have any more questions about it, feel free to ask!"}} | |
| event: response.output_item.done | |
| data: {"type":"response.output_item.done","sequence_number":104,"output_index":3,"item":{"id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` in the `dotnet/extensions` repository is:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the library, installation instructions, and usage examples for its core components. If you have any more questions about it, feel free to ask!"}],"role":"assistant"}} | |
| event: response.completed | |
| data: {"type":"response.completed","sequence_number":105,"response":{"id":"resp_68be44fd7298819e82fd82c8516e970d03a2537be0e84a54","object":"response","created_at":1757299965,"status":"completed","background":false,"error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"mcpl_68be44fd8f68819eba7a74a2f6d27a5a03a2537be0e84a54","type":"mcp_list_tools","server_label":"deepwiki","tools":[{"annotations":{"read_only":false},"description":"Get a list of documentation topics for a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"}},"required":["repoName"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"read_wiki_structure"},{"annotations":{"read_only":false},"description":"View documentation about a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"}},"required":["repoName"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"read_wiki_contents"},{"annotations":{"read_only":false},"description":"Ask any question about a GitHub repository","input_schema":{"type":"object","properties":{"repoName":{"type":"string","description":"GitHub repository: owner/repo (e.g. \"facebook/react\")"},"question":{"type":"string","description":"The question to ask about the repository"}},"required":["repoName","question"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"},"name":"ask_question"}]},{"id":"mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"{\"repoName\":\"dotnet/extensions\"}","error":null,"name":"read_wiki_structure","output":"Available pages for dotnet/extensions:\n\n- 1 Overview\n- 2 Build System and CI/CD\n- 3 AI Extensions Framework\n - 3.1 Core Abstractions\n - 3.2 AI Function System\n - 3.3 Chat Completion\n - 3.4 Caching System\n - 3.5 Evaluation and Reporting\n- 4 HTTP Resilience and Diagnostics\n - 4.1 Standard Resilience\n - 4.2 Hedging Strategies\n- 5 Telemetry and Compliance\n- 6 Testing Infrastructure\n - 6.1 AI Service Integration Testing\n - 6.2 Time Provider Testing","server_label":"deepwiki"},{"id":"mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54","type":"mcp_call","approval_request_id":null,"arguments":"{\"repoName\":\"dotnet/extensions\",\"question\":\"What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?\"}","error":null,"name":"ask_question","output":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` is `src/Libraries/Microsoft.Extensions.AI.Abstractions/README.md` . This file provides an overview of the `Microsoft.Extensions.AI.Abstractions` library, including installation instructions and usage examples for its core components like `IChatClient` and `IEmbeddingGenerator` .\n\n## README.md Content Overview\nThe `README.md` file for `Microsoft.Extensions.AI.Abstractions` details the purpose of the library, which is to provide abstractions for generative AI components . It includes instructions on how to install the NuGet package `Microsoft.Extensions.AI.Abstractions` .\n\nThe document also provides usage examples for the `IChatClient` interface, which defines methods for interacting with AI services that offer \"chat\" capabilities . This includes examples for requesting both complete and streaming chat responses .\n\nFurthermore, the `README.md` explains the `IEmbeddingGenerator` interface, which is used for generating vector embeddings from input values . It demonstrates how to use `GenerateAsync` to create embeddings . The file also discusses how both `IChatClient` and `IEmbeddingGenerator` implementations can be layered to create pipelines of functionality, incorporating features like caching and telemetry .\n\nNotes:\nThe user's query specifically asked for the path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions`. The provided codebase context, particularly the wiki page for \"AI Extensions Framework\", directly lists this file as a relevant source file . The content of the `README.md` file itself further confirms its relevance to the `Microsoft.Extensions.AI.Abstractions` library.\n\nWiki pages you might want to explore:\n- [AI Extensions Framework (dotnet/extensions)](/wiki/dotnet/extensions#3)\n- [Chat Completion (dotnet/extensions)](/wiki/dotnet/extensions#3.3)\n\nView this search on DeepWiki: https://deepwiki.com/search/what-is-the-path-to-the-readme_bb6bee43-3136-4b21-bc5d-02ca1611d857\n","server_label":"deepwiki"},{"id":"msg_68be450c39e8819eb9bf6fcb9fd16ecb03a2537be0e84a54","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"The path to the `README.md` file for `Microsoft.Extensions.AI.Abstractions` in the `dotnet/extensions` repository is:\n\n```\nsrc/Libraries/Microsoft.Extensions.AI.Abstractions/README.md\n```\n\nThis file provides an overview of the library, installation instructions, and usage examples for its core components. If you have any more questions about it, feel free to ask!"}],"role":"assistant"}],"parallel_tool_calls":true,"previous_response_id":null,"prompt_cache_key":null,"reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[{"type":"mcp","allowed_tools":null,"headers":null,"require_approval":"never","server_description":null,"server_label":"deepwiki","server_url":"https://mcp.deepwiki.com/<redacted>"}],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":1420,"input_tokens_details":{"cached_tokens":0},"output_tokens":149,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":1569},"user":null,"metadata":{}}} | |
| """; | |
| using VerbatimHttpHandler handler = new(Input, Output); | |
| using HttpClient httpClient = new(handler); | |
| using IChatClient client = CreateResponseClient(httpClient, "gpt-4o-mini"); | |
| ChatOptions chatOptions = new() | |
| { | |
| Tools = [new HostedMcpServerTool("deepwiki", new Uri("https://mcp.deepwiki.com/mcp")) | |
| { | |
| ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire, | |
| } | |
| ], | |
| }; | |
| var response = await client.GetStreamingResponseAsync("Tell me the path to the README.md file for Microsoft.Extensions.AI.Abstractions in the dotnet/extensions repository", chatOptions) | |
| .ToChatResponseAsync(); | |
| Assert.NotNull(response); | |
| Assert.Equal("resp_68be44fd7298819e82fd82c8516e970d03a2537be0e84a54", response.ResponseId); | |
| Assert.Equal("resp_68be44fd7298819e82fd82c8516e970d03a2537be0e84a54", response.ConversationId); | |
| Assert.Equal("gpt-4o-mini-2024-07-18", response.ModelId); | |
| Assert.Equal(DateTimeOffset.FromUnixTimeSeconds(1_757_299_965), response.CreatedAt); | |
| Assert.Equal(ChatFinishReason.Stop, response.FinishReason); | |
| var message = Assert.Single(response.Messages); | |
| Assert.Equal(ChatRole.Assistant, response.Messages[0].Role); | |
| Assert.StartsWith("The path to the `README.md` file", response.Messages[0].Text); | |
| Assert.Equal(6, message.Contents.Count); | |
| var firstCall = Assert.IsType<McpServerToolCallContent>(message.Contents[1]); | |
| Assert.Equal("mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54", firstCall.CallId); | |
| Assert.Equal("deepwiki", firstCall.ServerName); | |
| Assert.Equal("read_wiki_structure", firstCall.ToolName); | |
| Assert.NotNull(firstCall.Arguments); | |
| Assert.Single(firstCall.Arguments); | |
| Assert.Equal("dotnet/extensions", ((JsonElement)firstCall.Arguments["repoName"]!).GetString()); | |
| var firstResult = Assert.IsType<McpServerToolResultContent>(message.Contents[2]); | |
| Assert.Equal("mcp_68be4503d45c819e89cb574361c8eba003a2537be0e84a54", firstResult.CallId); | |
| Assert.NotNull(firstResult.Output); | |
| Assert.StartsWith("Available pages for dotnet/extensions", Assert.IsType<TextContent>(Assert.Single(firstResult.Output)).Text); | |
| var secondCall = Assert.IsType<McpServerToolCallContent>(message.Contents[3]); | |
| Assert.Equal("mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54", secondCall.CallId); | |
| Assert.Equal("deepwiki", secondCall.ServerName); | |
| Assert.Equal("ask_question", secondCall.ToolName); | |
| Assert.NotNull(secondCall.Arguments); | |
| Assert.Equal("dotnet/extensions", ((JsonElement)secondCall.Arguments["repoName"]!).GetString()); | |
| Assert.Equal("What is the path to the README.md file for Microsoft.Extensions.AI.Abstractions?", ((JsonElement)secondCall.Arguments["question"]!).GetString()); | |
| var secondResult = Assert.IsType<McpServerToolResultContent>(message.Contents[4]); | |
| Assert.Equal("mcp_68be4505f134819e806c002f27cce0c303a2537be0e84a54", secondResult.CallId); | |
| Assert.NotNull(secondResult.Output); | |
| Assert.StartsWith("The path to the `README.md` file", Assert.IsType<TextContent>(Assert.Single(secondResult.Output)).Text); | |
| Assert.NotNull(response.Usage); | |
| Assert.Equal(1420, response.Usage.InputTokenCount); | |
| Assert.Equal(149, response.Usage.OutputTokenCount); | |
| Assert.Equal(1569, response.Usage.TotalTokenCount); | |
| } |
Introduces a Headers property to HostedMcpServerTool for specifying additional request headers. Updates OpenAIResponsesChatClient to pass these headers when creating MCP tools and adds unit tests to verify header roundtripping.
Microsoft Reviewers: Open in CodeFlow