OpenVINO S2.7 Parser Protocol Registry Log
Date: 2026-06-15
This log records the tool-call and reasoning parser work after S2 prefix reuse. The decision from this session is strict:
- no model-output regex fallback;
- no chat-template scraping as a parser contract;
- no Contenox-invented tool-call schema;
- tool-call parsing requires a model/profile-declared OpenVINO parser protocol;
- reasoning parsing uses the same registry and bridge as tool-call parsing.
Problem
OpenVINO GenAI already ships parser and structured-output primitives, including
Llama 3 tool parsers, reasoning parsers, Python VLLMParserWrapper, and XGrammar
structured-output support. The runtime must select those primitives by declared
protocol name instead of hardcoding how a specific model happens to emit tool
calls.
The local Qwen chat template says it emits:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
That is useful model text, but it is not a stable machine-readable parser API. The runtime no longer parses that with a local regex.
Step Log
1. Audited OpenVINO GenAI Parser Surface
Verified against local OpenVINO GenAI 2026.2.0.0 headers:
ov::genai::ParserReasoningParserDeepSeekR1ReasoningParserPhi4ReasoningParserLlama3PythonicToolParserLlama3JsonToolParserIncrementalParserReasoningIncrementalParserDeepSeekR1ReasoningIncrementalParserPhi4ReasoningIncrementalParser
Also confirmed VLLMParserWrapper exists in the Python binding, not the public
C++ parser header used by this Go/C++ session bridge.
VLLMParserWrapper Gotcha
VLLMParserWrapper does not mean OpenVINO embeds vLLM as an inference backend,
and it does not mean there is a native C++ parser class we can instantiate from
Go.
In OpenVINO GenAI src/python/py_parsers.cpp, VLLMParserWrapper is a Python
binding adapter:
- it accepts an already constructed Python parser object from
vllm.entrypoints.openai.tool_parsers.*or vLLM reasoning parser modules; - if that Python object has
extract_tool_calls, OpenVINO calls it; - if that Python object has
extract_reasoning, OpenVINO calls it; - OpenVINO converts the Python result back into
JsonContainer; - the wrapper is exported to Python as
openvino_genai.VLLMParserWrapper.
Operational consequences for Contenox:
- a native Go/C++ OpenVINO session cannot create
VLLMParserWrapperfrom only a protocol string; - using it requires a Python runtime, vLLM installed, a concrete vLLM parser object, tokenizer setup when that parser needs one, and GIL-managed calls;
openvino:vllm_parser_wrapperis therefore registered as an explicit profile name, but the current native bridge returns a clear error instead of pretending it can run;- supporting it for real means either adding a Python parser-object bridge, upstreaming/exposing a native C++ equivalent, or choosing a different native parser protocol for that model.
This is compatibility reuse of vLLM’s parser ecosystem, not a portable model-native parser contract by itself.
2. Added Profile Declarations
File:
runtime/modelrepo/openvino/profile.go
New strict profile fields:
{
"tool_calls": {"protocol": "openvino:llama3_json_tool_parser"},
"reasoning": {"protocol": "openvino:deepseek_r1_reasoning_parser"}
}
Validation now rejects unknown protocol names while loading
contenox-openvino.json. tool_calls.protocol accepts parser protocols only;
openvino:regex and other structured-output primitives are not accepted as
tool-call parsers.
3. Added Protocol Registry
File:
runtime/modelrepo/openvino/protocols.go
Registered tool parser protocols:
openvino:llama3_pythonic_tool_parseropenvino:llama3_json_tool_parseropenvino:vllm_parser_wrapper
Registered reasoning parser protocols:
openvino:reasoning_parseropenvino:deepseek_r1_reasoning_parseropenvino:phi4_reasoning_parseropenvino:reasoning_incremental_parseropenvino:deepseek_r1_reasoning_incremental_parseropenvino:phi4_reasoning_incremental_parseropenvino:vllm_parser_wrapper
Registered structured-output protocols at the ovsession generation layer:
openvino:json_schemaopenvino:regexopenvino:ebnfopenvino:qwen_xml_parametersopenvino:structural_tagopenvino:triggered_tagsopenvino:tags_with_separatoropenvino:concatopenvino:unionopenvino:const_stringopenvino:any_text
Structured output constrains generation; it does not by itself produce neutral
modelrepo.ToolCall values. Tool-call extraction still needs a parser protocol.
4. Removed Qwen Regex Parsing
File:
runtime/modelrepo/openvino/tools.go
Removed the local parseQwenToolCalls path. The only remaining tool handling in
this file is serialization of tool definitions into the model chat template’s
tools argument.
5. Wired Provider Chat Through Parser Protocols
File:
runtime/modelrepo/openvino/client.go
Chat now:
- serializes tool definitions for the model chat template;
- fails fast if tools are requested and the model profile does not declare
tool_calls.protocol; - passes declared tool and reasoning parser protocols into
ovsession.Generate; - decodes parser JSON into
Message.Content,Message.Thinking, andMessage.ToolCalls.
No parser protocol means no tool call extraction. There is no hidden fallback.
6. Extended The Native GenAI ABI
Files:
runtime/modelrepo/openvino/ovsession/genai.hruntime/modelrepo/openvino/ovsession/genai.goruntime/modelrepo/openvino/ovsession/genai_stub.goruntime/modelrepo/openvino/ovsession/genai.cpp
GenerateOptions now carries:
ParserProtocols []stringStructuredOutput {Protocol, Payload}
GenAIResult now carries:
- raw
Text - parsed
ParsedJSON Metrics
The C ABI now passes parser protocol names and an output buffer for parsed JSON.
7. Implemented C++ Parser Bridge
File:
runtime/modelrepo/openvino/ovsession/genai.cpp
The bridge instantiates complete-output OpenVINO parser classes before generation:
openvino:llama3_pythonic_tool_parser->ov::genai::Llama3PythonicToolParseropenvino:llama3_json_tool_parser->ov::genai::Llama3JsonToolParseropenvino:reasoning_parser->ov::genai::ReasoningParseropenvino:deepseek_r1_reasoning_parser->ov::genai::DeepSeekR1ReasoningParseropenvino:phi4_reasoning_parser->ov::genai::Phi4ReasoningParser
Explicit non-support cases:
openvino:vllm_parser_wrapperreturns a clear native-bridge error because OpenVINO exposes it in Python, not in the C++ header used here.- Incremental reasoning parser protocols return a clear non-stream-chat error because they require the streaming parser bridge.
The complete-output parsers run on a JsonContainer seeded with content and
return the resulting JSON separately from raw generated text.
8. Added Structured-Output Bridge
File:
runtime/modelrepo/openvino/ovsession/genai.cpp
The lower session API can now apply OpenVINO structured-output primitives:
- JSON Schema
- Regex
- EBNF
- Qwen XML parameters format
- structural tag JSON
- triggered tags
- tags with separator
- concat
- union
- const string
- any text
This is generation control, not a tool-call parser. The runtime keeps that boundary explicit.
9. Normalized Parser Output
File:
runtime/modelrepo/openvino/protocols.go
decodeParsedGeneration normalizes parser JSON into runtime messages:
content-> assistant visible textreasoning_contentorreasoning->Message.Thinking- direct tool calls:
{"name": "...", "arguments": {...}} - wrapped tool calls:
{"type":"function","function":{"name":"...","arguments":{...}}}
This normalization operates on OpenVINO parser output, not raw model text.
10. Added Tests
Files:
runtime/modelrepo/openvino/tools_test.goruntime/modelrepo/openvino/profile_test.go
Coverage added:
- strict profile loading with
tool_callsandreasoningprotocol fields; - rejection of
openvino:regexastool_calls.protocol; - parser-output normalization for direct tool calls;
- parser-output normalization for wrapped tool calls;
- reasoning output normalization.
Verification
Default build:
go test ./runtime/modelrepo/openvino/...
Result:
ok github.com/contenox/runtime/runtime/modelrepo/openvino
? github.com/contenox/runtime/runtime/modelrepo/openvino/ovsession [no test files]
Full OpenVINO GenAI build:
make -f Makefile.openvino test-s1-5
Result:
ok github.com/contenox/runtime/runtime/modelrepo/openvino 30.609s
ok github.com/contenox/runtime/runtime/modelrepo/openvino/ovsession 157.973s
Post-cleanup native compile check:
make -f Makefile.openvino test-s1
Result:
--- PASS: TestSystem_OpenVINOGenAI_SchedulerControlsReachable
PASS
Current State
Done:
- profile-declared tool parser protocol slot;
- profile-declared reasoning parser protocol slot;
- shared registry pattern for tool and reasoning parser names;
- native C++ bridge for complete-output OpenVINO parser classes;
- native stream bridge for incremental reasoning parser classes, carrying
reasoning_contentasStreamParcel.Thinking; - native structured-output bridge at the generation layer;
- removal of local Qwen regex tool parsing;
- parser-output normalization into
modelrepo.Message.
Still open:
- C++ native support for
VLLMParserWrapper, unless OpenVINO exposes it outside Python or this runtime adds a Python parser-object bridge; - a model profile for each actual model family that declares the correct parser protocol;
- a real Qwen tool-call parser primitive from OpenVINO or an explicit model-profile parser adapter. Until then, the Qwen template text is rendered for the model, but the runtime will not guess a parser for it.