Merge remote-tracking branch 'refs/remotes/fork/codex/macos-support' into codex/macos-support

# Conflicts:
#	MeetingAssistant/Program.cs
#	README.md
This commit is contained in:
dh
2026-09-20 12:44:03 +02:00
15 changed files with 127 additions and 30 deletions
+6 -6
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PreserveCompilationContext>true</PreserveCompilationContext>
<MicrosoftSpeechVersion>1.51.1</MicrosoftSpeechVersion>
<MicrosoftSpeechVersion>1.51.2</MicrosoftSpeechVersion>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
@@ -41,16 +41,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.20.0" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" Version="1.21.0" />
<PackageReference Include="DiffPlex" Version="1.9.0" />
<PackageReference Include="Microsoft.CognitiveServices.Speech" Version="$(MicrosoftSpeechVersion)" />
<PackageReference Include="Microsoft.CognitiveServices.Speech.Extension.MAS" Version="$(MicrosoftSpeechVersion)" ExcludeAssets="build" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.11" />
<PackageReference Include="NAudio" Version="2.3.0" />
<PackageReference Include="NCalcSync" Version="7.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.12" />
<PackageReference Include="NAudio" Version="3.1.0" />
<PackageReference Include="NCalcSync" Version="7.2.0" />
<PackageReference Include="RazorLight" Version="2.3.1" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.5" />
<PackageReference Include="System.Drawing.Common" Version="10.0.11" />
<PackageReference Include="System.Drawing.Common" Version="10.0.12" />
<PackageReference Include="Whisper.net" Version="1.9.1" />
<PackageReference Include="Whisper.net.Runtime" Version="1.9.1" />
<PackageReference Include="YamlDotNet" Version="18.1.0" />
+5 -1
View File
@@ -17,11 +17,11 @@ using Microsoft.Extensions.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddProvider(new MeetingAssistantFileLoggerProvider());
builder.Services.AddSingleton(HostOperatingSystem.DetectCurrent());
builder.Services.AddSingleton<IValidateOptions<MeetingAssistantOptions>, MeetingAssistantSpeakerSampleOptionsValidator>();
builder.Services.AddOptions<MeetingAssistantOptions>()
.Bind(builder.Configuration.GetSection("MeetingAssistant"))
.ValidateOnStart();
builder.Services.AddSingleton(HostOperatingSystem.DetectCurrent());
builder.Services.AddSingleton<ILaunchProfileOptionsProvider, ConfigurationLaunchProfileOptionsProvider>();
#if WINDOWS
builder.Services.AddSingleton<MicrophoneDeviceSelection>();
@@ -129,7 +129,11 @@ builder.Services.AddSingleton<IMeetingSummaryRetryRunner, MeetingSummaryRetryRun
builder.Services.AddSingleton<IMeetingWorkflowRulesProvider, FileMeetingWorkflowRulesProvider>();
builder.Services.AddSingleton<IMeetingWorkflowEngine, MeetingWorkflowEngine>();
builder.Services.AddSingleton<IWorkflowRulesEditorInstructionBuilder, WorkflowRulesEditorInstructionBuilder>();
#if WINDOWS
builder.Services.AddSingleton<IWorkflowRulesEditorSamplePlaybackQueue, WorkflowRulesEditorSamplePlaybackQueue>();
#else
builder.Services.AddSingleton<IWorkflowRulesEditorSamplePlaybackQueue, UnavailableWorkflowRulesEditorSamplePlaybackQueue>();
#endif
builder.Services.AddSingleton<IWorkflowRulesEditorChatPipeline, WorkflowRulesEditorChatPipeline>();
builder.Services.AddTransient<WorkflowRulesEditorChatViewModel>();
#if WINDOWS
@@ -823,7 +823,9 @@ public sealed class MeetingRecordingCoordinator
run.RecordTranscriptActivity(segment, inactivityClock.Now);
if (!string.IsNullOrWhiteSpace(segment.Text))
{
await DismissInactivityPromptsForRunAsync(run, cancellationToken);
// Switching profiles holds the coordinator gate while draining this reader.
// Notification cleanup must not make transcript draining wait for that gate.
_ = DismissInactivityPromptsForRunAsync(run, run.CaptureCancellation);
}
}
}
@@ -832,19 +834,26 @@ public sealed class MeetingRecordingCoordinator
RecordingRun run,
CancellationToken cancellationToken)
{
await gate.WaitAsync(cancellationToken);
try
{
if (!ReferenceEquals(currentRun, run) || run.IsCaptureStopping)
await gate.WaitAsync(cancellationToken);
try
{
return;
}
if (!ReferenceEquals(currentRun, run) || run.IsCaptureStopping)
{
return;
}
await DismissInactivityPromptsAsync(cancellationToken);
await DismissInactivityPromptsAsync(cancellationToken);
}
finally
{
gate.Release();
}
}
finally
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
gate.Release();
// Pending cleanup is no longer needed after this run stops capturing.
}
}
@@ -7,7 +7,6 @@ using System.Text.Json.Nodes;
using Microsoft.Agents.AI.Compaction;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Logging;
using OpenAI;
using OpenAI.Responses;
namespace MeetingAssistant.Summary;
@@ -798,7 +797,7 @@ public sealed class LiteLlmResponsesChatClient : IChatClient
string apiKey,
AsyncLocal<string?> requestInitiator)
{
var options = new OpenAIClientOptions
var options = new ResponsesClientOptions
{
Endpoint = httpClient.BaseAddress
?? throw new InvalidOperationException("LiteLLM HTTP client requires a base address."),
@@ -8,6 +8,7 @@ public interface IWorkflowRulesEditorSamplePlaybackQueue
Task<string> QueueAsync(int sampleId, byte[] wavBytes, CancellationToken cancellationToken = default);
}
#if WINDOWS
public sealed class WorkflowRulesEditorSamplePlaybackQueue : IWorkflowRulesEditorSamplePlaybackQueue, IDisposable
{
private readonly Channel<QueuedSample> channel = Channel.CreateUnbounded<QueuedSample>();
@@ -98,3 +99,13 @@ public sealed class WorkflowRulesEditorSamplePlaybackQueue : IWorkflowRulesEdito
private sealed record QueuedSample(int SampleId, byte[] WavBytes);
}
#else
public sealed class UnavailableWorkflowRulesEditorSamplePlaybackQueue : IWorkflowRulesEditorSamplePlaybackQueue
{
public Task<string> QueueAsync(int sampleId, byte[] wavBytes, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult("Speaker sample playback requires the Windows build of Meeting Assistant.");
}
}
#endif