Summary
In 0.20.11, every vision prediction that passes an image fails:
max_length (2147483647) cannot be greater than model context_length (32768)
OnnxVisionModel.ResolveVisionInputTokenCount creates a probe generator with
max_length = int.MaxValue. ONNX Runtime GenAI 0.15.x validates max_length against the
model's context_length from genai_config.json and throws, so the probe added by the #44 fix
aborts the request before generation starts.
This affects Fara1.5-9B (declares context_length: 32768) and any model whose config declares
a context_length.
Evidence
Decompiled from ElBruno.LocalLLMs 0.20.11, ElBruno.LocalLLMs.Internal.OnnxVisionModel:
private const int ProbeMaxLength = int.MaxValue;
private static int ResolveVisionInputTokenCount(
IVisionGenerationRuntime runtime, string prompt, IVisionInputs inputs)
{
IVisionGenerator probeGenerator = runtime.CreateProbeGenerator(int.MaxValue); // 💥 throws here
try
{
probeGenerator.SetInputs(inputs);
return ResolveInputTokenCount(name =>
{
try { return probeGenerator.GetInputShape(name); }
catch { return null; }
}, runtime.CountPromptTokens(prompt));
}
finally { probeGenerator?.Dispose(); }
}
CreateProbeGenerator is not wrapped in a try/catch, so the exception propagates out of
GenerateWithImagesCore:
int inputTokenCount = imagePaths.Length != 0
? ResolveVisionInputTokenCount(runtime, prompt, inputs) // ← unguarded
: runtime.CountPromptTokens(prompt);
Both GenerateWithImagesCore and GenerateWithImagesStreamingCore take this path, so
GetResponseAsync and GetStreamingResponseAsync are both broken.
Note the real generation path is fine — ResolveMaxLength is correct:
internal static int ResolveMaxLength(int maxLength, int inputTokenCount, int? maxOutputTokens) =>
Math.Max(
maxOutputTokens.HasValue ? Math.Min(maxLength, inputTokenCount + maxOutputTokens.Value) : maxLength,
inputTokenCount + 1);
With MaxSequenceLength = 4096, inputTokenCount ≈ 2900, MaxOutputTokens = 128 it yields
3028, comfortably under context_length. Only the probe uses int.MaxValue.
Steps to reproduce
ElBruno.LocalLLMs 0.20.11, KnownModels.Fara15_9B, ExecutionProvider.Auto (resolves to CPU).
-
var response = await client.GetResponseAsync(
[new ChatMessage(ChatRole.User, "Predict the next action.")],
new VisionChatOptions { ImagePaths = [screenshotPath], MaxOutputTokens = 128, Temperature = 0.1f });
- The call throws before any tokens are generated:
max_length (2147483647) cannot be greater than model context_length (32768)
Reproduces with MaxOutputTokens set or unset, and with any MaxSequenceLength, because the
probe ignores both.
Expected
The input-token probe should never make a request the model can reject, and a probe failure
should never fail the user's request — it exists only to refine a token count that already has a
working fallback (runtime.CountPromptTokens(prompt)).
Suggested fix
Two independent changes; either one unblocks callers, and both together are ideal:
-
Clamp the probe length to the model's context length. GenAIConfigParser already parses
the config, so the value is available via Metadata:
var probeMaxLength = Math.Min(ProbeMaxLength, metadata?.ContextLength ?? ProbeMaxLength);
using var probeGenerator = runtime.CreateProbeGenerator(probeMaxLength);
(If ModelMetadata does not expose context_length yet, adding it would also help consumers
validate MaxSequenceLength up front.)
-
Make the probe non-fatal, so a future ORT validation change cannot break generation again:
private static int ResolveVisionInputTokenCount(
IVisionGenerationRuntime runtime, string prompt, IVisionInputs inputs)
{
var fallback = runtime.CountPromptTokens(prompt);
try
{
using var probe = runtime.CreateProbeGenerator(probeMaxLength);
probe.SetInputs(inputs);
return ResolveInputTokenCount(name => { try { return probe.GetInputShape(name); } catch { return null; } }, fallback);
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Vision input token probe failed; falling back to prompt token count.");
return fallback;
}
}
Suggested regression test
An integration test that runs a real image prediction against Fara1.5-9B on CPU would have
caught this. A cheaper unit-level guard: assert that the value handed to CreateProbeGenerator
is <= context_length for a config stub declaring context_length: 32768.
Environment
ElBruno.LocalLLMs 0.20.11
Microsoft.ML.OnnxRuntimeGenAI 0.15.1 (CPU)
- .NET 10, Windows 11 x64
- Model:
Fara1.5-9B (auto-downloaded, context_length: 32768)
- Consumer: elbruno/ElBruno.MagenticUI
Related
Summary
In 0.20.11, every vision prediction that passes an image fails:
OnnxVisionModel.ResolveVisionInputTokenCountcreates a probe generator withmax_length = int.MaxValue. ONNX Runtime GenAI 0.15.x validatesmax_lengthagainst themodel's
context_lengthfromgenai_config.jsonand throws, so the probe added by the #44 fixaborts the request before generation starts.
This affects
Fara1.5-9B(declarescontext_length: 32768) and any model whose config declaresa
context_length.Evidence
Decompiled from
ElBruno.LocalLLMs0.20.11,ElBruno.LocalLLMs.Internal.OnnxVisionModel:CreateProbeGeneratoris not wrapped in atry/catch, so the exception propagates out ofGenerateWithImagesCore:Both
GenerateWithImagesCoreandGenerateWithImagesStreamingCoretake this path, soGetResponseAsyncandGetStreamingResponseAsyncare both broken.Note the real generation path is fine —
ResolveMaxLengthis correct:With
MaxSequenceLength = 4096,inputTokenCount ≈ 2900,MaxOutputTokens = 128it yields3028, comfortably undercontext_length. Only the probe usesint.MaxValue.Steps to reproduce
ElBruno.LocalLLMs0.20.11,KnownModels.Fara15_9B,ExecutionProvider.Auto(resolves to CPU).max_length (2147483647) cannot be greater than model context_length (32768)Reproduces with
MaxOutputTokensset or unset, and with anyMaxSequenceLength, because theprobe ignores both.
Expected
The input-token probe should never make a request the model can reject, and a probe failure
should never fail the user's request — it exists only to refine a token count that already has a
working fallback (
runtime.CountPromptTokens(prompt)).Suggested fix
Two independent changes; either one unblocks callers, and both together are ideal:
Clamp the probe length to the model's context length.
GenAIConfigParseralready parsesthe config, so the value is available via
Metadata:(If
ModelMetadatadoes not exposecontext_lengthyet, adding it would also help consumersvalidate
MaxSequenceLengthup front.)Make the probe non-fatal, so a future ORT validation change cannot break generation again:
Suggested regression test
An integration test that runs a real image prediction against
Fara1.5-9Bon CPU would havecaught this. A cheaper unit-level guard: assert that the value handed to
CreateProbeGeneratoris
<= context_lengthfor a config stub declaringcontext_length: 32768.Environment
ElBruno.LocalLLMs0.20.11Microsoft.ML.OnnxRuntimeGenAI0.15.1 (CPU)Fara1.5-9B(auto-downloaded,context_length: 32768)Related
AssemblyVersionmismatch in the same release)