66[ ![ Version] ( https://img.shields.io/nuget/vpre/Devlooped.Extensions.AI.svg?color=royalblue )] ( https://www.nuget.org/packages/Devlooped.Extensions.AI )
77[ ![ Downloads] ( https://img.shields.io/nuget/dt/Devlooped.Extensions.AI.svg?color=green )] ( https://www.nuget.org/packages/Devlooped.Extensions.AI )
88
9- Extensions for Microsoft.Extensions.AI.
10-
11- <!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
12- ## Open Source Maintenance Fee
13-
14- To ensure the long-term sustainability of this project, users of this package who generate
15- revenue must pay an [ Open Source Maintenance Fee] ( https://opensourcemaintenancefee.org ) .
16- While the source code is freely available under the terms of the [ License] ( license.txt ) ,
17- this package and other aspects of the project require [ adherence to the Maintenance Fee] ( osmfeula.txt ) .
18-
19- To pay the Maintenance Fee, [ become a Sponsor] ( https://github.com/sponsors/devlooped ) at the proper
20- OSMF tier. A single fee covers all of [ Devlooped packages] ( https://www.nuget.org/profiles/Devlooped ) .
21-
22- <!-- https://github.com/devlooped/.github/raw/main/osmf.md -->
23-
249<!-- #extensions-title -->
2510Extensions for Microsoft.Extensions.AI
2611<!-- #extensions-title -->
@@ -60,56 +45,109 @@ var grok = app.Services.GetRequiredKeyedService<IChatClient>("Grok");
6045Changing the ` appsettings.json ` file will automatically update the client
6146configuration without restarting the application.
6247
63- ## OpenAI
64-
65- The support for OpenAI chat clients provided in [ Microsoft.Extensions.AI.OpenAI] ( https://www.nuget.org/packages/Microsoft.Extensions.AI.OpenAI ) fall short in some scenarios:
66-
67- * Specifying per-chat model identifier: the OpenAI client options only allow setting
68- a single model identifier for all requests, at the time the ` OpenAIClient.GetChatClient ` is
69- invoked.
70- * Setting reasoning effort: the Microsoft.Extensions.AI API does not expose a way to set reasoning
71- effort for reasoning-capable models, which is very useful for some models like ` gpt-5.2 ` .
72-
73- So solve both issues, this package provides an ` OpenAIChatClient ` that wraps the underlying
74- ` OpenAIClient ` and allows setting the model identifier and reasoning effort per request, just
75- like the above Grok examples showed:
48+ There's also a simpler ` Chat ` class for streamlined creation of chat messages, which can
49+ be used instead of creating an array of ` ChatMessage ` using ` ChatRole.[System|Assistant|User] ` :
7650
7751``` csharp
7852var messages = new Chat ()
7953{
8054 { " system" , " You are a highly intelligent AI assistant." },
8155 { " user" , " What is 101*3?" },
8256};
57+ ```
58+
59+ ## Tool Results
60+
61+ Given the following tool:
62+
63+ ``` csharp
64+ MyResult RunTool (string name , string description , string content ) { .. . }
65+ ```
8366
84- IChatClient chat = new OpenAIChatClient (Environment .GetEnvironmentVariable (" OPENAI_API_KEY" )! , " gpt-5" );
67+ You can use the ` ToolFactory ` and ` FindCall<MyResult> ` extension method to
68+ locate the function invocation, its outcome and the typed result for inspection:
8569
70+ ``` csharp
71+ AIFunction tool = ToolFactory .Create (RunTool );
72+ var options = new ChatOptions
73+ {
74+ ToolMode = ChatToolMode .RequireSpecific (tool .Name ), // 👈 forces the tool to be used
75+ Tools = [tool ]
76+ };
77+
78+ var response = await client .GetResponseAsync (chat , options );
79+ // 👇 finds the expected result of the tool call
80+ var result = response .FindCalls <MyResult >(tool ).FirstOrDefault ();
81+
82+ if (result != null )
83+ {
84+ // Successful tool call
85+ Console .WriteLine ($" Args: '{result .Call .Arguments .Count }'" );
86+ MyResult typed = result .Result ;
87+ }
88+ else
89+ {
90+ Console .WriteLine (" Tool call not found in response." );
91+ }
92+ ```
93+
94+ If the typed result is not found, you can also inspect the raw outcomes by finding
95+ untyped calls to the tool and checking their ` Outcome.Exception ` property:
96+
97+ ``` csharp
98+ var result = response .FindCalls (tool ).FirstOrDefault ();
99+ if (result .Outcome .Exception is not null )
100+ {
101+ Console .WriteLine ($" Tool call failed: {result .Outcome .Exception .Message }" );
102+ }
103+ else
104+ {
105+ Console .WriteLine ($" Tool call succeeded: {result .Outcome .Result }" );
106+ }
107+ ```
108+
109+ > [ !IMPORTANT]
110+ > The ` ToolFactory ` will also automatically sanitize the tool name
111+ > when using local functions to avoid invalid characters and honor
112+ > its original name.
113+
114+ ## OpenAI
115+
116+ OpenAI-specific extensions enable more seamless usage with the MS.E.AI API:
117+
118+ * Setting reasoning effort: the Microsoft.Extensions.AI API does not expose a way to set reasoning
119+ effort for reasoning-capable models, which is very useful for some models like
120+ [ ` gpt-5.2 ` ] ( https://platform.openai.com/docs/guides/latest-model#lower-reasoning-effort )
121+ * Setting output verbosity: similarly, [ output verbosity] ( https://platform.openai.com/docs/guides/latest-model#verbosity ) is not exposed in the base API.
122+
123+ These can be used as extension properties on ` ChatOptions ` whenever ` Devlooped.Extensions.AI.OpenAI ` is imported:
124+
125+ ``` csharp
86126var options = new ChatOptions
87127{
88- ModelId = " gpt-5-mini" , // 👈 can override the model on the client
89128 ReasoningEffort = ReasoningEffort .High , // 👈 or Medium/Low/Minimal/None, extension property
129+ Verbosity = Verbosity .Low // 👈 or Medium/High, extension property
90130 };
91131
92132var response = await chat .GetResponseAsync (messages , options );
93133```
94134
95- > [ !TIP]
96- > We provide support for the newest ` Minimal ` reasoning effort in the just-released
97- > GPT-5 model family as well as ` None ` which is the new default in GPT-5.2.
135+ Or you can opt to use the ` ChatOptions ` -derived ` OpenAIChatOptions ` class directly:
98136
99137### Web Search
100138
101- Similar to the Grok client, we provide the ` WebSearchTool ` to enable search customization
102- in OpenAI too :
139+ The ` WebSearchTool ` can be used to customize the web search behavior in a typed manner,
140+ unlike the generic ` HostedWebSearchTool ` :
103141
104142``` csharp
105143var options = new ChatOptions
106144{
107145 // 👇 search in Argentina, Bariloche region
108146 Tools = [new WebSearchTool (" AR" )
109147 {
110- Region = " Bariloche " , // 👈 Bariloche region
111- TimeZone = " America/Argentina/Buenos_Aires " , // 👈 IANA timezone
112- ContextSize = WebSearchToolContextSize . High // 👈 high search context size
148+ AllowedDomains = [ " catedralaltapatagonia.com " ], // 👈 restrict domain
149+ Region = " Bariloche " , // 👈 Bariloche region
150+ TimeZone = " America/Argentina/Buenos_Aires " , // 👈 IANA timezone
113151 }]
114152};
115153```
@@ -121,7 +159,6 @@ var options = new ChatOptions
121159If advanced search settings are not needed, you can use the built-in M.E.AI ` HostedWebSearchTool `
122160instead, which is a more generic tool and provides the basics out of the box.
123161
124-
125162## Observing Request/Response
126163
127164The underlying HTTP pipeline provided by the Azure SDK allows setting up
@@ -163,61 +200,6 @@ var openai = new OpenAIClient(
163200 OpenAIClientOptions .Observable (requests .Add , responses .Add ));
164201```
165202
166- ## Tool Results
167-
168- Given the following tool:
169-
170- ``` csharp
171- MyResult RunTool (string name , string description , string content ) { .. . }
172- ```
173-
174- You can use the ` ToolFactory ` and ` FindCall<MyResult> ` extension method to
175- locate the function invocation, its outcome and the typed result for inspection:
176-
177- ``` csharp
178- AIFunction tool = ToolFactory .Create (RunTool );
179- var options = new ChatOptions
180- {
181- ToolMode = ChatToolMode .RequireSpecific (tool .Name ), // 👈 forces the tool to be used
182- Tools = [tool ]
183- };
184-
185- var response = await client .GetResponseAsync (chat , options );
186- // 👇 finds the expected result of the tool call
187- var result = response .FindCalls <MyResult >(tool ).FirstOrDefault ();
188-
189- if (result != null )
190- {
191- // Successful tool call
192- Console .WriteLine ($" Args: '{result .Call .Arguments .Count }'" );
193- MyResult typed = result .Result ;
194- }
195- else
196- {
197- Console .WriteLine (" Tool call not found in response." );
198- }
199- ```
200-
201- If the typed result is not found, you can also inspect the raw outcomes by finding
202- untyped calls to the tool and checking their ` Outcome.Exception ` property:
203-
204- ``` csharp
205- var result = response .FindCalls (tool ).FirstOrDefault ();
206- if (result .Outcome .Exception is not null )
207- {
208- Console .WriteLine ($" Tool call failed: {result .Outcome .Exception .Message }" );
209- }
210- else
211- {
212- Console .WriteLine ($" Tool call succeeded: {result .Outcome .Result }" );
213- }
214- ```
215-
216- > [ !IMPORTANT]
217- > The ` ToolFactory ` will also automatically sanitize the tool name
218- > when using local functions to avoid invalid characters and honor
219- > its original name.
220-
221203## Console Logging
222204
223205Additional ` UseJsonConsoleLogging ` extension for rich JSON-formatted console logging of AI requests
@@ -261,14 +243,18 @@ IChatClient chat = new OpenAIChatClient(Environment.GetEnvironmentVariable("OPEN
261243```
262244<!-- #extensions -->
263245
264- # xAI (Grok)
246+ <!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
247+ ## Open Source Maintenance Fee
248+
249+ To ensure the long-term sustainability of this project, users of this package who generate
250+ revenue must pay an [ Open Source Maintenance Fee] ( https://opensourcemaintenancefee.org ) .
251+ While the source code is freely available under the terms of the [ License] ( license.txt ) ,
252+ this package and other aspects of the project require [ adherence to the Maintenance Fee] ( osmfeula.txt ) .
265253
266- [ ![ Version ] ( https://img.shields.io/nuget/vpre/xAI.svg?color=royalblue )] ( https://www.nuget.org/packages/xAI )
267- [ ![ Downloads ] ( https://img.shields.io/nuget/dt/xAI.svg?color=green )] ( https:// www.nuget.org/packages/xAI )
254+ To pay the Maintenance Fee, [ become a Sponsor ] ( https://github.com/sponsors/devlooped ) at the proper
255+ OSMF tier. A single fee covers all of [ Devlooped packages ] ( https://www.nuget.org/profiles/Devlooped ) .
268256
269- For Microsoft.Extensions.AI ` IChatClient ` integration with Grok (xAI), see the
270- [ xAI] ( https://nuget.org/packages/xAI ) package, which provides full support for all
271- [ agentic tools] ( https://docs.x.ai/docs/guides/tools/overview ) .
257+ <!-- https://github.com/devlooped/.github/raw/main/osmf.md -->
272258
273259<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
274260# Sponsors
0 commit comments