From c653a8c7ad03d31e9b22933aaa35d74998dafc82 Mon Sep 17 00:00:00 2001 From: Scott McKay Date: Fri, 19 Jun 2026 15:37:58 +1000 Subject: [PATCH 1/2] Cleanup some C# warnings and dispose behavior. Make native logging more deterministic when running in debug mode. Should make the log outputs match up better so CI logs are easier to debug. --- .../cs-debug-binding.instructions.md | 26 +++++++---- memories/repo/cs-item-ownership-transfer.md | 13 ++++++ sdk_v2/cpp/src/spdlog_logger.cc | 15 +++++- sdk_v2/cs/.editorconfig | 8 +++- sdk_v2/cs/src/Items/AudioItem.cs | 27 +++++------ sdk_v2/cs/src/Items/BytesItem.cs | 18 +++----- sdk_v2/cs/src/Items/ImageItem.cs | 18 +++----- sdk_v2/cs/src/Items/ItemQueue.cs | 10 ++-- sdk_v2/cs/src/Items/PinContext.cs | 46 ++++++++++++++++--- .../cs/src/Microsoft.AI.Foundry.Local.csproj | 12 +++++ .../Microsoft.AI.Foundry.Local.Tests.csproj | 11 +++++ 11 files changed, 144 insertions(+), 60 deletions(-) create mode 100644 memories/repo/cs-item-ownership-transfer.md diff --git a/.github/instructions/cs-debug-binding.instructions.md b/.github/instructions/cs-debug-binding.instructions.md index 3b38372d1..436e6a7f3 100644 --- a/.github/instructions/cs-debug-binding.instructions.md +++ b/.github/instructions/cs-debug-binding.instructions.md @@ -3,26 +3,34 @@ description: Use when changing the C ABI (foundry_local_c.h) and validating C# t applyTo: sdk_v2/cs/** --- -# C# Tests Auto-Load the C++ **Debug** Build +# C# Tests Auto-Load the C++ **RelWithDebInfo** Build The C# project (`sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj`) auto-detects -`sdk_v2/cpp/build/Windows/Debug/bin/Debug/foundry_local.dll` for inner-loop dev -and writes a `foundry_local.native.cfg` redirect file. The test project copies -this redirect to its output, so `dotnet test` always loads the **Debug** native -binary, never RelWithDebInfo. +`sdk_v2/cpp/build/Windows/RelWithDebInfo/bin/RelWithDebInfo/foundry_local.dll` +for inner-loop dev and writes a `foundry_local.native.cfg` redirect file. The +test project copies this redirect to its output, so `dotnet test` always loads +the **RelWithDebInfo** native binary. The auto-detect block only checks the +RelWithDebInfo config (one entry per OS) — it never probes a Debug build. + +To override (e.g. point at a Debug build or a NuGet runtime package), set +`FoundryLocalNativeBinDir` or `FoundryLocalRuntimeVersion` explicitly; otherwise +the RelWithDebInfo auto-detect wins. ## Implication When you change the C ABI surface (e.g. `foundry_local_c.h`, struct layouts, -function signatures in `c_api.cc`), you **must rebuild Debug** before running -C# tests, even if you've already built RelWithDebInfo for the C++ test suite: +function signatures in `c_api.cc`), you **must rebuild RelWithDebInfo** before +running C# tests: ```powershell cd sdk_v2/cpp -python build.py --build --config Debug +python build.py --build --config RelWithDebInfo ``` -## Symptoms of a stale Debug DLL +This is the same config the C++ integration test suite uses, so a single +RelWithDebInfo build serves both. + +## Symptoms of a stale RelWithDebInfo DLL - C# tests fail with native errors that don't match current C++ source line numbers - Dispatch falls through unexpectedly (e.g. JSON pass-through stops working diff --git a/memories/repo/cs-item-ownership-transfer.md b/memories/repo/cs-item-ownership-transfer.md new file mode 100644 index 000000000..baa0d269d --- /dev/null +++ b/memories/repo/cs-item-ownership-transfer.md @@ -0,0 +1,13 @@ +# C# Item Ownership Transfer & CA2000 + +- `Item : IDisposable` owns a native handle. Hand it to a container via the **generic** `ItemQueue.Push(Item)` or `Request.AddItem(Item)` — that is the only intended API. +- **Do NOT add per-type push/add helpers** (`PushBytes`, `PushText`, etc.) — they don't scale. Use `queue.Push(BytesItem.CreateOwned(chunk))` inline instead. +- Transfer order is leak-safe: native call first, then `item.ReleaseOwnership()` only on success (a throwing push under `using` won't leak). +- **Owned** items (`CreateOwned`, `AudioItem.CreateFormatDescriptor`): `_pinContext` is **never assigned** (not "set to null on transfer" — the owned factories use a private ctor that only allocates the native handle, and keep the pin in a local). The pin lives behind a `GCHandle` and is freed by the native deleter (`BytesDeleter` → `PinContext.ReleaseFromNative`) when the native item is destroyed via `flItem_Release`. +- Owned factories pin + root in one shot via **`PinContext.PinForNativeDeleter(data, out ptr, out len)`** (returns the `deleter_user_data` IntPtr). Do NOT pin-then-alloc as two separate locals in the factory — `PinForNativeDeleter` is the single ownership-transfer chokepoint and also guards the pin→GCHandle gap. New owned Item types should route through it. +- `Item.Dispose()` does exactly two things: `OnDisposing()` then release-native-`if (_ownsHandle)`. For an owned item *after transfer* both short-circuit — `OnDisposing` runs `_pinContext?.Dispose()` (no-op, field is null) and `_ownsHandle == false` skips the native release. So Dispose is fully inert; whoever now owns the handle triggers the deleter. Disposing an owned item *before* pushing still cleans up correctly: `_ownsHandle == true` → `flItem_Release` → same deleter → unpin. +- **Borrowed** items (`new BytesItem(ReadOnlyMemory)`, borrowed `AudioItem`) store the pin in `_pinContext` (no native deleter) and unpin in `OnDisposing` → unsafe to dispose after a queue push (native still references the buffer). For streaming/queue use the **owned** factories. +- See `sdk_v2/cs/docs/item-data-ownership.md` (States 1-4) for the full pin/ownership model. +- **CA2000 is intentionally disabled project-wide** via `$(NoWarn);CA2000` in both csprojs (+ `.editorconfig` severity `none`). It can't model ownership transfer and fires false positives on every hand-off. **IDisposableAnalyzers** (SDK project, `PrivateAssets=all` so it doesn't flow to tests) is the disposal-correctness authority. Do NOT re-add CA2000 pragmas or per-site suppressions. +- **IDISP001** (IDisposableAnalyzers) follows data flow into *same-assembly* callees, so passing a created disposable to a helper that roots it in a `GCHandle` (instead of disposing/returning it) does NOT suppress the warning — the analyzer fundamentally can't model ownership handed to unmanaged code freed by a native callback. The single justified `#pragma warning disable IDISP001` lives at the one transfer boundary in `PinContext.PinForNativeDeleter`; do not scatter suppressions across the owned factories. + diff --git a/sdk_v2/cpp/src/spdlog_logger.cc b/sdk_v2/cpp/src/spdlog_logger.cc index c49ff3549..f931fb9b1 100644 --- a/sdk_v2/cpp/src/spdlog_logger.cc +++ b/sdk_v2/cpp/src/spdlog_logger.cc @@ -73,7 +73,20 @@ SpdlogLogger::SpdlogLogger(LogLevel min_level, const std::string& logs_dir) { spdlog::async_overflow_policy::block); logger_->set_level(ToSpdlogLevel(min_level)); - logger_->flush_on(spdlog::level::warn); + + // Flush policy: by default we buffer low-severity logs and only force a flush at warning and + // above (plus on destruction), avoiding a per-message flush on the hot path. We flush on every + // message only when running in a debug build, or when the caller has explicitly opted into + // Debug/Verbose diagnostics -- in those cases prompt, crash-safe output is worth the cost. +#ifndef NDEBUG + constexpr bool debug_build = true; +#else + constexpr bool debug_build = false; +#endif + + const bool flush_every_message = debug_build || min_level <= LogLevel::Debug; + + logger_->flush_on(flush_every_message ? spdlog::level::trace : spdlog::level::warn); spdlog::register_logger(logger_); } diff --git a/sdk_v2/cs/.editorconfig b/sdk_v2/cs/.editorconfig index a14a74133..cf1c5cf39 100644 --- a/sdk_v2/cs/.editorconfig +++ b/sdk_v2/cs/.editorconfig @@ -300,8 +300,12 @@ dotnet_diagnostic.IDE0090.severity = error ## Suppressing this particular case due to issues in the analyzer's understanding of pattern matching. dotnet_diagnostic.IDE0072.severity = suggestion -# CA2000: Dispose objects before losing scope -dotnet_diagnostic.CA2000.severity = warning +# CA2000: Dispose objects before losing scope. +# Downgraded to 'none' — see the NoWarn + rationale in the .csproj files. The Item ownership model +# transfers a native handle into a container (Request/ItemQueue) and the C# wrapper's Dispose() is a +# no-op afterwards (docs/item-data-ownership.md), which CA2000 can't model. IDisposableAnalyzers is +# our authority for disposal correctness instead. +dotnet_diagnostic.CA2000.severity = none # IDE0046: Convert to conditional expression dotnet_diagnostic.IDE0046.severity = silent diff --git a/sdk_v2/cs/src/Items/AudioItem.cs b/sdk_v2/cs/src/Items/AudioItem.cs index 16aaaa281..c71a94f01 100644 --- a/sdk_v2/cs/src/Items/AudioItem.cs +++ b/sdk_v2/cs/src/Items/AudioItem.cs @@ -1,16 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +namespace Microsoft.AI.Foundry.Local; + using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -#pragma warning disable IDISP001 -#pragma warning disable IDISP023 - -namespace Microsoft.AI.Foundry.Local; - public sealed class AudioItem : Item { private IntPtr _data; @@ -158,15 +155,14 @@ public static AudioItem CreateOwned(string format, ReadOnlyMemory data) public static AudioItem CreateOwned(string format, Memory data) { var item = new AudioItem(ItemType.Audio); - var pinCtx = PinContext.Pin(data); - var userData = pinCtx.AllocForNativeDeleter(); + var userData = PinContext.PinForNativeDeleter(data, out var dataPtr, out var dataSize); try { item.Format = format; - item.SetNativeAudioOwned(pinCtx.Pointer, pinCtx.Length, pinCtx.Pointer, format, s_deleterPtr, userData); - item._data = pinCtx.Pointer; - item._dataSize = pinCtx.Length; + item.SetNativeAudioOwned(dataPtr, dataSize, dataPtr, format, s_deleterPtr, userData); + item._data = dataPtr; + item._dataSize = dataSize; return item; } catch @@ -196,18 +192,17 @@ public static AudioItem CreateOwned(string format, ReadOnlyMemory data, in public static AudioItem CreateOwned(string format, Memory data, int sampleRate, int channels) { var item = new AudioItem(ItemType.Audio); - var pinCtx = PinContext.Pin(data); - var userData = pinCtx.AllocForNativeDeleter(); + var userData = PinContext.PinForNativeDeleter(data, out var dataPtr, out var dataSize); try { item.Format = format; item.SampleRate = sampleRate; item.Channels = channels; - item.SetNativeAudioOwned(pinCtx.Pointer, pinCtx.Length, pinCtx.Pointer, format, s_deleterPtr, userData, + item.SetNativeAudioOwned(dataPtr, dataSize, dataPtr, format, s_deleterPtr, userData, sampleRate, channels); - item._data = pinCtx.Pointer; - item._dataSize = pinCtx.Length; + item._data = dataPtr; + item._dataSize = dataSize; return item; } catch diff --git a/sdk_v2/cs/src/Items/BytesItem.cs b/sdk_v2/cs/src/Items/BytesItem.cs index 26619bd2a..df25d7717 100644 --- a/sdk_v2/cs/src/Items/BytesItem.cs +++ b/sdk_v2/cs/src/Items/BytesItem.cs @@ -1,16 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +namespace Microsoft.AI.Foundry.Local; + using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -#pragma warning disable IDISP001 -#pragma warning disable IDISP023 - -namespace Microsoft.AI.Foundry.Local; - public sealed class BytesItem : Item { private IntPtr _data; @@ -85,14 +82,13 @@ public static BytesItem CreateOwned(ReadOnlyMemory data) public static BytesItem CreateOwned(Memory data) { var item = new BytesItem(ItemType.Bytes); - var pinCtx = PinContext.Pin(data); - var userData = pinCtx.AllocForNativeDeleter(); + var userData = PinContext.PinForNativeDeleter(data, out var dataPtr, out var dataSize); try { - item.SetNativeBytesOwned(pinCtx.Pointer, pinCtx.Length, pinCtx.Pointer, s_deleterPtr, userData); - item._data = pinCtx.Pointer; - item._dataSize = pinCtx.Length; + item.SetNativeBytesOwned(dataPtr, dataSize, dataPtr, s_deleterPtr, userData); + item._data = dataPtr; + item._dataSize = dataSize; return item; } catch diff --git a/sdk_v2/cs/src/Items/ImageItem.cs b/sdk_v2/cs/src/Items/ImageItem.cs index 16c4b3a63..0a832f115 100644 --- a/sdk_v2/cs/src/Items/ImageItem.cs +++ b/sdk_v2/cs/src/Items/ImageItem.cs @@ -1,16 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +namespace Microsoft.AI.Foundry.Local; + using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -#pragma warning disable IDISP001 -#pragma warning disable IDISP023 - -namespace Microsoft.AI.Foundry.Local; - public sealed class ImageItem : Item { private IntPtr _data; @@ -148,15 +145,14 @@ public static ImageItem CreateOwned(string format, ReadOnlyMemory data) public static ImageItem CreateOwned(string format, Memory data) { var item = new ImageItem(ItemType.Image); - var pinCtx = PinContext.Pin(data); - var userData = pinCtx.AllocForNativeDeleter(); + var userData = PinContext.PinForNativeDeleter(data, out var dataPtr, out var dataSize); try { item.Format = format; - item.SetNativeImageOwned(pinCtx.Pointer, pinCtx.Length, pinCtx.Pointer, format, s_deleterPtr, userData); - item._data = pinCtx.Pointer; - item._dataSize = pinCtx.Length; + item.SetNativeImageOwned(dataPtr, dataSize, dataPtr, format, s_deleterPtr, userData); + item._data = dataPtr; + item._dataSize = dataSize; return item; } catch diff --git a/sdk_v2/cs/src/Items/ItemQueue.cs b/sdk_v2/cs/src/Items/ItemQueue.cs index b07759ce5..08d5e0fa3 100644 --- a/sdk_v2/cs/src/Items/ItemQueue.cs +++ b/sdk_v2/cs/src/Items/ItemQueue.cs @@ -34,12 +34,16 @@ internal ItemQueue(IntPtr ptr, bool ownsHandle) : base(ptr, ownsHandle) Api.CheckStatus(Api.Item.GetQueue(Ptr, out _queuePtr)); } - /// Push an item into the queue. Transfers ownership of the item. + /// Push an item into the queue. Transfers ownership of the item on success. public void Push(Item item) { Detail.Throw.IfNull(item); - var nativePtr = item.ReleaseOwnership(); - Api.CheckStatus(Api.Item.QueuePush(_queuePtr, nativePtr)); + + // Hand the native handle to the queue first; only relinquish C#-side ownership once the push + // has succeeded. If QueuePush throws, the caller still owns the item and can dispose it (e.g. + // via a `using`), so a failed push never leaks the handle. + Api.CheckStatus(Api.Item.QueuePush(_queuePtr, item.Ptr)); + item.ReleaseOwnership(); } /// Try to pop an item from the queue. Returns null if queue is empty. diff --git a/sdk_v2/cs/src/Items/PinContext.cs b/sdk_v2/cs/src/Items/PinContext.cs index f07d599f9..325f4cf9e 100644 --- a/sdk_v2/cs/src/Items/PinContext.cs +++ b/sdk_v2/cs/src/Items/PinContext.cs @@ -1,11 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +namespace Microsoft.AI.Foundry.Local; + using System.Buffers; using System.Runtime.InteropServices; -namespace Microsoft.AI.Foundry.Local; - /// /// Manages pinning of Memory/ReadOnlyMemory buffers for native interop. /// Borrowed items hold a PinContext and dispose it. Owned items transfer @@ -44,15 +44,47 @@ public static PinContext Pin(ReadOnlyMemory data) public static PinContext Pin(Memory data) => Pin((ReadOnlyMemory)data); + /// + /// Pin and immediately transfer ownership of the pin to a GCHandle + /// that the native deleter releases via . Returns the IntPtr + /// to pass as deleter_user_data, along with the stable pointer/length of the pinned data. + /// + /// + /// No escapes to the caller: it is created and rooted in the GCHandle + /// entirely within this call, so the pin lives until the native item is destroyed. If rooting + /// fails, the pin is released here so the buffer is never left pinned. + /// + public static IntPtr PinForNativeDeleter(Memory data, out IntPtr pointer, out int length) + { + // IDisposableAnalyzers cannot model ownership that is handed to unmanaged code: the pin is + // rooted in a GCHandle and released by a native deleter callback, neither of which the + // analyzer can see. This is the single ownership-transfer boundary for all owned items, so + // the suppression lives here once rather than being scattered across the item factories. +#pragma warning disable IDISP001 // Dispose created — ownership is transferred to the native deleter. + var ctx = Pin(data); +#pragma warning restore IDISP001 + pointer = ctx.Pointer; + length = ctx.Length; + + try + { + return AllocForNativeDeleter(ctx); + } + catch + { + ctx.Dispose(); + throw; + } + } + /// /// Allocate a GCHandle so the native deleter can find this PinContext. /// Returns the IntPtr to pass as deleter_user_data. - /// After this call, the PinContext is kept alive by the GCHandle — the caller - /// should NOT store or dispose it. + /// After this call, the PinContext is kept alive by the GCHandle. /// - public IntPtr AllocForNativeDeleter() + private static IntPtr AllocForNativeDeleter(PinContext ctx) { - var gcHandle = GCHandle.Alloc(this, GCHandleType.Normal); + var gcHandle = GCHandle.Alloc(ctx, GCHandleType.Normal); return GCHandle.ToIntPtr(gcHandle); } diff --git a/sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj b/sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj index cd4c1c6de..b300666f2 100644 --- a/sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj +++ b/sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj @@ -110,6 +110,18 @@ + + + $(NoWarn);CA2000 + + diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj b/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj index 9ab9aa853..2f1e6f1a0 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj +++ b/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj @@ -21,6 +21,17 @@ false + + + $(NoWarn);CA2000 + + From 6460962b36498d01fe734805bafcbcad3b564654 Mon Sep 17 00:00:00 2001 From: Scott McKay Date: Fri, 19 Jun 2026 18:35:37 +1000 Subject: [PATCH 2/2] Run code cleanup to make code formatting more consistent. --- sdk_v2/cs/src/Catalog.cs | 1 - sdk_v2/cs/src/Detail/DllLoader.Modern.cs | 3 +- sdk_v2/cs/src/Detail/DllLoader.NetStandard.cs | 3 +- sdk_v2/cs/src/Detail/DllLoader.cs | 3 +- sdk_v2/cs/src/Detail/FoundryLocalApi.cs | 1236 ++++++------- sdk_v2/cs/src/Detail/NativeMethods.cs | 1595 +++++++++-------- sdk_v2/cs/src/Detail/Throw.cs | 7 +- sdk_v2/cs/src/Detail/Utf8.cs | 7 +- sdk_v2/cs/src/Enums.cs | 7 +- sdk_v2/cs/src/FoundryModelInfo.cs | 1 - sdk_v2/cs/src/GlobalSuppressions.cs | 1 - sdk_v2/cs/src/Items/AudioItem.cs | 7 +- sdk_v2/cs/src/Items/BytesItem.cs | 7 +- sdk_v2/cs/src/Items/ImageItem.cs | 7 +- sdk_v2/cs/src/Items/InputOutputInfo.cs | 9 +- sdk_v2/cs/src/Items/Item.cs | 30 +- sdk_v2/cs/src/Items/ItemQueue.cs | 5 +- sdk_v2/cs/src/Items/JsonItem.cs | 7 +- sdk_v2/cs/src/Items/MessageItem.cs | 11 +- sdk_v2/cs/src/Items/PinContext.cs | 7 +- sdk_v2/cs/src/Items/TensorItem.cs | 10 +- sdk_v2/cs/src/Items/TextItem.cs | 10 +- sdk_v2/cs/src/Items/ToolCallItem.cs | 10 +- sdk_v2/cs/src/Items/ToolResultItem.cs | 10 +- sdk_v2/cs/src/OpenAI/ChatClient.cs | 5 +- .../ChatCompletionRequestResponseTypes.cs | 4 +- .../OpenAI/LiveAudioTranscriptionClient.cs | 1 + .../src/OpenAI/LiveAudioTranscriptionTypes.cs | 8 + sdk_v2/cs/src/OpenAI/ToolCallingExtensions.cs | 4 +- sdk_v2/cs/src/Request.cs | 5 +- sdk_v2/cs/src/Session.cs | 1 - sdk_v2/cs/src/Utils.cs | 3 +- .../test/FoundryLocal.Tests/CatalogTests.cs | 1 - .../FoundryLocal.Tests/ChatSessionTests.cs | 2 +- .../EmbeddingsSessionTests.cs | 3 +- .../FoundryLocalManagerTest.cs | 1 + .../LiveAudioTranscriptionTests.cs | 4 +- .../SessionItemLifecycleTests.cs | 3 +- .../FoundryLocal.Tests/SkipInCIAttribute.cs | 4 +- .../cs/test/FoundryLocal.Tests/VisionTests.cs | 1 - 40 files changed, 1543 insertions(+), 1501 deletions(-) diff --git a/sdk_v2/cs/src/Catalog.cs b/sdk_v2/cs/src/Catalog.cs index 7b58ba313..95d50a5e0 100644 --- a/sdk_v2/cs/src/Catalog.cs +++ b/sdk_v2/cs/src/Catalog.cs @@ -6,7 +6,6 @@ namespace Microsoft.AI.Foundry.Local; -using System; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/sdk_v2/cs/src/Detail/DllLoader.Modern.cs b/sdk_v2/cs/src/Detail/DllLoader.Modern.cs index c61b66a60..4307ab8cf 100644 --- a/sdk_v2/cs/src/Detail/DllLoader.Modern.cs +++ b/sdk_v2/cs/src/Detail/DllLoader.Modern.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -12,6 +12,7 @@ namespace Microsoft.AI.Foundry.Local.Detail; using System.Runtime.InteropServices; + using Microsoft.AI.Foundry.Local.Detail.Interop; internal static partial class DllLoader diff --git a/sdk_v2/cs/src/Detail/DllLoader.NetStandard.cs b/sdk_v2/cs/src/Detail/DllLoader.NetStandard.cs index bad97278d..f9df521a8 100644 --- a/sdk_v2/cs/src/Detail/DllLoader.NetStandard.cs +++ b/sdk_v2/cs/src/Detail/DllLoader.NetStandard.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -16,6 +16,7 @@ namespace Microsoft.AI.Foundry.Local.Detail; using System.Runtime.InteropServices; + using Microsoft.AI.Foundry.Local.Detail.Interop; internal static partial class DllLoader diff --git a/sdk_v2/cs/src/Detail/DllLoader.cs b/sdk_v2/cs/src/Detail/DllLoader.cs index 062b44866..1f1104f4a 100644 --- a/sdk_v2/cs/src/Detail/DllLoader.cs +++ b/sdk_v2/cs/src/Detail/DllLoader.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -7,6 +7,7 @@ namespace Microsoft.AI.Foundry.Local.Detail; using System.Runtime.InteropServices; + using Microsoft.AI.Foundry.Local.Detail.Interop; /// diff --git a/sdk_v2/cs/src/Detail/FoundryLocalApi.cs b/sdk_v2/cs/src/Detail/FoundryLocalApi.cs index e286c7e83..32c508a73 100644 --- a/sdk_v2/cs/src/Detail/FoundryLocalApi.cs +++ b/sdk_v2/cs/src/Detail/FoundryLocalApi.cs @@ -1,805 +1,807 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + // High-level managed API mirroring the C++ foundry_local class hierarchy. // Native handles are internal implementation details; public API returns domain classes. -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Microsoft.AI.Foundry.Local.Detail.Interop; - // Suppress IDisposableAnalyzers warnings for the bindings layer: // - IDISP015: Item cache pattern is intentional (ModelList holds non-owning Model references) // - IDISP023: Item.~Item finalizer accesses Api which is a static, always available #pragma warning disable IDISP015 #pragma warning disable IDISP023 -namespace Microsoft.AI.Foundry.Local.Detail.Native +namespace Microsoft.AI.Foundry.Local.Detail.Native; + +using System.Runtime.InteropServices; + +using Microsoft.AI.Foundry.Local.Detail.Interop; + + +// =================================================================== +// Internal API bootstrap (hidden from consumers) +// =================================================================== + +internal static class Api { - // =================================================================== - // Internal API bootstrap (hidden from consumers) - // =================================================================== - - internal static class Api - { - internal static FlApi Root; - internal static FlItemApi Item; - internal static FlInferenceApi Inference; - internal static FlConfigurationApi Config; - internal static FlCatalogApi Catalog; - internal static FlModelApi Model; - private static volatile bool _initialized; - private static readonly object _initLock = new(); - - internal static void EnsureInitialized() + internal static FlApi Root; + internal static FlItemApi Item; + internal static FlInferenceApi Inference; + internal static FlConfigurationApi Config; + internal static FlCatalogApi Catalog; + internal static FlModelApi Model; + private static volatile bool _initialized; + private static readonly object _initLock = new(); + + internal static void EnsureInitialized() + { + if (_initialized) + { + return; + } + + lock (_initLock) { if (_initialized) { return; } - lock (_initLock) + var apiPtr = NativeMethods.FoundryLocalGetApi(NativeMethods.ApiVersion); + if (apiPtr == IntPtr.Zero) { - if (_initialized) - { - return; - } - - var apiPtr = NativeMethods.FoundryLocalGetApi(NativeMethods.ApiVersion); - if (apiPtr == IntPtr.Zero) - { - throw new InvalidOperationException( - $"FoundryLocalGetApi returned null for version {NativeMethods.ApiVersion}."); - } - - Root = Marshal.PtrToStructure(apiPtr); - - var p = Root.GetItemApi(); - if (p != IntPtr.Zero) - { - Item = Marshal.PtrToStructure(p); - } - - p = Root.GetInferenceApi(); - if (p != IntPtr.Zero) - { - Inference = Marshal.PtrToStructure(p); - } - - p = Root.GetConfigurationApi(); - if (p != IntPtr.Zero) - { - Config = Marshal.PtrToStructure(p); - } - - p = Root.GetCatalogApi(); - if (p != IntPtr.Zero) - { - Catalog = Marshal.PtrToStructure(p); - } + throw new InvalidOperationException( + $"FoundryLocalGetApi returned null for version {NativeMethods.ApiVersion}."); + } - p = Root.GetModelApi(); - if (p != IntPtr.Zero) - { - Model = Marshal.PtrToStructure(p); - } + Root = Marshal.PtrToStructure(apiPtr); - _initialized = true; + var p = Root.GetItemApi(); + if (p != IntPtr.Zero) + { + Item = Marshal.PtrToStructure(p); } - } - internal static void CheckStatus(IntPtr status) - { - if (status == IntPtr.Zero) + p = Root.GetInferenceApi(); + if (p != IntPtr.Zero) { - return; + Inference = Marshal.PtrToStructure(p); } - var code = Root.StatusGetErrorCode(status); - var msgPtr = Root.StatusGetErrorMessage(status); - var msg = msgPtr == IntPtr.Zero ? "Unknown error" : Detail.Utf8.PtrToString(msgPtr) ?? "Unknown error"; - Root.StatusRelease(status); - - if (code == FlErrorCode.OperationCancelled) + p = Root.GetConfigurationApi(); + if (p != IntPtr.Zero) { - throw new OperationCanceledException(msg); + Config = Marshal.PtrToStructure(p); } - throw new Microsoft.AI.Foundry.Local.FoundryLocalException(msg); - } + p = Root.GetCatalogApi(); + if (p != IntPtr.Zero) + { + Catalog = Marshal.PtrToStructure(p); + } - /// - /// Finalizer-safe native handle release. Skips when the runtime is shutting down - /// (the native DLL may already be unloaded) and swallows any exception (finalizers - /// must not throw). Intended only for use from ~Type(); Dispose() - /// paths should call the release delegate directly. - /// - internal static void FinalizeRelease(IntPtr ptr, Action release) - { - if (ptr == IntPtr.Zero || Environment.HasShutdownStarted) + p = Root.GetModelApi(); + if (p != IntPtr.Zero) { - return; + Model = Marshal.PtrToStructure(p); } - try { release(ptr); } catch { } + _initialized = true; } } - // =================================================================== - // Static entry point - // =================================================================== - - public static class FoundryLocal + internal static void CheckStatus(IntPtr status) { - public static string GetVersionString() + if (status == IntPtr.Zero) { - var ptr = NativeMethods.FoundryLocalGetVersionString(); - return ptr == IntPtr.Zero ? string.Empty : Utf8.PtrToString(ptr) ?? string.Empty; + return; } - } - - // =================================================================== - // Configuration — fluent builder, owns flConfiguration* - // =================================================================== - public sealed class Configuration : IDisposable - { - internal IntPtr Ptr { get; private set; } - private bool _disposed; + var code = Root.StatusGetErrorCode(status); + var msgPtr = Root.StatusGetErrorMessage(status); + var msg = msgPtr == IntPtr.Zero ? "Unknown error" : Detail.Utf8.PtrToString(msgPtr) ?? "Unknown error"; + Root.StatusRelease(status); - public Configuration(string appName) + if (code == FlErrorCode.OperationCancelled) { - Api.EnsureInitialized(); - var status = Api.Config.Create(appName, out var ptr); - Api.CheckStatus(status); - Ptr = ptr; + throw new OperationCanceledException(msg); } - public Configuration SetAppDataDir(string dir) - { - Api.CheckStatus(Api.Config.SetAppDataDir(Ptr, dir)); - return this; - } + throw new Microsoft.AI.Foundry.Local.FoundryLocalException(msg); + } - public Configuration SetLogsDir(string dir) + /// + /// Finalizer-safe native handle release. Skips when the runtime is shutting down + /// (the native DLL may already be unloaded) and swallows any exception (finalizers + /// must not throw). Intended only for use from ~Type(); Dispose() + /// paths should call the release delegate directly. + /// + internal static void FinalizeRelease(IntPtr ptr, Action release) + { + if (ptr == IntPtr.Zero || Environment.HasShutdownStarted) { - Api.CheckStatus(Api.Config.SetLogsDir(Ptr, dir)); - return this; + return; } - public Configuration SetModelCacheDir(string dir) - { - Api.CheckStatus(Api.Config.SetModelCacheDir(Ptr, dir)); - return this; - } + try { release(ptr); } catch { } + } +} - public Configuration SetDefaultLogLevel(FlLogLevel level) - { - Api.CheckStatus(Api.Config.SetDefaultLogLevel(Ptr, level)); - return this; - } +// =================================================================== +// Static entry point +// =================================================================== - public Configuration AddCatalogUrl(string url, string? filterOverride = null) - { - Api.CheckStatus(Api.Config.AddCatalogUrl(Ptr, url, filterOverride)); - return this; - } +public static class FoundryLocal +{ + public static string GetVersionString() + { + var ptr = NativeMethods.FoundryLocalGetVersionString(); + return ptr == IntPtr.Zero ? string.Empty : Utf8.PtrToString(ptr) ?? string.Empty; + } +} - public Configuration AddWebServiceEndpoint(string url) - { - Api.CheckStatus(Api.Config.AddWebServiceEndpoint(Ptr, url)); - return this; - } +// =================================================================== +// Configuration — fluent builder, owns flConfiguration* +// =================================================================== - public Configuration SetAdditionalOptions(IntPtr options) - { - Api.CheckStatus(Api.Config.SetAdditionalOptions(Ptr, options)); - return this; - } +public sealed class Configuration : IDisposable +{ + internal IntPtr Ptr { get; private set; } + private bool _disposed; - public Configuration SetExternalServiceUrl(string url) - { - Api.CheckStatus(Api.Config.SetExternalServiceUrl(Ptr, url)); - return this; - } + public Configuration(string appName) + { + Api.EnsureInitialized(); + var status = Api.Config.Create(appName, out var ptr); + Api.CheckStatus(status); + Ptr = ptr; + } - public Configuration SetCatalogRegion(string region) - { - Api.CheckStatus(Api.Config.SetCatalogRegion(Ptr, region)); - return this; - } + public Configuration SetAppDataDir(string dir) + { + Api.CheckStatus(Api.Config.SetAppDataDir(Ptr, dir)); + return this; + } - public void Dispose() - { - if (!_disposed && Ptr != IntPtr.Zero) - { - Api.Config.Release(Ptr); - Ptr = IntPtr.Zero; - _disposed = true; - } + public Configuration SetLogsDir(string dir) + { + Api.CheckStatus(Api.Config.SetLogsDir(Ptr, dir)); + return this; + } - GC.SuppressFinalize(this); - } + public Configuration SetModelCacheDir(string dir) + { + Api.CheckStatus(Api.Config.SetModelCacheDir(Ptr, dir)); + return this; + } - ~Configuration() - { - if (!_disposed) - { - Api.FinalizeRelease(Ptr, Api.Config.Release.Invoke); - } - } + public Configuration SetDefaultLogLevel(FlLogLevel level) + { + Api.CheckStatus(Api.Config.SetDefaultLogLevel(Ptr, level)); + return this; } - // =================================================================== - // Manager — owns flManager*, created from Configuration - // =================================================================== + public Configuration AddCatalogUrl(string url, string? filterOverride = null) + { + Api.CheckStatus(Api.Config.AddCatalogUrl(Ptr, url, filterOverride)); + return this; + } - public sealed class Manager : IDisposable + public Configuration AddWebServiceEndpoint(string url) { - internal IntPtr Ptr { get; private set; } - private bool _disposed; + Api.CheckStatus(Api.Config.AddWebServiceEndpoint(Ptr, url)); + return this; + } - public Manager(Configuration config) - { - Api.EnsureInitialized(); - var status = Api.Root.ManagerCreate(config.Ptr, out var ptr); - Api.CheckStatus(status); - Ptr = ptr; - } + public Configuration SetAdditionalOptions(IntPtr options) + { + Api.CheckStatus(Api.Config.SetAdditionalOptions(Ptr, options)); + return this; + } - public Catalog GetCatalog() - { - var status = Api.Root.ManagerGetCatalog(Ptr, out var catalogPtr); - Api.CheckStatus(status); - return new Catalog(catalogPtr); - } + public Configuration SetExternalServiceUrl(string url) + { + Api.CheckStatus(Api.Config.SetExternalServiceUrl(Ptr, url)); + return this; + } - public void StartService() + public Configuration SetCatalogRegion(string region) + { + Api.CheckStatus(Api.Config.SetCatalogRegion(Ptr, region)); + return this; + } + + public void Dispose() + { + if (!_disposed && Ptr != IntPtr.Zero) { - Api.CheckStatus(Api.Root.ManagerWebServiceStart(Ptr)); + Api.Config.Release(Ptr); + Ptr = IntPtr.Zero; + _disposed = true; } - public void StopService() + GC.SuppressFinalize(this); + } + + ~Configuration() + { + if (!_disposed) { - Api.CheckStatus(Api.Root.ManagerWebServiceStop(Ptr)); + Api.FinalizeRelease(Ptr, Api.Config.Release.Invoke); } + } +} - public string[] GetServiceUrls() - { - var status = Api.Root.ManagerWebServiceUrls(Ptr, out var urlsPtr, out var count); - Api.CheckStatus(status); +// =================================================================== +// Manager — owns flManager*, created from Configuration +// =================================================================== - var numUrls = (int)(ulong)count; - var urls = new string[numUrls]; - for (int i = 0; i < numUrls; i++) - { - var strPtr = Marshal.ReadIntPtr(urlsPtr, i * IntPtr.Size); - urls[i] = Utf8.PtrToString(strPtr) ?? string.Empty; - } +public sealed class Manager : IDisposable +{ + internal IntPtr Ptr { get; private set; } + private bool _disposed; - return urls; - } + public Manager(Configuration config) + { + Api.EnsureInitialized(); + var status = Api.Root.ManagerCreate(config.Ptr, out var ptr); + Api.CheckStatus(status); + Ptr = ptr; + } - public EpInfo[] GetDiscoverableEps() - { - var status = Api.Root.ManagerGetDiscoverableEps(Ptr, out var epsPtr, out var count); - Api.CheckStatus(status); + public Catalog GetCatalog() + { + var status = Api.Root.ManagerGetCatalog(Ptr, out var catalogPtr); + Api.CheckStatus(status); + return new Catalog(catalogPtr); + } - var numEps = (int)(ulong)count; - var result = new EpInfo[numEps]; + public void StartService() + { + Api.CheckStatus(Api.Root.ManagerWebServiceStart(Ptr)); + } - if (numEps > 0) - { - var structSize = Marshal.SizeOf(); - for (int i = 0; i < numEps; i++) - { - var entryPtr = IntPtr.Add(epsPtr, i * structSize); - var entry = Marshal.PtrToStructure(entryPtr); - result[i] = new EpInfo - { - Name = Utf8.PtrToString(entry.Name) ?? string.Empty, - IsRegistered = entry.IsRegistered, - }; - } - } + public void StopService() + { + Api.CheckStatus(Api.Root.ManagerWebServiceStop(Ptr)); + } - return result; - } + public string[] GetServiceUrls() + { + var status = Api.Root.ManagerWebServiceUrls(Ptr, out var urlsPtr, out var count); + Api.CheckStatus(status); - public void DownloadAndRegisterEps(string[]? epNames, FlEpProgressCallback? callback) + var numUrls = (int)(ulong)count; + var urls = new string[numUrls]; + for (int i = 0; i < numUrls; i++) { - IntPtr namesArray = IntPtr.Zero; - UIntPtr nameCount = UIntPtr.Zero; - GCHandle[]? handles = null; - GCHandle ptrHandle = default; + var strPtr = Marshal.ReadIntPtr(urlsPtr, i * IntPtr.Size); + urls[i] = Utf8.PtrToString(strPtr) ?? string.Empty; + } - try - { - if (epNames != null && epNames.Length > 0) - { - handles = new GCHandle[epNames.Length]; - var ptrs = new IntPtr[epNames.Length]; + return urls; + } - for (int i = 0; i < epNames.Length; i++) - { - var bytes = System.Text.Encoding.UTF8.GetBytes(epNames[i] + '\0'); - handles[i] = GCHandle.Alloc(bytes, GCHandleType.Pinned); - ptrs[i] = handles[i].AddrOfPinnedObject(); - } + public EpInfo[] GetDiscoverableEps() + { + var status = Api.Root.ManagerGetDiscoverableEps(Ptr, out var epsPtr, out var count); + Api.CheckStatus(status); - ptrHandle = GCHandle.Alloc(ptrs, GCHandleType.Pinned); - namesArray = ptrHandle.AddrOfPinnedObject(); - nameCount = (UIntPtr)epNames.Length; + var numEps = (int)(ulong)count; + var result = new EpInfo[numEps]; - var status = Api.Root.ManagerDownloadAndRegisterEps(Ptr, namesArray, nameCount, callback, IntPtr.Zero); - Api.CheckStatus(status); - } - else - { - var status = Api.Root.ManagerDownloadAndRegisterEps(Ptr, IntPtr.Zero, UIntPtr.Zero, callback, IntPtr.Zero); - Api.CheckStatus(status); - } - } - finally + if (numEps > 0) + { + var structSize = Marshal.SizeOf(); + for (int i = 0; i < numEps; i++) { - if (ptrHandle.IsAllocated) + var entryPtr = IntPtr.Add(epsPtr, i * structSize); + var entry = Marshal.PtrToStructure(entryPtr); + result[i] = new EpInfo { - ptrHandle.Free(); - } - - if (handles != null) - { - foreach (var h in handles) - { - if (h.IsAllocated) - { - h.Free(); - } - } - } + Name = Utf8.PtrToString(entry.Name) ?? string.Empty, + IsRegistered = entry.IsRegistered, + }; } } - public bool IsEpDownloadInProgress() - { - return Api.Root.ManagerIsEpDownloadInProgress(Ptr); - } + return result; + } - public void Shutdown() - { - Api.CheckStatus(Api.Root.ManagerShutdown(Ptr)); - } + public void DownloadAndRegisterEps(string[]? epNames, FlEpProgressCallback? callback) + { + IntPtr namesArray = IntPtr.Zero; + UIntPtr nameCount = UIntPtr.Zero; + GCHandle[]? handles = null; + GCHandle ptrHandle = default; - public bool IsShutdownRequested() + try { - return Api.Root.ManagerIsShutdownRequested(Ptr); - } + if (epNames != null && epNames.Length > 0) + { + handles = new GCHandle[epNames.Length]; + var ptrs = new IntPtr[epNames.Length]; - public void Dispose() - { - if (!_disposed && Ptr != IntPtr.Zero) + for (int i = 0; i < epNames.Length; i++) + { + var bytes = System.Text.Encoding.UTF8.GetBytes(epNames[i] + '\0'); + handles[i] = GCHandle.Alloc(bytes, GCHandleType.Pinned); + ptrs[i] = handles[i].AddrOfPinnedObject(); + } + + ptrHandle = GCHandle.Alloc(ptrs, GCHandleType.Pinned); + namesArray = ptrHandle.AddrOfPinnedObject(); + nameCount = (UIntPtr)epNames.Length; + + var status = Api.Root.ManagerDownloadAndRegisterEps(Ptr, namesArray, nameCount, callback, IntPtr.Zero); + Api.CheckStatus(status); + } + else { - Api.Root.ManagerRelease(Ptr); - Ptr = IntPtr.Zero; - _disposed = true; + var status = Api.Root.ManagerDownloadAndRegisterEps(Ptr, IntPtr.Zero, UIntPtr.Zero, callback, IntPtr.Zero); + Api.CheckStatus(status); } - - GC.SuppressFinalize(this); } - - ~Manager() + finally { - if (!_disposed) + if (ptrHandle.IsAllocated) { - Api.FinalizeRelease(Ptr, Api.Root.ManagerRelease.Invoke); + ptrHandle.Free(); + } + + if (handles != null) + { + foreach (var h in handles) + { + if (h.IsAllocated) + { + h.Free(); + } + } } } } - // =================================================================== - // Catalog — non-owning (lifetime tied to Manager) - // =================================================================== - - public sealed class Catalog + public bool IsEpDownloadInProgress() { - internal IntPtr Ptr { get; } + return Api.Root.ManagerIsEpDownloadInProgress(Ptr); + } - internal Catalog(IntPtr ptr) => Ptr = ptr; + public void Shutdown() + { + Api.CheckStatus(Api.Root.ManagerShutdown(Ptr)); + } - public string GetName() - { - var status = Api.Catalog.GetName(Ptr, out var namePtr); - Api.CheckStatus(status); - return Utf8.PtrToString(namePtr) ?? string.Empty; - } + public bool IsShutdownRequested() + { + return Api.Root.ManagerIsShutdownRequested(Ptr); + } - public ModelList GetModels() + public void Dispose() + { + if (!_disposed && Ptr != IntPtr.Zero) { - var status = Api.Catalog.GetModels(Ptr, out var ptr); - Api.CheckStatus(status); - return new ModelList(ptr); + Api.Root.ManagerRelease(Ptr); + Ptr = IntPtr.Zero; + _disposed = true; } - public Model? GetModel(string alias) - { - var status = Api.Catalog.GetModel(Ptr, alias, out var ptr); - Api.CheckStatus(status); - return ptr == IntPtr.Zero ? null : new Model(ptr); - } + GC.SuppressFinalize(this); + } - public Model? GetModelVariant(string modelId) + ~Manager() + { + if (!_disposed) { - var status = Api.Catalog.GetModelVariant(Ptr, modelId, out var ptr); - Api.CheckStatus(status); - return ptr == IntPtr.Zero ? null : new Model(ptr); + Api.FinalizeRelease(Ptr, Api.Root.ManagerRelease.Invoke); } + } +} - public Model GetLatestVersion(Model model) - { - var status = Api.Catalog.GetLatestVersion(Ptr, model.Ptr, out var ptr); - Api.CheckStatus(status); +// =================================================================== +// Catalog — non-owning (lifetime tied to Manager) +// =================================================================== - if (ptr == IntPtr.Zero) - { - // Defensive: native should already have returned INVALID_ARGUMENT (which - // CheckStatus throws above). Reaching here means the input IModel was not - // produced by this catalog — user error, since IModel instances should - // only come from Catalog APIs. - throw new FoundryLocalException( - "GetLatestVersion returned no model. The IModel argument was not produced by this catalog."); - } - - return new Model(ptr); - } +public sealed class Catalog +{ + internal IntPtr Ptr { get; } - public ModelList GetCachedModels() - { - var status = Api.Catalog.GetCachedModels(Ptr, out var ptr); - Api.CheckStatus(status); - return new ModelList(ptr); - } + internal Catalog(IntPtr ptr) => Ptr = ptr; - public ModelList GetLoadedModels() - { - var status = Api.Catalog.GetLoadedModels(Ptr, out var ptr); - Api.CheckStatus(status); - return new ModelList(ptr); - } + public string GetName() + { + var status = Api.Catalog.GetName(Ptr, out var namePtr); + Api.CheckStatus(status); + return Utf8.PtrToString(namePtr) ?? string.Empty; } - // =================================================================== - // ModelInfo — non-owning read-only view (lifetime tied to Model) - // =================================================================== - - public sealed class ModelInfo - { - private readonly IntPtr _ptr; - - internal ModelInfo(IntPtr ptr) => _ptr = ptr; - - // Core identity (always present — never null) - public string Id => Utf8.PtrToString(Api.Model.InfoGetId(_ptr))!; - public string Name => Utf8.PtrToString(Api.Model.InfoGetName(_ptr))!; - public int Version => Api.Model.InfoGetVersion(_ptr); - public string Alias => Utf8.PtrToString(Api.Model.InfoGetAlias(_ptr))!; - public string? Uri => Utf8.PtrToString(Api.Model.InfoGetUri(_ptr)); - public FlDeviceType DeviceType => Api.Model.InfoGetDeviceType(_ptr); - public string? ExecutionProvider => Utf8.PtrToString(Api.Model.InfoGetExecutionProvider(_ptr)); - public string? Task => Utf8.PtrToString(Api.Model.InfoGetTask(_ptr)); - - // Generic property accessors - public string? GetStringProperty(string key) => - Utf8.PtrToString(Api.Model.InfoGetStringProperty(_ptr, key)); - - public long GetIntProperty(string key, long defaultValue = -1) => - Api.Model.InfoGetIntProperty(_ptr, key, defaultValue); - - // Typed convenience properties - public string? DisplayName => GetStringProperty(ModelProperties.DisplayName); - public string? ModelType => GetStringProperty(ModelProperties.ModelType); - public string? Publisher => GetStringProperty(ModelProperties.Publisher); - public string? License => GetStringProperty(ModelProperties.License); - public string? LicenseDescription => GetStringProperty(ModelProperties.LicenseDescription); - public string? ModelProvider => GetStringProperty(ModelProperties.ModelProvider); - public string? MinFlVersion => GetStringProperty(ModelProperties.MinFlVersion); - public string? ParentUri => GetStringProperty(ModelProperties.ParentUri); - public string? ToolCallStart => GetStringProperty(ModelProperties.ToolCallStart); - public string? ToolCallEnd => GetStringProperty(ModelProperties.ToolCallEnd); - - public long SupportsToolCalling => GetIntProperty(ModelProperties.SupportsToolCalling, -1); - public long FilesizeMb => GetIntProperty(ModelProperties.FileSizeMb, -1); - public long MaxOutputTokens => GetIntProperty(ModelProperties.MaxOutputTokens, -1); - public long CreatedAtUnix => GetIntProperty(ModelProperties.CreatedAtUnix, 0); - public long IsTestModel => GetIntProperty(ModelProperties.IsTestModel, 0); - - /// - /// Enumerates the model's default/recommended settings as a key/value dictionary. - /// Returns null if the model has no settings declared. - /// - public Dictionary? GetModelSettings() - { - var kvpsPtr = Api.Model.InfoGetModelSettings(_ptr); - if (kvpsPtr == IntPtr.Zero) - { - return null; - } + public ModelList GetModels() + { + var status = Api.Catalog.GetModels(Ptr, out var ptr); + Api.CheckStatus(status); + return new ModelList(ptr); + } - Api.Root.GetKeyValuePairs(kvpsPtr, out var keysPtr, out var valuesPtr, out var count); - var numEntries = (int)(ulong)count; - if (numEntries == 0) - { - return new Dictionary(); - } + public Model? GetModel(string alias) + { + var status = Api.Catalog.GetModel(Ptr, alias, out var ptr); + Api.CheckStatus(status); + return ptr == IntPtr.Zero ? null : new Model(ptr); + } - var result = new Dictionary(numEntries); - unsafe - { - var keys = (IntPtr*)keysPtr; - var values = (IntPtr*)valuesPtr; - for (int i = 0; i < numEntries; i++) - { - var key = Utf8.PtrToString(keys[i]); - if (key == null) - { - continue; - } + public Model? GetModelVariant(string modelId) + { + var status = Api.Catalog.GetModelVariant(Ptr, modelId, out var ptr); + Api.CheckStatus(status); + return ptr == IntPtr.Zero ? null : new Model(ptr); + } - result[key] = Utf8.PtrToString(values[i]); - } - } + public Model GetLatestVersion(Model model) + { + var status = Api.Catalog.GetLatestVersion(Ptr, model.Ptr, out var ptr); + Api.CheckStatus(status); - return result; + if (ptr == IntPtr.Zero) + { + // Defensive: native should already have returned INVALID_ARGUMENT (which + // CheckStatus throws above). Reaching here means the input IModel was not + // produced by this catalog — user error, since IModel instances should + // only come from Catalog APIs. + throw new FoundryLocalException( + "GetLatestVersion returned no model. The IModel argument was not produced by this catalog."); } + + return new Model(ptr); } - // =================================================================== - // Model — non-owning (lifetime tied to ModelList/Catalog) - // =================================================================== + public ModelList GetCachedModels() + { + var status = Api.Catalog.GetCachedModels(Ptr, out var ptr); + Api.CheckStatus(status); + return new ModelList(ptr); + } - public sealed class Model + public ModelList GetLoadedModels() { - internal IntPtr Ptr { get; } + var status = Api.Catalog.GetLoadedModels(Ptr, out var ptr); + Api.CheckStatus(status); + return new ModelList(ptr); + } +} - internal Model(IntPtr ptr) => Ptr = ptr; +// =================================================================== +// ModelInfo — non-owning read-only view (lifetime tied to Model) +// =================================================================== - public ModelInfo GetInfo() +public sealed class ModelInfo +{ + private readonly IntPtr _ptr; + + internal ModelInfo(IntPtr ptr) => _ptr = ptr; + + // Core identity (always present — never null) + public string Id => Utf8.PtrToString(Api.Model.InfoGetId(_ptr))!; + public string Name => Utf8.PtrToString(Api.Model.InfoGetName(_ptr))!; + public int Version => Api.Model.InfoGetVersion(_ptr); + public string Alias => Utf8.PtrToString(Api.Model.InfoGetAlias(_ptr))!; + public string? Uri => Utf8.PtrToString(Api.Model.InfoGetUri(_ptr)); + public FlDeviceType DeviceType => Api.Model.InfoGetDeviceType(_ptr); + public string? ExecutionProvider => Utf8.PtrToString(Api.Model.InfoGetExecutionProvider(_ptr)); + public string? Task => Utf8.PtrToString(Api.Model.InfoGetTask(_ptr)); + + // Generic property accessors + public string? GetStringProperty(string key) => + Utf8.PtrToString(Api.Model.InfoGetStringProperty(_ptr, key)); + + public long GetIntProperty(string key, long defaultValue = -1) => + Api.Model.InfoGetIntProperty(_ptr, key, defaultValue); + + // Typed convenience properties + public string? DisplayName => GetStringProperty(ModelProperties.DisplayName); + public string? ModelType => GetStringProperty(ModelProperties.ModelType); + public string? Publisher => GetStringProperty(ModelProperties.Publisher); + public string? License => GetStringProperty(ModelProperties.License); + public string? LicenseDescription => GetStringProperty(ModelProperties.LicenseDescription); + public string? ModelProvider => GetStringProperty(ModelProperties.ModelProvider); + public string? MinFlVersion => GetStringProperty(ModelProperties.MinFlVersion); + public string? ParentUri => GetStringProperty(ModelProperties.ParentUri); + public string? ToolCallStart => GetStringProperty(ModelProperties.ToolCallStart); + public string? ToolCallEnd => GetStringProperty(ModelProperties.ToolCallEnd); + + public long SupportsToolCalling => GetIntProperty(ModelProperties.SupportsToolCalling, -1); + public long FilesizeMb => GetIntProperty(ModelProperties.FileSizeMb, -1); + public long MaxOutputTokens => GetIntProperty(ModelProperties.MaxOutputTokens, -1); + public long CreatedAtUnix => GetIntProperty(ModelProperties.CreatedAtUnix, 0); + public long IsTestModel => GetIntProperty(ModelProperties.IsTestModel, 0); + + /// + /// Enumerates the model's default/recommended settings as a key/value dictionary. + /// Returns null if the model has no settings declared. + /// + public Dictionary? GetModelSettings() + { + var kvpsPtr = Api.Model.InfoGetModelSettings(_ptr); + if (kvpsPtr == IntPtr.Zero) { - var status = Api.Model.GetInfo(Ptr, out var infoPtr); - Api.CheckStatus(status); - return new ModelInfo(infoPtr); + return null; } - public bool IsCached + Api.Root.GetKeyValuePairs(kvpsPtr, out var keysPtr, out var valuesPtr, out var count); + var numEntries = (int)(ulong)count; + if (numEntries == 0) { - get - { - var status = Api.Model.IsCached(Ptr, out var cached); - Api.CheckStatus(status); - return cached != 0; - } + return new Dictionary(); } - public bool IsLoaded + var result = new Dictionary(numEntries); + unsafe { - get + var keys = (IntPtr*)keysPtr; + var values = (IntPtr*)valuesPtr; + for (int i = 0; i < numEntries; i++) { - var status = Api.Model.IsLoaded(Ptr, out var loaded); - Api.CheckStatus(status); - return loaded != 0; + var key = Utf8.PtrToString(keys[i]); + if (key == null) + { + continue; + } + + result[key] = Utf8.PtrToString(values[i]); } } - public string? GetPath() - { - var status = Api.Model.GetPath(Ptr, out var pathPtr); - Api.CheckStatus(status); - return Utf8.PtrToString(pathPtr); - } + return result; + } +} - public void Download(Func? progress = null) - { - FlProgressCallback? nativeCallback = null; - if (progress != null) - { - nativeCallback = (value, _) => progress(value); - } +// =================================================================== +// Model — non-owning (lifetime tied to ModelList/Catalog) +// =================================================================== - var status = Api.Model.Download(Ptr, nativeCallback, IntPtr.Zero); - Api.CheckStatus(status); - } +public sealed class Model +{ + internal IntPtr Ptr { get; } - public void Load() - { - Api.CheckStatus(Api.Model.Load(Ptr)); - } + internal Model(IntPtr ptr) => Ptr = ptr; - public void Unload() - { - Api.CheckStatus(Api.Model.Unload(Ptr)); - } + public ModelInfo GetInfo() + { + var status = Api.Model.GetInfo(Ptr, out var infoPtr); + Api.CheckStatus(status); + return new ModelInfo(infoPtr); + } - public void RemoveFromCache() + public bool IsCached + { + get { - Api.CheckStatus(Api.Model.RemoveFromCache(Ptr)); + var status = Api.Model.IsCached(Ptr, out var cached); + Api.CheckStatus(status); + return cached != 0; } + } - public ModelList GetVariants() + public bool IsLoaded + { + get { - var status = Api.Model.GetVariants(Ptr, out var ptr); + var status = Api.Model.IsLoaded(Ptr, out var loaded); Api.CheckStatus(status); - return new ModelList(ptr); + return loaded != 0; } + } - public void SelectVariant(Model variant) + public string? GetPath() + { + var status = Api.Model.GetPath(Ptr, out var pathPtr); + Api.CheckStatus(status); + return Utf8.PtrToString(pathPtr); + } + + public void Download(Func? progress = null) + { + FlProgressCallback? nativeCallback = null; + if (progress != null) { - Api.CheckStatus(Api.Model.SelectVariant(Ptr, variant.Ptr)); + nativeCallback = (value, _) => progress(value); } + + var status = Api.Model.Download(Ptr, nativeCallback, IntPtr.Zero); + Api.CheckStatus(status); + } + + public void Load() + { + Api.CheckStatus(Api.Model.Load(Ptr)); } - // =================================================================== - // ModelList — owns flModelList*, disposes it - // =================================================================== + public void Unload() + { + Api.CheckStatus(Api.Model.Unload(Ptr)); + } + + public void RemoveFromCache() + { + Api.CheckStatus(Api.Model.RemoveFromCache(Ptr)); + } + + public ModelList GetVariants() + { + var status = Api.Model.GetVariants(Ptr, out var ptr); + Api.CheckStatus(status); + return new ModelList(ptr); + } - public sealed class ModelList : IDisposable + public void SelectVariant(Model variant) { - private IntPtr _ptr; - private bool _disposed; - private readonly List _models; + Api.CheckStatus(Api.Model.SelectVariant(Ptr, variant.Ptr)); + } +} + +// =================================================================== +// ModelList — owns flModelList*, disposes it +// =================================================================== + +public sealed class ModelList : IDisposable +{ + private IntPtr _ptr; + private bool _disposed; + private readonly List _models; - internal ModelList(IntPtr ptr) + internal ModelList(IntPtr ptr) + { + _ptr = ptr; + var count = (int)(ulong)Api.Root.ModelListSize(ptr); + _models = new List(count); + for (int i = 0; i < count; i++) { - _ptr = ptr; - var count = (int)(ulong)Api.Root.ModelListSize(ptr); - _models = new List(count); - for (int i = 0; i < count; i++) - { - _models.Add(new Model(Api.Root.ModelListGetAt(ptr, (UIntPtr)i))); - } + _models.Add(new Model(Api.Root.ModelListGetAt(ptr, (UIntPtr)i))); } + } - public IReadOnlyList Models => _models; + public IReadOnlyList Models => _models; - public void Dispose() + public void Dispose() + { + if (!_disposed && _ptr != IntPtr.Zero) { - if (!_disposed && _ptr != IntPtr.Zero) - { - Api.Root.ModelListRelease(_ptr); - _ptr = IntPtr.Zero; - _disposed = true; - } - - GC.SuppressFinalize(this); + Api.Root.ModelListRelease(_ptr); + _ptr = IntPtr.Zero; + _disposed = true; } - ~ModelList() + GC.SuppressFinalize(this); + } + + ~ModelList() + { + if (!_disposed) { - if (!_disposed) - { - Api.FinalizeRelease(_ptr, Api.Root.ModelListRelease.Invoke); - } + Api.FinalizeRelease(_ptr, Api.Root.ModelListRelease.Invoke); } } +} - // =================================================================== - // NOTE: The Item / Request / Response / *Content types that previously lived here - // were removed because the public hierarchies in Microsoft.AI.Foundry.Local - // (Items/Item.cs, Request.cs, Response.cs) are the single canonical wrappers used - // by both user code and NativeRequestRunner. Do not reintroduce parallel internal - // copies — extend the public types instead. - // =================================================================== +// =================================================================== +// NOTE: The Item / Request / Response / *Content types that previously lived here +// were removed because the public hierarchies in Microsoft.AI.Foundry.Local +// (Items/Item.cs, Request.cs, Response.cs) are the single canonical wrappers used +// by both user code and NativeRequestRunner. Do not reintroduce parallel internal +// copies — extend the public types instead. +// =================================================================== - // =================================================================== - // Session — owns flSession*, created from a loaded Model - // =================================================================== +// =================================================================== +// Session — owns flSession*, created from a loaded Model +// =================================================================== - public sealed class Session : IDisposable - { - internal IntPtr Ptr { get; private set; } - private bool _disposed; - private FlStreamingCallback? _callbackRef; // prevent GC +public sealed class Session : IDisposable +{ + internal IntPtr Ptr { get; private set; } + private bool _disposed; + private FlStreamingCallback? _callbackRef; // prevent GC - public Session(Model model) - { - Api.EnsureInitialized(); - var status = Api.Inference.SessionCreate(model.Ptr, out var ptr); - Api.CheckStatus(status); - Ptr = ptr; - } + public Session(Model model) + { + Api.EnsureInitialized(); + var status = Api.Inference.SessionCreate(model.Ptr, out var ptr); + Api.CheckStatus(status); + Ptr = ptr; + } - /// Add a tool definition to the session. The session copies the data. - public Session AddToolDefinition(string name, string description, string jsonSchema) + /// Add a tool definition to the session. The session copies the data. + public Session AddToolDefinition(string name, string description, string jsonSchema) + { + var nameNative = Utf8.StringToCoTaskMem(name); + var descNative = Utf8.StringToCoTaskMem(description); + var schemaNative = Utf8.StringToCoTaskMem(jsonSchema); + try { - var nameNative = Utf8.StringToCoTaskMem(name); - var descNative = Utf8.StringToCoTaskMem(description); - var schemaNative = Utf8.StringToCoTaskMem(jsonSchema); - try + var toolDef = new FlToolDefinition { - var toolDef = new FlToolDefinition - { - Version = NativeMethods.ApiVersion, - Name = nameNative, - Description = descNative, - JsonSchema = schemaNative, - }; - Api.CheckStatus(Api.Inference.SessionAddToolDefinition(Ptr, ref toolDef)); - } - finally - { - Marshal.FreeCoTaskMem(nameNative); - Marshal.FreeCoTaskMem(descNative); - Marshal.FreeCoTaskMem(schemaNative); - } - - return this; + Version = NativeMethods.ApiVersion, + Name = nameNative, + Description = descNative, + JsonSchema = schemaNative, + }; + Api.CheckStatus(Api.Inference.SessionAddToolDefinition(Ptr, ref toolDef)); } - - /// - /// Remove a previously-added tool definition by name. - /// Returns true if a matching tool was found and removed, false if no tool with that name was registered. - /// - public bool RemoveToolDefinition(string toolName) + finally { - Api.CheckStatus(Api.Inference.SessionRemoveToolDefinition(Ptr, toolName, out var removed)); - return removed; + Marshal.FreeCoTaskMem(nameNative); + Marshal.FreeCoTaskMem(descNative); + Marshal.FreeCoTaskMem(schemaNative); } - /// Set a streaming callback. Pass null to unset. - public Session SetStreamingCallback(FlStreamingCallback? callback) - { - _callbackRef = callback; - Api.CheckStatus(Api.Inference.SessionSetStreamingCallback(Ptr, callback, IntPtr.Zero)); - return this; - } + return this; + } - /// Set session-level inference options. Applies to all subsequent ProcessRequest calls. - public Session SetOptions(IntPtr options) - { - Api.CheckStatus(Api.Inference.SessionSetOptions(Ptr, options)); - return this; - } + /// + /// Remove a previously-added tool definition by name. + /// Returns true if a matching tool was found and removed, false if no tool with that name was registered. + /// + public bool RemoveToolDefinition(string toolName) + { + Api.CheckStatus(Api.Inference.SessionRemoveToolDefinition(Ptr, toolName, out var removed)); + return removed; + } - /// - /// Process a request. Returns a new Response pointer. Caller owns it. - /// - internal IntPtr ProcessRequest(IntPtr requestPtr) - { - IntPtr responsePtr = IntPtr.Zero; - Api.CheckStatus(Api.Inference.SessionProcessRequest(Ptr, requestPtr, ref responsePtr)); - return responsePtr; - } + /// Set a streaming callback. Pass null to unset. + public Session SetStreamingCallback(FlStreamingCallback? callback) + { + _callbackRef = callback; + Api.CheckStatus(Api.Inference.SessionSetStreamingCallback(Ptr, callback, IntPtr.Zero)); + return this; + } - /// Get the number of completed turns in the session. - public ulong TurnCount => (ulong)Api.Inference.SessionGetTurnCount(Ptr); + /// Set session-level inference options. Applies to all subsequent ProcessRequest calls. + public Session SetOptions(IntPtr options) + { + Api.CheckStatus(Api.Inference.SessionSetOptions(Ptr, options)); + return this; + } - /// - /// Undo the last turns: rewinds the generator and removes - /// the turns' messages from history. If all turns are undone, the cached generator is destroyed. - /// - public void UndoTurns(ulong count) - { - Api.CheckStatus(Api.Inference.SessionUndoTurns(Ptr, checked((UIntPtr)count))); - } + /// + /// Process a request. Returns a new Response pointer. Caller owns it. + /// + internal IntPtr ProcessRequest(IntPtr requestPtr) + { + IntPtr responsePtr = IntPtr.Zero; + Api.CheckStatus(Api.Inference.SessionProcessRequest(Ptr, requestPtr, ref responsePtr)); + return responsePtr; + } - public void Dispose() - { - if (!_disposed && Ptr != IntPtr.Zero) - { - _callbackRef = null; - Api.Inference.SessionRelease(Ptr); - Ptr = IntPtr.Zero; - _disposed = true; - } + /// Get the number of completed turns in the session. + public ulong TurnCount => (ulong)Api.Inference.SessionGetTurnCount(Ptr); - GC.SuppressFinalize(this); + /// + /// Undo the last turns: rewinds the generator and removes + /// the turns' messages from history. If all turns are undone, the cached generator is destroyed. + /// + public void UndoTurns(ulong count) + { + Api.CheckStatus(Api.Inference.SessionUndoTurns(Ptr, checked((UIntPtr)count))); + } + + public void Dispose() + { + if (!_disposed && Ptr != IntPtr.Zero) + { + _callbackRef = null; + Api.Inference.SessionRelease(Ptr); + Ptr = IntPtr.Zero; + _disposed = true; } - ~Session() + GC.SuppressFinalize(this); + } + + ~Session() + { + if (!_disposed) { - if (!_disposed) - { - Api.FinalizeRelease(Ptr, Api.Inference.SessionRelease.Invoke); - } + Api.FinalizeRelease(Ptr, Api.Inference.SessionRelease.Invoke); } } } diff --git a/sdk_v2/cs/src/Detail/NativeMethods.cs b/sdk_v2/cs/src/Detail/NativeMethods.cs index 3f913715a..52c3252fa 100644 --- a/sdk_v2/cs/src/Detail/NativeMethods.cs +++ b/sdk_v2/cs/src/Detail/NativeMethods.cs @@ -1,6 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -// +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + // Low-level P/Invoke bindings for the Foundry Local C API. // Generated from foundry_local_c.h — update when the C header changes. // @@ -16,963 +19,961 @@ // var api = Marshal.PtrToStructure(apiPtr); // // api.ManagerCreate(...), api.GetCatalogApi(), etc. -using System; -using System.Runtime.InteropServices; - // Suppress analyzer warnings for generated interop bindings that must match the C API header exactly. #pragma warning disable CA1720 // Identifier contains type name (enum values must match C header) #pragma warning disable CA1401 // P/Invokes should not be visible (internal use only, via Detail.Native.Api) #pragma warning disable SYSLIB1054 // Use LibraryImportAttribute (delegates use DllImport-only marshalling features) -namespace Microsoft.AI.Foundry.Local.Detail.Interop +namespace Microsoft.AI.Foundry.Local.Detail.Interop; + +using System.Runtime.InteropServices; + +// ----------------------------------------------------------------------- +// Constants +// ----------------------------------------------------------------------- +public static partial class NativeMethods { - // ----------------------------------------------------------------------- - // Constants - // ----------------------------------------------------------------------- - public static partial class NativeMethods + public const uint ApiVersion = 1; + public const string LibraryName = "foundry_local"; + + // The first P/Invoke through this class can come from any of several entry + // points (FoundryLocalManager, but also direct uses of Request/Item/ItemQueue + // by tests and consumers). Run the native-library bootstrap here so it always + // happens before the JIT resolves the first DllImport regardless of caller. + // DllLoader.Initialize is idempotent and cheap. + static NativeMethods() { - public const uint ApiVersion = 1; - public const string LibraryName = "foundry_local"; - - // The first P/Invoke through this class can come from any of several entry - // points (FoundryLocalManager, but also direct uses of Request/Item/ItemQueue - // by tests and consumers). Run the native-library bootstrap here so it always - // happens before the JIT resolves the first DllImport regardless of caller. - // DllLoader.Initialize is idempotent and cheap. - static NativeMethods() - { - DllLoader.Initialize(); - } - - // ----------------------------------------------------------------------- - // Exported functions — the ONLY two DLL exports - // ----------------------------------------------------------------------- - - [DllImport(LibraryName, CallingConvention = CallingConvention.Winapi, EntryPoint = "FoundryLocalGetApi")] - public static extern IntPtr FoundryLocalGetApi(uint version); - - [DllImport(LibraryName, CallingConvention = CallingConvention.Winapi, EntryPoint = "FoundryLocalGetVersionString")] - public static extern IntPtr FoundryLocalGetVersionString(); + DllLoader.Initialize(); } // ----------------------------------------------------------------------- - // Enums (values must match foundry_local_c.h exactly) + // Exported functions — the ONLY two DLL exports // ----------------------------------------------------------------------- - public enum FlErrorCode - { - Ok = 0, - NotImplemented = 1, - Internal = 2, - InvalidArgument = 3, - InvalidUsage = 4, - OperationCancelled = 5, - Network = 6, - } + [DllImport(LibraryName, CallingConvention = CallingConvention.Winapi, EntryPoint = "FoundryLocalGetApi")] + public static extern IntPtr FoundryLocalGetApi(uint version); - public enum FlLogLevel - { - Verbose = 0, - Debug = 1, - Info = 2, - Warning = 3, - Error = 4, - Fatal = 5, - } + [DllImport(LibraryName, CallingConvention = CallingConvention.Winapi, EntryPoint = "FoundryLocalGetVersionString")] + public static extern IntPtr FoundryLocalGetVersionString(); +} - public enum FlDeviceType - { - NotSet = 0, - CPU = 1, - GPU = 2, - NPU = 3, - } +// ----------------------------------------------------------------------- +// Enums (values must match foundry_local_c.h exactly) +// ----------------------------------------------------------------------- - public enum FlTensorDataType - { - Undefined = 0, - Float = 1, - UInt8 = 2, - Int8 = 3, - UInt16 = 4, - Int16 = 5, - Int32 = 6, - Int64 = 7, - String = 8, - Bool = 9, - Float16 = 10, - Double = 11, - UInt32 = 12, - UInt64 = 13, - Complex64 = 14, - Complex128 = 15, - BFloat16 = 16, - Float8E4M3FN = 17, - Float8E4M3FNUZ = 18, - Float8E5M2 = 19, - Float8E5M2FNUZ = 20, - UInt4 = 21, - Int4 = 22, - Float4E2M1 = 23, - Float8E8M0 = 24, - } +public enum FlErrorCode +{ + Ok = 0, + NotImplemented = 1, + Internal = 2, + InvalidArgument = 3, + InvalidUsage = 4, + OperationCancelled = 5, + Network = 6, +} - public enum FlItemType - { - Unknown = 0, - Bytes = 1, - Tensor = 10, - Text = 20, - Message = 21, - Image = 25, - Audio = 30, - ToolCall = 100, - ToolResult = 101, - Queue = 200, - } +public enum FlLogLevel +{ + Verbose = 0, + Debug = 1, + Info = 2, + Warning = 3, + Error = 4, + Fatal = 5, +} - /// - /// Subtype tag for TEXT items. Distinguishes ordinary assistant text from reasoning content - /// and from opaque OpenAI REST JSON payloads carried as text. - /// - public enum FlTextItemType - { - Default = 0, - Reasoning = 1, - OpenAIJson = 2, - } +public enum FlDeviceType +{ + NotSet = 0, + CPU = 1, + GPU = 2, + NPU = 3, +} - public enum FlMessageRole - { - None = 0, - System = 1, - User = 2, - Assistant = 3, - Tool = 4, - Developer = 5, - } +public enum FlTensorDataType +{ + Undefined = 0, + Float = 1, + UInt8 = 2, + Int8 = 3, + UInt16 = 4, + Int16 = 5, + Int32 = 6, + Int64 = 7, + String = 8, + Bool = 9, + Float16 = 10, + Double = 11, + UInt32 = 12, + UInt64 = 13, + Complex64 = 14, + Complex128 = 15, + BFloat16 = 16, + Float8E4M3FN = 17, + Float8E4M3FNUZ = 18, + Float8E5M2 = 19, + Float8E5M2FNUZ = 20, + UInt4 = 21, + Int4 = 22, + Float4E2M1 = 23, + Float8E8M0 = 24, +} - public enum FlFinishReason - { - None = 0, - Error = 1, - Stop = 2, - Length = 3, - ToolCalls = 4, - } +public enum FlItemType +{ + Unknown = 0, + Bytes = 1, + Tensor = 10, + Text = 20, + Message = 21, + Image = 25, + Audio = 30, + ToolCall = 100, + ToolResult = 101, + Queue = 200, +} - // ----------------------------------------------------------------------- - // Versioned data structs (layout must match C header on x64) - // - // Default StructLayout Sequential packing matches C natural alignment: - // uint32 before a pointer gets 4 bytes of implicit padding. - // ----------------------------------------------------------------------- +/// +/// Subtype tag for TEXT items. Distinguishes ordinary assistant text from reasoning content +/// and from opaque OpenAI REST JSON payloads carried as text. +/// +public enum FlTextItemType +{ + Default = 0, + Reasoning = 1, + OpenAIJson = 2, +} - [StructLayout(LayoutKind.Sequential)] - public struct FlUsage - { - public uint Version; - // 4 bytes implicit padding - public long PromptTokens; - public long CompletionTokens; - public long TotalTokens; - } +public enum FlMessageRole +{ + None = 0, + System = 1, + User = 2, + Assistant = 3, + Tool = 4, + Developer = 5, +} - [StructLayout(LayoutKind.Sequential)] - public struct FlBytesData - { - public uint Version; - public FlItemType ItemType; - public IntPtr Data; // const void* - public IntPtr MutableData; // void* (NULL for read-only) - public UIntPtr DataSize; - public IntPtr Deleter; // flBytesDataDeleter (NULL if not owned) - public IntPtr DeleterUserData; - } +public enum FlFinishReason +{ + None = 0, + Error = 1, + Stop = 2, + Length = 3, + ToolCalls = 4, +} - [StructLayout(LayoutKind.Sequential)] - public struct FlTensorData - { - public uint Version; - public FlTensorDataType DataType; - public IntPtr Data; // const void* - public IntPtr MutableData; // void* (NULL for read-only) - public IntPtr Shape; // const int64_t* - public UIntPtr Rank; - public IntPtr Deleter; // flTensorDataDeleter (NULL if not owned) - public IntPtr DeleterUserData; - } +// ----------------------------------------------------------------------- +// Versioned data structs (layout must match C header on x64) +// +// Default StructLayout Sequential packing matches C natural alignment: +// uint32 before a pointer gets 4 bytes of implicit padding. +// ----------------------------------------------------------------------- - [StructLayout(LayoutKind.Sequential)] - public struct FlMessageData - { - public uint Version; - public FlMessageRole Role; - public IntPtr ContentItems; // const flItem* const* (pointer to array of flItem*) - public UIntPtr ContentItemsCount; // size_t - public IntPtr Name; // const char* (nullable) - } +[StructLayout(LayoutKind.Sequential)] +public struct FlUsage +{ + public uint Version; + // 4 bytes implicit padding + public long PromptTokens; + public long CompletionTokens; + public long TotalTokens; +} - [StructLayout(LayoutKind.Sequential)] - public struct FlTextData - { - public uint Version; - public IntPtr Text; // const char* (UTF-8) - public FlTextItemType Type; - // 4 bytes implicit trailing padding to 8-byte alignment - } +[StructLayout(LayoutKind.Sequential)] +public struct FlBytesData +{ + public uint Version; + public FlItemType ItemType; + public IntPtr Data; // const void* + public IntPtr MutableData; // void* (NULL for read-only) + public UIntPtr DataSize; + public IntPtr Deleter; // flBytesDataDeleter (NULL if not owned) + public IntPtr DeleterUserData; +} - [StructLayout(LayoutKind.Sequential)] - public struct FlImageData - { - public uint Version; - // 4 bytes implicit padding - public IntPtr Data; // const void* - public IntPtr MutableData; // void* (NULL for read-only) - public UIntPtr DataSize; - public IntPtr Format; // const char* - public IntPtr Uri; // const char* - public IntPtr Deleter; // flImageDataDeleter (NULL if not owned) - public IntPtr DeleterUserData; - } +[StructLayout(LayoutKind.Sequential)] +public struct FlTensorData +{ + public uint Version; + public FlTensorDataType DataType; + public IntPtr Data; // const void* + public IntPtr MutableData; // void* (NULL for read-only) + public IntPtr Shape; // const int64_t* + public UIntPtr Rank; + public IntPtr Deleter; // flTensorDataDeleter (NULL if not owned) + public IntPtr DeleterUserData; +} - [StructLayout(LayoutKind.Sequential)] - public struct FlAudioData - { - public uint Version; - // 4 bytes implicit padding - public IntPtr Data; // const void* - public IntPtr MutableData; // void* (NULL for read-only) - public UIntPtr DataSize; - public IntPtr Format; // const char* - public IntPtr Uri; // const char* - public int SampleRate; // int (4 bytes) - public int Channels; // int (4 bytes) - public IntPtr Deleter; // flAudioDataDeleter (NULL if not owned) - public IntPtr DeleterUserData; - } +[StructLayout(LayoutKind.Sequential)] +public struct FlMessageData +{ + public uint Version; + public FlMessageRole Role; + public IntPtr ContentItems; // const flItem* const* (pointer to array of flItem*) + public UIntPtr ContentItemsCount; // size_t + public IntPtr Name; // const char* (nullable) +} - [StructLayout(LayoutKind.Sequential)] - public struct FlToolCallData - { - public uint Version; - // 4 bytes implicit padding - public IntPtr CallId; // const char* - public IntPtr Name; // const char* - public IntPtr Arguments; // const char* - } +[StructLayout(LayoutKind.Sequential)] +public struct FlTextData +{ + public uint Version; + public IntPtr Text; // const char* (UTF-8) + public FlTextItemType Type; + // 4 bytes implicit trailing padding to 8-byte alignment +} - [StructLayout(LayoutKind.Sequential)] - public struct FlToolResultData - { - public uint Version; - // 4 bytes implicit padding - public IntPtr CallId; // const char* - public IntPtr Result; // const char* - } +[StructLayout(LayoutKind.Sequential)] +public struct FlImageData +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr Data; // const void* + public IntPtr MutableData; // void* (NULL for read-only) + public UIntPtr DataSize; + public IntPtr Format; // const char* + public IntPtr Uri; // const char* + public IntPtr Deleter; // flImageDataDeleter (NULL if not owned) + public IntPtr DeleterUserData; +} - [StructLayout(LayoutKind.Sequential)] - public struct FlStreamingCallbackData - { - public uint Version; - // 4 bytes implicit padding - public IntPtr ItemQueue; - } +[StructLayout(LayoutKind.Sequential)] +public struct FlAudioData +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr Data; // const void* + public IntPtr MutableData; // void* (NULL for read-only) + public UIntPtr DataSize; + public IntPtr Format; // const char* + public IntPtr Uri; // const char* + public int SampleRate; // int (4 bytes) + public int Channels; // int (4 bytes) + public IntPtr Deleter; // flAudioDataDeleter (NULL if not owned) + public IntPtr DeleterUserData; +} - [StructLayout(LayoutKind.Sequential)] - public struct FlToolDefinition - { - public uint Version; - // 4 bytes implicit padding - public IntPtr Name; // const char* - public IntPtr Description; // const char* - public IntPtr JsonSchema; // const char* - } +[StructLayout(LayoutKind.Sequential)] +public struct FlToolCallData +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr CallId; // const char* + public IntPtr Name; // const char* + public IntPtr Arguments; // const char* +} - [StructLayout(LayoutKind.Sequential)] - public struct FlEpInfo - { - public uint Version; - // 4 bytes implicit padding - public IntPtr Name; // const char* (UTF-8, owned by Manager) - [MarshalAs(UnmanagedType.U1)] - public bool IsRegistered; - // 7 bytes implicit trailing padding to 8-byte alignment - } +[StructLayout(LayoutKind.Sequential)] +public struct FlToolResultData +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr CallId; // const char* + public IntPtr Result; // const char* +} - // ----------------------------------------------------------------------- - // Callback delegates (Cdecl — plain C function pointers) - // ----------------------------------------------------------------------- +[StructLayout(LayoutKind.Sequential)] +public struct FlStreamingCallbackData +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr ItemQueue; +} - /// Progress callback for model downloads. Return 0 to continue, non-zero to cancel. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FlProgressCallback(float value, IntPtr userData); +[StructLayout(LayoutKind.Sequential)] +public struct FlToolDefinition +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr Name; // const char* + public IntPtr Description; // const char* + public IntPtr JsonSchema; // const char* +} - /// Streaming response callback. Return 0 to continue, non-zero to cancel. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FlStreamingCallback(FlStreamingCallbackData data, IntPtr userData); +[StructLayout(LayoutKind.Sequential)] +public struct FlEpInfo +{ + public uint Version; + // 4 bytes implicit padding + public IntPtr Name; // const char* (UTF-8, owned by Manager) + [MarshalAs(UnmanagedType.U1)] + public bool IsRegistered; + // 7 bytes implicit trailing padding to 8-byte alignment +} - /// Item destructor callback. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FlItemDeleter(IntPtr item, IntPtr userData); +// ----------------------------------------------------------------------- +// Callback delegates (Cdecl — plain C function pointers) +// ----------------------------------------------------------------------- - /// Deleter for bytes data. Called when native item is destroyed. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FlBytesDataDeleterDelegate(ref FlBytesData data, IntPtr userData); +/// Progress callback for model downloads. Return 0 to continue, non-zero to cancel. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate int FlProgressCallback(float value, IntPtr userData); - /// Deleter for image data. Called when native item is destroyed. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FlImageDataDeleterDelegate(ref FlImageData data, IntPtr userData); +/// Streaming response callback. Return 0 to continue, non-zero to cancel. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate int FlStreamingCallback(FlStreamingCallbackData data, IntPtr userData); - /// Deleter for audio data. Called when native item is destroyed. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FlAudioDataDeleterDelegate(ref FlAudioData data, IntPtr userData); +/// Item destructor callback. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate void FlItemDeleter(IntPtr item, IntPtr userData); - // EP detection +/// Deleter for bytes data. Called when native item is destroyed. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate void FlBytesDataDeleterDelegate(ref FlBytesData data, IntPtr userData); - /// EP download progress callback. Return 0 to continue, non-zero to cancel. - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FlEpProgressCallback( - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string epName, - float value, - IntPtr userData); +/// Deleter for image data. Called when native item is destroyed. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate void FlImageDataDeleterDelegate(ref FlImageData data, IntPtr userData); - // ----------------------------------------------------------------------- - // Delegate types for vtable function pointers - // - // Naming: Fl{SubApi}_{FunctionName}Delegate - // All delegates use StdCall to match FL_API_CALL (__stdcall). - // Functions returning flStatus* return IntPtr (non-null = error). - // Opaque handle types are IntPtr. - // ----------------------------------------------------------------------- +/// Deleter for audio data. Called when native item is destroyed. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate void FlAudioDataDeleterDelegate(ref FlAudioData data, IntPtr userData); - // --- Root API (flApi) delegates --- +// EP detection - // Status - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_StatusCreateDelegate(FlErrorCode errorCode, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string errorMsg); +/// EP download progress callback. Return 0 to continue, non-zero to cancel. +[UnmanagedFunctionPointer(CallingConvention.Cdecl)] +public delegate int FlEpProgressCallback( + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string epName, + float value, + IntPtr userData); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_StatusReleaseDelegate(IntPtr status); +// ----------------------------------------------------------------------- +// Delegate types for vtable function pointers +// +// Naming: Fl{SubApi}_{FunctionName}Delegate +// All delegates use StdCall to match FL_API_CALL (__stdcall). +// Functions returning flStatus* return IntPtr (non-null = error). +// Opaque handle types are IntPtr. +// ----------------------------------------------------------------------- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate FlErrorCode FlApi_StatusGetErrorCodeDelegate(IntPtr status); +// --- Root API (flApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_StatusGetErrorMessageDelegate(IntPtr status); +// Status +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_StatusCreateDelegate(FlErrorCode errorCode, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string errorMsg); - // Manager lifecycle - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerCreateDelegate(IntPtr config, out IntPtr outManager); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_StatusReleaseDelegate(IntPtr status); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_ManagerReleaseDelegate(IntPtr manager); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate FlErrorCode FlApi_StatusGetErrorCodeDelegate(IntPtr status); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerGetCatalogDelegate(IntPtr manager, out IntPtr outCatalog); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_StatusGetErrorMessageDelegate(IntPtr status); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerWebServiceStartDelegate(IntPtr manager); +// Manager lifecycle +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerCreateDelegate(IntPtr config, out IntPtr outManager); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerWebServiceUrlsDelegate(IntPtr manager, out IntPtr outUrls, out UIntPtr outNumUrls); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_ManagerReleaseDelegate(IntPtr manager); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerWebServiceStopDelegate(IntPtr manager); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerGetCatalogDelegate(IntPtr manager, out IntPtr outCatalog); - // Sub-API accessors - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_GetSubApiDelegate(); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerWebServiceStartDelegate(IntPtr manager); - // KeyValuePairs - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_CreateKeyValuePairsDelegate(out IntPtr outKvps); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerWebServiceUrlsDelegate(IntPtr manager, out IntPtr outUrls, out UIntPtr outNumUrls); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_AddKeyValuePairDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string value); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerWebServiceStopDelegate(IntPtr manager); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_GetKeyValueDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); +// Sub-API accessors +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_GetSubApiDelegate(); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_GetKeyValuePairsDelegate(IntPtr kvps, out IntPtr keys, out IntPtr values, out UIntPtr numEntries); +// KeyValuePairs +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_CreateKeyValuePairsDelegate(out IntPtr outKvps); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_RemoveKeyValuePairDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_AddKeyValuePairDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string value); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_KeyValuePairsReleaseDelegate(IntPtr kvps); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_GetKeyValueDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); - // ModelList - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlApi_ModelListReleaseDelegate(IntPtr models); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_GetKeyValuePairsDelegate(IntPtr kvps, out IntPtr keys, out IntPtr values, out UIntPtr numEntries); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate UIntPtr FlApi_ModelListSizeDelegate(IntPtr models); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_RemoveKeyValuePairDelegate(IntPtr kvps, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ModelListGetAtDelegate(IntPtr models, UIntPtr idx); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_KeyValuePairsReleaseDelegate(IntPtr kvps); - // EP detection - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerGetDiscoverableEpsDelegate( - IntPtr manager, - out IntPtr outEps, - out UIntPtr outCount); +// ModelList +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlApi_ModelListReleaseDelegate(IntPtr models); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerDownloadAndRegisterEpsDelegate( - IntPtr manager, - IntPtr epNames, - UIntPtr numEpNames, - FlEpProgressCallback? callback, - IntPtr userData); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate UIntPtr FlApi_ModelListSizeDelegate(IntPtr models); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool FlApi_ManagerIsEpDownloadInProgressDelegate(IntPtr manager); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ModelListGetAtDelegate(IntPtr models, UIntPtr idx); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlApi_ManagerShutdownDelegate(IntPtr manager); +// EP detection +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerGetDiscoverableEpsDelegate( + IntPtr manager, + out IntPtr outEps, + out UIntPtr outCount); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool FlApi_ManagerIsShutdownRequestedDelegate(IntPtr manager); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerDownloadAndRegisterEpsDelegate( + IntPtr manager, + IntPtr epNames, + UIntPtr numEpNames, + FlEpProgressCallback? callback, + IntPtr userData); - // --- Item API (flItemApi) delegates --- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +[return: MarshalAs(UnmanagedType.U1)] +public delegate bool FlApi_ManagerIsEpDownloadInProgressDelegate(IntPtr manager); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_CreateDelegate(FlItemType type, out IntPtr outItem); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlApi_ManagerShutdownDelegate(IntPtr manager); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlItem_ReleaseDelegate(IntPtr item); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +[return: MarshalAs(UnmanagedType.U1)] +public delegate bool FlApi_ManagerIsShutdownRequestedDelegate(IntPtr manager); - // ItemQueue - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_QueueCreateDelegate(out IntPtr outQueue); +// --- Item API (flItemApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlItem_QueueReleaseDelegate(IntPtr queue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_CreateDelegate(FlItemType type, out IntPtr outItem); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_QueuePushDelegate(IntPtr queue, IntPtr item); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlItem_ReleaseDelegate(IntPtr item); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool FlItem_QueueTryPopDelegate(IntPtr queue, out IntPtr outItem); +// ItemQueue +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_QueueCreateDelegate(out IntPtr outQueue); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate UIntPtr FlItem_QueueSizeDelegate(IntPtr queue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlItem_QueueReleaseDelegate(IntPtr queue); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlItem_QueueMarkFinishedDelegate(IntPtr queue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_QueuePushDelegate(IntPtr queue, IntPtr item); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.U1)] - public delegate bool FlItem_QueueGetFinishedDelegate(IntPtr queue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +[return: MarshalAs(UnmanagedType.U1)] +public delegate bool FlItem_QueueTryPopDelegate(IntPtr queue, out IntPtr outItem); - // Item type - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate FlItemType FlItem_GetTypeDelegate(IntPtr item); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate UIntPtr FlItem_QueueSizeDelegate(IntPtr queue); - // Setters — take versioned struct by pointer (ref in C#) - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetBytesDelegate(IntPtr item, ref FlBytesData bytes); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlItem_QueueMarkFinishedDelegate(IntPtr queue); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetTensorDelegate(IntPtr item, ref FlTensorData tensor); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +[return: MarshalAs(UnmanagedType.U1)] +public delegate bool FlItem_QueueGetFinishedDelegate(IntPtr queue); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetTextDelegate(IntPtr item, ref FlTextData text); +// Item type +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate FlItemType FlItem_GetTypeDelegate(IntPtr item); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetMessageDelegate(IntPtr item, ref FlMessageData message); +// Setters — take versioned struct by pointer (ref in C#) +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetBytesDelegate(IntPtr item, ref FlBytesData bytes); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetImageDelegate(IntPtr item, ref FlImageData image); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetTensorDelegate(IntPtr item, ref FlTensorData tensor); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetAudioDelegate(IntPtr item, ref FlAudioData audio); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetTextDelegate(IntPtr item, ref FlTextData text); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetToolCallDelegate(IntPtr item, ref FlToolCallData toolCall); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetMessageDelegate(IntPtr item, ref FlMessageData message); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_SetToolResultDelegate(IntPtr item, ref FlToolResultData toolResult); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetImageDelegate(IntPtr item, ref FlImageData image); - // Getters — fill versioned struct by pointer (out in C#) - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetBytesDelegate(IntPtr item, out FlBytesData outBytes); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetAudioDelegate(IntPtr item, ref FlAudioData audio); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetTextDelegate(IntPtr item, out FlTextData outText); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetToolCallDelegate(IntPtr item, ref FlToolCallData toolCall); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetMessageDelegate(IntPtr item, out FlMessageData outMessage); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_SetToolResultDelegate(IntPtr item, ref FlToolResultData toolResult); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetTensorDelegate(IntPtr item, out FlTensorData outTensor); +// Getters — fill versioned struct by pointer (out in C#) +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetBytesDelegate(IntPtr item, out FlBytesData outBytes); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetImageDelegate(IntPtr item, out FlImageData outImage); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetTextDelegate(IntPtr item, out FlTextData outText); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetAudioDelegate(IntPtr item, out FlAudioData outAudio); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetMessageDelegate(IntPtr item, out FlMessageData outMessage); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetToolCallDelegate(IntPtr item, out FlToolCallData outToolCall); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetTensorDelegate(IntPtr item, out FlTensorData outTensor); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetToolResultDelegate(IntPtr item, out FlToolResultData outToolResult); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetImageDelegate(IntPtr item, out FlImageData outImage); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetMetadataDelegate(IntPtr item, out IntPtr outMetadata); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetAudioDelegate(IntPtr item, out FlAudioData outAudio); - // Queue item get - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlItem_GetQueueDelegate(IntPtr item, out IntPtr outQueue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetToolCallDelegate(IntPtr item, out FlToolCallData outToolCall); - // --- Inference API (flInferenceApi) delegates --- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetToolResultDelegate(IntPtr item, out FlToolResultData outToolResult); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_RequestCreateDelegate(out IntPtr outRequest); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetMetadataDelegate(IntPtr item, out IntPtr outMetadata); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlInference_RequestReleaseDelegate(IntPtr request); +// Queue item get +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlItem_GetQueueDelegate(IntPtr item, out IntPtr outQueue); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_RequestAddItemDelegate(IntPtr request, IntPtr item, [MarshalAs(UnmanagedType.U1)] bool takeOwnership); +// --- Inference API (flInferenceApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate UIntPtr FlInference_RequestGetItemCountDelegate(IntPtr request); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_RequestCreateDelegate(out IntPtr outRequest); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_RequestGetItemDelegate(IntPtr request, UIntPtr idx, out IntPtr outItem); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlInference_RequestReleaseDelegate(IntPtr request); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_RequestSetOptionsDelegate(IntPtr request, IntPtr options); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_RequestAddItemDelegate(IntPtr request, IntPtr item, [MarshalAs(UnmanagedType.U1)] bool takeOwnership); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_RequestCancelDelegate(IntPtr request); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate UIntPtr FlInference_RequestGetItemCountDelegate(IntPtr request); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_ResponseCreateDelegate(out IntPtr outResponse); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_RequestGetItemDelegate(IntPtr request, UIntPtr idx, out IntPtr outItem); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlInference_ResponseReleaseDelegate(IntPtr response); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_RequestSetOptionsDelegate(IntPtr request, IntPtr options); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate UIntPtr FlInference_ResponseGetItemCountDelegate(IntPtr response); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_RequestCancelDelegate(IntPtr request); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_ResponseGetItemDelegate(IntPtr response, UIntPtr idx, out IntPtr outItem); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_ResponseCreateDelegate(out IntPtr outResponse); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate FlFinishReason FlInference_ResponseGetFinishReasonDelegate(IntPtr response); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlInference_ResponseReleaseDelegate(IntPtr response); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_ResponseGetUsageDelegate(IntPtr response, out FlUsage outUsage); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate UIntPtr FlInference_ResponseGetItemCountDelegate(IntPtr response); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionCreateDelegate(IntPtr model, out IntPtr outSession); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_ResponseGetItemDelegate(IntPtr response, UIntPtr idx, out IntPtr outItem); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlInference_SessionReleaseDelegate(IntPtr session); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate FlFinishReason FlInference_ResponseGetFinishReasonDelegate(IntPtr response); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionAddToolDefinitionDelegate(IntPtr session, ref FlToolDefinition toolDef); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_ResponseGetUsageDelegate(IntPtr response, out FlUsage outUsage); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionRemoveToolDefinitionDelegate(IntPtr session, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string toolName, - [MarshalAs(UnmanagedType.U1)] out bool outRemoved); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionCreateDelegate(IntPtr model, out IntPtr outSession); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionSetStreamingCallbackDelegate(IntPtr session, - FlStreamingCallback? callback, IntPtr userData); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlInference_SessionReleaseDelegate(IntPtr session); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionSetOptionsDelegate(IntPtr session, IntPtr options); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionAddToolDefinitionDelegate(IntPtr session, ref FlToolDefinition toolDef); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionProcessRequestDelegate(IntPtr session, IntPtr request, ref IntPtr response); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionRemoveToolDefinitionDelegate(IntPtr session, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string toolName, + [MarshalAs(UnmanagedType.U1)] out bool outRemoved); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate UIntPtr FlInference_SessionGetTurnCountDelegate(IntPtr session); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionSetStreamingCallbackDelegate(IntPtr session, + FlStreamingCallback? callback, IntPtr userData); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlInference_SessionUndoTurnsDelegate(IntPtr session, UIntPtr count); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionSetOptionsDelegate(IntPtr session, IntPtr options); - // --- Configuration API (flConfigurationApi) delegates --- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionProcessRequestDelegate(IntPtr session, IntPtr request, ref IntPtr response); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_CreateDelegate([MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string appName, out IntPtr outConfig); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate UIntPtr FlInference_SessionGetTurnCountDelegate(IntPtr session); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate void FlConfig_ReleaseDelegate(IntPtr config); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlInference_SessionUndoTurnsDelegate(IntPtr session, UIntPtr count); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_SetStringDelegate(IntPtr config, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string value); +// --- Configuration API (flConfigurationApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_SetDefaultLogLevelDelegate(IntPtr config, FlLogLevel level); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_CreateDelegate([MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string appName, out IntPtr outConfig); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_AddCatalogUrlDelegate(IntPtr config, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string? filterOverride); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate void FlConfig_ReleaseDelegate(IntPtr config); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_AddWebServiceEndpointDelegate(IntPtr config, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_SetStringDelegate(IntPtr config, [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string value); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_SetAdditionalOptionsDelegate(IntPtr config, IntPtr options); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_SetDefaultLogLevelDelegate(IntPtr config, FlLogLevel level); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlConfig_SetExternalServiceUrlDelegate(IntPtr config, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_AddCatalogUrlDelegate(IntPtr config, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string? filterOverride); - // --- Catalog API (flCatalogApi) delegates --- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_AddWebServiceEndpointDelegate(IntPtr config, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetModelsDelegate(IntPtr catalog, out IntPtr outModels); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_SetAdditionalOptionsDelegate(IntPtr config, IntPtr options); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetModelDelegate(IntPtr catalog, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string alias, out IntPtr outModel); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlConfig_SetExternalServiceUrlDelegate(IntPtr config, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string url); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetModelVariantDelegate(IntPtr catalog, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string modelId, out IntPtr outModel); +// --- Catalog API (flCatalogApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetLatestVersionDelegate(IntPtr catalog, - IntPtr model, out IntPtr outModel); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetModelsDelegate(IntPtr catalog, out IntPtr outModels); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetCachedModelsDelegate(IntPtr catalog, out IntPtr outModels); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetModelDelegate(IntPtr catalog, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string alias, out IntPtr outModel); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetLoadedModelsDelegate(IntPtr catalog, out IntPtr outModels); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetModelVariantDelegate(IntPtr catalog, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string modelId, out IntPtr outModel); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlCatalog_GetNameDelegate(IntPtr catalog, out IntPtr outName); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetLatestVersionDelegate(IntPtr catalog, + IntPtr model, out IntPtr outModel); - // --- Model API (flModelApi) delegates --- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetCachedModelsDelegate(IntPtr catalog, out IntPtr outModels); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_GetInputOutputInfoDelegate(IntPtr model, - out IntPtr outInputs, out UIntPtr outNumInputs, out IntPtr outOutputs, out UIntPtr outNumOutputs); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetLoadedModelsDelegate(IntPtr catalog, out IntPtr outModels); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_IsCachedDelegate(IntPtr model, out int outCached); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlCatalog_GetNameDelegate(IntPtr catalog, out IntPtr outName); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_IsLoadedDelegate(IntPtr model, out int outLoaded); +// --- Model API (flModelApi) delegates --- - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_GetPathDelegate(IntPtr model, out IntPtr outPath); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_GetInputOutputInfoDelegate(IntPtr model, + out IntPtr outInputs, out UIntPtr outNumInputs, out IntPtr outOutputs, out UIntPtr outNumOutputs); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_DownloadDelegate(IntPtr model, FlProgressCallback? callback, IntPtr userData); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_IsCachedDelegate(IntPtr model, out int outCached); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_LoadDelegate(IntPtr model); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_IsLoadedDelegate(IntPtr model, out int outLoaded); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_UnloadDelegate(IntPtr model); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_GetPathDelegate(IntPtr model, out IntPtr outPath); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_RemoveFromCacheDelegate(IntPtr model); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_DownloadDelegate(IntPtr model, FlProgressCallback? callback, IntPtr userData); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_GetInfoDelegate(IntPtr model, out IntPtr outInfo); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_LoadDelegate(IntPtr model); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_GetVariantsDelegate(IntPtr model, out IntPtr outVariants); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_UnloadDelegate(IntPtr model); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_SelectVariantDelegate(IntPtr model, IntPtr variant); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_RemoveFromCacheDelegate(IntPtr model); - // ModelInfo accessors - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_InfoGetStringDelegate(IntPtr info); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_GetInfoDelegate(IntPtr model, out IntPtr outInfo); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate int FlModel_InfoGetVersionDelegate(IntPtr info); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_GetVariantsDelegate(IntPtr model, out IntPtr outVariants); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate FlDeviceType FlModel_InfoGetDeviceTypeDelegate(IntPtr info); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_SelectVariantDelegate(IntPtr model, IntPtr variant); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_InfoGetKvpDelegate(IntPtr info); +// ModelInfo accessors +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_InfoGetStringDelegate(IntPtr info); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate IntPtr FlModel_InfoGetStringPropertyDelegate(IntPtr info, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate int FlModel_InfoGetVersionDelegate(IntPtr info); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - public delegate long FlModel_InfoGetIntPropertyDelegate(IntPtr info, - [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key, long defaultValue); +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate FlDeviceType FlModel_InfoGetDeviceTypeDelegate(IntPtr info); - // ----------------------------------------------------------------------- - // Vtable structs — marshalled from the native function pointer tables. - // Field order MUST match the C header exactly. - // ----------------------------------------------------------------------- +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_InfoGetKvpDelegate(IntPtr info); - /// Root API table returned by FoundryLocalGetApi(). - [StructLayout(LayoutKind.Sequential)] - public struct FlApi - { - // Status - public FlApi_StatusCreateDelegate StatusCreate; - public FlApi_StatusReleaseDelegate StatusRelease; - public FlApi_StatusGetErrorCodeDelegate StatusGetErrorCode; - public FlApi_StatusGetErrorMessageDelegate StatusGetErrorMessage; - - // Manager lifecycle - public FlApi_ManagerCreateDelegate ManagerCreate; - public FlApi_ManagerReleaseDelegate ManagerRelease; - public FlApi_ManagerGetCatalogDelegate ManagerGetCatalog; - public FlApi_ManagerWebServiceStartDelegate ManagerWebServiceStart; - public FlApi_ManagerWebServiceUrlsDelegate ManagerWebServiceUrls; - public FlApi_ManagerWebServiceStopDelegate ManagerWebServiceStop; - - // Sub-API accessors - public FlApi_GetSubApiDelegate GetCatalogApi; - public FlApi_GetSubApiDelegate GetConfigurationApi; - public FlApi_GetSubApiDelegate GetItemApi; - public FlApi_GetSubApiDelegate GetInferenceApi; - public FlApi_GetSubApiDelegate GetModelApi; - - // KeyValuePairs - public FlApi_CreateKeyValuePairsDelegate CreateKeyValuePairs; - public FlApi_AddKeyValuePairDelegate AddKeyValuePair; - public FlApi_GetKeyValueDelegate GetKeyValue; - public FlApi_GetKeyValuePairsDelegate GetKeyValuePairs; - public FlApi_RemoveKeyValuePairDelegate RemoveKeyValuePair; - public FlApi_KeyValuePairsReleaseDelegate KeyValuePairsRelease; - - // ModelList - public FlApi_ModelListReleaseDelegate ModelListRelease; - public FlApi_ModelListSizeDelegate ModelListSize; - public FlApi_ModelListGetAtDelegate ModelListGetAt; - - // EP detection - public FlApi_ManagerGetDiscoverableEpsDelegate ManagerGetDiscoverableEps; - public FlApi_ManagerDownloadAndRegisterEpsDelegate ManagerDownloadAndRegisterEps; - public FlApi_ManagerIsEpDownloadInProgressDelegate ManagerIsEpDownloadInProgress; - - // Manager shutdown - public FlApi_ManagerShutdownDelegate ManagerShutdown; - public FlApi_ManagerIsShutdownRequestedDelegate ManagerIsShutdownRequested; - } +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate IntPtr FlModel_InfoGetStringPropertyDelegate(IntPtr info, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key); - /// Item API table — field order MUST match flItemApi in foundry_local_c.h. - [StructLayout(LayoutKind.Sequential)] - public struct FlItemApi - { - // Lifecycle - public FlItem_CreateDelegate Create; - public FlItem_ReleaseDelegate Release; - - // Type — 'new' hides inherited object.GetType(). Name must match C vtable layout. - public new FlItem_GetTypeDelegate GetType; - - // Setters - public FlItem_SetBytesDelegate SetBytes; - public FlItem_SetTensorDelegate SetTensor; - public FlItem_SetTextDelegate SetText; - public FlItem_SetMessageDelegate SetMessage; - public FlItem_SetImageDelegate SetImage; - public FlItem_SetAudioDelegate SetAudio; - public FlItem_SetToolCallDelegate SetToolCall; - public FlItem_SetToolResultDelegate SetToolResult; - - // Getters - public FlItem_GetBytesDelegate GetBytes; - public FlItem_GetTextDelegate GetText; - public FlItem_GetMessageDelegate GetMessage; - public FlItem_GetTensorDelegate GetTensor; - public FlItem_GetImageDelegate GetImage; - public FlItem_GetAudioDelegate GetAudio; - public FlItem_GetToolCallDelegate GetToolCall; - public FlItem_GetToolResultDelegate GetToolResult; - - // Metadata - public FlItem_GetMetadataDelegate GetMetadata; - public FlItem_GetMetadataDelegate GetMutableMetadata; - - // Queue item - public FlItem_GetQueueDelegate GetQueue; - - // ItemQueue - public FlItem_QueueCreateDelegate QueueCreate; - public FlItem_QueueReleaseDelegate QueueRelease; - public FlItem_QueuePushDelegate QueuePush; - public FlItem_QueueTryPopDelegate QueueTryPop; - public FlItem_QueueSizeDelegate QueueSize; - public FlItem_QueueMarkFinishedDelegate QueueMarkFinished; - public FlItem_QueueGetFinishedDelegate QueueGetFinished; - } +[UnmanagedFunctionPointer(CallingConvention.Winapi)] +public delegate long FlModel_InfoGetIntPropertyDelegate(IntPtr info, + [MarshalAs((UnmanagedType)48 /* LPUTF8Str */)] string key, long defaultValue); - /// Inference API table — request, response, session. - [StructLayout(LayoutKind.Sequential)] - public struct FlInferenceApi - { - // Request - public FlInference_RequestCreateDelegate RequestCreate; - public FlInference_RequestReleaseDelegate RequestRelease; - public FlInference_RequestAddItemDelegate RequestAddItem; - public FlInference_RequestGetItemCountDelegate RequestGetItemCount; - public FlInference_RequestGetItemDelegate RequestGetItem; - public FlInference_RequestSetOptionsDelegate RequestSetOptions; - public FlInference_RequestCancelDelegate RequestCancel; - - // Response - public FlInference_ResponseCreateDelegate ResponseCreate; - public FlInference_ResponseReleaseDelegate ResponseRelease; - public FlInference_ResponseGetItemCountDelegate ResponseGetItemCount; - public FlInference_ResponseGetItemDelegate ResponseGetItem; - public FlInference_ResponseGetFinishReasonDelegate ResponseGetFinishReason; - public FlInference_ResponseGetUsageDelegate ResponseGetUsage; - - // Session - public FlInference_SessionCreateDelegate SessionCreate; - public FlInference_SessionReleaseDelegate SessionRelease; - public FlInference_SessionSetStreamingCallbackDelegate SessionSetStreamingCallback; - public FlInference_SessionSetOptionsDelegate SessionSetOptions; - public FlInference_SessionProcessRequestDelegate SessionProcessRequest; - - // Chat session features - public FlInference_SessionAddToolDefinitionDelegate SessionAddToolDefinition; - public FlInference_SessionRemoveToolDefinitionDelegate SessionRemoveToolDefinition; - public FlInference_SessionGetTurnCountDelegate SessionGetTurnCount; - public FlInference_SessionUndoTurnsDelegate SessionUndoTurns; - } +// ----------------------------------------------------------------------- +// Vtable structs — marshalled from the native function pointer tables. +// Field order MUST match the C header exactly. +// ----------------------------------------------------------------------- - /// Configuration API table. - [StructLayout(LayoutKind.Sequential)] - public struct FlConfigurationApi - { - public FlConfig_CreateDelegate Create; - public FlConfig_ReleaseDelegate Release; - public FlConfig_SetDefaultLogLevelDelegate SetDefaultLogLevel; - public FlConfig_SetStringDelegate SetAppDataDir; - public FlConfig_SetStringDelegate SetLogsDir; - public FlConfig_SetStringDelegate SetModelCacheDir; - public FlConfig_AddCatalogUrlDelegate AddCatalogUrl; - public FlConfig_SetStringDelegate SetCatalogRegion; - public FlConfig_AddWebServiceEndpointDelegate AddWebServiceEndpoint; - public FlConfig_SetExternalServiceUrlDelegate SetExternalServiceUrl; - public FlConfig_SetAdditionalOptionsDelegate SetAdditionalOptions; - } +/// Root API table returned by FoundryLocalGetApi(). +[StructLayout(LayoutKind.Sequential)] +public struct FlApi +{ + // Status + public FlApi_StatusCreateDelegate StatusCreate; + public FlApi_StatusReleaseDelegate StatusRelease; + public FlApi_StatusGetErrorCodeDelegate StatusGetErrorCode; + public FlApi_StatusGetErrorMessageDelegate StatusGetErrorMessage; - /// Catalog API table. - [StructLayout(LayoutKind.Sequential)] - public struct FlCatalogApi - { - public FlCatalog_GetNameDelegate GetName; - public FlCatalog_GetModelsDelegate GetModels; - public FlCatalog_GetModelDelegate GetModel; - public FlCatalog_GetModelVariantDelegate GetModelVariant; - public FlCatalog_GetLatestVersionDelegate GetLatestVersion; - public FlCatalog_GetCachedModelsDelegate GetCachedModels; - public FlCatalog_GetLoadedModelsDelegate GetLoadedModels; - } + // Manager lifecycle + public FlApi_ManagerCreateDelegate ManagerCreate; + public FlApi_ManagerReleaseDelegate ManagerRelease; + public FlApi_ManagerGetCatalogDelegate ManagerGetCatalog; + public FlApi_ManagerWebServiceStartDelegate ManagerWebServiceStart; + public FlApi_ManagerWebServiceUrlsDelegate ManagerWebServiceUrls; + public FlApi_ManagerWebServiceStopDelegate ManagerWebServiceStop; - /// Model API table — model operations and ModelInfo accessors. - [StructLayout(LayoutKind.Sequential)] - public struct FlModelApi - { - // ModelInfo (GetInfo first — matches C header order) - public FlModel_GetInfoDelegate GetInfo; - - // Model operations - public FlModel_GetInputOutputInfoDelegate GetInputOutputInfo; - public FlModel_IsCachedDelegate IsCached; - public FlModel_GetPathDelegate GetPath; - public FlModel_DownloadDelegate Download; - public FlModel_IsLoadedDelegate IsLoaded; - public FlModel_LoadDelegate Load; - public FlModel_UnloadDelegate Unload; - public FlModel_RemoveFromCacheDelegate RemoveFromCache; - - // Variant support - public FlModel_GetVariantsDelegate GetVariants; - public FlModel_SelectVariantDelegate SelectVariant; - - // ModelInfo accessors - public FlModel_InfoGetStringDelegate InfoGetId; - public FlModel_InfoGetStringDelegate InfoGetName; - public FlModel_InfoGetVersionDelegate InfoGetVersion; - public FlModel_InfoGetStringDelegate InfoGetAlias; - public FlModel_InfoGetStringDelegate InfoGetUri; - public FlModel_InfoGetDeviceTypeDelegate InfoGetDeviceType; - public FlModel_InfoGetStringDelegate InfoGetExecutionProvider; - public FlModel_InfoGetStringDelegate InfoGetTask; - public FlModel_InfoGetKvpDelegate InfoGetPromptTemplates; - public FlModel_InfoGetKvpDelegate InfoGetModelSettings; - public FlModel_InfoGetStringPropertyDelegate InfoGetStringProperty; - public FlModel_InfoGetIntPropertyDelegate InfoGetIntProperty; - } + // Sub-API accessors + public FlApi_GetSubApiDelegate GetCatalogApi; + public FlApi_GetSubApiDelegate GetConfigurationApi; + public FlApi_GetSubApiDelegate GetItemApi; + public FlApi_GetSubApiDelegate GetInferenceApi; + public FlApi_GetSubApiDelegate GetModelApi; - // ----------------------------------------------------------------------- - // Well-known property key constants - // ----------------------------------------------------------------------- + // KeyValuePairs + public FlApi_CreateKeyValuePairsDelegate CreateKeyValuePairs; + public FlApi_AddKeyValuePairDelegate AddKeyValuePair; + public FlApi_GetKeyValueDelegate GetKeyValue; + public FlApi_GetKeyValuePairsDelegate GetKeyValuePairs; + public FlApi_RemoveKeyValuePairDelegate RemoveKeyValuePair; + public FlApi_KeyValuePairsReleaseDelegate KeyValuePairsRelease; - public static class ModelProperties - { - // String properties - public const string DisplayName = "display_name"; - public const string ModelType = "type"; - public const string Publisher = "publisher"; - public const string License = "license"; - public const string LicenseDescription = "license_description"; - public const string Task = "task"; - public const string ModelProvider = "model_provider"; - public const string MinFlVersion = "min_fl_version"; - public const string ParentUri = "parent_uri"; - public const string ToolCallStart = "tool_call_start"; - public const string ToolCallEnd = "tool_call_end"; - public const string ReasoningStart = "reasoning_start"; - public const string ReasoningEnd = "reasoning_end"; - - // Int properties - public const string SupportsToolCalling = "supports_tool_calling"; - public const string SupportsReasoning = "supports_reasoning"; - public const string FileSizeMb = "filesize_mb"; - public const string MaxOutputTokens = "max_output_tokens"; - public const string CreatedAtUnix = "created_at_unix"; - public const string IsTestModel = "is_test_model"; - } + // ModelList + public FlApi_ModelListReleaseDelegate ModelListRelease; + public FlApi_ModelListSizeDelegate ModelListSize; + public FlApi_ModelListGetAtDelegate ModelListGetAt; - public static class Parameters - { - // Sampling / generation - public const string Temperature = "temperature"; - public const string TopP = "top_p"; - public const string TopK = "top_k"; - public const string MaxOutputTokens = "max_output_tokens"; - public const string Stop = "stop"; - public const string FrequencyPenalty = "frequency_penalty"; - public const string PresencePenalty = "presence_penalty"; - public const string Seed = "seed"; - public const string EarlyStopping = "early_stopping"; - - // Tool calling - public const string ToolChoice = "tool_choice"; - - // Output format - public const string ResponseFormat = "response_format"; - - // Conversation state - public const string PreviousResponseId = "previous_response_id"; - public const string Instructions = "instructions"; - public const string Store = "store"; - - // Reasoning - public const string ReasoningEffort = "reasoning_effort"; - } + // EP detection + public FlApi_ManagerGetDiscoverableEpsDelegate ManagerGetDiscoverableEps; + public FlApi_ManagerDownloadAndRegisterEpsDelegate ManagerDownloadAndRegisterEps; + public FlApi_ManagerIsEpDownloadInProgressDelegate ManagerIsEpDownloadInProgress; + + // Manager shutdown + public FlApi_ManagerShutdownDelegate ManagerShutdown; + public FlApi_ManagerIsShutdownRequestedDelegate ManagerIsShutdownRequested; +} + +/// Item API table — field order MUST match flItemApi in foundry_local_c.h. +[StructLayout(LayoutKind.Sequential)] +public struct FlItemApi +{ + // Lifecycle + public FlItem_CreateDelegate Create; + public FlItem_ReleaseDelegate Release; + + // Type — 'new' hides inherited object.GetType(). Name must match C vtable layout. + public new FlItem_GetTypeDelegate GetType; + + // Setters + public FlItem_SetBytesDelegate SetBytes; + public FlItem_SetTensorDelegate SetTensor; + public FlItem_SetTextDelegate SetText; + public FlItem_SetMessageDelegate SetMessage; + public FlItem_SetImageDelegate SetImage; + public FlItem_SetAudioDelegate SetAudio; + public FlItem_SetToolCallDelegate SetToolCall; + public FlItem_SetToolResultDelegate SetToolResult; + + // Getters + public FlItem_GetBytesDelegate GetBytes; + public FlItem_GetTextDelegate GetText; + public FlItem_GetMessageDelegate GetMessage; + public FlItem_GetTensorDelegate GetTensor; + public FlItem_GetImageDelegate GetImage; + public FlItem_GetAudioDelegate GetAudio; + public FlItem_GetToolCallDelegate GetToolCall; + public FlItem_GetToolResultDelegate GetToolResult; + + // Metadata + public FlItem_GetMetadataDelegate GetMetadata; + public FlItem_GetMetadataDelegate GetMutableMetadata; + + // Queue item + public FlItem_GetQueueDelegate GetQueue; + + // ItemQueue + public FlItem_QueueCreateDelegate QueueCreate; + public FlItem_QueueReleaseDelegate QueueRelease; + public FlItem_QueuePushDelegate QueuePush; + public FlItem_QueueTryPopDelegate QueueTryPop; + public FlItem_QueueSizeDelegate QueueSize; + public FlItem_QueueMarkFinishedDelegate QueueMarkFinished; + public FlItem_QueueGetFinishedDelegate QueueGetFinished; +} + +/// Inference API table — request, response, session. +[StructLayout(LayoutKind.Sequential)] +public struct FlInferenceApi +{ + // Request + public FlInference_RequestCreateDelegate RequestCreate; + public FlInference_RequestReleaseDelegate RequestRelease; + public FlInference_RequestAddItemDelegate RequestAddItem; + public FlInference_RequestGetItemCountDelegate RequestGetItemCount; + public FlInference_RequestGetItemDelegate RequestGetItem; + public FlInference_RequestSetOptionsDelegate RequestSetOptions; + public FlInference_RequestCancelDelegate RequestCancel; + + // Response + public FlInference_ResponseCreateDelegate ResponseCreate; + public FlInference_ResponseReleaseDelegate ResponseRelease; + public FlInference_ResponseGetItemCountDelegate ResponseGetItemCount; + public FlInference_ResponseGetItemDelegate ResponseGetItem; + public FlInference_ResponseGetFinishReasonDelegate ResponseGetFinishReason; + public FlInference_ResponseGetUsageDelegate ResponseGetUsage; + + // Session + public FlInference_SessionCreateDelegate SessionCreate; + public FlInference_SessionReleaseDelegate SessionRelease; + public FlInference_SessionSetStreamingCallbackDelegate SessionSetStreamingCallback; + public FlInference_SessionSetOptionsDelegate SessionSetOptions; + public FlInference_SessionProcessRequestDelegate SessionProcessRequest; + + // Chat session features + public FlInference_SessionAddToolDefinitionDelegate SessionAddToolDefinition; + public FlInference_SessionRemoveToolDefinitionDelegate SessionRemoveToolDefinition; + public FlInference_SessionGetTurnCountDelegate SessionGetTurnCount; + public FlInference_SessionUndoTurnsDelegate SessionUndoTurns; +} + +/// Configuration API table. +[StructLayout(LayoutKind.Sequential)] +public struct FlConfigurationApi +{ + public FlConfig_CreateDelegate Create; + public FlConfig_ReleaseDelegate Release; + public FlConfig_SetDefaultLogLevelDelegate SetDefaultLogLevel; + public FlConfig_SetStringDelegate SetAppDataDir; + public FlConfig_SetStringDelegate SetLogsDir; + public FlConfig_SetStringDelegate SetModelCacheDir; + public FlConfig_AddCatalogUrlDelegate AddCatalogUrl; + public FlConfig_SetStringDelegate SetCatalogRegion; + public FlConfig_AddWebServiceEndpointDelegate AddWebServiceEndpoint; + public FlConfig_SetExternalServiceUrlDelegate SetExternalServiceUrl; + public FlConfig_SetAdditionalOptionsDelegate SetAdditionalOptions; +} + +/// Catalog API table. +[StructLayout(LayoutKind.Sequential)] +public struct FlCatalogApi +{ + public FlCatalog_GetNameDelegate GetName; + public FlCatalog_GetModelsDelegate GetModels; + public FlCatalog_GetModelDelegate GetModel; + public FlCatalog_GetModelVariantDelegate GetModelVariant; + public FlCatalog_GetLatestVersionDelegate GetLatestVersion; + public FlCatalog_GetCachedModelsDelegate GetCachedModels; + public FlCatalog_GetLoadedModelsDelegate GetLoadedModels; +} + +/// Model API table — model operations and ModelInfo accessors. +[StructLayout(LayoutKind.Sequential)] +public struct FlModelApi +{ + // ModelInfo (GetInfo first — matches C header order) + public FlModel_GetInfoDelegate GetInfo; + + // Model operations + public FlModel_GetInputOutputInfoDelegate GetInputOutputInfo; + public FlModel_IsCachedDelegate IsCached; + public FlModel_GetPathDelegate GetPath; + public FlModel_DownloadDelegate Download; + public FlModel_IsLoadedDelegate IsLoaded; + public FlModel_LoadDelegate Load; + public FlModel_UnloadDelegate Unload; + public FlModel_RemoveFromCacheDelegate RemoveFromCache; + + // Variant support + public FlModel_GetVariantsDelegate GetVariants; + public FlModel_SelectVariantDelegate SelectVariant; + + // ModelInfo accessors + public FlModel_InfoGetStringDelegate InfoGetId; + public FlModel_InfoGetStringDelegate InfoGetName; + public FlModel_InfoGetVersionDelegate InfoGetVersion; + public FlModel_InfoGetStringDelegate InfoGetAlias; + public FlModel_InfoGetStringDelegate InfoGetUri; + public FlModel_InfoGetDeviceTypeDelegate InfoGetDeviceType; + public FlModel_InfoGetStringDelegate InfoGetExecutionProvider; + public FlModel_InfoGetStringDelegate InfoGetTask; + public FlModel_InfoGetKvpDelegate InfoGetPromptTemplates; + public FlModel_InfoGetKvpDelegate InfoGetModelSettings; + public FlModel_InfoGetStringPropertyDelegate InfoGetStringProperty; + public FlModel_InfoGetIntPropertyDelegate InfoGetIntProperty; +} + +// ----------------------------------------------------------------------- +// Well-known property key constants +// ----------------------------------------------------------------------- + +public static class ModelProperties +{ + // String properties + public const string DisplayName = "display_name"; + public const string ModelType = "type"; + public const string Publisher = "publisher"; + public const string License = "license"; + public const string LicenseDescription = "license_description"; + public const string Task = "task"; + public const string ModelProvider = "model_provider"; + public const string MinFlVersion = "min_fl_version"; + public const string ParentUri = "parent_uri"; + public const string ToolCallStart = "tool_call_start"; + public const string ToolCallEnd = "tool_call_end"; + public const string ReasoningStart = "reasoning_start"; + public const string ReasoningEnd = "reasoning_end"; + + // Int properties + public const string SupportsToolCalling = "supports_tool_calling"; + public const string SupportsReasoning = "supports_reasoning"; + public const string FileSizeMb = "filesize_mb"; + public const string MaxOutputTokens = "max_output_tokens"; + public const string CreatedAtUnix = "created_at_unix"; + public const string IsTestModel = "is_test_model"; +} + +public static class Parameters +{ + // Sampling / generation + public const string Temperature = "temperature"; + public const string TopP = "top_p"; + public const string TopK = "top_k"; + public const string MaxOutputTokens = "max_output_tokens"; + public const string Stop = "stop"; + public const string FrequencyPenalty = "frequency_penalty"; + public const string PresencePenalty = "presence_penalty"; + public const string Seed = "seed"; + public const string EarlyStopping = "early_stopping"; + + // Tool calling + public const string ToolChoice = "tool_choice"; + + // Output format + public const string ResponseFormat = "response_format"; + + // Conversation state + public const string PreviousResponseId = "previous_response_id"; + public const string Instructions = "instructions"; + public const string Store = "store"; + + // Reasoning + public const string ReasoningEffort = "reasoning_effort"; } diff --git a/sdk_v2/cs/src/Detail/Throw.cs b/sdk_v2/cs/src/Detail/Throw.cs index 33ce384d5..1dfcde2cf 100644 --- a/sdk_v2/cs/src/Detail/Throw.cs +++ b/sdk_v2/cs/src/Detail/Throw.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local.Detail; diff --git a/sdk_v2/cs/src/Detail/Utf8.cs b/sdk_v2/cs/src/Detail/Utf8.cs index d3f35e6da..e5cabec10 100644 --- a/sdk_v2/cs/src/Detail/Utf8.cs +++ b/sdk_v2/cs/src/Detail/Utf8.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local.Detail; diff --git a/sdk_v2/cs/src/Enums.cs b/sdk_v2/cs/src/Enums.cs index b75f116a7..24bc9a292 100644 --- a/sdk_v2/cs/src/Enums.cs +++ b/sdk_v2/cs/src/Enums.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/FoundryModelInfo.cs b/sdk_v2/cs/src/FoundryModelInfo.cs index 91477de4c..cbf5dfc78 100644 --- a/sdk_v2/cs/src/FoundryModelInfo.cs +++ b/sdk_v2/cs/src/FoundryModelInfo.cs @@ -10,7 +10,6 @@ namespace Microsoft.AI.Foundry.Local; using System.Text.Json.Serialization; using NativeModelType = Microsoft.AI.Foundry.Local.Detail.Native.Model; -using NativeModelInfo = Microsoft.AI.Foundry.Local.Detail.Native.ModelInfo; [JsonConverter(typeof(JsonStringEnumConverter))] public enum DeviceType diff --git a/sdk_v2/cs/src/GlobalSuppressions.cs b/sdk_v2/cs/src/GlobalSuppressions.cs index b6f22e9ef..1c5ab3376 100644 --- a/sdk_v2/cs/src/GlobalSuppressions.cs +++ b/sdk_v2/cs/src/GlobalSuppressions.cs @@ -3,4 +3,3 @@ // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. -using System.Diagnostics.CodeAnalysis; diff --git a/sdk_v2/cs/src/Items/AudioItem.cs b/sdk_v2/cs/src/Items/AudioItem.cs index c71a94f01..e3e404a27 100644 --- a/sdk_v2/cs/src/Items/AudioItem.cs +++ b/sdk_v2/cs/src/Items/AudioItem.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/BytesItem.cs b/sdk_v2/cs/src/Items/BytesItem.cs index df25d7717..e528a0192 100644 --- a/sdk_v2/cs/src/Items/BytesItem.cs +++ b/sdk_v2/cs/src/Items/BytesItem.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/ImageItem.cs b/sdk_v2/cs/src/Items/ImageItem.cs index 0a832f115..76bb09dd1 100644 --- a/sdk_v2/cs/src/Items/ImageItem.cs +++ b/sdk_v2/cs/src/Items/ImageItem.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/InputOutputInfo.cs b/sdk_v2/cs/src/Items/InputOutputInfo.cs index b77f79e8a..889d0f4aa 100644 --- a/sdk_v2/cs/src/Items/InputOutputInfo.cs +++ b/sdk_v2/cs/src/Items/InputOutputInfo.cs @@ -1,7 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Collections.Generic; +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/Item.cs b/sdk_v2/cs/src/Items/Item.cs index d6afbb6f4..d3cb720d8 100644 --- a/sdk_v2/cs/src/Items/Item.cs +++ b/sdk_v2/cs/src/Items/Item.cs @@ -1,8 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.AI.Foundry.Local.Detail.Interop; -using Microsoft.AI.Foundry.Local.Detail.Native; +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- // Suppress IDisposableAnalyzers warnings for the Item base: // - IDISP023: Dispose accesses static Api which is always available @@ -11,6 +11,8 @@ #pragma warning disable IDISP025 namespace Microsoft.AI.Foundry.Local; +using Microsoft.AI.Foundry.Local.Detail.Interop; +using Microsoft.AI.Foundry.Local.Detail.Native; public class Item : IDisposable { @@ -41,16 +43,16 @@ internal static Item FromNative(IntPtr ptr, bool ownsHandle) return type switch { - ItemType.Bytes => new BytesItem(ptr, ownsHandle), - ItemType.Text => new TextItem(ptr, ownsHandle), - ItemType.Message => new MessageItem(ptr, ownsHandle), - ItemType.Image => new ImageItem(ptr, ownsHandle), - ItemType.Audio => new AudioItem(ptr, ownsHandle), - ItemType.ToolCall => new ToolCallItem(ptr, ownsHandle), + ItemType.Bytes => new BytesItem(ptr, ownsHandle), + ItemType.Text => new TextItem(ptr, ownsHandle), + ItemType.Message => new MessageItem(ptr, ownsHandle), + ItemType.Image => new ImageItem(ptr, ownsHandle), + ItemType.Audio => new AudioItem(ptr, ownsHandle), + ItemType.ToolCall => new ToolCallItem(ptr, ownsHandle), ItemType.ToolResult => new ToolResultItem(ptr, ownsHandle), - ItemType.Tensor => new TensorItem(ptr, ownsHandle), - ItemType.Queue => new ItemQueue(ptr, ownsHandle), - _ => new Item(ptr, ownsHandle), + ItemType.Tensor => new TensorItem(ptr, ownsHandle), + ItemType.Queue => new ItemQueue(ptr, ownsHandle), + _ => new Item(ptr, ownsHandle), }; } diff --git a/sdk_v2/cs/src/Items/ItemQueue.cs b/sdk_v2/cs/src/Items/ItemQueue.cs index 08d5e0fa3..82454d699 100644 --- a/sdk_v2/cs/src/Items/ItemQueue.cs +++ b/sdk_v2/cs/src/Items/ItemQueue.cs @@ -1,12 +1,11 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- -using Microsoft.AI.Foundry.Local.Detail.Native; - namespace Microsoft.AI.Foundry.Local; +using Microsoft.AI.Foundry.Local.Detail.Native; /// /// A queue of items used for streaming. Items can be pushed and popped. diff --git a/sdk_v2/cs/src/Items/JsonItem.cs b/sdk_v2/cs/src/Items/JsonItem.cs index 7b0a81a65..e968afb16 100644 --- a/sdk_v2/cs/src/Items/JsonItem.cs +++ b/sdk_v2/cs/src/Items/JsonItem.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/MessageItem.cs b/sdk_v2/cs/src/Items/MessageItem.cs index 42f811cdc..71babaca0 100644 --- a/sdk_v2/cs/src/Items/MessageItem.cs +++ b/sdk_v2/cs/src/Items/MessageItem.cs @@ -1,14 +1,15 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- -using System.Collections.Generic; +namespace Microsoft.AI.Foundry.Local; using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -namespace Microsoft.AI.Foundry.Local; - /// /// Chat message with role, typed content parts, and optional participant name. /// diff --git a/sdk_v2/cs/src/Items/PinContext.cs b/sdk_v2/cs/src/Items/PinContext.cs index 325f4cf9e..f7a01a1d5 100644 --- a/sdk_v2/cs/src/Items/PinContext.cs +++ b/sdk_v2/cs/src/Items/PinContext.cs @@ -1,5 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local; diff --git a/sdk_v2/cs/src/Items/TensorItem.cs b/sdk_v2/cs/src/Items/TensorItem.cs index 70ab836ce..f670f6b0d 100644 --- a/sdk_v2/cs/src/Items/TensorItem.cs +++ b/sdk_v2/cs/src/Items/TensorItem.cs @@ -1,13 +1,15 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace Microsoft.AI.Foundry.Local; using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -namespace Microsoft.AI.Foundry.Local; - public sealed class TensorItem : Item { public FlTensorDataType DataType { get; } diff --git a/sdk_v2/cs/src/Items/TextItem.cs b/sdk_v2/cs/src/Items/TextItem.cs index 9b34092fa..e8b84fa2f 100644 --- a/sdk_v2/cs/src/Items/TextItem.cs +++ b/sdk_v2/cs/src/Items/TextItem.cs @@ -1,13 +1,15 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace Microsoft.AI.Foundry.Local; using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -namespace Microsoft.AI.Foundry.Local; - public class TextItem : Item { public string Text { get; } diff --git a/sdk_v2/cs/src/Items/ToolCallItem.cs b/sdk_v2/cs/src/Items/ToolCallItem.cs index 1c182300e..dc7f0d820 100644 --- a/sdk_v2/cs/src/Items/ToolCallItem.cs +++ b/sdk_v2/cs/src/Items/ToolCallItem.cs @@ -1,13 +1,15 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace Microsoft.AI.Foundry.Local; using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -namespace Microsoft.AI.Foundry.Local; - public sealed class ToolCallItem : Item { /// Identifier the model assigned to this tool call. Always present. diff --git a/sdk_v2/cs/src/Items/ToolResultItem.cs b/sdk_v2/cs/src/Items/ToolResultItem.cs index 8a1159777..0b5e55cf3 100644 --- a/sdk_v2/cs/src/Items/ToolResultItem.cs +++ b/sdk_v2/cs/src/Items/ToolResultItem.cs @@ -1,13 +1,15 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace Microsoft.AI.Foundry.Local; using System.Runtime.InteropServices; using Microsoft.AI.Foundry.Local.Detail.Interop; using Microsoft.AI.Foundry.Local.Detail.Native; -namespace Microsoft.AI.Foundry.Local; - public sealed class ToolResultItem : Item { /// Identifier of the tool call this result satisfies. Always present. diff --git a/sdk_v2/cs/src/OpenAI/ChatClient.cs b/sdk_v2/cs/src/OpenAI/ChatClient.cs index b30ded2b0..872070fee 100644 --- a/sdk_v2/cs/src/OpenAI/ChatClient.cs +++ b/sdk_v2/cs/src/OpenAI/ChatClient.cs @@ -12,14 +12,13 @@ namespace Microsoft.AI.Foundry.Local; using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels; using Betalgo.Ranul.OpenAI.ObjectModels.ResponseModels; -using OpenAIChatMessage = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ChatMessage; -using OpenAIToolChoice = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ToolChoice; - using Microsoft.AI.Foundry.Local.Detail; using Microsoft.AI.Foundry.Local.OpenAI; using Microsoft.Extensions.Logging; using NativeModel = Microsoft.AI.Foundry.Local.Detail.Native.Model; +using OpenAIChatMessage = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ChatMessage; +using OpenAIToolChoice = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ToolChoice; /// /// Chat Client that uses the OpenAI API. diff --git a/sdk_v2/cs/src/OpenAI/ChatCompletionRequestResponseTypes.cs b/sdk_v2/cs/src/OpenAI/ChatCompletionRequestResponseTypes.cs index ffcf8638f..41b53bf59 100644 --- a/sdk_v2/cs/src/OpenAI/ChatCompletionRequestResponseTypes.cs +++ b/sdk_v2/cs/src/OpenAI/ChatCompletionRequestResponseTypes.cs @@ -13,12 +13,12 @@ namespace Microsoft.AI.Foundry.Local.OpenAI; using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels; using Betalgo.Ranul.OpenAI.ObjectModels.ResponseModels; -using OpenAIChatMessage = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ChatMessage; - using Microsoft.AI.Foundry.Local; using Microsoft.AI.Foundry.Local.Detail; using Microsoft.Extensions.Logging; +using OpenAIChatMessage = Betalgo.Ranul.OpenAI.ObjectModels.RequestModels.ChatMessage; + // https://platform.openai.com/docs/api-reference/chat/create // Using the Betalgo ChatCompletionCreateRequest and extending with the `metadata` field for additional parameters // which is part of the OpenAI spec but for some reason not part of the Betalgo request object. diff --git a/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionClient.cs b/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionClient.cs index 0895503e3..6d0deb815 100644 --- a/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionClient.cs +++ b/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionClient.cs @@ -10,6 +10,7 @@ namespace Microsoft.AI.Foundry.Local.OpenAI; using System.Threading.Channels; using Betalgo.Ranul.OpenAI.ObjectModels.RealtimeModels; + using Microsoft.AI.Foundry.Local; using Microsoft.AI.Foundry.Local.Detail.Interop; diff --git a/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionTypes.cs b/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionTypes.cs index 7409ee32c..c28b51a41 100644 --- a/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionTypes.cs +++ b/sdk_v2/cs/src/OpenAI/LiveAudioTranscriptionTypes.cs @@ -1,8 +1,16 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) Microsoft. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + namespace Microsoft.AI.Foundry.Local.OpenAI; using System.Text.Json; using System.Text.Json.Serialization; + using Betalgo.Ranul.OpenAI.ObjectModels.RealtimeModels; + using Microsoft.AI.Foundry.Local; using Microsoft.AI.Foundry.Local.Detail; diff --git a/sdk_v2/cs/src/OpenAI/ToolCallingExtensions.cs b/sdk_v2/cs/src/OpenAI/ToolCallingExtensions.cs index cb94a0ad0..307cb1e91 100644 --- a/sdk_v2/cs/src/OpenAI/ToolCallingExtensions.cs +++ b/sdk_v2/cs/src/OpenAI/ToolCallingExtensions.cs @@ -6,10 +6,10 @@ namespace Microsoft.AI.Foundry.Local.OpenAI; -using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels; - using System.Text.Json.Serialization; +using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels; + // Extend response format beyond the OpenAI spec for LARK grammars. // Note: this type is registered in JsonSerializationContext for source-generated (AOT-safe) // serialization. It currently has no derived types; if any are introduced, add diff --git a/sdk_v2/cs/src/Request.cs b/sdk_v2/cs/src/Request.cs index 418243e90..7761f0e61 100644 --- a/sdk_v2/cs/src/Request.cs +++ b/sdk_v2/cs/src/Request.cs @@ -1,12 +1,11 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- -using Microsoft.AI.Foundry.Local.Detail.Native; - namespace Microsoft.AI.Foundry.Local; +using Microsoft.AI.Foundry.Local.Detail.Native; public sealed class Request : IDisposable { diff --git a/sdk_v2/cs/src/Session.cs b/sdk_v2/cs/src/Session.cs index f2f76b504..111ae4855 100644 --- a/sdk_v2/cs/src/Session.cs +++ b/sdk_v2/cs/src/Session.cs @@ -6,7 +6,6 @@ namespace Microsoft.AI.Foundry.Local; -using System.Collections.Generic; using System.Threading.Channels; using Microsoft.AI.Foundry.Local.Detail.Interop; diff --git a/sdk_v2/cs/src/Utils.cs b/sdk_v2/cs/src/Utils.cs index 7ee9c1575..65698385f 100644 --- a/sdk_v2/cs/src/Utils.cs +++ b/sdk_v2/cs/src/Utils.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -7,6 +7,7 @@ namespace Microsoft.AI.Foundry.Local; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; internal class Utils diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/CatalogTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/CatalogTests.cs index d6fbd095f..1a4cccb64 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/CatalogTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/CatalogTests.cs @@ -5,7 +5,6 @@ // -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local.Tests; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/ChatSessionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/ChatSessionTests.cs index 091a47f59..7157ee966 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/ChatSessionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/ChatSessionTests.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/EmbeddingsSessionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/EmbeddingsSessionTests.cs index 3bfbf8145..9af09a059 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/EmbeddingsSessionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/EmbeddingsSessionTests.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -10,6 +10,7 @@ namespace Microsoft.AI.Foundry.Local.Tests; using System.Threading.Tasks; using Microsoft.AI.Foundry.Local.Detail.Interop; + using TUnit.Core.Exceptions; #pragma warning disable CA2000 // Items are transferred to Request via AddItem diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/FoundryLocalManagerTest.cs b/sdk_v2/cs/test/FoundryLocal.Tests/FoundryLocalManagerTest.cs index 3da959ef3..ca9c13da5 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/FoundryLocalManagerTest.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/FoundryLocalManagerTest.cs @@ -11,6 +11,7 @@ namespace Microsoft.AI.Foundry.Local.Tests; using System.Linq; using Microsoft.AI.Foundry.Local; + using TUnit.Core.Exceptions; [SkipUnlessIntegration] diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/LiveAudioTranscriptionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/LiveAudioTranscriptionTests.cs index 0853c7c3a..fb859ea8b 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/LiveAudioTranscriptionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/LiveAudioTranscriptionTests.cs @@ -5,10 +5,8 @@ // -------------------------------------------------------------------------------------------------------------------- namespace Microsoft.AI.Foundry.Local.Tests; - -using System.Text.Json; -using Microsoft.AI.Foundry.Local.Detail; using Microsoft.AI.Foundry.Local.OpenAI; + using TUnit.Core.Exceptions; internal sealed class LiveAudioTranscriptionTests diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs index 1ed3a0170..e8d3d44ea 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) Microsoft. All rights reserved. // @@ -6,7 +6,6 @@ namespace Microsoft.AI.Foundry.Local.Tests; -using System.Collections.Generic; using System.Threading.Tasks; using TUnit.Core.Exceptions; diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/SkipInCIAttribute.cs b/sdk_v2/cs/test/FoundryLocal.Tests/SkipInCIAttribute.cs index c4d17e5b9..69db2f858 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/SkipInCIAttribute.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/SkipInCIAttribute.cs @@ -6,10 +6,10 @@ namespace Microsoft.AI.Foundry.Local.Tests; -using TUnit.Core; - using System.Threading.Tasks; +using TUnit.Core; + public class SkipInCIAttribute() : SkipAttribute("This test is only supported locally. Skipped on CIs.") { public override Task ShouldSkip(TestRegisteredContext context) diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/VisionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/VisionTests.cs index 07be22307..965dc9fb5 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/VisionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/VisionTests.cs @@ -6,7 +6,6 @@ namespace Microsoft.AI.Foundry.Local.Tests; -using System.Collections.Generic; using System.Text; using System.Threading.Tasks;