@map-audio/pam-mcp-server 1.27.0 → 1.28.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.
Files changed (59) hide show
  1. package/README.md +31 -10
  2. package/dist/bridge.d.ts +5 -1
  3. package/dist/bridge.js +41 -40
  4. package/dist/bridge.js.map +1 -1
  5. package/dist/daemon.d.ts +32 -0
  6. package/dist/daemon.js +871 -0
  7. package/dist/daemon.js.map +7 -0
  8. package/dist/drumSynth.d.ts +12 -0
  9. package/dist/drumSynth.js +14 -2
  10. package/dist/drumSynth.js.map +1 -1
  11. package/dist/drumSynthEngines.json +9 -1
  12. package/dist/{fgemma-format.d.ts → functiongemma-format.d.ts} +25 -7
  13. package/dist/{fgemma-format.js → functiongemma-format.js} +34 -11
  14. package/dist/functiongemma-format.js.map +1 -0
  15. package/dist/functiongemma-grammar.d.ts +14 -0
  16. package/dist/functiongemma-grammar.js +140 -0
  17. package/dist/functiongemma-grammar.js.map +1 -0
  18. package/dist/functiongemma-params.d.ts +33 -0
  19. package/dist/functiongemma-params.js +128 -0
  20. package/dist/functiongemma-params.js.map +1 -0
  21. package/dist/{fgemma-runner.d.ts → functiongemma-runner.d.ts} +8 -5
  22. package/dist/{fgemma-runner.js → functiongemma-runner.js} +87 -21
  23. package/dist/functiongemma-runner.js.map +1 -0
  24. package/dist/generativePlayerPresets.json +9 -0
  25. package/dist/generativePlayers.json +14 -0
  26. package/dist/launcher.d.ts +2 -0
  27. package/dist/launcher.js +36 -0
  28. package/dist/launcher.js.map +1 -0
  29. package/dist/manifest-mfx.json +12920 -277
  30. package/dist/manifest-msq.json +1989 -107
  31. package/dist/manifest.d.ts +2 -0
  32. package/dist/manifest.js +7 -27
  33. package/dist/manifest.js.map +1 -1
  34. package/dist/manifest.json +24194 -345
  35. package/dist/mfxCombos.d.ts +2 -0
  36. package/dist/mfxCombos.js +179 -56
  37. package/dist/mfxCombos.js.map +1 -1
  38. package/dist/midiFile.d.ts +19 -5
  39. package/dist/midiFile.js +21 -13
  40. package/dist/midiFile.js.map +1 -1
  41. package/dist/mixAssist.js +3 -2
  42. package/dist/mixAssist.js.map +1 -1
  43. package/dist/players.d.ts +22 -0
  44. package/dist/players.js +70 -0
  45. package/dist/players.js.map +1 -1
  46. package/dist/productProfile.d.ts +4 -4
  47. package/dist/productProfile.js +10 -1
  48. package/dist/productProfile.js.map +1 -1
  49. package/dist/qwen-format.d.ts +85 -0
  50. package/dist/qwen-format.js +355 -0
  51. package/dist/qwen-format.js.map +1 -0
  52. package/dist/registration.mjs +41 -0
  53. package/dist/server.js +1309 -187
  54. package/dist/server.js.map +1 -1
  55. package/dist/variationSessionKeys.json +6 -4
  56. package/package.json +13 -7
  57. package/dist/fgemma-format.js.map +0 -1
  58. package/dist/fgemma-runner.js.map +0 -1
  59. package/dist/manifest-cell1.json +0 -12968
