Skip to main content
Glama
classListFormatter.ts6.67 kB
/** * Class List Formatter * * Formats TouchDesigner Python class/module lists with token optimization. * Used by GET_TD_CLASSES and GET_TD_CLASS_DETAILS tools. */ import type { TdPythonClassDetails, TdPythonClassInfo, } from "../../../gen/endpoints/TouchDesignerAPI.js"; import { DEFAULT_PRESENTER_FORMAT, type PresenterFormat, presentStructuredData, } from "./presenter.js"; import type { FormatterOptions } from "./responseFormatter.js"; import { finalizeFormattedText, limitArray, mergeFormatterOptions, } from "./responseFormatter.js"; /** * Class list data structure (matches API response) */ export interface ClassListData { classes?: TdPythonClassInfo[]; modules?: string[]; totalCount?: number; [key: string]: unknown; } /** * Class details data structure (matches API response) */ export type ClassDetailsData = TdPythonClassDetails; /** * Format class/module list */ export function formatClassList( data: ClassListData | undefined, options?: FormatterOptions, ): string { const opts = mergeFormatterOptions(options); if (!data) { return "No classes or modules found."; } const classes = data.classes || []; const modules = data.modules || []; const total = classes.length + modules.length; if (total === 0) { return "No classes or modules found."; } if (opts.detailLevel === "detailed") { return formatDetailed(data, opts.responseFormat); } const { text, context } = opts.detailLevel === "minimal" ? formatClassListMinimal(classes, modules, opts.limit) : formatClassListSummary(classes, modules, opts.limit); const ctx = context as Record<string, unknown>; return finalizeFormattedText(text, opts, { context: ctx, structured: ctx, template: "classListSummary", }); } /** * Format class details */ export function formatClassDetails( data: ClassDetailsData | undefined, options?: FormatterOptions, ): string { const opts = mergeFormatterOptions(options); if (!data || !data.name) { return "No class details available."; } if (opts.detailLevel === "detailed") { return formatDetailed(data, opts.responseFormat); } const { text, context } = opts.detailLevel === "minimal" ? formatClassDetailsMinimal(data) : formatClassDetailsSummary(data, opts.limit); const ctx = context as Record<string, unknown>; return finalizeFormattedText(text, opts, { context: ctx, structured: ctx, template: "classDetailsSummary", }); } function formatClassListMinimal( classes: TdPythonClassInfo[], modules: string[], limit?: number, ) { const { items: limitedClasses, truncated: classTruncated } = limitArray( classes, limit, ); let text = `Classes (${classes.length}): ${limitedClasses .map((c) => c.name) .join(", ")}`; if (classTruncated) { text += `\n💡 ${classes.length - limitedClasses.length} more classes omitted.`; } if (modules.length > 0) { text += `\nModules (${modules.length}): ${modules.join(", ")}`; } return { context: buildClassListContext(classes, modules), text, }; } function formatClassListSummary( classes: TdPythonClassInfo[], modules: string[], limit?: number, ) { const { items: limitedClasses } = limitArray(classes, limit); const text = `Classes (${classes.length}):\n${limitedClasses .map((c) => `- ${c.name} — ${c.description || ""}`) .join("\n")}\n\nModules (${modules.length}):\n${modules .map((m) => `- ${m}`) .join("\n")}`; return { context: buildClassListContext(classes, modules), text, }; } function buildClassListContext( classes: TdPythonClassInfo[], modules: string[], ) { return { classCount: classes.length, classes: classes.map((cls) => ({ description: cls.description, name: cls.name, })), moduleCount: modules.length, modules, }; } function formatClassDetailsMinimal(data: ClassDetailsData) { const text = `Class: ${data.name}\nType: ${data.type}`; return { context: { description: data.description, methods: [], methodsShown: 0, methodsTotal: data.methods?.length ?? 0, name: data.name, properties: [], propertiesShown: 0, propertiesTotal: data.properties?.length ?? 0, truncated: false, type: data.type, }, text, }; } function formatClassDetailsSummary(data: ClassDetailsData, limit?: number) { const methods = data.methods || []; const properties = data.properties || []; const { items: limitedMethods, truncated: methodsTruncated } = limitArray( methods, limit, ); const { items: limitedProps, truncated: propsTruncated } = limitArray( properties, limit, ); let text = `${data.name}`; if (data.type) text += ` (${data.type})`; text += "\n"; if (data.description) { text += `\n${data.description}\n`; } if (limitedMethods.length > 0) { text += `\nMETHODS (${methods.length}):\n`; for (const method of limitedMethods) { const sig = method.signature || `${method.name}()`; const doc = method.description ? ` - ${method.description.split("\n")[0]}` : ""; text += ` • ${sig}${doc}\n`; } if (methodsTruncated) { text += ` 💡 ${methods.length - limitedMethods.length} more methods omitted.\n`; } } if (limitedProps.length > 0) { text += `\nPROPERTIES (${properties.length}):\n`; for (const prop of limitedProps) { const typeInfo = prop.type ? `: ${prop.type}` : ""; const valueInfo = prop.value !== undefined ? ` = ${JSON.stringify(prop.value)}` : ""; text += ` • ${prop.name}${typeInfo}${valueInfo}\n`; } if (propsTruncated) { text += ` 💡 ${properties.length - limitedProps.length} more properties omitted.\n`; } } return { context: { description: data.description, methods: limitedMethods.map((method) => ({ signature: method.signature || `${method.name}()`, summary: method.description?.split("\n")[0] ?? "", })), methodsShown: limitedMethods.length, methodsTotal: methods.length, name: data.name, properties: limitedProps.map((prop) => ({ name: prop.name, type: prop.type, })), propertiesShown: limitedProps.length, propertiesTotal: properties.length, truncated: methodsTruncated || propsTruncated, type: data.type, }, text, }; } function formatDetailed( data: ClassListData | ClassDetailsData, format: PresenterFormat | undefined, ): string { const title = "name" in (data as ClassDetailsData) ? `Class ${(data as ClassDetailsData).name ?? "details"}` : "TouchDesigner Classes"; const payloadFormat = format ?? DEFAULT_PRESENTER_FORMAT; return presentStructuredData( { context: { payloadFormat, title, }, detailLevel: "detailed", structured: data, template: "detailedPayload", text: title, }, payloadFormat, ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8beeeaaat/touchdesigner-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server