17#include <nlohmann/json.hpp>
55static std::vector<Message>
parse_msgs(
const char* json_str) {
56 std::vector<Message> msgs;
57 if (!json_str) {
return msgs; }
58 auto arr = nlohmann::json::parse(json_str,
nullptr,
false);
59 if (!arr.is_array()) {
return msgs; }
60 for (
const auto& obj : arr) {
62 m.
role = obj.value(
"role",
"");
63 m.
content = obj.value(
"content",
"");
64 msgs.push_back(std::move(m));
79 const char* key, T& dst) {
80 if (j.contains(key)) { dst = j[key].get<T>(); }
92 const nlohmann::json& j,
93 std::unordered_map<int32_t, float>& dst)
95 if (!j.contains(
"logit_bias") || !j[
"logit_bias"].is_object()) {
98 for (
auto it = j[
"logit_bias"].begin(); it != j[
"logit_bias"].end(); ++it) {
100 dst[std::stoi(it.key())] = it.value().get<
float>();
101 }
catch (
const std::exception&) {
116 if (!json_str) {
return p; }
117 auto j = nlohmann::json::parse(json_str,
nullptr,
false);
118 if (!j.is_object()) {
return p; }
144 const std::string& default_tier) {
145 if (!json_str) {
return default_tier; }
146 auto j = nlohmann::json::parse(json_str,
nullptr,
false);
147 if (j.is_object() && j.contains(
"tier")) {
148 return j[
"tier"].get<std::string>();
160static char*
dup(
const std::string& s) {
161 return strdup(s.c_str());
172 const char* params_json,
178 auto tier =
extract_tier(params_json, ctx->default_tier);
179 auto result = ctx->orchestrator->generate(
180 messages, params, tier);
181 auto& out = result.raw_content.empty()
182 ? result.content : result.raw_content;
183 *result_json =
dup(out);
203 const char* msgs_json,
const char* params_json,
204 void (*on_token)(
const char*,
size_t,
void*),
205 void* token_ud,
int* cancel,
void* user_data) {
209 std::atomic<bool> cancel_flag(
false);
210 auto cb = [on_token, token_ud, cancel, &cancel_flag]
211 (std::string_view tok) {
212 on_token(tok.data(), tok.size(), token_ud);
213 if (cancel !=
nullptr && *cancel != 0) {
214 cancel_flag.store(
true, std::memory_order_release);
217 auto tier =
extract_tier(params_json, ctx->default_tier);
218 ctx->orchestrator->generate_streaming(
219 messages, params, cb, cancel_flag, tier);
235 const char* msgs_json,
const char* params_json,
236 char** result_json,
int* cancel,
void* user_data) {
240 auto tier =
extract_tier(params_json, ctx->default_tier);
242 std::atomic<bool> cancel_flag(
false);
243 std::atomic<bool> done(
false);
245 if (cancel !=
nullptr) {
246 poller = std::thread([cancel, &cancel_flag, &done]() {
247 while (!done.load(std::memory_order_acquire)) {
249 cancel_flag.store(true, std::memory_order_release);
252 std::this_thread::sleep_for(
253 std::chrono::milliseconds(10));
258 auto result = ctx->orchestrator->generate(
259 messages, params, cancel_flag, tier);
261 done.store(
true, std::memory_order_release);
262 if (poller.joinable()) { poller.join(); }
264 auto& out = result.raw_content.empty()
265 ? result.content : result.raw_content;
266 *result_json =
dup(out);
276 char** result_json,
void* user_data) {
279 auto tier = ctx->orchestrator->route(messages);
280 *result_json =
dup(tier);
290 const char* params_json,
291 char** result_json,
void* user_data) {
293 auto tier =
extract_tier(params_json, ctx->default_tier);
299 auto result = ctx->orchestrator->generate(
300 {msg}, params, tier);
301 *result_json =
dup(result.content);
319 char** tool_calls_json,
322 std::string raw_str = raw ? raw :
"";
324 auto tier = ctx->orchestrator->last_used_tier();
325 if (tier.empty()) { tier = ctx->default_tier; }
327 ctx->orchestrator->get_backend(tier));
329 if (llama !=
nullptr && llama->common_chat_parse_reliable()) {
332 *cleaned =
dup(parsed.content);
340 auto* adapter = ctx->orchestrator->get_adapter(tier);
341 if (adapter ==
nullptr) {
342 *cleaned =
dup(raw_str);
343 *tool_calls_json =
dup(
"[]");
346 auto parsed = adapter->parse_tool_calls(raw_str);
347 *cleaned =
dup(parsed.cleaned_content);
358 const char* tool_calls_json,
360 if (!tool_calls_json) {
return 1; }
361 auto tc = nlohmann::json::parse(tool_calls_json,
nullptr,
false);
362 return (tc.is_array() && !tc.empty()) ? 0 : 1;
377 const std::string& default_tier,
380 if (out_context) { *out_context = ctx; }
382 InferenceInterface iface;
390 iface.free_fn = free;
391 iface.backend_data = ctx;
392 iface.orchestrator_data = ctx;
393 iface.adapter_data = ctx;
ChatAdapter concrete base class.
LlamaCppBackend — common llama.cpp patterns (15% layer).
CommonChatResult parse_response(const std::string &raw) const
Parse a raw model emission via the last captured render params.
Multi-model lifecycle and routing orchestrator.
Configuration structs with defaults.
Factory for building InferenceInterface from a ModelOrchestrator.
LlamaCppBackend — llama.cpp C API integration.
Message struct for conversation history.
Activate model on GPU (WARM → ACTIVE).
static void assign_if_present(const nlohmann::json &j, const char *key, T &dst)
Conditionally assign a typed JSON field into a destination.
static int iface_generate_with_cancel(const char *msgs_json, const char *params_json, char **result_json, int *cancel, void *user_data)
Batch generate with cancel via orchestrator (gh#81, v2.4.2).
static int iface_parse_tool_calls(const char *raw, char **cleaned, char **tool_calls_json, void *user_data)
Parse tool calls from raw model output (gh#87 3b).
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;...
std::string serialize_tool_calls(const std::vector< ToolCall > &calls)
Serialize parsed tool calls to the C-ABI JSON array form.
static std::vector< Message > parse_msgs(const char *json_str)
Parse JSON message array into Message vector.
static GenerationParams parse_params(const char *json_str)
Parse generation params from JSON string.
static int iface_is_complete(const char *, const char *tool_calls_json, void *)
Check if response is complete (no pending tool calls).
static int iface_generate(const char *msgs_json, const char *params_json, char **result_json, void *user_data)
Generate via orchestrator.
static void parse_logit_bias_into(const nlohmann::json &j, std::unordered_map< int32_t, float > &dst)
Populate logit_bias map from a JSON object of token→bias.
static int iface_route(const char *msgs_json, char **result_json, void *user_data)
Route messages to tier via orchestrator.
static std::string extract_tier(const char *json_str, const std::string &default_tier)
Extract tier name from params JSON, falling back to default.
void destroy_orchestrator_interface(InterfaceContext *context)
Free a context returned by build_orchestrator_interface().
static int iface_generate_stream(const char *msgs_json, const char *params_json, void(*on_token)(const char *, size_t, void *), void *token_ud, int *cancel, void *user_data)
Streaming generate via orchestrator.
static int iface_complete(const char *prompt, const char *params_json, char **result_json, void *user_data)
Raw text completion via orchestrator.
static char * dup(const std::string &s)
Heap-allocate a C string copy.
InferenceInterface build_orchestrator_interface(ModelOrchestrator *orchestrator, const std::string &default_tier, InterfaceContext **out_context)
Build an InferenceInterface wired to an orchestrator.
ModelOrchestrator — multi-model lifecycle and routing.
Generation parameters for a single inference call.
std::unordered_map< int32_t, float > logit_bias
Per-token logit bias map (gh#23 MVP item 4).
float repeat_penalty
Repetition penalty.
std::string tools
Active tool definitions for this turn, as an MCP tool-list JSON array ([{name, description,...
float temperature
Sampling temperature.
std::string grammar_key
Grammar registry key.
float frequency_penalty
Frequency-penalty term in llama.cpp's penalties sampler (gh#23 MVP item 3).
float presence_penalty
Presence-penalty term in llama.cpp's penalties sampler (gh#23 MVP item 2).
bool enable_thinking
Enable <think> blocks (false if reasoning_budget == 0)
float min_p
Min-p nucleus sampling threshold (gh#23 MVP item 1).
int max_tokens
Maximum tokens to generate.
float top_p
Nucleus sampling threshold.
int seed
RNG seed for reproducible sampling.
Holds orchestrator + tier for C callback user_data.
ModelOrchestrator * orchestrator
Orchestrator pointer.
std::string default_tier
Default tier name.
A message in a conversation.
std::string content
Message text content (always populated)
std::string role
Message role.