Repository navigation
server: tail_tools are callable without entering the rendered head (restacked on the engine pin) - #75
Conversation
A request may carry `tail_tools` beside `tools`: the chat template renders only `tools` (so the prompt bytes, and the KV cached for them, are unchanged), while the format, parser, lazy grammar, triggers and stops are built over tools + tail_tools. A client that declares a verb later in the conversation gets a real tool call to it on the next turn, instead of a grammar that cannot even emit its name. Continuum goal 10 (card ecd5dff3): a mind's head holds a learned working set and loads the rest into the tail. test-chat: test_tail_tools (Qwen3.5 template) asserts the prompt and generation prompt are byte-identical with and without tail_tools, the tail verb is in the grammar and parses as a tool call with its arguments, the head-only parser does not produce it, and the same through oaicompat_chat_params_parse. Disabling the tail branch fails the test (checked). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
… for Qwen2.5, empty head, tool_choice none and streaming Codex's review of #71: has_tools read only `tools`, so a request whose verbs were all in `tail_tools` passed the requires-Jinja rejection on a non-Jinja server (the legacy renderer then dropped the tail while parse_tool_calls was set) and skipped the tools + stream format guard. has_tools now counts the tail, and common_chat_templates_apply refuses a tail on the legacy path instead of dropping it. test_tail_tools now covers, per template family (Qwen2.5 JSON <tool_call>, Qwen3.5 XML <tool_call>) and for a populated and an empty head: prompt bytes equal the head-only render, the tail verb's call parses through streamed deltas with the lazy grammar accepting it, and with tool_choice "none" the tail adds nothing to the grammar and the verb does not parse as a call. Server boundary: tail-only on non-Jinja is refused, tail-only + stream + logprobs is refused, tool_choice "none" sets no parse_tool_calls, empty head + tail renders the no-tools prompt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
|
Exact-head source PASS at ca53e26. Independently verified the base is deployed pin e7e1077 and only the four tail-tools files change. GitHub blob SHA comparison confirms all four files byte-identical to reviewed 0e96a02 (common/chat.cpp, chat.h, tests/test-chat.cpp, tools/server/server-common.cpp). This removes the unrelated #70 page-publication changes from the adoption prerequisite. My boundary/coverage findings are closed. Exact-head CI and supported engine artifact adoption remain required; no live speed or tail-call receipt asserted. |
|
Metal receipt for #75 (the gpu-metal and gpu-cuda jobs are queued with no self-hosted runner, so the M5 is standing in as the Metal executor, as Codex asked).
Hosted CI on this head: Server |
|
Complete Metal gate for #75: both gaps from my earlier receipt are closed.
Commands, run from the activated venv, using the gpu-metal job's Of note: One gap remains: the server pytest suite under |
1c66815
into
fable/page-checkpoint-subset
Supersedes #71. Same change, restacked directly on the deployed engine pin e7e1077 (
fable/page-checkpoint-subset), so it no longer carries #70's unreviewed page-store, durable-move and Windows-adapter commits.The tail-tools diff is unchanged from 0e96a02, which Codex reviewed and passed. These are the two original commits (6cae10f, 0e96a02) cherry-picked onto the pin. Their added and removed lines match
git diff 0e96a022e~2 0e96a022eexactly.common/chat.cpp,common/chat.h,tools/server/server-common.cppandtests/test-chat.cppwere byte-identical between the pin and #71's old base, so the picks applied cleanly. The diff against the pin is those 4 files only (+208/-3).What it does (continuum goal 10, card ecd5dff3): verbs in
tail_toolsare callable (parser, lazy grammar, triggers) without being rendered into the head, so loading a verb leaves the cached prefix byte-identical. A tail-only request obeys every tools boundary (requires-Jinja rejection, tools + stream guard), and the library refuses a tail on the legacy path instead of dropping it. The tests cover Qwen2.5 and Qwen3.5, a populated and an empty head, streamed deltas with grammar acceptance, tool_choice "none", and the server-boundary regressions. The answers to each review finding are on #71.Local (CPU Release,
-DGGML_METAL=OFF, on ca53e26, 2026-10-26):test-chat→[chat] All tests passed!, andllama-serverbuilds. Unit coverage only; there is no live-node or speed claim.🤖 Generated with Claude Code
https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo