diff --git a/.github/instructions/cs-debug-binding.instructions.md b/.github/instructions/cs-debug-binding.instructions.md
index 3b38372d..436e6a7f 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 00000000..baa0d269
--- /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 c49ff354..f931fb9b 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 a14a7413..cf1c5cf3 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/Catalog.cs b/sdk_v2/cs/src/Catalog.cs
index 7b58ba31..95d50a5e 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 c61b66a6..4307ab8c 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 bad97278..f9df521a 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 062b4486..1f1104f4 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 e286c7e8..32c508a7 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 3f913715..52c3252f 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 33ce384d..1dfcde2c 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 d3f35e6d..e5cabec1 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 b75f116a..24bc9a29 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 91477de4..cbf5dfc7 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 b6f22e9e..1c5ab337 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 16aaaa28..e3e404a2 100644
--- a/sdk_v2/cs/src/Items/AudioItem.cs
+++ b/sdk_v2/cs/src/Items/AudioItem.cs
@@ -1,16 +1,16 @@
-// 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;
-#pragma warning disable IDISP001
-#pragma warning disable IDISP023
-
-namespace Microsoft.AI.Foundry.Local;
-
public sealed class AudioItem : Item
{
private IntPtr _data;
@@ -158,15 +158,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 +195,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 26619bd2..e528a019 100644
--- a/sdk_v2/cs/src/Items/BytesItem.cs
+++ b/sdk_v2/cs/src/Items/BytesItem.cs
@@ -1,16 +1,16 @@
-// 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;
-#pragma warning disable IDISP001
-#pragma warning disable IDISP023
-
-namespace Microsoft.AI.Foundry.Local;
-
public sealed class BytesItem : Item
{
private IntPtr _data;
@@ -85,14 +85,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 16c4b3a6..76bb09dd 100644
--- a/sdk_v2/cs/src/Items/ImageItem.cs
+++ b/sdk_v2/cs/src/Items/ImageItem.cs
@@ -1,16 +1,16 @@
-// 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;
-#pragma warning disable IDISP001
-#pragma warning disable IDISP023
-
-namespace Microsoft.AI.Foundry.Local;
-
public sealed class ImageItem : Item
{
private IntPtr _data;
@@ -148,15 +148,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/InputOutputInfo.cs b/sdk_v2/cs/src/Items/InputOutputInfo.cs
index b77f79e8..889d0f4a 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 d6afbb6f..d3cb720d 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 b07759ce..82454d69 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.
@@ -34,12 +33,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/JsonItem.cs b/sdk_v2/cs/src/Items/JsonItem.cs
index 7b0a81a6..e968afb1 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 42f811cd..71babaca 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 f07d599f..f7a01a1d 100644
--- a/sdk_v2/cs/src/Items/PinContext.cs
+++ b/sdk_v2/cs/src/Items/PinContext.cs
@@ -1,11 +1,14 @@
-// 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.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 +47,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/Items/TensorItem.cs b/sdk_v2/cs/src/Items/TensorItem.cs
index 70ab836c..f670f6b0 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 9b34092f..e8b84fa2 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 1c182300..dc7f0d82 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 8a115977..0b5e55cf 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/Microsoft.AI.Foundry.Local.csproj b/sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj
index cd4c1c6d..b300666f 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/src/OpenAI/ChatClient.cs b/sdk_v2/cs/src/OpenAI/ChatClient.cs
index b30ded2b..872070fe 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 ffcf8638..41b53bf5 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 0895503e..6d0deb81 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 7409ee32..c28b51a4 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 cb94a0ad..307cb1e9 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 418243e9..7761f0e6 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 f2f76b50..111ae485 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 7ee9c157..65698385 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 d6fbd095..1a4cccb6 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 091a47f5..7157ee96 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 3bfbf814..9af09a05 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 3da959ef..ca9c13da 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 0853c7c3..fb859ea8 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/Microsoft.AI.Foundry.Local.Tests.csproj b/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj
index 9ab9aa85..2f1e6f1a 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
+
+
diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/SessionItemLifecycleTests.cs
index 1ed3a017..e8d3d44e 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 c4d17e5b..69db2f85 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 07be2230..965dc9fb 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;