Arinti.Langfuse.Tracing.MEAI
1.0.0-alpha.2
dotnet add package Arinti.Langfuse.Tracing.MEAI --version 1.0.0-alpha.2
NuGet\Install-Package Arinti.Langfuse.Tracing.MEAI -Version 1.0.0-alpha.2
<PackageReference Include="Arinti.Langfuse.Tracing.MEAI" Version="1.0.0-alpha.2" />
<PackageVersion Include="Arinti.Langfuse.Tracing.MEAI" Version="1.0.0-alpha.2" />
<PackageReference Include="Arinti.Langfuse.Tracing.MEAI" />
paket add Arinti.Langfuse.Tracing.MEAI --version 1.0.0-alpha.2
#r "nuget: Arinti.Langfuse.Tracing.MEAI, 1.0.0-alpha.2"
#:package Arinti.Langfuse.Tracing.MEAI@1.0.0-alpha.2
#addin nuget:?package=Arinti.Langfuse.Tracing.MEAI&version=1.0.0-alpha.2&prerelease
#tool nuget:?package=Arinti.Langfuse.Tracing.MEAI&version=1.0.0-alpha.2&prerelease
Arinti.Langfuse.Tracing.MEAI
An IChatClient middleware that records one Langfuse generation observation per provider
request, shaped per the OpenTelemetry GenAI semantic
conventions (chat span). Plug it into a
ChatClientBuilder
pipeline and observability falls out — works with any Microsoft.Extensions.AI adapter (OpenAI,
Azure OpenAI, Mistral, Gemini, …).
Usage
using Arinti.Langfuse.Tracing.MEAI;
using Microsoft.Extensions.AI;
using OpenAI;
ApiKeyCredential cred = new(apiKey);
IChatClient baseClient = new OpenAIClient(cred).GetChatClient(modelId).AsIChatClient();
IChatClient client = new ChatClientBuilder(baseClient)
.UseFunctionInvocation() // your tool loop
.Use(next => new LangfuseGenerationChatClient(next)) // observation
.Build();
The provider name (for gen_ai.provider.name) and the default model id (for
gen_ai.request.model when ChatOptions.ModelId is not set per call) are read from the inner
client's ChatClientMetadata. Every first-party MEAI adapter populates these. If a custom adapter
doesn't, the span reports gen_ai.provider.name="_OTHER" — the OTel SemConv convention for
unenumerated values — and that attribute itself is the diagnostic signal in your tracing UI.
Linking a Langfuse prompt
When the messages come from a Langfuse-managed prompt (fetched via the SDK), attach the prompt
reference to the call with WithLangfusePrompt. The middleware stamps
langfuse.observation.prompt.name / .version on the generation span, so Langfuse links the
observation to the exact prompt version that produced it:
using Arinti.Langfuse.Prompts; // Compile()
using Arinti.Langfuse.Tracing.MEAI; // WithLangfusePrompt()
ChatPrompt prompt = (ChatPrompt)await prompts.GetPromptAsync("chat.system.default");
ChatOptions options = new ChatOptions { ModelId = modelId }
.WithLangfusePrompt(prompt); // or .WithLangfusePrompt(prompt.Name, prompt.Version)
await client.GetResponseAsync(prompt.Compile(variables), options);
Both the non-streaming and streaming paths carry the tags. Version is optional — pass a name only
(.WithLangfusePrompt(prompt.Name)) to link without pinning a version.
This works whenever you build the ChatOptions yourself — including a Semantic Kernel project
configured to run on this IChatClient pipeline, as long as you pass the tagged ChatOptions
through to the call. When something else owns the span (a manual span you create, or SK's own
OTel connector spans), stamp the tags on that span directly with the underlying primitive:
using Arinti.Langfuse.Tracing.ContextPropagation;
activity.SetLangfusePrompt(prompt.Name, prompt.Version); // `activity` is the span you own
Sensitive data
The middleware records the full conversation on gen_ai.input.messages and the assistant
response on gen_ai.output.messages. Both routinely contain raw user content, system prompts,
tool results, or model output — material the OTel GenAI SemConv explicitly flags as sensitive.
Disable either tag via LangfuseGenerationChatClientOptions:
IChatClient client = new ChatClientBuilder(baseClient)
.UseFunctionInvocation()
.Use(next => new LangfuseGenerationChatClient(
next,
new LangfuseGenerationChatClientOptions
{
RecordInputMessages = false,
RecordOutputMessages = false,
}))
.Build();
Response metadata (id, model, finish reason, usage tokens) is unaffected — only the message payloads are suppressed.
Long-conversation cap
When input messages are recorded, the middleware re-serializes the full chat history into
gen_ai.input.messages on every round-trip, which scales O(N²) over the turn count. A soft
cap of 50 messages keeps the worst case bounded — beyond that, the oldest messages are
elided and a synthetic [N earlier messages truncated] system marker is prepended so the
Langfuse view stays accurate about what was dropped. Setting RecordInputMessages = false
sidesteps the cost entirely.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Arinti.Langfuse.Abstractions (>= 1.0.0-alpha.1)
- Arinti.Langfuse.Tracing.ContextPropagation (>= 1.0.0-alpha.1)
- Arinti.Langfuse.Tracing.SemanticConventions (>= 1.0.0-alpha.1)
- Microsoft.Extensions.AI (>= 10.6.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Options (>= 9.0.0)
- OpenTelemetry.Api (>= 1.15.3)
-
net9.0
- Arinti.Langfuse.Abstractions (>= 1.0.0-alpha.1)
- Arinti.Langfuse.Tracing.ContextPropagation (>= 1.0.0-alpha.1)
- Arinti.Langfuse.Tracing.SemanticConventions (>= 1.0.0-alpha.1)
- Microsoft.Extensions.AI (>= 10.6.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Options (>= 9.0.0)
- OpenTelemetry.Api (>= 1.15.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-alpha.2 | 571 | 7/10/2026 |
| 1.0.0-alpha.1 | 172 | 6/22/2026 |
| 1.0.0-alpha.0 | 76 | 6/21/2026 |