@map-audio/pam-mcp-server 1.12.0 → 1.21.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,119 @@
1
+ /**
2
+ * FunctionGemma wire format — renderer + parser.
3
+ *
4
+ * Byte-parity with HF `tokenizer.apply_chat_template` is REQUIRED and pinned by
5
+ * scripts/check-fgemma-format.mjs against fixtures dumped by
6
+ * packages/fgemma-poc/dump_template_fixture.py. Empirical rules (from the
7
+ * fixtures, 2026-07-03, google/functiongemma-270m-it template):
8
+ *
9
+ * - Prompt starts with literal `<bos>` (template-added; serving layers that
10
+ * add BOS themselves must not receive it twice — see buildGenerationPrompt).
11
+ * - Developer turn: trigger phrase + declarations back-to-back, input order.
12
+ * - Schema objects render with keys sorted alphabetically at every level;
13
+ * `type` values are UPPERCASED; all schema strings are <escape>-wrapped.
14
+ * - Tool call/response argument objects ALSO sort keys at every level (the
15
+ * template dictsorts them — pinned by fixtures/hf_dictsort_probe.txt; the
16
+ * original fixtures were accidentally all-alphabetical and hid this);
17
+ * strings are <escape>-wrapped, numbers/booleans bare.
18
+ * - The tool call AND its function response live inside ONE continuous
19
+ * `model` turn: app appends `<start_function_response>response:…` inline
20
+ * and generation resumes — no new turn markers.
21
+ * - Multi-exchange history (fixtures hf_followup_prompt.txt /
22
+ * hf_followup_text_prompt.txt): a user message directly after a tool
23
+ * response is INLINED into the same model turn (no `<end_of_turn>` /
24
+ * `<start_of_turn>user` markers); a user message after assistant TEXT gets
25
+ * normal turn markers. buildGenerationPrompt's `history` option reproduces
26
+ * this byte-exactly.
27
+ * - Session context: `renderContextLine` renders the compact `[ctx]` state
28
+ * line prepended to the LAST user turn (grammar pinned against
29
+ * fixtures/context_line.txt; Python twin: packages/fgemma-poc/fgemma_context.py).
30
+ */
31
+ export interface ToolDef {
32
+ name: string;
33
+ description: string;
34
+ parameters: Record<string, unknown>;
35
+ aliasOf?: string;
36
+ }
37
+ export interface FunctionCall {
38
+ name: string;
39
+ arguments: Record<string, unknown>;
40
+ }
41
+ export declare const TRIGGER_PHRASE = "You are a model that can do function calling with the following functions";
42
+ /** Stop sequences for generation (per docs; <end_function_call> is deliberately
43
+ * absent — parallel calls arrive in one turn). */
44
+ export declare const STOP_SEQUENCES: string[];
45
+ /** Render a call/response VALUE: keys sorted at every level (matches the
46
+ * template's dictsort — training/inference byte-parity), strings escaped,
47
+ * no uppercasing. null/undefined render as bare `null` — never trained, but
48
+ * reachable at runtime (get_state of an absent key) and must not throw. */
49
+ export declare function renderValue(v: unknown): string;
50
+ export declare function renderDeclaration(tool: ToolDef): string;
51
+ export declare function renderDeveloperTurn(tools: ToolDef[]): string;
52
+ export declare function renderUserTurn(text: string): string;
53
+ export declare function renderFunctionCall(call: FunctionCall): string;
54
+ export declare function renderFunctionResponse(name: string, response: unknown): string;
55
+ export interface ContextCell {
56
+ id: number;
57
+ /** RAW name — sample path/basename or `Engine(synth)`; sanitized here. */
58
+ name: string;
59
+ }
60
+ export interface AssistantContext {
61
+ bpm: number;
62
+ playing: boolean;
63
+ /** Current main view — the set_view tool's lowercase token vocabulary
64
+ * (fgemma_context.py CTX_VIEWS); absent renders as the default `cells`. */
65
+ view?: string;
66
+ /** Active preset display name (RAW — sanitized here); absent → `none`. */
67
+ preset?: string | null;
68
+ /** Selected cell id (1-based); null/undefined/0 renders as `none`. */
69
+ sel?: number | null;
70
+ /** Muted cell ids (1-based); omitted/empty renders as `none`. */
71
+ muted?: number[];
72
+ cells: ContextCell[];
73
+ }
74
+ /** Basename, one extension stripped, whitespace→_, grammar-safe, ≤24 chars.
75
+ * Must match fgemma_context.py `sanitize_label` step for step. */
76
+ export declare function sanitizeContextLabel(name: string): string;
77
+ /** The compact `[ctx]` session-state line (fixed field order, all fields
78
+ * always present) — pinned against fixtures/context_line.txt. */
79
+ export declare function renderContextLine(ctx: AssistantContext): string;
80
+ /** The exact user-turn content shape: ctx line, newline, raw text. */
81
+ export declare function withContext(userText: string, ctx?: AssistantContext | null): string;
82
+ export interface HistoryExchange {
83
+ /** RAW user text of the past exchange (history turns carry no ctx line). */
84
+ user: string;
85
+ /** The full model-turn inner text as generated/executed: call blocks +
86
+ * inline function responses + any final text. */
87
+ model: string;
88
+ }
89
+ /**
90
+ * Full generation prompt: declarations [+ completed history exchanges] +
91
+ * user turn + `<start_of_turn>model\n`.
92
+ * `bos: "text"` embeds the literal `<bos>` (matches the HF render exactly);
93
+ * `bos: "none"` (runner default) leaves BOS insertion to the serving layer.
94
+ * History stitching mirrors the chat template exactly (pinned by
95
+ * hf_followup_prompt.txt / hf_followup_text_prompt.txt): an exchange whose
96
+ * model turn ends in a function response leaves the turn OPEN — the next user
97
+ * content is inlined with no turn markers; a text-final turn is closed with
98
+ * `<end_of_turn>` and the next user turn opens normally.
99
+ */
100
+ export declare function buildGenerationPrompt(tools: ToolDef[], userText: string, opts?: {
101
+ bos?: "text" | "none";
102
+ history?: HistoryExchange[];
103
+ }): string;
104
+ /**
105
+ * Parse every `<start_function_call>call:name{…}<end_function_call>` block.
106
+ * Balanced-brace scan with <escape>-span awareness (the docs' flat reference
107
+ * regex cannot handle object/array argument values like update_pattern's
108
+ * sequence or get_state's keys).
109
+ */
110
+ export declare function parseFunctionCalls(text: string): FunctionCall[];
111
+ /**
112
+ * Cut a completion at the first model-FABRICATED function response. Serving
113
+ * stacks that strip special tokens from output (LM Studio; llama-server
114
+ * without --special) erase <start_function_response> before the stop-string
115
+ * matcher can see it, so generation runs on and invents response:{…} payloads
116
+ * plus follow-up calls conditioned on them. Text before the first fabricated
117
+ * response is the model's real intent; everything after must not be executed.
118
+ */
119
+ export declare function truncateAtFabricatedResponse(text: string): string;
@@ -0,0 +1,292 @@
1
+ /**
2
+ * FunctionGemma wire format — renderer + parser.
3
+ *
4
+ * Byte-parity with HF `tokenizer.apply_chat_template` is REQUIRED and pinned by
5
+ * scripts/check-fgemma-format.mjs against fixtures dumped by
6
+ * packages/fgemma-poc/dump_template_fixture.py. Empirical rules (from the
7
+ * fixtures, 2026-07-03, google/functiongemma-270m-it template):
8
+ *
9
+ * - Prompt starts with literal `<bos>` (template-added; serving layers that
10
+ * add BOS themselves must not receive it twice — see buildGenerationPrompt).
11
+ * - Developer turn: trigger phrase + declarations back-to-back, input order.
12
+ * - Schema objects render with keys sorted alphabetically at every level;
13
+ * `type` values are UPPERCASED; all schema strings are <escape>-wrapped.
14
+ * - Tool call/response argument objects ALSO sort keys at every level (the
15
+ * template dictsorts them — pinned by fixtures/hf_dictsort_probe.txt; the
16
+ * original fixtures were accidentally all-alphabetical and hid this);
17
+ * strings are <escape>-wrapped, numbers/booleans bare.
18
+ * - The tool call AND its function response live inside ONE continuous
19
+ * `model` turn: app appends `<start_function_response>response:…` inline
20
+ * and generation resumes — no new turn markers.
21
+ * - Multi-exchange history (fixtures hf_followup_prompt.txt /
22
+ * hf_followup_text_prompt.txt): a user message directly after a tool
23
+ * response is INLINED into the same model turn (no `<end_of_turn>` /
24
+ * `<start_of_turn>user` markers); a user message after assistant TEXT gets
25
+ * normal turn markers. buildGenerationPrompt's `history` option reproduces
26
+ * this byte-exactly.
27
+ * - Session context: `renderContextLine` renders the compact `[ctx]` state
28
+ * line prepended to the LAST user turn (grammar pinned against
29
+ * fixtures/context_line.txt; Python twin: packages/fgemma-poc/fgemma_context.py).
30
+ */
31
+ export const TRIGGER_PHRASE = "You are a model that can do function calling with the following functions";
32
+ /** Stop sequences for generation (per docs; <end_function_call> is deliberately
33
+ * absent — parallel calls arrive in one turn). */
34
+ export const STOP_SEQUENCES = ["<end_of_turn>", "<start_function_response>"];
35
+ const ESC = "<escape>";
36
+ function escStr(s) {
37
+ return `${ESC}${s}${ESC}`;
38
+ }
39
+ // Jinja's dictsort (what the chat template uses on every object) is
40
+ // case-INSENSITIVE by default; both sorts here must match it exactly.
41
+ // Stable sort keeps insertion order on lowercase ties, same as Python.
42
+ function byKeyDictsort([a], [b]) {
43
+ const la = a.toLowerCase();
44
+ const lb = b.toLowerCase();
45
+ return la < lb ? -1 : la > lb ? 1 : 0;
46
+ }
47
+ function renderNumber(n) {
48
+ if (!Number.isFinite(n))
49
+ throw new Error(`non-finite number in fgemma render: ${n}`);
50
+ return Number.isInteger(n) ? String(n) : String(n);
51
+ }
52
+ /** Render a JSON-Schema node in declaration position: keys sorted, `type`
53
+ * values uppercased, strings escaped. */
54
+ function renderSchema(node, keyIsType = false) {
55
+ if (typeof node === "string")
56
+ return escStr(keyIsType ? node.toUpperCase() : node);
57
+ if (typeof node === "number")
58
+ return renderNumber(node);
59
+ if (typeof node === "boolean")
60
+ return String(node);
61
+ if (Array.isArray(node))
62
+ return `[${node.map((v) => renderSchema(v)).join(",")}]`;
63
+ if (node && typeof node === "object") {
64
+ const entries = Object.entries(node)
65
+ .sort(byKeyDictsort)
66
+ .map(([k, v]) => `${k}:${renderSchema(v, k === "type")}`);
67
+ return `{${entries.join(",")}}`;
68
+ }
69
+ throw new Error(`unsupported schema node: ${JSON.stringify(node)}`);
70
+ }
71
+ /** Render a call/response VALUE: keys sorted at every level (matches the
72
+ * template's dictsort — training/inference byte-parity), strings escaped,
73
+ * no uppercasing. null/undefined render as bare `null` — never trained, but
74
+ * reachable at runtime (get_state of an absent key) and must not throw. */
75
+ export function renderValue(v) {
76
+ if (v === null || v === undefined)
77
+ return "null";
78
+ if (typeof v === "string")
79
+ return escStr(v);
80
+ if (typeof v === "number")
81
+ return renderNumber(v);
82
+ if (typeof v === "boolean")
83
+ return String(v);
84
+ if (Array.isArray(v))
85
+ return `[${v.map(renderValue).join(",")}]`;
86
+ if (typeof v === "object") {
87
+ const entries = Object.entries(v)
88
+ .sort(byKeyDictsort)
89
+ .map(([k, val]) => `${k}:${renderValue(val)}`);
90
+ return `{${entries.join(",")}}`;
91
+ }
92
+ throw new Error(`unsupported value in fgemma render: ${JSON.stringify(v)}`);
93
+ }
94
+ export function renderDeclaration(tool) {
95
+ const body = `{description:${escStr(tool.description)},parameters:${renderSchema(tool.parameters)}}`;
96
+ return `<start_function_declaration>declaration:${tool.name}${body}<end_function_declaration>`;
97
+ }
98
+ export function renderDeveloperTurn(tools) {
99
+ const decls = tools.map(renderDeclaration).join("");
100
+ return `<start_of_turn>developer\n${TRIGGER_PHRASE}${decls}<end_of_turn>\n`;
101
+ }
102
+ export function renderUserTurn(text) {
103
+ return `<start_of_turn>user\n${text}<end_of_turn>\n`;
104
+ }
105
+ export function renderFunctionCall(call) {
106
+ return `<start_function_call>call:${call.name}${renderValue(call.arguments)}<end_function_call>`;
107
+ }
108
+ export function renderFunctionResponse(name, response) {
109
+ return `<start_function_response>response:${name}${renderValue(response)}<end_function_response>`;
110
+ }
111
+ const LABEL_MAX = 24;
112
+ /** Basename, one extension stripped, whitespace→_, grammar-safe, ≤24 chars.
113
+ * Must match fgemma_context.py `sanitize_label` step for step. */
114
+ export function sanitizeContextLabel(name) {
115
+ let base = String(name).split(/[/\\]/).pop() ?? "";
116
+ base = base.replace(/\.[A-Za-z0-9]{1,4}$/, "");
117
+ base = base.replace(/\s+/g, "_");
118
+ base = base.replace(/[^A-Za-z0-9._#&+()'-]/g, "");
119
+ base = base.slice(0, LABEL_MAX);
120
+ return base || "sample";
121
+ }
122
+ /** The compact `[ctx]` session-state line (fixed field order, all fields
123
+ * always present) — pinned against fixtures/context_line.txt. */
124
+ export function renderContextLine(ctx) {
125
+ const cells = [...(ctx.cells ?? [])].sort((a, b) => a.id - b.id);
126
+ const cellStr = cells.map((c) => `${c.id}=${sanitizeContextLabel(c.name)}`).join(" ") || "none";
127
+ const sel = ctx.sel ? String(ctx.sel) : "none";
128
+ const preset = ctx.preset ? sanitizeContextLabel(ctx.preset) : "none";
129
+ const muted = [...new Set((ctx.muted ?? []).filter((id) => Number.isInteger(id) && id > 0))]
130
+ .sort((a, b) => a - b)
131
+ .join(",") || "none";
132
+ return `[ctx] bpm=${Math.round(ctx.bpm)} playing=${ctx.playing ? "yes" : "no"} view=${ctx.view || "cells"} preset=${preset} sel=${sel} muted:${muted} cells: ${cellStr}`;
133
+ }
134
+ /** The exact user-turn content shape: ctx line, newline, raw text. */
135
+ export function withContext(userText, ctx) {
136
+ return ctx ? `${renderContextLine(ctx)}\n${userText}` : userText;
137
+ }
138
+ /**
139
+ * Full generation prompt: declarations [+ completed history exchanges] +
140
+ * user turn + `<start_of_turn>model\n`.
141
+ * `bos: "text"` embeds the literal `<bos>` (matches the HF render exactly);
142
+ * `bos: "none"` (runner default) leaves BOS insertion to the serving layer.
143
+ * History stitching mirrors the chat template exactly (pinned by
144
+ * hf_followup_prompt.txt / hf_followup_text_prompt.txt): an exchange whose
145
+ * model turn ends in a function response leaves the turn OPEN — the next user
146
+ * content is inlined with no turn markers; a text-final turn is closed with
147
+ * `<end_of_turn>` and the next user turn opens normally.
148
+ */
149
+ export function buildGenerationPrompt(tools, userText, opts = {}) {
150
+ const bos = opts.bos === "text" ? "<bos>" : "";
151
+ let p = `${bos}${renderDeveloperTurn(tools)}`;
152
+ let inModelTurn = false;
153
+ for (const ex of opts.history ?? []) {
154
+ p += inModelTurn ? `${ex.user}<end_of_turn>\n` : renderUserTurn(ex.user);
155
+ p += `<start_of_turn>model\n${ex.model}`;
156
+ inModelTurn = ex.model.endsWith("<end_function_response>");
157
+ if (!inModelTurn)
158
+ p += "<end_of_turn>\n";
159
+ }
160
+ p += inModelTurn ? `${userText}<end_of_turn>\n` : renderUserTurn(userText);
161
+ return `${p}<start_of_turn>model\n`;
162
+ }
163
+ // --- Parser ------------------------------------------------------------
164
+ const CALL_OPEN = "<start_function_call>call:";
165
+ const CALL_CLOSE = "<end_function_call>";
166
+ /**
167
+ * Parse every `<start_function_call>call:name{…}<end_function_call>` block.
168
+ * Balanced-brace scan with <escape>-span awareness (the docs' flat reference
169
+ * regex cannot handle object/array argument values like update_pattern's
170
+ * sequence or get_state's keys).
171
+ */
172
+ export function parseFunctionCalls(text) {
173
+ const calls = [];
174
+ let idx = 0;
175
+ for (;;) {
176
+ const start = text.indexOf(CALL_OPEN, idx);
177
+ if (start === -1)
178
+ break;
179
+ let p = start + CALL_OPEN.length;
180
+ const braceAt = text.indexOf("{", p);
181
+ if (braceAt === -1)
182
+ break;
183
+ const name = text.slice(p, braceAt).trim();
184
+ let value;
185
+ let endPos;
186
+ try {
187
+ [value, endPos] = parseValueAt(text, braceAt);
188
+ }
189
+ catch {
190
+ idx = braceAt + 1; // malformed value (e.g. truncation) — skip block, keep scanning
191
+ continue;
192
+ }
193
+ const closeAt = text.indexOf(CALL_CLOSE, endPos);
194
+ if (closeAt === -1 || text.slice(endPos, closeAt).trim() !== "") {
195
+ idx = endPos;
196
+ continue; // malformed block — skip, keep scanning
197
+ }
198
+ if (name && value && typeof value === "object" && !Array.isArray(value)) {
199
+ calls.push({ name, arguments: value });
200
+ }
201
+ idx = closeAt + CALL_CLOSE.length;
202
+ }
203
+ return calls;
204
+ }
205
+ /**
206
+ * Cut a completion at the first model-FABRICATED function response. Serving
207
+ * stacks that strip special tokens from output (LM Studio; llama-server
208
+ * without --special) erase <start_function_response> before the stop-string
209
+ * matcher can see it, so generation runs on and invents response:{…} payloads
210
+ * plus follow-up calls conditioned on them. Text before the first fabricated
211
+ * response is the model's real intent; everything after must not be executed.
212
+ */
213
+ export function truncateAtFabricatedResponse(text) {
214
+ let cut = text.length;
215
+ const tagAt = text.indexOf("<start_function_response>");
216
+ if (tagAt !== -1)
217
+ cut = Math.min(cut, tagAt);
218
+ const bare = /<end_function_call>\s*response:/.exec(text);
219
+ if (bare)
220
+ cut = Math.min(cut, bare.index + CALL_CLOSE.length);
221
+ if (/^\s*response:/.test(text))
222
+ cut = 0;
223
+ return cut === text.length ? text : text.slice(0, cut);
224
+ }
225
+ function skipWs(text, p) {
226
+ while (p < text.length && /\s/.test(text[p]))
227
+ p++;
228
+ return p;
229
+ }
230
+ /** Parse one value starting at `p`; returns [value, positionAfter]. */
231
+ function parseValueAt(text, p) {
232
+ p = skipWs(text, p);
233
+ if (text.startsWith(ESC, p)) {
234
+ const end = text.indexOf(ESC, p + ESC.length);
235
+ if (end === -1)
236
+ throw new Error("unterminated <escape> string");
237
+ return [text.slice(p + ESC.length, end), end + ESC.length];
238
+ }
239
+ if (text[p] === "{") {
240
+ const obj = {};
241
+ p = skipWs(text, p + 1);
242
+ if (text[p] === "}")
243
+ return [obj, p + 1];
244
+ for (;;) {
245
+ const colon = text.indexOf(":", p);
246
+ if (colon === -1)
247
+ throw new Error("missing ':' in object");
248
+ const key = text.slice(p, colon).trim();
249
+ const [val, after] = parseValueAt(text, colon + 1);
250
+ obj[key] = val;
251
+ p = skipWs(text, after);
252
+ if (text[p] === ",") {
253
+ p = skipWs(text, p + 1);
254
+ continue;
255
+ }
256
+ if (text[p] === "}")
257
+ return [obj, p + 1];
258
+ throw new Error(`expected ',' or '}' at ${p}: …${text.slice(p, p + 24)}`);
259
+ }
260
+ }
261
+ if (text[p] === "[") {
262
+ const arr = [];
263
+ p = skipWs(text, p + 1);
264
+ if (text[p] === "]")
265
+ return [arr, p + 1];
266
+ for (;;) {
267
+ const [val, after] = parseValueAt(text, p);
268
+ arr.push(val);
269
+ p = skipWs(text, after);
270
+ if (text[p] === ",") {
271
+ p = skipWs(text, p + 1);
272
+ continue;
273
+ }
274
+ if (text[p] === "]")
275
+ return [arr, p + 1];
276
+ throw new Error(`expected ',' or ']' at ${p}`);
277
+ }
278
+ }
279
+ // bare scalar: number / boolean / unquoted string — ends at , } ] or a tag
280
+ let end = p;
281
+ while (end < text.length && !",}]<".includes(text[end]))
282
+ end++;
283
+ const raw = text.slice(p, end).trim();
284
+ if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(raw))
285
+ return [Number(raw), end];
286
+ if (raw === "true")
287
+ return [true, end];
288
+ if (raw === "false")
289
+ return [false, end];
290
+ return [raw, end];
291
+ }
292
+ //# sourceMappingURL=fgemma-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fgemma-format.js","sourceRoot":"","sources":["../src/fgemma-format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ /**
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),
5
+ * NOT the OpenAI chat+tools API: raw /completions + our own renderer/parser is
6
+ * deterministic and byte-matches training (agent.ts remains the big-model
7
+ * OpenAI-style baseline harness).
8
+ *
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]
13
+ *
14
+ * Flags: --toolpack <path> --bos text|none (default none; use text if the
15
+ * serving layer does NOT add BOS itself) --max-tokens N --final (generate a
16
+ * model NL summary after write-tool calls; read-tools always continue)
17
+ * --no-ctx (skip the live [ctx] session line).
18
+ *
19
+ * Session context (dataset v3): each command's user turn is prefixed with the
20
+ * [ctx] state line built live from the bridge (get_transport +
21
+ * get_design_overview; sel is UI-only so it renders `none` here). The REPL
22
+ * additionally threads the last completed exchanges as history — the same
23
+ * shapes the in-plugin executor produces. Within one command the runner does
24
+ * up to MAX_ROUNDS call→response continuations inside the same model turn
25
+ * (the trained repair/introspect pattern).
26
+ */
27
+ export {};