Skip to content

Commit 8df5c44

Browse files
committed
replace courseWare question type lookup with ...
reconstructed dataShape from a schema definition
1 parent c7a0037 commit 8df5c44

File tree

1 file changed

+62
-16
lines changed

1 file changed

+62
-16
lines changed

packages/mcp/src/tools/create-card.ts

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import {
44
type CreateCardInput,
55
type CreateCardOutput,
66
} from '../types/tools.js';
7-
import { toCourseElo, NameSpacer } from '@vue-skuilder/common';
8-
import { getAllDataShapesRaw } from '@vue-skuilder/courseware/backend';
7+
import { toCourseElo, NameSpacer, FieldType, type DataShape, type FieldDefinition } from '@vue-skuilder/common';
98
import {
109
MCP_AGENT_AUTHOR,
1110
handleToolError,
@@ -14,6 +13,58 @@ import {
1413
logToolWarning,
1514
} from '../utils/index.js';
1615

16+
/**
17+
* Reconstructs a minimal DataShape from course config's serialized JSON Schema
18+
* Only extracts field names and types - no validators or custom logic
19+
*/
20+
function reconstructDataShapeFromConfig(
21+
dataShapeName: string,
22+
serializedSchema: string
23+
): DataShape {
24+
const jsonSchema = JSON.parse(serializedSchema);
25+
const fields: FieldDefinition[] = [];
26+
27+
if (jsonSchema.properties) {
28+
for (const [fieldName, fieldSchema] of Object.entries(jsonSchema.properties)) {
29+
const schema = fieldSchema as any;
30+
31+
// Map JSON Schema types to FieldType enum
32+
let fieldType: FieldType = FieldType.STRING; // default
33+
34+
if (schema.type === 'string') {
35+
if (schema.contentEncoding === 'base64' || fieldName.toLowerCase().includes('image')) {
36+
fieldType = FieldType.IMAGE;
37+
} else if (fieldName.toLowerCase().includes('audio')) {
38+
fieldType = FieldType.AUDIO;
39+
} else if (schema.description?.includes('Markdown') || schema.description?.includes('markdown')) {
40+
fieldType = FieldType.MARKDOWN;
41+
} else {
42+
fieldType = FieldType.STRING;
43+
}
44+
} else if (schema.type === 'number') {
45+
fieldType = FieldType.NUMBER;
46+
} else if (schema.type === 'integer') {
47+
fieldType = FieldType.INT;
48+
} else if (schema.type === 'array') {
49+
// Check if it's uploads/media
50+
if (fieldName === 'Uploads' || fieldName.toLowerCase().includes('upload')) {
51+
fieldType = FieldType.MEDIA_UPLOADS;
52+
}
53+
}
54+
55+
fields.push({
56+
name: fieldName,
57+
type: fieldType,
58+
});
59+
}
60+
}
61+
62+
return {
63+
name: dataShapeName as any, // Cast to DataShapeName - it's just a string at runtime
64+
fields,
65+
};
66+
}
67+
1768
export async function handleCreateCard(
1869
courseDB: CourseDBInterface,
1970
input: CreateCardInput
@@ -56,7 +107,7 @@ export async function handleCreateCard(
56107
throw new Error(errorMsg);
57108
}
58109

59-
// Get the complete DataShape definition from course config
110+
// Get the DataShape definition from course config
60111
const matchingDataShape = courseConfig.dataShapes.find(
61112
(ds) => ds.name === validatedInput.datashape
62113
);
@@ -66,24 +117,19 @@ export async function handleCreateCard(
66117
throw new Error(errorMsg);
67118
}
68119

69-
// Get runtime DataShape definition from courseware
70-
const runtimeDataShape = getAllDataShapesRaw()
71-
.find((ds) => ds.name === shapeDescriptor.dataShape);
72-
73-
if (!runtimeDataShape) {
74-
const errorMsg = `Runtime DataShape not found in courseware: ${shapeDescriptor.dataShape}`;
75-
logToolWarning(TOOL_NAME, errorMsg);
76-
throw new Error(errorMsg);
77-
}
120+
// Reconstruct DataShape from course config's serialized schema
121+
// This bypasses the need for runtime courseware loading - we only need
122+
// field names and types, which we can derive from the JSON Schema
123+
const dataShape = reconstructDataShapeFromConfig(
124+
shapeDescriptor.dataShape,
125+
matchingDataShape.serializedZodSchema!
126+
);
78127

79128
logToolStart(
80129
TOOL_NAME,
81-
`Using runtime DataShape with ${runtimeDataShape.fields.length} fields`
130+
`Using DataShape with ${dataShape.fields.length} fields (reconstructed from course config)`
82131
);
83132

84-
// Use complete DataShape with field definitions from courseware
85-
const dataShape = runtimeDataShape;
86-
87133
// Create the card via courseDB
88134
const result = await courseDB.addNote(
89135
shapeDescriptor.course, // Use courseware name, not courseID

0 commit comments

Comments
 (0)