peerllm-host-cli 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,387 @@
1
+ // src/core/openai-tools.ts
2
+ //
3
+ // 🔧 OpenAI tool-calling ⇄ node-llama-cpp translation — the PURE mapping layer.
4
+ // No I/O, no model, no HTTP: just the wire-format conversion, so it is unit-tested
5
+ // as a table the way hybrid-router is.
6
+ //
7
+ // Two directions:
8
+ // IN OpenAI `tools[]` + `messages[]` → ChatModelFunctions + ChatHistoryItem[]
9
+ // OUT LlamaChat `functionCalls[]` → OpenAI `tool_calls[]`
10
+ //
11
+ // WHY THIS EXISTS AT ALL: until now the local REST server flattened `messages` into
12
+ // "role: content" prose and dropped `tools` on the floor — a silent HTTP 200 with the
13
+ // tool schema never reaching the prompt (reported 2026-08-18). Both halves are fixed
14
+ // here: real chat history through the model's own template, and real tool schemas.
15
+ //
16
+ // The two places node-llama-cpp's schema dialect diverges from OpenAI's, and what we
17
+ // do about each:
18
+ //
19
+ // 1. `required` is IGNORED by node-llama-cpp — every key in `properties` is forced
20
+ // (see GbnfJsonObjectSchema's deprecated `required`). Emitting a tool call that
21
+ // fills in optional parameters the caller never asked for is exactly the class of
22
+ // quiet wrongness this fix is about, so we encode optionality the only way the
23
+ // grammar can express it: an optional property becomes `oneOf: [<schema>, null]`,
24
+ // and the null is pruned back out of the arguments on the way to the client.
25
+ // 2. `allOf` / `not` have no sound grammar translation. We REJECT them (400) rather
26
+ // than dropping them — a silently relaxed constraint is how we got here.
27
+ //
28
+ // `anyOf` maps to `oneOf`: any value the oneOf grammar can generate validates against
29
+ // the corresponding anyOf, so the approximation is sound in the generation direction.
30
+ // ---------------------------------------------------------------------------
31
+ // Schema conversion
32
+ // ---------------------------------------------------------------------------
33
+ const SCALAR_TYPES = new Set(["string", "number", "integer", "boolean", "null"]);
34
+ /** Does this schema already admit `null`, so wrapping it for optionality is redundant? */
35
+ function admitsNull(schema) {
36
+ if (schema.const === null)
37
+ return true;
38
+ if (Array.isArray(schema.type))
39
+ return schema.type.includes("null");
40
+ if (schema.type === "null")
41
+ return true;
42
+ if (Array.isArray(schema.enum) && schema.enum.includes(null))
43
+ return true;
44
+ const branches = schema.oneOf ?? schema.anyOf;
45
+ if (Array.isArray(branches))
46
+ return branches.some((b) => b && admitsNull(b));
47
+ return false;
48
+ }
49
+ /**
50
+ * Convert one OpenAI/JSON-Schema node into node-llama-cpp's GBNF-JSON dialect.
51
+ * Unsupported *structural* keywords are collected into `errors` (→ 400); purely
52
+ * advisory ones we cannot enforce (`pattern`, `format`, …) are dropped, which only
53
+ * relaxes generation and never produces a wrong tool call.
54
+ */
55
+ function convertSchema(schema, path, errors) {
56
+ if (schema == null || typeof schema !== "object") {
57
+ errors.push({ path, message: "schema node must be an object" });
58
+ return { type: "string" };
59
+ }
60
+ if (schema.allOf !== undefined) {
61
+ errors.push({ path, message: "`allOf` is not supported by the local tool-calling grammar" });
62
+ }
63
+ if (schema.not !== undefined) {
64
+ errors.push({ path, message: "`not` is not supported by the local tool-calling grammar" });
65
+ }
66
+ // $ref/$defs pass through — node-llama-cpp resolves them itself. `definitions` is the
67
+ // draft-07 spelling; normalize it so older tool definitions keep working.
68
+ const out = {};
69
+ if (schema.description !== undefined)
70
+ out.description = schema.description;
71
+ if (schema.$ref !== undefined)
72
+ out.$ref = schema.$ref;
73
+ const defs = schema.$defs ?? schema.definitions;
74
+ if (defs !== undefined) {
75
+ const converted = {};
76
+ for (const [name, def] of Object.entries(defs)) {
77
+ converted[name] = convertSchema(def, `${path}.$defs.${name}`, errors);
78
+ }
79
+ out.$defs = converted;
80
+ }
81
+ if (schema.const !== undefined) {
82
+ out.const = schema.const;
83
+ return out;
84
+ }
85
+ if (schema.enum !== undefined) {
86
+ if (!Array.isArray(schema.enum) || schema.enum.length === 0) {
87
+ errors.push({ path, message: "`enum` must be a non-empty array" });
88
+ }
89
+ else {
90
+ out.enum = schema.enum;
91
+ }
92
+ return out;
93
+ }
94
+ const branches = schema.oneOf ?? schema.anyOf;
95
+ if (branches !== undefined) {
96
+ if (!Array.isArray(branches) || branches.length === 0) {
97
+ errors.push({ path, message: "`oneOf`/`anyOf` must be a non-empty array" });
98
+ }
99
+ else {
100
+ const key = schema.oneOf ? "oneOf" : "anyOf";
101
+ out.oneOf = branches.map((b, i) => convertSchema(b, `${path}.${key}[${i}]`, errors));
102
+ }
103
+ return out;
104
+ }
105
+ if (schema.$ref !== undefined)
106
+ return out;
107
+ const type = schema.type;
108
+ if (type === undefined) {
109
+ // An untyped node means "any value". The grammar needs something concrete, and a
110
+ // free string is the only choice that can carry any JSON scalar the caller sends back.
111
+ out.type = "string";
112
+ return out;
113
+ }
114
+ if (Array.isArray(type)) {
115
+ const bad = type.filter((t) => !SCALAR_TYPES.has(t) && t !== "object" && t !== "array");
116
+ if (bad.length > 0)
117
+ errors.push({ path, message: `unsupported type(s): ${bad.join(", ")}` });
118
+ out.type = type;
119
+ return out;
120
+ }
121
+ if (type === "object") {
122
+ out.type = "object";
123
+ const props = schema.properties ?? {};
124
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
125
+ const converted = {};
126
+ for (const [key, propSchema] of Object.entries(props)) {
127
+ const child = convertSchema(propSchema, `${path}.properties.${key}`, errors);
128
+ // See note (1) in the file header: node-llama-cpp forces every declared property,
129
+ // so optionality has to be expressed as "or null" and pruned back out afterwards.
130
+ converted[key] = required.has(key) || admitsNull(child)
131
+ ? child
132
+ : { oneOf: [child, { type: "null" }], ...(child.description ? { description: child.description } : {}) };
133
+ }
134
+ out.properties = converted;
135
+ if (typeof schema.additionalProperties === "boolean") {
136
+ out.additionalProperties = schema.additionalProperties;
137
+ }
138
+ else if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
139
+ out.additionalProperties = convertSchema(schema.additionalProperties, `${path}.additionalProperties`, errors);
140
+ }
141
+ return out;
142
+ }
143
+ if (type === "array") {
144
+ out.type = "array";
145
+ if (schema.items)
146
+ out.items = convertSchema(schema.items, `${path}.items`, errors);
147
+ if (Array.isArray(schema.prefixItems)) {
148
+ out.prefixItems = schema.prefixItems.map((s, i) => convertSchema(s, `${path}.prefixItems[${i}]`, errors));
149
+ }
150
+ if (typeof schema.minItems === "number")
151
+ out.minItems = schema.minItems;
152
+ if (typeof schema.maxItems === "number")
153
+ out.maxItems = schema.maxItems;
154
+ return out;
155
+ }
156
+ if (!SCALAR_TYPES.has(type)) {
157
+ errors.push({ path, message: `unsupported type: ${type}` });
158
+ out.type = "string";
159
+ return out;
160
+ }
161
+ out.type = type;
162
+ if (type === "string") {
163
+ if (typeof schema.minLength === "number")
164
+ out.minLength = schema.minLength;
165
+ if (typeof schema.maxLength === "number")
166
+ out.maxLength = schema.maxLength;
167
+ }
168
+ return out;
169
+ }
170
+ /**
171
+ * Remove the `null`s we injected for optional properties (see note (1)), so the caller
172
+ * gets the arguments it would have got from any other OpenAI server. Walks the ORIGINAL
173
+ * schema, so a property the caller genuinely declared as nullable keeps its null.
174
+ */
175
+ export function pruneOptionalNulls(value, schema) {
176
+ if (value == null || schema == null || typeof schema !== "object")
177
+ return value;
178
+ if (schema.type === "object" && typeof value === "object" && !Array.isArray(value)) {
179
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
180
+ const props = schema.properties ?? {};
181
+ const out = {};
182
+ for (const [key, v] of Object.entries(value)) {
183
+ const propSchema = props[key];
184
+ // Injected null for a property the caller marked optional → drop it entirely.
185
+ if (v === null && !required.has(key) && propSchema && !admitsNull(propSchema))
186
+ continue;
187
+ out[key] = pruneOptionalNulls(v, propSchema);
188
+ }
189
+ return out;
190
+ }
191
+ if (schema.type === "array" && Array.isArray(value) && schema.items) {
192
+ return value.map((v) => pruneOptionalNulls(v, schema.items));
193
+ }
194
+ return value;
195
+ }
196
+ export function mapTools(tools) {
197
+ const errors = [];
198
+ const functions = {};
199
+ const originalParams = {};
200
+ if (!Array.isArray(tools)) {
201
+ errors.push({ path: "tools", message: "`tools` must be an array" });
202
+ return { functions: functions, originalParams, errors };
203
+ }
204
+ tools.forEach((tool, i) => {
205
+ const path = `tools[${i}]`;
206
+ if (tool == null || typeof tool !== "object") {
207
+ errors.push({ path, message: "each tool must be an object" });
208
+ return;
209
+ }
210
+ if (tool.type !== undefined && tool.type !== "function") {
211
+ errors.push({ path: `${path}.type`, message: `unsupported tool type "${tool.type}" (only "function")` });
212
+ return;
213
+ }
214
+ const fn = tool.function;
215
+ if (fn == null || typeof fn !== "object" || typeof fn.name !== "string" || fn.name.length === 0) {
216
+ errors.push({ path: `${path}.function.name`, message: "a tool must declare a non-empty function name" });
217
+ return;
218
+ }
219
+ if (Object.prototype.hasOwnProperty.call(functions, fn.name)) {
220
+ errors.push({ path: `${path}.function.name`, message: `duplicate tool name "${fn.name}"` });
221
+ return;
222
+ }
223
+ const entry = {};
224
+ if (typeof fn.description === "string")
225
+ entry.description = fn.description;
226
+ if (fn.parameters !== undefined) {
227
+ entry.params = convertSchema(fn.parameters, `${path}.function.parameters`, errors);
228
+ }
229
+ functions[fn.name] = entry;
230
+ originalParams[fn.name] = fn.parameters;
231
+ });
232
+ return { functions: functions, originalParams, errors };
233
+ }
234
+ /**
235
+ * Resolve `tool_choice`. "auto" (and absent) enable the tools; "none" withholds them so
236
+ * the model answers in prose. "required" and named-function forcing have no equivalent in
237
+ * node-llama-cpp's generation path — we say so plainly instead of quietly treating them
238
+ * as "auto" and returning a prose answer the caller will fail to parse.
239
+ */
240
+ export function resolveToolChoice(choice) {
241
+ if (choice === undefined || choice === "auto")
242
+ return { enabled: true };
243
+ if (choice === "none")
244
+ return { enabled: false };
245
+ if (choice === "required") {
246
+ return {
247
+ enabled: true,
248
+ error: {
249
+ path: "tool_choice",
250
+ message: 'tool_choice "required" is not supported when serving locally; use "auto"',
251
+ },
252
+ };
253
+ }
254
+ if (typeof choice === "object" && choice?.function?.name) {
255
+ return {
256
+ enabled: true,
257
+ error: {
258
+ path: "tool_choice",
259
+ message: `forcing a specific tool ("${choice.function.name}") is not supported when serving locally; use "auto"`,
260
+ },
261
+ };
262
+ }
263
+ return { enabled: true, error: { path: "tool_choice", message: "unrecognized tool_choice" } };
264
+ }
265
+ // ---------------------------------------------------------------------------
266
+ // messages[] → ChatHistoryItem[]
267
+ // ---------------------------------------------------------------------------
268
+ /** Flatten OpenAI's string-or-parts content into plain text. */
269
+ export function contentToText(content) {
270
+ if (content == null)
271
+ return "";
272
+ if (typeof content === "string")
273
+ return content;
274
+ if (!Array.isArray(content))
275
+ return "";
276
+ return content
277
+ .filter((part) => part && (part.type === undefined || part.type === "text"))
278
+ .map((part) => part.text ?? "")
279
+ .join("");
280
+ }
281
+ /**
282
+ * Build real chat history so the model's own template renders it — replacing the old
283
+ * `"role: content"` concatenation, which collapsed system prompts and tool results into
284
+ * one undifferentiated user turn.
285
+ *
286
+ * `tool` messages are folded back onto the assistant `functionCall` they answer (matched
287
+ * by `tool_call_id`), because that is the shape node-llama-cpp's history expects.
288
+ */
289
+ export function mapMessages(messages) {
290
+ const errors = [];
291
+ const history = [];
292
+ if (!Array.isArray(messages) || messages.length === 0) {
293
+ errors.push({ path: "messages", message: "`messages` must be a non-empty array" });
294
+ return { history, errors };
295
+ }
296
+ // Pre-index tool results so an assistant turn can carry them inline.
297
+ const toolResults = new Map();
298
+ messages.forEach((m) => {
299
+ if (m?.role === "tool" && typeof m.tool_call_id === "string") {
300
+ toolResults.set(m.tool_call_id, contentToText(m.content));
301
+ }
302
+ });
303
+ messages.forEach((message, i) => {
304
+ const path = `messages[${i}]`;
305
+ if (message == null || typeof message !== "object" || typeof message.role !== "string") {
306
+ errors.push({ path, message: "each message must be an object with a role" });
307
+ return;
308
+ }
309
+ switch (message.role) {
310
+ case "system":
311
+ case "developer":
312
+ history.push({ type: "system", text: contentToText(message.content) });
313
+ return;
314
+ case "user":
315
+ history.push({ type: "user", text: contentToText(message.content) });
316
+ return;
317
+ case "assistant": {
318
+ const parts = [];
319
+ const text = contentToText(message.content);
320
+ if (text.length > 0)
321
+ parts.push(text);
322
+ for (const call of message.tool_calls ?? []) {
323
+ if (!call?.function?.name) {
324
+ errors.push({ path: `${path}.tool_calls`, message: "each tool call needs function.name" });
325
+ continue;
326
+ }
327
+ let params = undefined;
328
+ const raw = call.function.arguments;
329
+ if (typeof raw === "string" && raw.trim().length > 0) {
330
+ try {
331
+ params = JSON.parse(raw);
332
+ }
333
+ catch {
334
+ errors.push({
335
+ path: `${path}.tool_calls`,
336
+ message: `arguments for "${call.function.name}" are not valid JSON`,
337
+ });
338
+ }
339
+ }
340
+ parts.push({
341
+ type: "functionCall",
342
+ name: call.function.name,
343
+ params,
344
+ result: toolResults.get(call.id) ?? "",
345
+ });
346
+ }
347
+ if (parts.length > 0) {
348
+ history.push({ type: "model", response: parts });
349
+ }
350
+ return;
351
+ }
352
+ case "tool":
353
+ // Already folded onto its assistant turn above.
354
+ if (typeof message.tool_call_id !== "string") {
355
+ errors.push({ path, message: "a tool message needs tool_call_id" });
356
+ }
357
+ return;
358
+ default:
359
+ errors.push({ path: `${path}.role`, message: `unsupported role "${message.role}"` });
360
+ }
361
+ });
362
+ return { history, errors };
363
+ }
364
+ // ---------------------------------------------------------------------------
365
+ // functionCalls[] → OpenAI tool_calls[]
366
+ // ---------------------------------------------------------------------------
367
+ /** OpenAI-shaped call id. Clients echo it back as `tool_call_id`, so it only has to be unique. */
368
+ export function newToolCallId() {
369
+ return `call_${Math.random().toString(36).slice(2, 10)}${Math.random().toString(36).slice(2, 10)}`;
370
+ }
371
+ export function toOpenAiToolCalls(calls, originalParams = {}) {
372
+ if (!Array.isArray(calls))
373
+ return [];
374
+ return calls.map((call) => {
375
+ const pruned = pruneOptionalNulls(call.params, originalParams[call.functionName]);
376
+ return {
377
+ id: newToolCallId(),
378
+ type: "function",
379
+ function: {
380
+ name: call.functionName,
381
+ // OpenAI carries arguments as a JSON *string*, not an object.
382
+ arguments: JSON.stringify(pruned ?? {}),
383
+ },
384
+ };
385
+ });
386
+ }
387
+ //# sourceMappingURL=openai-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-tools.js","sourceRoot":"","sources":["../../src/core/openai-tools.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,19 @@
1
1
  import type { HostConfig } from "../shared/config-types.js";
