Conversation
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
… forms The Qwen tool-call parser accepted only the original <tool_call> / <function=NAME> / <parameter=NAME> markup. Claude Code and other agent harnesses emit the same call in XML forms the parser did not recognise, so those responses fell back to plain text and the harness never saw a tool call: <tool_call><function name="X"><parameter name="d">v</parameter></function></tool_call> <function_calls><invoke name="X"><parameter name="d">v</parameter></invoke></function_calls> <invoke name="X"><param name="d">v</param></invoke> Names are now read from the tag header, accepting either the original =NAME form or a name= attribute, with attribute-token boundaries so an unrelated filename= attribute cannot satisfy the name lookup, and with quote stripping. Opening and closing forms must match, so a <function ...> closed by </invoke> is a structural failure rather than a silent misparse. A <function_calls> container accepts several children, and ordinary assistant text before the call is preserved as content. The streaming decoder tracked only a <tool_call> prefix; it now buffers any partial marker from the full marker set, so every variant is detected incrementally instead of leaking into visible content. Parameter value nesting is counted against the matching close tag, so a nested <param ...> inside a string value no longer truncates the value. Taken from upstream PR Neroued#300 (tool-call parsing), by pkochubey, resolving upstream issue Neroued#276. The PR rejects a repeated parameter with conflicting values; this fork keeps the last value instead, per the local rule merged with PR Neroued#299, so the duplicate branch writes the last value and counts the repair in duplicate_parameters_repaired as before. Verification: ninfer_tool_call_parser_test passes, including the new function-name-attribute, invoke, function_calls container, standalone-invoke, attribute-boundary, mismatched-closing-tag and Plan+TaskCreate reproduction cases.
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
The chat-completions validator refused every response_format but
{"type":"text"} with response_format_not_supported. Clients that always send a
format - Hermes-style harnesses among them - were therefore refused before the
request reached the Engine, even though the field only ever asked for a shape
the sampler was free to attempt.
The validator now accepts text, json_object and json_schema, and rejects only
an unknown type string.
Nothing else consumes response_format: there is still no constrained decoding,
so the requested shape is not enforced. docs/serving.md now says that on the
supported-options line instead of implying the schema is honoured, and keeps
`strict:true` and the grammar/structured_outputs/guided_* extensions in the
rejected list, where an unenforceable promise would be a real defect.
Taken from upstream PR Neroued#300, by pkochubey.
Verification: ninfer_openai_schema_test passes, with the rejection case moved
from json_schema to an unknown type and the neutral-request case switched to
json_object.
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
A response cut short by the output limit or by context capacity still carries whatever tool call the model had emitted, and both adapters checked the tool call first. A client that trusts the terminal reason therefore saw "tool_calls" / "tool_use" and acted on a call whose arguments may be incomplete. The truncation reasons now win: chat completions -> "length" Messages -> "max_tokens" / "model_context_window_exceeded" The Anthropic adapter's switch keeps its OutputLimit and ContextCapacity cases so it still covers every FinishReason; the early returns sit above them and above the tool-call check. Streaming still delivers the partial tool-call delta, but the terminal chunk carries the truncation reason instead of claiming the call completed. Taken from upstream PR Neroued#300, by pkochubey. Verification: ninfer_openai_schema_test and ninfer_anthropic_schema_test pass. Their tool-call presentation cases terminate on StopToken, so they still report "tool_calls" / "tool_use", and the empty-output ContextCapacity case still reports "model_context_window_exceeded".
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
Anthropic Messages already treated a request whose final message is an
assistant turn as an assistant prefill, but only when that turn was text-only
with thinking off. Chat Completions had no prefill mode at all, so an agent
client holding an output-limited partial assistant turn could not hand it back
and have the Engine continue it in place.
* chat completions now select ContinueFinalAssistant when the final message
is an assistant message, matching Messages;
* the Anthropic "a final assistant prefill must contain only text" rejection
is gone;
* the "assistant prefill cannot be combined with enabled thinking" capability
rejection is gone, so the template's own guard becomes the authority and
the request is refused later as invalid_prompt;
* the chat template accepts a final assistant turn carrying reasoning content
or tool calls - an output-limited turn can carry either - while still
refusing media and thinking-enabled prefill.
The thinking guard is deliberately kept, unlike the upstream PR. Removing it
lets render_chat() build an ambiguous reasoning opener, which
test_assistant_continuation pins with "assistant continuation accepted an
ambiguous Thinking opener"; the PR ran no CI and did not catch this.
Continuability is otherwise still decided against the rendered layout: the
template must expose that message's content region unambiguously and throws
otherwise, so a final turn the template cannot continue fails loudly instead of
rendering a wrong prompt.
This is not the suspended-generation design from upstream issue Neroued#172 - the
request is a normal new request that may reuse existing
context-cache/continuation state.
Taken from upstream PR Neroued#300, by pkochubey.
Verification: ninfer_qwen3_5_frontend_test, ninfer_tool_call_parser_test,
ninfer_openai_schema_test, ninfer_anthropic_schema_test,
ninfer_resource_manager_test, ninfer_http_transport_test,
ninfer_request_log_test and ninfer_serve_options_test all pass. The OpenAI
suite's new case asserts [system,user,assistant,user] stays NewAssistantTurn
while [system,user,assistant] selects ContinueFinalAssistant and reaches the
PromptInput options; the Anthropic suite's thinking-on prefill case now expects
acceptance at capability resolution, while the frontend suite's ambiguous
Thinking-opener case still expects a throw.
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
The portfolio valuation credited an owner for retaining every catalogued checkpoint it held, including checkpoints whose shortlist frontier the incoming request cannot reach. Those are not hits the request can take, so the planner priced recovery loss for reuse that could never happen, biasing retention decisions toward whichever owners happened to hold unreachable state. Checkpoints now carry an `unreachable` flag, set where the policy is built by comparing the request's own shortlist key at that frontier against the checkpoint's key: reachable -> an incoming key exists at the frontier and matches unreachable -> no incoming key at that frontier, or a different key The portfolio value skips unreachable checkpoints, so they contribute no recovery saving and no owner is credited for them. The capture-time policies, which describe state the request is about to create rather than state it might hit, are marked reachable. Taken from upstream PR Neroued#300, by pkochubey, resolving upstream issue Neroued#178. Verification: ninfer_resource_manager_test passes. Only the PR's unreachable-checkpoint half is taken here; its separate publication-order eviction tie-break and its broader victim-enumeration gate are not, because this fork already answers upstream issue Neroued#251 with its own automatic shared-prefix catalog reclaim.
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 22, 2026
…calls Ported from the gzenz/ninfer fork by David Oelfke (gzenz), September 2026: commit b2267e0 adds the flag and recovers complete calls with malformed wrapper or suffix output, commit 0ce6e3f recovers a single truncated final call when closing tags are cut off at region end, commit 0f3c9f5 recovers the function name when the closing bracket is omitted before a parameter tag, commit 3870983 keeps a value cut by the output budget and requires at least one complete parameter for a truncated final call (with the operational Info record guarded on kept calls), and commit 44f2c9c keeps complete calls with undeclared tool names. gzenz's implementation sits on a divergent canonical parser, so the recovery logic is ported onto this fork's multi-marker parser, preserving PR Neroued#300 marker recognition and PR Neroued#299 last-value-wins duplicate handling. Tolerant mode keeps a good call when a trailing suffix or a malformed second call follows it (truncated_tail diagnostic, logged at Info), keeps a single final call cut at the region end with its partial value, recovers a missing closing bracket after the function name by an identifier-run scan, and keeps undeclared tool names structured. A truncated tail that keeps no call is returned as text with the reason recorded. The strict parser is unchanged and remains the default. Tests cover the tolerant paths; README and docs/serving.md credit the source.
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 24, 2026
…n its own lineage eb5396b (the unreachable-checkpoint half of upstream PR Neroued#300) marked every checkpoint the incoming request could not reach as `unreachable`, and `ContextPortfolioValue::fold` skipped those entirely: no demand value, no private transition loss, no explicit shared credit. So every other conversation's prefix, and every shared prefix a request did not start with, was worth nothing to that request's planner. Any path that could evict one did so for free. On the GPU this is what let the rescue probe and the ladder wipe automatic shared prefixes after one unrelated request, and it was a large part of why shared-saturation-reclaim and shared-replacement failed. Issue Neroued#178 asked for something narrower: a checkpoint is dead once the same lineage has moved past it, i.e. the conversation's next prompt diverges from the checkpoint's prefix at its frontier. `lineage_diverged` now marks a private checkpoint unreachable only when the incoming request carries the same session key as the owner and its prompt has a different shortlist key at that frontier. A shorter prompt that does not reach the frontier is not proof, and neither is a keyless request. Shared prefixes are never marked; they serve many lineages. Demand from the current request was already absent for unreachable keys, so nothing else is double-counted. Applied at all three places policies are built: materialization pressure (private and shared), and the projected portfolio in shared-capture selection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jo3VN3VZQy3pm5QVfbcjfu
Wallawalla47
pushed a commit
to Wallawalla47/ninfer-custom
that referenced
this pull request
Sep 24, 2026
…fix caching The Local changes section now opens with Prefix caching, rewritten as a high-level summary of everything the fork changes against upstream NInfer: the leased Device KV, demote-before-destroy, the recency-ordered ladder with sparing (and its top-rung, keep-in-place, rescue and defer-on-seal-failure behaviour), lineage-scoped checkpoint valuation, the single `--host-cache-mib` budget, engine-automatic long anchors with geometric spacing and least-coverage replacement, salvaged prefills, and shared-capture seal safety. The two items implemented from other people's issues (Neroued#229 cost-scaled search budget, Neroued#251 shared-catalog reclaim) are kept and credited as before. The replay measurement is kept and labelled as predating the later fixes, alongside the engine-real scenario results. The merged PR Neroued#300 unreachable-checkpoint entry notes that the fork later narrowed it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jo3VN3VZQy3pm5QVfbcjfu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sorry for my sheet in PR and all this mess, I check Issues in project and fixed some issues, what related for me nvfp4+dflash2+agent coding long context+hermes.
Bellow AI bullshit-summary by PR:
Problem and scope
Related Issues:
max_shared_prefixes) is smaller than one request's own candidate ceiling, silently killing prefix-cache hits at low concurrency #270 — shared-prefix catalog capacity too small for one request's candidate setThis PR fixes several context-cache, long-context CUDA, NVFP4 and tool-calling edge cases that showed up in long-running agent workloads with Qwen models.
The main user-visible problems were:
The PR does not implement the suspended-generation capability proposed in #172. Assistant continuation remains a new request that can reuse the existing context-cache/private-continuation state rather than an opaque resumable generation handle.
Implementation
Context-cache planning and retention
Private continuation entries now carry their
publication_orderthrough the materialization policy and planning cost.When the private continuation catalog is full and an eviction is required, the planner can select the oldest eligible publication instead of failing to make progress.
publication_orderis also included in pressure-target ordering so replacement decisions remain deterministic when higher-priority retention metrics are equal.Unreachable checkpoints are explicitly represented in the checkpoint policy and excluded from portfolio recovery-loss accounting.
Shared-capture planning can explore replacement targets when the requested materialization is physically infeasible, even when the previous pressure-evidence condition is absent.
The default shared-prefix capacity is increased to cover the maximum prepared-prompt candidate count produced by one request, preventing candidate discovery from exhausting the catalog immediately.
Long-context small-T attention
The special quantized attention path that forced the maximum split count for
tokens == 1at large windows was removed.Quantized attention now uses the normal split calculation, including the page-count-derived lower bound.
Page staging computes the actual required page count and asserts that it fits the compile-time
PageIdscapacity instead of silently truncating the page range.This keeps split geometry and paged-KV staging consistent for long-context decode.
Ragged NVFP4 fused SwiGLU
The NVFP4 A4 fused SwiGLU TMA path now supports ragged token counts rather than requiring exact tile multiples.
Workspace/TMA scheduling uses the padded execution extent while output stores remain guarded by the real token count.
This allows the fused path to be used for arbitrary M values without writing the padded tail.
Tool-call parsing
The Qwen tool-call parser is extended to recognize the XML forms observed from Claude Code and other agent harnesses, including:
Tool and parameter names can be supplied either by the original
=<name>representation or through aname=attribute.Attribute parsing uses token boundaries so unrelated attributes such as
filename=do not satisfy thenamelookup.Opening and closing XML forms must match (
function/function,invoke/invoke,parameter/parameter,param/param).Tool output may contain normal assistant text before the structured call; that prefix is preserved as assistant content.
Repeated parameters with the same name and the same value are coalesced. Repeated parameters with conflicting values still fail with
DuplicateParameter.Declared tool names and parameter schemas continue to be enforced after the XML representation has been normalized.
Assistant continuation / prefill
OpenAI Chat Completions and Anthropic Messages now treat a request whose final message is an assistant message as:
The chat template sets
continue_final_messageand does not add a new assistant generation prompt.This enables agent clients to send an output-limited partial assistant response back to NInfer and continue the same assistant turn.
The request still goes through normal admission/planning. Existing private continuation/context-cache state can be reused when the token prefix matches; this is not the suspended-generation/resume-capability design proposed in #172.
Verification
Regression coverage was added or expanded for the affected components.
Context cache
Added coverage for private continuation saturation to verify that, with a full private catalog, the older
publication_orderis selected for eviction.Added a continuous shared-catalog turnover regression for #251 to exercise repeated capture/replacement cycles instead of testing only a single planning operation.
The planner tests also cover the updated unreachable-checkpoint and replacement behavior.
NVFP4 SwiGLU
The NVFP4 A4 correctness matrix now includes ragged and tile-boundary values including:
These cases exercise both sides of the relevant 128/256/512/1024 tile boundaries and compare the fused implementation with the existing mathematical oracle.
Tool-call parser
Regression tests cover:
function name="..."syntax;invokesyntax;function_callscontainers;<param>and<parameter>forms;TaskCreateagent-response reproduction.Assistant continuation
Schema tests verify that:
remains a normal
NewAssistantTurn, while:selects
ContinueFinalAssistant, and that this mode reaches the finalPromptInput.Commands
A full verification run should include the normal project test suite:
For the CUDA changes, the affected long-context attention and NVFP4 SwiGLU tests should additionally be run under CUDA Compute Sanitizer, in particular
memcheckandsynccheck.At the time of this report, the branch HEAD has no published GitHub CI/status checks, so a clean full build, complete registered test run and sanitizer run are not claimed by this PR description unless attached separately.
The following remain outside the scope of this change:
OutputLimit;