Entropic 2.11.1
Local-first agentic inference engine
Loading...
Searching...
No Matches
response_parse.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
8#include "response_parse.h"
9
10#include "llama_cpp_backend.h"
11
13
14#include <nlohmann/json.hpp>
15
16#include <utility>
17
18static auto logger = entropic::log::get("inference.parse");
19
20namespace entropic {
21
31static std::vector<std::string> required_params(const std::string& tools_json,
32 const std::string& name,
33 bool& found) {
34 found = false;
35 std::vector<std::string> out;
36 auto tools = nlohmann::json::parse(tools_json, nullptr, false);
37 if (!tools.is_array()) { return out; }
38 for (const auto& t : tools) {
39 if (!t.is_object() || t.value("name", std::string{}) != name) {
40 continue;
41 }
42 found = true;
43 auto req = t.value("inputSchema", nlohmann::json::object())
44 .value("required", nlohmann::json::array());
45 for (const auto& r : req) {
46 if (r.is_string()) { out.push_back(r.get<std::string>()); }
47 }
48 break;
49 }
50 return out;
51}
52
65static bool has_all_required(const nlohmann::json& args,
66 const std::vector<std::string>& required,
67 const std::string& call_name) {
68 for (const auto& key : required) {
69 if (!args.contains(key)) {
70 logger->warn(
71 "Template parse of '{}' is missing required parameter '{}' — "
72 "common_chat's PEG autoparser extracts only the first "
73 "<parameter=>; falling back to the adapter parser.",
74 call_name, key);
75 return false;
76 }
77 }
78 return true;
79}
80
89static bool one_call_satisfies_schema(const ToolCall& call,
90 const std::string& tools_json) {
91 bool known = false;
92 auto required = required_params(tools_json, call.name, known);
93 // An unknown tool is not evidence of a truncated parse.
94 if (!known || required.empty()) { return true; }
95
96 auto args = nlohmann::json::parse(call.arguments_json, nullptr, false);
97 return args.is_object() && has_all_required(args, required, call.name);
98}
99
110bool calls_satisfy_schema(const std::vector<ToolCall>& calls,
111 const std::string& tools_json) {
112 if (calls.empty() || tools_json.empty()) { return true; }
113
114 for (const auto& call : calls) {
115 if (!one_call_satisfies_schema(call, tools_json)) { return false; }
116 }
117 return true;
118}
119
136static bool try_template_parse(LlamaCppBackend* llama, const std::string& raw,
137 ParsedModelResponse& out) {
138 if (llama == nullptr || !llama->common_chat_parse_reliable()) {
139 return false;
140 }
141 auto parsed = llama->parse_response(raw);
142 apply_action_envelope_recovery(parsed.tool_calls, raw); // gh#88
143 if (!calls_satisfy_schema(parsed.tool_calls, llama->active_tools_json())) {
144 return false;
145 }
146 out.content = std::move(parsed.content);
147 out.tool_calls = std::move(parsed.tool_calls);
148 out.used_template = true;
149 return true;
150}
151
173 ChatAdapter* adapter,
174 const std::string& raw) {
176
177 if (!try_template_parse(llama, raw, out)) {
178 if (adapter != nullptr) {
179 auto parsed = adapter->parse_tool_calls(raw);
180 out.content = std::move(parsed.cleaned_content);
181 out.tool_calls = std::move(parsed.tool_calls);
182 } else {
183 out.content = raw;
184 }
185 }
186
187 // Content cleanup ALWAYS runs the adapter's strip, on either branch.
188 // Idempotent: a no-op when the template already removed reasoning. This is
189 // what closes the gemma4 hole — before v2.10.3 the template branch was the
190 // only one that stripped channels, and it is unreachable without a tooled
191 // render.
192 if (adapter != nullptr) {
193 out.content = adapter->strip_think_blocks(out.content);
194 }
195 return out;
196}
197
198} // namespace entropic
Concrete base class for chat format adapters (80% logic).
std::string strip_think_blocks(const std::string &content) const
Strip this family's reasoning blocks from content (gh#108).
LlamaCppBackend — common llama.cpp patterns (15% layer).
bool common_chat_parse_reliable() const
True iff common_chat parsing is reliable for the last render (gh#87).
const std::string & active_tools_json() const
Return the tool definitions staged for the current turn.
CommonChatResult parse_response(const std::string &raw) const
Parse a raw model emission via the last captured render params.
LlamaCppBackend — llama.cpp C API integration.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Activate model on GPU (WARM → ACTIVE).
void apply_action_envelope_recovery(std::vector< ToolCall > &calls, const std::string &raw)
gh#88: substitute recovered bare-JSON calls when a reliable (PEG_GEMMA4 / gemma) parse produced none;...
static bool has_all_required(const nlohmann::json &args, const std::vector< std::string > &required, const std::string &call_name)
Verify every required key is present, warning on the first absent one.
bool calls_satisfy_schema(const std::vector< ToolCall > &calls, const std::string &tools_json)
Check that every call's declared required parameters are present.
static bool try_template_parse(LlamaCppBackend *llama, const std::string &raw, ParsedModelResponse &out)
Tool calls from the template parser, when trustworthy.
ParsedModelResponse parse_model_response(LlamaCppBackend *llama, ChatAdapter *adapter, const std::string &raw)
Parse a raw emission: template first, adapter second.
static bool one_call_satisfies_schema(const ToolCall &call, const std::string &tools_json)
Check one call's declared required parameters are all present.
static std::vector< std::string > required_params(const std::string &tools_json, const std::string &name, bool &found)
Required parameter names declared by a tool's inputSchema.
One template-first / adapter-second parse rule for raw model output.
Content and tool calls extracted from one raw emission.
bool used_template
True when common_chat produced the calls.
std::vector< ToolCall > tool_calls
Extracted calls.
std::string content
Reasoning-stripped content.
A tool call request parsed from model output.
Definition tool_call.h:31
std::string arguments_json
Original JSON string (for passthrough dispatch)
Definition tool_call.h:35
std::string name
Tool name (e.g. "filesystem.read_file")
Definition tool_call.h:33