2
2
  import type { ResolvedPaths } from "./paths.js";
3
+ /** A tool call the model emitted, before OpenAI-shaping. */
4
+ export interface RunnerToolCall {
5
+ functionName: string;
6
+ params?: unknown;
7
+ }
8
+ interface PromptResult {
9
+ text: string;
10
+ promptTokens: number;
11
+ completionTokens: number;
12
+ /** Present (possibly empty) only when the turn offered tools. */
13
+ toolCalls?: RunnerToolCall[];
14
+ /** node-llama-cpp stop reason; "functionCalls" means the model chose to call a tool. */
15
+ stopReason?: string;
16
+ }
3
17
  export interface ModelState {
4
18
  modelId: string;
5
19
  isLoaded: boolean;
@@ -103,11 +117,14 @@ export declare class SharedGGUFRunner {
103
117
  stop?: string[];
104
118
  grammar?: string;
105
119
  grammarRoot?: string;
106
- }): Promise<{
107
- text: string;
108
- promptTokens: number;
109
- completionTokens: number;
110
- }>;
120
+ /**
121
+ * OpenAI tool turn (local REST only). When present, the worker renders this history
122
+ * through the model's own chat template and answers with the model's tool calls
123
+ * instead of executing them — `input` is then only a fallback for token accounting.
124
+ */
125
+ chatHistory?: unknown[];
126
+ tools?: Record<string, unknown>;
127
+ }): Promise<PromptResult>;
111
128
  cancel(conversationId: string): void;