@@ -0,0 +1,140 @@
1
+ // GBNF from a toolpack: declared tools, keys in renderValue's dictsort order, schema-typed values.
2
+ // "lazy" roots at the call token (llama-server trigger); "full" also admits call-free text (wllama).
3
+ import { byKeyDictsort, renderNumber } from "./functiongemma-format.js";
4
+ export const CALL_TRIGGER = "<start_function_call>";
5
+ export const DEFAULT_MAX_CALLS = 12;
6
+ const PRIMITIVES = [
7
+ 'string ::= <escape> [^<]* <escape>',
8
+ 'integer ::= "-"? ([0-9] | [1-9] [0-9]{1,15})',
9
+ 'number ::= "-"? ([0-9] | [1-9] [0-9]{1,15}) ("." [0-9]{1,16})? ([eE] [-+]? [0-9]{1,3})?',
10
+ 'boolean ::= "true" | "false"',
11
+ 'any-value ::= string | number | boolean | "null" | any-array | any-object',
12
+ 'any-array ::= "[" (any-value ("," any-value)*)? "]"',
13
+ 'any-object ::= "{" (any-key ":" any-value ("," any-key ":" any-value)*)? "}"',
14
+ 'any-key ::= [A-Za-z_] [A-Za-z0-9_]*',
15
+ ];
16
+ export function gbnfLiteral(text) {
17
+ const body = [...text]
18
+ .map((ch) => {
19
+ if (ch === '"' || ch === "\\")
20
+ return `\\${ch}`;
21
+ if (ch === "\n")
22
+ return "\\n";
23
+ if (ch === "\t")
24
+ return "\\t";
25
+ if (ch === "\r")
26
+ return "\\r";
27
+ const cp = ch.codePointAt(0);
28
+ return cp < 0x20 ? `\\x${cp.toString(16).padStart(2, "0")}` : ch;
29
+ })
30
+ .join("");
31
+ return `"${body}"`;
32
+ }
33
+ function enumLiteral(value) {
34
+ if (typeof value === "string")
35
+ return `<escape> ${gbnfLiteral(value)} <escape>`;
36
+ if (typeof value === "number")
37
+ return gbnfLiteral(renderNumber(value));
38
+ if (typeof value === "boolean" || value === null)
39
+ return gbnfLiteral(String(value));
40
+ throw new Error(`unsupported enum value in FunctionGemma grammar: ${JSON.stringify(value)}`);
41
+ }
42
+ class RuleSet {
43
+ rules = [];
44
+ names = new Set(PRIMITIVES.map((r) => r.split(" ::= ")[0]));
45
+ name(base) {
46
+ const stem = base.replace(/[^A-Za-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "rule";
47
+ let name = stem;
48
+ for (let i = 2; this.names.has(name); i++)
49
+ name = `${stem}-${i}`;
50
+ this.names.add(name);
51
+ return name;
52
+ }
53
+ add(name, body) {
54
+ this.rules.push(`${name} ::= ${body}`);
55
+ return name;
56
+ }
57
+ /** The rule (or inline expression) matching one value of `schema`. */
58
+ value(schema, base) {
59
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
60
+ return this.add(this.name(base), schema.enum.map(enumLiteral).join(" | "));
61
+ }
62
+ const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : [];
63
+ if (types.length === 0)
64
+ return "any-value";
65
+ const alts = types.map((type) => {
66
+ switch (type) {
67
+ case "string":
68
+ case "integer":
69
+ case "number":
70
+ case "boolean":
71
+ return type;
72
+ case "null":
73
+ return '"null"';
74
+ case "array": {
75
+ const item = schema.items ? this.value(schema.items, `${base}-item`) : "any-value";
76
+ return this.add(this.name(`${base}-array`), `"[" (${item} ("," ${item})*)? "]"`);
77
+ }
78
+ case "object":
79
+ return schema.properties ? this.object(schema, base) : "any-object";
80
+ default:
81
+ throw new Error(`unsupported schema type in FunctionGemma grammar: ${type}`);
82
+ }
83
+ });
84
+ return alts.length === 1 ? alts[0] : `(${alts.join(" | ")})`;
85
+ }
86
+ /** Declared keys in renderValue order; each optional key may be skipped, every required one appears. */
87
+ object(schema, base) {
88
+ const name = this.name(base);
89
+ const required = new Set(schema.required ?? []);
90
+ const keys = Object.entries(schema.properties ?? {}).sort(byKeyDictsort);
91
+ if (keys.length === 0)
92
+ return this.add(name, '"{" "}"');
93
+ const pairs = keys.map(([key, sub]) => `${gbnfLiteral(`${key}:`)} ${this.value(sub, `${base}-${key}`)}`);
94
+ // after[i]: the rest of the object once some earlier key was written.
95
+ const after = new Array(keys.length + 1).fill("");
96
+ for (let i = keys.length - 1; i >= 1; i--) {
97
+ const item = required.has(keys[i][0]) ? `"," ${pairs[i]}` : `("," ${pairs[i]})?`;
98
+ after[i] = this.add(this.name(`${base}-after-${keys[i][0]}`), `${item}${after[i + 1] ? ` ${after[i + 1]}` : ""}`);
99
+ }
100
+ const firstRequired = keys.findIndex(([key]) => required.has(key));
101
+ const heads = keys
102
+ .slice(0, firstRequired === -1 ? keys.length : firstRequired + 1)
103
+ .map((_, i) => `${pairs[i]}${after[i + 1] ? ` ${after[i + 1]}` : ""}`);
104
+ const optional = firstRequired === -1;
105
+ const body = heads.length === 1 && !optional ? heads[0] : `(${heads.join(" | ")})${optional ? "?" : ""}`;
106
+ return this.add(name, `"{" ${body} "}"`);
107
+ }
108
+ }
109
+ /** GBNF for one assistant turn's call blocks, generated from the toolpack the model is prompted with. */
110
+ export function buildToolGrammar(tools, opts = {}) {
111
+ const mode = opts.mode ?? "lazy";
112
+ const maxCalls = opts.maxCalls ?? DEFAULT_MAX_CALLS;
113
+ if (!Number.isInteger(maxCalls) || maxCalls < 1)
114
+ throw new Error(`maxCalls must be a positive integer: ${maxCalls}`);
115
+ if (tools.length === 0)
116
+ throw new Error("FunctionGemma grammar needs at least one tool");
117
+ const set = new RuleSet();
118
+ const toolRules = tools.map((tool) => {
119
+ const args = set.object((tool.parameters ?? { type: "object", properties: {} }), `${tool.name}-args`);
120
+ return set.add(set.name(`tool-${tool.name}`), `${gbnfLiteral(tool.name)} ${args}`);
121
+ });
122
+ const calls = `call-block{1,${maxCalls}} <start_function_response>?`;
123
+ const header = [
124
+ `root ::= ${mode === "full" ? `${calls} | free-text` : calls}`,
125
+ "call-block ::= <start_function_call> \"call:\" call-body <end_function_call>",
126
+ `call-body ::= ${toolRules.join(" | ")}`,
127
+ ...(mode === "full" ? ["free-text ::= (!<start_function_call>)*"] : []),
128
+ ];
129
+ return [...header, ...set.rules, ...PRIMITIVES].join("\n") + "\n";
130
+ }
131
+ /** llama-server request fields that apply `grammar` lazily from the first call token. */
132
+ export function lazyGrammarRequest(grammar) {
133
+ return {
134
+ grammar,
135
+ grammar_lazy: true,
136
+ grammar_triggers: [{ type: 1, value: CALL_TRIGGER }],
137
+ preserved_tokens: [CALL_TRIGGER],
138
+ };
139
+ }
140
+ //# sourceMappingURL=functiongemma-grammar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functiongemma-grammar.js","sourceRoot":"","sources":["../src/functiongemma-grammar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export interface ParamKind {
2
+ id: string;
3
+ label: string;
4
+ words: string[];
5
+ phrases: string[];
6
+ scope: "cell" | "lfo" | "looper" | "master" | "global";
7
+ unit?: string;
8
+ text: string;
9
+ }
10
+ export interface ParamIndex {
11
+ stopwords: string[];
12
+ synonyms: Record<string, string[]>;
13
+ idf: Record<string, number>;
14
+ kinds: ParamKind[];
15
+ }
16
+ export declare const PARAMS_MAX_ENTRIES = 6;
17
+ export declare const PARAMS_MAX_CHARS = 700;
18
+ export declare const UNIT_FILL = 3;
19
+ export declare function queryTokens(text: string, index: ParamIndex): string[];
20
+ export declare function rankKinds(text: string, index: ParamIndex, sel?: number | null): ParamKind[];
21
+ export declare function unitWord(text: string): string | null;
22
+ /** The stated unit's kinds: the previous turn's first, then the generic ones (volume / cutoff). */
23
+ export declare function unitFill(text: string, index: ParamIndex, opts?: {
24
+ sel?: number | null;
25
+ previous?: string | null;
26
+ }): {
27
+ unit: string | null;
28
+ fill: ParamKind[];
29
+ };
30
+ export declare function renderParamsLine(text: string, index: ParamIndex, opts?: {
31
+ sel?: number | null;
32
+ previous?: string | null;
33
+ }): string;
@@ -0,0 +1,128 @@
1
+ export const PARAMS_MAX_ENTRIES = 6;
2
+ export const PARAMS_MAX_CHARS = 700;
3
+ const SPLIT = /[^a-z0-9]+/;
4
+ const CELL = /\bcell\s*\d/;
5
+ const LFO = /\blfo\s*\d/;
6
+ const TRACK = /\btrack\s*\d/;
7
+ // When the best name match has a different unit, include up to UNIT_FILL matches for the stated unit.
8
+ const UNITS = [
9
+ [/[0-9] *db(?![a-z0-9])/i, "db", "volume"],
10
+ [/[0-9] *k?hz(?![a-z0-9])/i, "hz", "cutoff"],
11
+ ];
12
+ const UNIT_STRIP = /([0-9]) *(?:db|k?hz)(?![a-z0-9])/gi;
13
+ export const UNIT_FILL = 3;
14
+ const stem = (w) => (w.length > 3 && w.endsWith("s") && !w.endsWith("ss") ? w.slice(0, -1) : w);
15
+ const prepared = new WeakMap();
16
+ function prep(index) {
17
+ let p = prepared.get(index);
18
+ if (!p) {
19
+ const stop = new Set(index.stopwords);
20
+ const words = index.kinds.map((k) => new Set(k.words));
21
+ const labelWords = index.kinds.map((k) => {
22
+ const out = [];
23
+ for (const raw of k.label.toLowerCase().split(SPLIT)) {
24
+ if (!raw || /^\d+$/.test(raw))
25
+ continue;
26
+ const ws = stem(raw);
27
+ if (!stop.has(ws))
28
+ out.push(ws);
29
+ }
30
+ return out;
31
+ });
32
+ p = { stop, words, labelWords };
33
+ prepared.set(index, p);
34
+ }
35
+ return p;
36
+ }
37
+ export function queryTokens(text, index) {
38
+ const { stop } = prep(index);
39
+ const out = [];
40
+ const camelSplit = String(text).replace(/([a-z0-9])([A-Z])/g, "$1 $2");
41
+ for (const raw of camelSplit.toLowerCase().split(SPLIT)) {
42
+ if (!raw || /^\d+$/.test(raw))
43
+ continue;
44
+ const w = stem(raw);
45
+ if (stop.has(w))
46
+ continue;
47
+ const synonyms = Object.hasOwn(index.synonyms, w) ? index.synonyms[w] : [];
48
+ for (const t of [w, ...synonyms])
49
+ if (!out.includes(t))
50
+ out.push(t);
51
+ }
52
+ return out;
53
+ }
54
+ function scopeOf(text, sel) {
55
+ const low = String(text).toLowerCase();
56
+ const words = new Set(low.split(SPLIT));
57
+ if (words.has("master"))
58
+ return "master";
59
+ if (LFO.test(low))
60
+ return "lfo";
61
+ if (words.has("looper") || TRACK.test(low))
62
+ return "looper";
63
+ if (CELL.test(low) || sel)
64
+ return "cell";
65
+ return null;
66
+ }
67
+ export function rankKinds(text, index, sel) {
68
+ const { words, labelWords } = prep(index);
69
+ const tokens = queryTokens(text, index);
70
+ const joined = ` ${tokens.join(" ")} `;
71
+ const scope = scopeOf(text, sel);
72
+ const tokenSet = new Set(tokens);
73
+ const scored = [];
74
+ index.kinds.forEach((kind, pos) => {
75
+ let s = 0;
76
+ for (const w of tokens)
77
+ if (words[pos].has(w))
78
+ s += index.idf[w];
79
+ for (const phrase of kind.phrases)
80
+ if (joined.includes(` ${phrase} `))
81
+ s += 1.0;
82
+ if (s > 0 && labelWords[pos].length && labelWords[pos].every((lw) => tokenSet.has(lw)))
83
+ s += 1.0;
84
+ if (s > 0 && kind.scope === scope)
85
+ s += 0.5;
86
+ if (s > 0)
87
+ scored.push([-s, pos, kind]);
88
+ });
89
+ scored.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
90
+ return scored.slice(0, PARAMS_MAX_ENTRIES).map(([, , k]) => k);
91
+ }
92
+ export function unitWord(text) {
93
+ return UNITS.find(([re]) => re.test(String(text)))?.[2] ?? null;
94
+ }
95
+ /** The stated unit's kinds: the previous turn's first, then the generic ones (volume / cutoff). */
96
+ export function unitFill(text, index, opts = {}) {
97
+ const stated = UNITS.find(([re]) => re.test(String(text)));
98
+ if (!stated)
99
+ return { unit: null, fill: [] };
100
+ const [, unit, word] = stated;
101
+ const strip = (t) => String(t).replace(UNIT_STRIP, "$1 ");
102
+ const fill = opts.previous ? rankKinds(strip(opts.previous), index, opts.sel).filter((k) => k.unit === unit) : [];
103
+ const bare = strip(text);
104
+ for (const k of rankKinds(`${bare} ${word}`, index, opts.sel))
105
+ if (k.unit === unit && !fill.includes(k))
106
+ fill.push(k);
107
+ return { unit, fill: fill.slice(0, UNIT_FILL) };
108
+ }
109
+ export function renderParamsLine(text, index, opts = {}) {
110
+ const { unit, fill } = unitFill(text, index, opts);
111
+ // The unit token is not a parameter word ("db" would rank retriggerDecayDb), so rank without it.
112
+ let kinds = rankKinds(unit ? String(text).replace(UNIT_STRIP, "$1 ") : text, index, opts.sel);
113
+ if (unit && kinds[0]?.unit !== unit) {
114
+ const head = kinds.slice(0, PARAMS_MAX_ENTRIES - fill.length);
115
+ kinds = [...head, ...fill.filter((kind) => !head.includes(kind))];
116
+ }
117
+ if (!kinds.length && opts.previous)
118
+ kinds = rankKinds(opts.previous, index, opts.sel);
119
+ const head = "[params] ";
120
+ const parts = [];
121
+ for (const kind of kinds) {
122
+ if ((head + [...parts, kind.text].join(" | ")).length > PARAMS_MAX_CHARS)
123
+ break;
124
+ parts.push(kind.text);
125
+ }
126
+ return head + (parts.length ? parts.join(" | ") : "none");
127
+ }
128
+ //# sourceMappingURL=functiongemma-params.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functiongemma-params.js","sourceRoot":"","sources":["../src/functiongemma-params.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * PAM FunctionGemma runner — drives a (fine-tuned) FunctionGemma model against
4
- * the PAM MCP server using the model's native wire format (fgemma-format.ts),
4
+ * the PAM MCP server using the model's native wire format (functiongemma-format.ts),
5
5
  * NOT the OpenAI chat+tools API: raw /completions + our own renderer/parser is
