dist-mcp / mcp / sourceNotation.js
dist-mcp / mcp / sourceNotation.js
export const ATTACHMENT_NOTATION = /^a([1-9]\d*|n)?$/i;
export class UnsupportedAttachmentNotationError extends Error {
constructor(value) {
super(`Source "${value}" uses LM-Studio attachment notation (aN), which is not supported here. ` +
`Use load_file_attachment first, then pass the resulting scratchpad filename as the source instead.`);
this.name = "UnsupportedAttachmentNotationError";
}
}
function rejectIfAttachmentNotation(value) {
if (typeof value !== "string")
return;
const trimmed = value.trim();
if (ATTACHMENT_NOTATION.test(trimmed)) {
throw new UnsupportedAttachmentNotationError(trimmed);
}
}
/** No-ops entirely for the unsloth preset (see module doc comment above). */
export function assertNoAttachmentNotation(args, preset) {
if (preset.name === "unsloth")
return;
const { canvas, moodboard } = args;
if (Array.isArray(canvas)) {
canvas.forEach(rejectIfAttachmentNotation);
}
else {
rejectIfAttachmentNotation(canvas);
}
if (Array.isArray(moodboard)) {
moodboard.forEach(rejectIfAttachmentNotation);
}
else if (typeof moodboard === "string") {
// moodboard also accepts a comma/space-separated string (see SourceNotationList in schemas.ts).
moodboard.split(/[\s,]+/).forEach(rejectIfAttachmentNotation);
}
}
/** Collects every aN-shaped token out of canvas/moodboard, deduplicated — used to feed
* McpResultPreset.beforeToolCall()'s `attachmentTokens` (unsloth only). */
export function collectAttachmentTokens(args) {
const { canvas, moodboard } = args;
const tokens = new Set();
const consider = (value) => {
if (typeof value !== "string")
return;
const trimmed = value.trim();
if (ATTACHMENT_NOTATION.test(trimmed))
tokens.add(trimmed);
};
if (Array.isArray(canvas))
canvas.forEach(consider);
else
consider(canvas);
if (Array.isArray(moodboard))
moodboard.forEach(consider);
else if (typeof moodboard === "string")
moodboard.split(/[\s,]+/).forEach(consider);
return [...tokens];
}
// No separate path-resolution step here: core/tools.ts's own handlers already parse and resolve
// canvas/moodboard themselves (notation, comma/space-separated string, or a scratchpad
// basename/absolute path). Re-resolving here duplicated that logic with a second implementation.
export const ATTACHMENT_NOTATION = /^a([1-9]\d*|n)?$/i;
export class UnsupportedAttachmentNotationError extends Error {
constructor(value) {
super(`Source "${value}" uses LM-Studio attachment notation (aN), which is not supported here. ` +
`Use load_file_attachment first, then pass the resulting scratchpad filename as the source instead.`);
this.name = "UnsupportedAttachmentNotationError";
}
}
function rejectIfAttachmentNotation(value) {
if (typeof value !== "string")
return;
const trimmed = value.trim();
if (ATTACHMENT_NOTATION.test(trimmed)) {
throw new UnsupportedAttachmentNotationError(trimmed);
}
}
/** No-ops entirely for the unsloth preset (see module doc comment above). */
export function assertNoAttachmentNotation(args, preset) {
if (preset.name === "unsloth")
return;
const { canvas, moodboard } = args;
if (Array.isArray(canvas)) {
canvas.forEach(rejectIfAttachmentNotation);
}
else {
rejectIfAttachmentNotation(canvas);
}
if (Array.isArray(moodboard)) {
moodboard.forEach(rejectIfAttachmentNotation);
}
else if (typeof moodboard === "string") {
// moodboard also accepts a comma/space-separated string (see SourceNotationList in schemas.ts).
moodboard.split(/[\s,]+/).forEach(rejectIfAttachmentNotation);
}
}
/** Collects every aN-shaped token out of canvas/moodboard, deduplicated — used to feed
* McpResultPreset.beforeToolCall()'s `attachmentTokens` (unsloth only). */
export function collectAttachmentTokens(args) {
const { canvas, moodboard } = args;
const tokens = new Set();
const consider = (value) => {
if (typeof value !== "string")
return;
const trimmed = value.trim();
if (ATTACHMENT_NOTATION.test(trimmed))
tokens.add(trimmed);
};
if (Array.isArray(canvas))
canvas.forEach(consider);
else
consider(canvas);
if (Array.isArray(moodboard))
moodboard.forEach(consider);
else if (typeof moodboard === "string")
moodboard.split(/[\s,]+/).forEach(consider);
return [...tokens];
}
// No separate path-resolution step here: core/tools.ts's own handlers already parse and resolve
// canvas/moodboard themselves (notation, comma/space-separated string, or a scratchpad
// basename/absolute path). Re-resolving here duplicated that logic with a second implementation.