Grafana.Sigil
0.3.0
Prefix Reserved
dotnet add package Grafana.Sigil --version 0.3.0
NuGet\Install-Package Grafana.Sigil -Version 0.3.0
<PackageReference Include="Grafana.Sigil" Version="0.3.0" />
<PackageVersion Include="Grafana.Sigil" Version="0.3.0" />
<PackageReference Include="Grafana.Sigil" />
paket add Grafana.Sigil --version 0.3.0
#r "nuget: Grafana.Sigil, 0.3.0"
#:package Grafana.Sigil@0.3.0
#addin nuget:?package=Grafana.Sigil&version=0.3.0
#tool nuget:?package=Grafana.Sigil&version=0.3.0
Grafana.Sigil
Core runtime for normalized generation export and OpenTelemetry-aligned instrumentation.
Install
dotnet add package Grafana.Sigil
Configure SigilClient
using Grafana.Sigil;
var client = new SigilClient(new SigilClientConfig
{
GenerationExport = new GenerationExportConfig
{
Protocol = GenerationExportProtocol.Grpc,
Endpoint = "localhost:4317",
Auth = new AuthConfig
{
Mode = ExportAuthMode.Tenant,
TenantId = "dev-tenant",
},
BatchSize = 100,
FlushInterval = TimeSpan.FromSeconds(1),
QueueSize = 2000,
MaxRetries = 5,
InitialBackoff = TimeSpan.FromMilliseconds(100),
MaxBackoff = TimeSpan.FromSeconds(5),
},
Api = new ApiConfig
{
Endpoint = "http://localhost:8080",
},
});
Configure OTEL exporters (traces/metrics) separately in your application's OTEL setup.
Quick OTEL setup pattern before creating the Sigil client:
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource("github.com/grafana/sigil/sdks/dotnet")
.AddOtlpExporter()
.Build();
using var meterProvider = Sdk.CreateMeterProviderBuilder()
.AddMeter("github.com/grafana/sigil/sdks/dotnet")
.AddOtlpExporter()
.Build();
Generation export auth is configured in GenerationExport.Auth.
Api.Endpoint configures helper API calls such as SubmitConversationRatingAsync(...).
Generation export transport protocols:
GenerationExportProtocol.GrpcGenerationExportProtocol.HttpGenerationExportProtocol.None(instrumentation-only; no generation transport)
Instrumentation-only mode (no generation send)
var client = new SigilClient(new SigilClientConfig
{
GenerationExport = new GenerationExportConfig
{
Protocol = GenerationExportProtocol.None,
},
});
Manual generation instrumentation (sync)
Use this API for unsupported providers or custom pipelines.
var recorder = client.StartGeneration(new GenerationStart
{
ConversationId = "conv-9b2f",
AgentName = "assistant-core",
AgentVersion = "1.0.0",
Model = new ModelRef
{
Provider = "openai",
Name = "gpt-5",
},
});
try
{
var providerResponseText = await Task.FromResult("Paris is 18C and sunny.");
recorder.SetResult(new Generation
{
Input = new List<Message>
{
Message.UserTextMessage("Give me a short weather summary for Paris."),
},
Output = new List<Message>
{
Message.AssistantTextMessage(providerResponseText),
},
Usage = new TokenUsage
{
InputTokens = 120,
OutputTokens = 42,
TotalTokens = 162,
},
StopReason = "stop",
});
}
catch (Exception ex)
{
recorder.SetCallError(ex);
throw;
}
finally
{
recorder.End();
}
Manual generation instrumentation (stream)
var recorder = client.StartStreamingGeneration(new GenerationStart
{
ConversationId = "conv-stream",
AgentName = "assistant-core",
AgentVersion = "1.0.0",
Model = new ModelRef
{
Provider = "openai",
Name = "gpt-5",
},
});
try
{
var chunks = new List<string>();
await foreach (var chunk in StreamAsync())
{
chunks.Add(chunk);
}
recorder.SetResult(new Generation
{
Input = new List<Message>
{
Message.UserTextMessage("Stream a short weather summary for Paris."),
},
Output = new List<Message>
{
Message.AssistantTextMessage(string.Concat(chunks)),
},
});
}
catch (Exception ex)
{
recorder.SetCallError(ex);
throw;
}
finally
{
recorder.End();
}
static async IAsyncEnumerable<string> StreamAsync()
{
yield return "Paris is ";
yield return "18C and sunny.";
await Task.CompletedTask;
}
Tool execution instrumentation
var tool = client.StartToolExecution(new ToolExecutionStart
{
ToolName = "weather",
ToolCallId = "call_weather_1",
ToolType = "function",
ToolDescription = "Get weather by city",
ConversationId = "conv-9b2f",
AgentName = "assistant-core",
AgentVersion = "1.0.0",
IncludeContent = true,
});
try
{
var args = new { city = "Paris" };
var result = await Task.FromResult<object>(new
{
city = "Paris",
tempC = 18,
condition = "sunny",
});
tool.SetResult(new ToolExecutionEnd
{
Arguments = args,
Result = result,
});
}
catch (Exception ex)
{
tool.SetExecutionError(ex);
throw;
}
finally
{
tool.End();
}
Context defaults with async-local scopes
using var _conversation = SigilContext.WithConversationId("conv-default");
using var _agentName = SigilContext.WithAgentName("assistant-core");
using var _agentVersion = SigilContext.WithAgentVersion("1.0.0");
var recorder = client.StartGeneration(new GenerationStart
{
Model = new ModelRef
{
Provider = "openai",
Name = "gpt-5",
},
});
If ConversationId, AgentName, or AgentVersion are omitted in GenerationStart or ToolExecutionStart, the current SigilContext values are applied.
Error semantics
SetCallError(...)records provider-call failures as generationCallErrorand span status.SetResult(..., mappingError)lets you keep generation data while marking mapper failures.GenerationRecorder.ErrorandToolExecutionRecorder.Errorrepresent local SDK failures only (validation/enqueue/shutdown path), not provider-call failures.- Generation/tool spans always include:
sigil.sdk.name=sdk-dotnet
- Normalized generation metadata always includes the same key.
- If caller metadata provides a conflicting value for this key, the SDK overwrites it.
Auth modes and header precedence
Per export path, supported auth modes are:
ExportAuthMode.NoneExportAuthMode.Tenant(X-Scope-OrgID)ExportAuthMode.Bearer(Authorization: Bearer <token>)ExportAuthMode.Basic(requiresBasicPassword+BasicUserorTenantId, injectsAuthorization: Basic <base64(user:password)>; also injectsX-Scope-OrgIDwhenTenantIdis set — for multi-tenant deployments only, not needed for Grafana Cloud)
Explicit transport headers take precedence over auth-derived headers (Authorization, X-Scope-OrgID, case-insensitive).
Grafana Cloud auth (basic)
For Grafana Cloud, use Basic auth mode. The username is your Grafana Cloud instance/tenant ID and the password is your Grafana Cloud API key:
Auth = new AuthConfig
{
Mode = ExportAuthMode.Basic,
TenantId = Environment.GetEnvironmentVariable("SIGIL_AUTH_TENANT_ID") ?? "",
BasicPassword = Environment.GetEnvironmentVariable("SIGIL_AUTH_TOKEN") ?? "",
},
If your deployment requires a distinct username, set BasicUser explicitly:
Auth = new AuthConfig
{
Mode = ExportAuthMode.Basic,
TenantId = Environment.GetEnvironmentVariable("SIGIL_AUTH_TENANT_ID") ?? "",
BasicUser = Environment.GetEnvironmentVariable("SIGIL_AUTH_TENANT_ID") ?? "",
BasicPassword = Environment.GetEnvironmentVariable("SIGIL_AUTH_TOKEN") ?? "",
},
Lifecycle and performance guidance
- Reuse one
SigilClientfor the process lifetime. - Call
ShutdownAsync(...)on graceful shutdown to flush pending generation batches. - Use
FlushAsync(...)before short-lived jobs exit if needed. - Keep raw artifacts disabled by default in production.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 was computed. 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 is compatible. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Google.Protobuf (>= 3.34.1)
- Grpc.Net.Client (>= 2.76.0)
- OpenTelemetry (>= 1.15.3)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
- System.Text.Json (>= 10.0.0)
-
net10.0
- Google.Protobuf (>= 3.34.1)
- Grpc.Net.Client (>= 2.76.0)
- OpenTelemetry (>= 1.15.3)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
-
net8.0
- Google.Protobuf (>= 3.34.1)
- Grpc.Net.Client (>= 2.76.0)
- OpenTelemetry (>= 1.15.3)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.15.3)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Grafana.Sigil:
| Package | Downloads |
|---|---|
|
Grafana.Sigil.Anthropic
Grafana Sigil Anthropic provider helpers for .NET. |
|
|
Grafana.Sigil.OpenAI
Grafana Sigil OpenAI provider helpers for .NET. |
|
|
Grafana.Sigil.Gemini
Grafana Sigil Google Gemini provider helpers for .NET. |
GitHub repositories
This package is not used by any popular GitHub repositories.