112
129
  cancelAll(): void;
113
130
  clearConversation(conversationId: string): void;
@@ -120,4 +137,5 @@ export declare class SharedGGUFRunner {
120
137
  private validateModelFile;
121
138
  private logTransition;
122
139
  }
140
+ export {};
123
141
  //# sourceMappingURL=shared-runner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-runner.d.ts","sourceRoot":"","sources":["../../src/core/shared-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared-runner.d.ts","sourceRoot":"","sources":["../../src/core/shared-runner.ts"],"names":[],"mappings":"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"}
@@ -421,7 +421,13 @@ export class SharedGGUFRunner {
421
421
  case "done": {
422
422
  const cb = this._takePromptCallback(msg.requestId);
423
423
  if (cb) {
424
- cb.resolve({ text: msg.text, promptTokens: msg.promptTokens, completionTokens: msg.completionTokens });
424
+ cb.resolve({
425
+ text: msg.text,
426
+ promptTokens: msg.promptTokens,
427
+ completionTokens: msg.completionTokens,
428
+ ...(msg.functionCalls !== undefined ? { toolCalls: msg.functionCalls } : {}),
429
+ ...(msg.stopReason !== undefined ? { stopReason: msg.stopReason } : {}),
430
+ });
425
431
  }
426
432
  break;
427
433
  }
@@ -688,7 +694,7 @@ export class SharedGGUFRunner {
688
694
  // ---------------------------------------------------------------------------
689
695
  // Context management
690
696
  // ---------------------------------------------------------------------------
691
- async _ensureContext(conversationId, gen, agentic = true) {
697
+ async _ensureContext(conversationId, gen, agentic = true, chatMode = false) {
692
698
  const existing = this.contextTrackers.get(conversationId);
693
699
  if (existing) {
694
700
  existing.lastUsedAt = Date.now();
@@ -732,7 +738,7 @@ export class SharedGGUFRunner {
732
738
  gen,
733
739
  };
734
740
  this._contextCallbacks.set(conversationId, entry);
735
- if (!this._workerSend({ type: "create-context", conversationId, agentic })) {
741
+ if (!this._workerSend({ type: "create-context", conversationId, agentic, chatMode })) {
736
742
  clearTimeout(deadman);
737
743
  this._contextCallbacks.delete(conversationId);
738
744
  reject(new Error("worker IPC send failed (create-context) — worker unavailable"));
@@ -755,7 +761,16 @@ export class SharedGGUFRunner {
755
761
  // window); plain turns get a smaller context to free KV-cache VRAM/RAM. Only the
756
762
  // FIRST prompt on a conversation sizes it — agentic emissions always use a fresh
757
763
  // conversationId, so an agentic turn is never stuck with a chat-sized context.
758
- const agentic = !!options?.grammar;
764
+ // Two independent decisions:
765
+ // chatMode — build the context around LlamaChat (real history) vs LlamaChatSession.
766
+ // agentic — size the context window. Only a FAT prompt earns the 16K agentic
767
+ // window: a GBNF grammar turn, or a chat turn that actually carries tool
768
+ // schemas. Plain chat keeps the smaller window, which is what frees
769
+ // KV-cache VRAM back to GPU layers — routing all chat through history
770
+ // must not quietly double every REST chat request's memory cost.
771
+ const chatMode = Array.isArray(options?.chatHistory);
772
+ const agentic = !!options?.grammar
773
+ || (!!options?.tools && Object.keys(options.tools).length > 0);
759
774
  // v1.9.16: a context-create failure must NOT leak the request slot. This
760
775
  // await used to be bare — the throw escaped with activeRequestCount stuck
761
776
  // at +1 and the idle timer cleared, so the runner looked busy FOREVER:
@@ -765,7 +780,7 @@ export class SharedGGUFRunner {
765
780
  // every later load on the box failed for hours. Mirrors the Electron
766
781
  // host's guard, plus re-arming the idle timer cleared above.
767
782
  try {
768
- await this._ensureContext(conversationId, gen, agentic);
783
+ await this._ensureContext(conversationId, gen, agentic, chatMode);
769
784
  }
770
785
  catch (err) {
771
786
  if (this.generation === gen) {
@@ -797,7 +812,15 @@ export class SharedGGUFRunner {
797
812
  // S14-5: arm the deadman before sending — covers a worker that wedges
798
813
  // during prompt-eval (silent phase before the first token).
799
814
  this._armPromptDeadman(cb, requestId);
800
- if (!this._workerSend({ type: "prompt", requestId, conversationId, input, options })) {
815
+ if (!this._workerSend({
816
+ type: "prompt",
817
+ requestId,
818
+ conversationId,
819
+ input,
820
+ options,
821
+ ...(options?.chatHistory ? { chatHistory: options.chatHistory } : {}),
822
+ ...(options?.tools ? { tools: options.tools } : {}),
823
+ })) {
801
824
  // S14-5: the send never reached the worker — settle NOW instead of
802
825
  // leaving an orphaned callback behind a dead IPC channel.
803
826
  this._takePromptCallback(requestId);