6
6
  * deterministic and byte-matches training (agent.ts remains the big-model
7
7
  * OpenAI-style baseline harness).
8
8
  *
9
9
  * Modes:
10
- * REPL (default) npx tsx src/fgemma-runner.ts [--url http://localhost:1234/v1] [--model id]
11
- * Offline eval ... --eval ../fgemma-poc/out/eval.jsonl --out ../fgemma-poc/out/predictions.jsonl
12
- * Live e2e ... --live ../fgemma-poc/scenarios/live.jsonl [--gold]
10
+ * REPL (default) npx tsx src/functiongemma-runner.ts [--url http://localhost:1234/v1] [--model id]
11
+ * Offline eval ... --eval ../ml-research/out/dev.jsonl --out ../ml-research/out/predictions.jsonl
12
+ * Live e2e ... --live ../ml-research/data/seeds/live_scenarios.jsonl [--gold]
13
13
  *
14
14
  * Flags: --toolpack <path> --bos text|none (default none; use text if the
15
15
  * serving layer does NOT add BOS itself) --max-tokens N --final (generate a
16
16
  * model NL summary after write-tool calls; read-tools always continue)
17
17
  * --no-ctx (skip the live [ctx] session line).
18
+ * --grammar [--grammar-mode lazy|full] constrains calls to the toolpack's GBNF (functiongemma-grammar.ts);
19
+ * --probs [K] records P(first token = <start_function_call>) per eval row from a one-token probe;
20
+ * --token-probs streams the main request and records each generated token's [id, logprob, text].
18
21
  *
19
22
  * Session context (dataset v3): each command's user turn is prefixed with the
20
23
  * [ctx] state line built live from the bridge (get_transport +
@@ -22,6 +25,6 @@
22
25
  * additionally threads the last completed exchanges as history — the same
23
26
  * shapes the in-plugin executor produces. Within one command the runner does
24
27
  * up to MAX_ROUNDS call→response continuations inside the same model turn
25
- * (the trained repair/introspect pattern).
28
+ * (the trained repair/state_read pattern).
26
29
  */
27
30
  export {};
@@ -1,20 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * PAM FunctionGemma runner — drives a (fine-tuned) FunctionGemma model against
4
- * the PAM MCP server using the model's native wire format (fgemma-format.ts),
4
+ * the PAM MCP server using the model's native wire format (functiongemma-format.ts),
5
5
  * NOT the OpenAI chat+tools API: raw /completions + our own renderer/parser is
6
6
  * deterministic and byte-matches training (agent.ts remains the big-model
7
7
  * OpenAI-style baseline harness).
8
8
  *
9
9
  * Modes:
10
- * REPL (default) npx tsx src/fgemma-runner.ts [--url http://localhost:1234/v1] [--model id]
11
- * Offline eval ... --eval ../fgemma-poc/out/eval.jsonl --out ../fgemma-poc/out/predictions.jsonl
12
- * Live e2e ... --live ../fgemma-poc/scenarios/live.jsonl [--gold]
10
+ * REPL (default) npx tsx src/functiongemma-runner.ts [--url http://localhost:1234/v1] [--model id]
11
+ * Offline eval ... --eval ../ml-research/out/dev.jsonl --out ../ml-research/out/predictions.jsonl
12
+ * Live e2e ... --live ../ml-research/data/seeds/live_scenarios.jsonl [--gold]
13
13
  *
14
14
  * Flags: --toolpack <path> --bos text|none (default none; use text if the
15
15
  * serving layer does NOT add BOS itself) --max-tokens N --final (generate a
16
16
  * model NL summary after write-tool calls; read-tools always continue)
17
17
  * --no-ctx (skip the live [ctx] session line).
18
+ * --grammar [--grammar-mode lazy|full] constrains calls to the toolpack's GBNF (functiongemma-grammar.ts);
19
+ * --probs [K] records P(first token = <start_function_call>) per eval row from a one-token probe;
20
+ * --token-probs streams the main request and records each generated token's [id, logprob, text].
18
21
  *
19
22
  * Session context (dataset v3): each command's user turn is prefixed with the
20
23
  * [ctx] state line built live from the bridge (get_transport +
@@ -22,7 +25,7 @@
22
25
  * additionally threads the last completed exchanges as history — the same
23
26
  * shapes the in-plugin executor produces. Within one command the runner does
24
27
  * up to MAX_ROUNDS call→response continuations inside the same model turn
25
- * (the trained repair/introspect pattern).
28
+ * (the trained repair/state_read pattern).
26
29
  */
27
30
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
28
31
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
@@ -30,9 +33,10 @@ import { createInterface } from "node:readline";
30
33
  import { readFileSync, writeFileSync } from "node:fs";
31
34
  import { resolve, dirname } from "node:path";
32
35
  import { fileURLToPath } from "node:url";
33
- import { STOP_SEQUENCES, buildGenerationPrompt, renderFunctionCall, renderFunctionResponse, parseFunctionCalls, truncateAtFabricatedResponse, withContext, } from "./fgemma-format.js";
36
+ import { STOP_SEQUENCES, buildGenerationPrompt, renderFunctionCall, renderFunctionResponse, parseFunctionCalls, truncateAtFabricatedResponse, withContext, } from "./functiongemma-format.js";
37
+ import { CALL_TRIGGER, buildToolGrammar, lazyGrammarRequest } from "./functiongemma-grammar.js";
34
38
  const __dirname = dirname(fileURLToPath(import.meta.url));
35
- const DEFAULT_TOOLPACK = resolve(__dirname, "../../fgemma-poc/out/toolpack.json");
39
+ const DEFAULT_TOOLPACK = resolve(__dirname, "../../ml-research/out/toolpack.json");
36
40
  const MAX_ROUNDS = 3;
37
41
  const RESULT_TRUNC = 400; // chars of tool-result JSON fed back as function response
38
42
  function parseArgs() {
@@ -53,6 +57,9 @@ function parseArgs() {
53
57
  outPath: get("--out"),
54
58
  livePath: get("--live"),
55
59
  gold: a.includes("--gold"),
60
+ grammar: a.includes("--grammar") ? (get("--grammar-mode") || "lazy") : null,
61
+ probs: a.includes("--probs") ? Number(/^\d+$/.test(get("--probs") ?? "") ? get("--probs") : 20) : 0,
62
+ tokenProbs: a.includes("--token-probs"),
56
63
  };
57
64
  }
58
65
  const config = parseArgs();
@@ -73,8 +80,10 @@ function resolveAlias(call, pack) {
73
80
  }
74
81
  const READ_TOOL_RE = /^(get_|list_|connection_status)/;
75
82
  // --- generation ----------------------------------------------------------
83
+ let grammarFields = {};
76
84
  async function complete(prompt) {
77
85
  const t0 = Date.now();
86
+ const stream = config.tokenProbs;
78
87
  const resp = await fetch(`${config.url}/completions`, {
79
88
  method: "POST",
80
89
  headers: { "Content-Type": "application/json" },
@@ -84,13 +93,58 @@ async function complete(prompt) {
84
93
  max_tokens: config.maxTokens,
85
94
  temperature: 0,
86
95
  stop: STOP_SEQUENCES,
87
- stream: false,
96
+ stream,
97
+ ...(stream ? { n_probs: 1 } : {}),
98
+ ...grammarFields,
88
99
  }),
89
100
  });
101
+ if (!resp.ok)
102
+ throw new Error(`LLM API error ${resp.status}: ${await resp.text()}`);
103
+ if (!stream) {
104
+ const data = (await resp.json());
105
+ return { text: data.choices[0].text, ms: Date.now() - t0 };
106
+ }
107
+ // Streamed chunks carry every token's probability; the final non-streamed response trims them by the stop word.
108
+ let text = "";
109
+ let buffer = "";
110
+ const tokens = [];
111
+ const decoder = new TextDecoder();
112
+ for await (const chunk of resp.body) {
113
+ buffer += decoder.decode(chunk, { stream: true });
114
+ for (let nl = buffer.indexOf("\n"); nl >= 0; nl = buffer.indexOf("\n")) {
115
+ const line = buffer.slice(0, nl).trim();
116
+ buffer = buffer.slice(nl + 1);
117
+ if (!line.startsWith("data:") || line.endsWith("[DONE]"))
118
+ continue;
119
+ const choice = JSON.parse(line.slice(5)).choices?.[0];
120
+ text += choice?.text ?? "";
121
+ for (const t of choice?.logprobs?.content ?? []) {
122
+ tokens.push([t.id, Math.round(t.logprob * 1e4) / 1e4, t.top_logprobs?.[0]?.id === t.id ? t.top_logprobs[0].token : t.token]);
123
+ }
124
+ }
125
+ }
126
+ return { text, ms: Date.now() - t0, tokens };
127
+ }
128
+ /** The unconstrained first-token distribution; a separate request because llama-server trims
129
+ * final-response probs by the stop word's text tokenization, which can eat a short call's first token. */
130
+ async function probeFirstToken(prompt) {
131
+ const t0 = Date.now();
132
+ const resp = await fetch(`${config.url}/completions`, {
133
+ method: "POST",
134
+ headers: { "Content-Type": "application/json" },
135
+ body: JSON.stringify({ model: config.model, prompt, max_tokens: 1, temperature: 0, n_probs: config.probs, stream: false }),
136
+ });
90
137
  if (!resp.ok)
91
138
  throw new Error(`LLM API error ${resp.status}: ${await resp.text()}`);
92
139
  const data = (await resp.json());
93
- return { text: data.choices[0].text, ms: Date.now() - t0 };
140
+ const top = (data.choices[0].logprobs?.content?.[0]?.top_logprobs ?? []).map((t) => ({
141
+ token: t.token,
142
+ p: Math.exp(t.logprob),
143
+ }));
144
+ if (top.length === 0)
145
+ throw new Error("probe returned no top_logprobs (server too old, or n_probs ignored)");
146
+ const call = top.find((t) => t.token === CALL_TRIGGER);
147
+ return { p_call: call?.p ?? 0, top: top.slice(0, 5), probe_ms: Date.now() - t0 };
94
148
  }
95
149
  // --- MCP -----------------------------------------------------------------
96
150
  async function createMcpClient() {
@@ -99,7 +153,7 @@ async function createMcpClient() {
99
153
  args: ["tsx", resolve(__dirname, "server.ts")],
100
154
  stderr: "inherit",
101
155
  });
102
- const client = new Client({ name: "pam-fgemma-runner", version: "1.0.0" });
156
+ const client = new Client({ name: "pam-functiongemma-runner", version: "1.0.0" });
103
157
  await client.connect(transport);
104
158
  return client;
105
159
  }
@@ -191,7 +245,7 @@ async function runCommandExec(userText, tools, client, log, opts = {}) {
191
245
  const { text: rawFull, ms } = await complete(prompt);
192
246
  const raw = truncateAtFabricatedResponse(rawFull);
193
247
  if (raw !== rawFull) {
194
- trace.quarantineHistory = true;
248
+ trace.droppedHistory = true;
195
249
  log(" (dropped fabricated function-response continuation)");
196
250
  }
197
251
  const calls = parseFunctionCalls(raw);
@@ -203,7 +257,7 @@ async function runCommandExec(userText, tools, client, log, opts = {}) {
203
257
  }
204
258
  const unknown = calls.filter((c) => !declared.has(c.name));
205
259
  if (unknown.length) {
206
- trace.quarantineHistory = true;
260
+ trace.droppedHistory = true;
207
261
  log(` refusing undeclared tool(s): ${unknown.map((c) => c.name).join(", ")}`);
208
262
  return trace;
209
263
  }
@@ -213,7 +267,7 @@ async function runCommandExec(userText, tools, client, log, opts = {}) {
213
267
  for (const call of calls) {
214
268
  const signature = `${call.name} ${JSON.stringify(call.arguments)}`;
215
269
  if (failedCalls.has(signature)) {
216
- trace.quarantineHistory = true;
270
+ trace.droppedHistory = true;
217
271
  log(` stopped — the model repeated a call that already failed (${call.name}).`);
218
272
  return trace;
219
273
  }
@@ -221,7 +275,7 @@ async function runCommandExec(userText, tools, client, log, opts = {}) {
221
275
  const { text, isError } = await execCall(client, call, tools);
222
276
  if (isError) {
223
277
  failedCalls.add(signature);
224
- trace.quarantineHistory = true;
278
+ trace.droppedHistory = true;
225
279
  }
226
280
  trace.executed.push({ call, resultText: text, isError });
227
281
  log(` → ${text.length > 200 ? text.slice(0, 200) + "…" : text || "(ok)"}`);
@@ -307,7 +361,7 @@ async function runEval(tools) {
307
361
  const utterance = String(user?.content ?? "");
308
362
  const gold = firstAssistant?.tool_calls
309
363
  ? firstAssistant.tool_calls.map((tc) => ({ name: tc.function.name, arguments: tc.function.arguments }))
310
- : null; // null = abstain expected
364
+ : null; // null = an irrelevance row: no call expected
311
365
  // Protocol: always generate against the FULL toolpack (deployment prompt),
312
366
  // regardless of the subset recorded in the row.
313
367
  const prompt = buildGenerationPrompt(tools, utterance, {
@@ -316,25 +370,33 @@ async function runEval(tools) {
316
370
  });
317
371
  let raw = "";
318
372
  let ms = -1;
373
+ let probs = {};
374
+ let tokenLp = {};
319
375
  try {
320
376
  const r = await complete(prompt);
321
377
  raw = r.text;
322
378
  ms = r.ms;
323
379
  latencies.push(ms);
380
+ if (r.tokens)
381
+ tokenLp = { token_lp: r.tokens };
382
+ if (config.probs > 0)
383
+ probs = await probeFirstToken(prompt);
324
384
  }
325
385
  catch (e) {
326
386
  raw = `__GENERATION_ERROR__ ${e.message}`;
327
387
  }
328
388
  const calls = parseFunctionCalls(raw);
329
- out.push(JSON.stringify({ idx: i, meta: row._meta, utterance, gold, raw, calls, ms }));
389
+ out.push(JSON.stringify({ idx: i, meta: row._meta, utterance, gold, raw, calls, ms, ...probs, ...tokenLp }));
330
390
  if ((i + 1) % 25 === 0)
331
391
  console.error(`eval ${i + 1}/${rows.length}`);
332
392
  }
333
393
  writeFileSync(outPath, out.join("\n") + "\n");
334
394
  latencies.sort((a, b) => a - b);
335
395
  const p = (q) => latencies[Math.min(latencies.length - 1, Math.floor(q * latencies.length))] ?? -1;
336
- console.log(`wrote ${out.length} predictions -> ${outPath}\nlatency ms p50=${p(0.5)} p95=${p(0.95)} (n=${latencies.length})`);
337
- console.log("score with: python3 packages/fgemma-poc/eval_offline.py " + outPath);
396
+ const total = latencies.reduce((sum, ms) => sum + ms, 0);
397
+ console.log(`wrote ${out.length} predictions -> ${outPath}\nlatency ms p50=${p(0.5)} p95=${p(0.95)} total=${total} (n=${latencies.length})` +
398
+ (config.grammar ? ` grammar=${config.grammar}` : ""));
399
+ console.log("score with: uv run --project packages/ml-research pam-ml scoring calls " + outPath);
338
400
  }
339
401
  function callMatches(call, tool, argsSubset) {
340
402
  if (call.name !== tool)
@@ -378,7 +440,7 @@ async function runLive(tools) {
378
440
  let this_ok = false;
379
441
  let detail = "";
380
442
  const allCalls = trace.rounds.flatMap((r) => r.calls);
381
- if (ex.kind === "no_calls") {
443
+ if (ex.kind === "irrelevance") {
382
444
  this_ok = allCalls.length === 0;
383
445
  detail = this_ok ? "" : `emitted ${allCalls.map((c) => c.name).join(",")}`;
384
446
  }
@@ -453,7 +515,7 @@ async function runRepl(tools) {
453
515
  history: history.slice(-HISTORY_MAX_EXCHANGES),
454
516
  failedCalls,
455
517
  });
456
- if (!trace.quarantineHistory && trace.modelTurn && trace.modelTurn.length <= HISTORY_TURN_MAX_CHARS) {
518
+ if (!trace.droppedHistory && trace.modelTurn && trace.modelTurn.length <= HISTORY_TURN_MAX_CHARS) {
457
519
  history.push({ user: input, model: trace.modelTurn });
458
520
  }
459
521
  if (trace.finalText)
@@ -478,6 +540,10 @@ async function runRepl(tools) {
478
540
  }
479
541
  async function main() {
480
542
  const tools = loadToolpack();
543
+ if (config.grammar) {
544
+ const grammar = buildToolGrammar(tools, { mode: config.grammar });
545
+ grammarFields = config.grammar === "lazy" ? lazyGrammarRequest(grammar) : { grammar };
546
+ }
481
547
  if (config.evalPath)
482
548
  return runEval(tools);
483
549
  if (config.livePath)
@@ -488,4 +554,4 @@ main().catch((e) => {
488
554
  console.error("Fatal:", e.message);
489
555
  process.exit(1);
490
556
  });
491
- //# sourceMappingURL=fgemma-runner.js.map
557
+ //# sourceMappingURL=functiongemma-runner.js.map