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
1 change: 1 addition & 0 deletions Extensions.AI.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
</Configurations>
<Project Path="src/Extensions.CodeAnalysis/Extensions.CodeAnalysis.csproj" />
<Project Path="src/Extensions/Extensions.csproj" />
<Project Path="src/Extensions.Console/Extensions.Console.csproj" />
<Project Path="src/Tests/Tests.csproj" />
</Solution>
18 changes: 10 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,20 @@ else

OpenAI-specific extensions enable more seamless usage with the MS.E.AI API:

* Setting reasoning effort: the Microsoft.Extensions.AI API does not expose a way to set reasoning
effort for reasoning-capable models, which is very useful for some models like
[`gpt-5.2`](https://platform.openai.com/docs/guides/latest-model#lower-reasoning-effort)
* Setting output verbosity: similarly, [output verbosity](https://platform.openai.com/docs/guides/latest-model#verbosity) is not exposed in the base API.

These can be used as extension properties on `ChatOptions` whenever `Devlooped.Extensions.AI.OpenAI` is imported:

```csharp
var options = new ChatOptions
{
ReasoningEffort = ReasoningEffort.High, // 👈 or Medium/Low/Minimal/None, extension property
Verbosity = Verbosity.Low // 👈 or Medium/High, extension property
};

var response = await chat.GetResponseAsync(messages, options);
```

Or you can opt to use the `ChatOptions`-derived `OpenAIChatOptions` class directly:
Or you can opt to use the `ChatOptions`-derived `OpenAIChatOptions` class directly.

### Web Search

Expand Down Expand Up @@ -199,11 +195,13 @@ var openai = new OpenAIClient(
Environment.GetEnvironmentVariable("OPENAI_API_KEY")!,
OpenAIClientOptions.Observable(requests.Add, responses.Add));
```
<!-- #extensions -->

<!-- #console -->
## Console Logging

Additional `UseJsonConsoleLogging` extension for rich JSON-formatted console logging of AI requests
are provided at two levels:
Additional `UseJsonConsoleLogging` extension for rich JSON-formatted console logging
of `IChatClient` requests and responses are provided at two levels:

* Chat pipeline: similar to `UseLogging`.
* HTTP pipeline: lowest possible layer before the request is sent to the AI service,
Expand Down Expand Up @@ -241,7 +239,11 @@ IChatClient chat = new OpenAIChatClient(Environment.GetEnvironmentVariable("OPEN
})
.Build();
```
<!-- #extensions -->

> [!IMPORTANT]
> By default, the logging will only be performed if the console is interactive.

<!-- #console -->

<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
## Open Source Maintenance Fee
Expand Down
34 changes: 34 additions & 0 deletions src/Extensions.Console/Extensions.Console.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<LangVersion>Preview</LangVersion>
<AssemblyName>Devlooped.Extensions.AI.Console</AssemblyName>
<RootNamespace>Devlooped.Extensions.AI</RootNamespace>
<PackageId>Devlooped.Extensions.AI.Console</PackageId>
<Description>Console logging extensions for Devlooped.Extensions.AI</Description>
<PackageLicenseExpression></PackageLicenseExpression>
<PackageLicenseFile>OSMFEULA.txt</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NuGetizer" Version="1.4.7" PrivateAssets="all" />
<PackageReference Include="Spectre.Console" Version="0.54.0" />
<PackageReference Include="Spectre.Console.Json" Version="0.54.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Extensions\Extensions.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\osmfeula.txt" Link="osmfeula.txt" PackagePath="OSMFEULA.txt" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Devlooped.Agents.AI" />
<InternalsVisibleTo Include="Tests" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ChatClientBuilder UseJsonConsoleLogging(JsonConsoleOptions? consoleOption
{
consoleOptions ??= JsonConsoleOptions.Default;

if (consoleOptions.InteractiveConfirm && ConsoleExtensions.IsConsoleInteractive && !AnsiConsole.Confirm("Do you want to enable rich JSON console logging for HTTP pipeline messages?"))
if (consoleOptions.InteractiveConfirm && ConsoleExtensions.IsConsoleInteractive && !AnsiConsole.Confirm("Do you want to enable rich JSON console logging for chat messages and responses?"))
return builder;

if (consoleOptions.InteractiveOnly && !ConsoleExtensions.IsConsoleInteractive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,16 @@ internal Panel CreatePanel(object value)
}

#pragma warning disable CS9113 // Parameter is unread. BOGUS
sealed class WrappedJsonText(string json, int maxWidth) : Renderable
sealed class WrappedJsonText(string json, int fixedMaxWidth) : Renderable
#pragma warning restore CS9113 // Parameter is unread. BOGUS
{
readonly JsonText jsonText = new(json);

protected override Measurement Measure(RenderOptions options, int maxWidth)
{
// Clamp the measurement to the desired maxWidth
return new Measurement(Math.Min(maxWidth, maxWidth), Math.Min(maxWidth, maxWidth));
var width = Math.Min(fixedMaxWidth, maxWidth);
return new Measurement(width, width);
}

protected override IEnumerable<Segment> Render(RenderOptions options, int maxWidth)
Expand All @@ -170,7 +171,7 @@ protected override IEnumerable<Segment> Render(RenderOptions options, int maxWid
var idx = 0;
while (idx < text.Length)
{
var len = Math.Min(maxWidth, text.Length - idx);
var len = Math.Min(fixedMaxWidth, text.Length - idx);
wrapped.Add(new Segment(text.Substring(idx, len), style));
idx += len;
if (idx < text.Length)
Expand Down
8 changes: 8 additions & 0 deletions src/Extensions.Console/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black&color=C9FF30)](osmfeula.txt)
[![OSS](https://img.shields.io/github/license/devlooped/oss.svg?color=blue)](license.txt)
[![GitHub](https://img.shields.io/badge/-source-181717.svg?logo=GitHub)](https://github.com/devlooped/AI)

<!-- include ../../readme.md#console -->
<!-- include https://github.com/devlooped/.github/raw/main/osmf.md -->
<!-- include https://github.com/devlooped/sponsors/raw/main/footer.md -->
<!-- exclude -->
2 changes: 0 additions & 2 deletions src/Extensions/Extensions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
<PackageReference Include="NuGetizer" Version="1.4.7" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.AI" Version="10.3.0" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="10.3.0" />
<PackageReference Include="Spectre.Console" Version="0.54.0" />
<PackageReference Include="Spectre.Console.Json" Version="0.54.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.4" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.4" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.4" />
Expand Down
1 change: 1 addition & 0 deletions src/Tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<ItemGroup>
<ProjectReference Include="..\Extensions.CodeAnalysis\Extensions.CodeAnalysis.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\Extensions\Extensions.csproj" />
<ProjectReference Include="..\Extensions.Console\Extensions.Console.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading