@lydt/geogebra-studio 0.0.0-stage → 0.4.0-rc.2

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 (189) hide show
  1. package/.agents/plugins/marketplace.json +21 -0
  2. package/.codex-plugin/plugin.json +21 -0
  3. package/.mcp.json +18 -0
  4. package/LICENSE +339 -0
  5. package/LICENSE-MIT +21 -0
  6. package/README.md +108 -2
  7. package/README.zh-CN.md +89 -0
  8. package/THIRD_PARTY_NOTICES.md +35 -0
  9. package/dist/cli.d.ts +27 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +234 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/export/files.d.ts +4 -0
  14. package/dist/export/files.d.ts.map +1 -0
  15. package/dist/export/files.js +44 -0
  16. package/dist/export/files.js.map +1 -0
  17. package/dist/export/gikz.d.ts +11 -0
  18. package/dist/export/gikz.d.ts.map +1 -0
  19. package/dist/export/gikz.js +28 -0
  20. package/dist/export/gikz.js.map +1 -0
  21. package/dist/export/html.d.ts +14 -0
  22. package/dist/export/html.d.ts.map +1 -0
  23. package/dist/export/html.js +97 -0
  24. package/dist/export/html.js.map +1 -0
  25. package/dist/export/semantic.d.ts +43 -0
  26. package/dist/export/semantic.d.ts.map +1 -0
  27. package/dist/export/semantic.js +212 -0
  28. package/dist/export/semantic.js.map +1 -0
  29. package/dist/export/viewer-themes.d.ts +76 -0
  30. package/dist/export/viewer-themes.d.ts.map +1 -0
  31. package/dist/export/viewer-themes.js +169 -0
  32. package/dist/export/viewer-themes.js.map +1 -0
  33. package/dist/export/workspace.d.ts +4 -0
  34. package/dist/export/workspace.d.ts.map +1 -0
  35. package/dist/export/workspace.js +25 -0
  36. package/dist/export/workspace.js.map +1 -0
  37. package/dist/gikz-browser.js +770 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +84 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/server.d.ts +35 -0
  43. package/dist/server.d.ts.map +1 -0
  44. package/dist/server.js +187 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/studio/artifact.d.ts +37 -0
  47. package/dist/studio/artifact.d.ts.map +1 -0
  48. package/dist/studio/artifact.js +61 -0
  49. package/dist/studio/artifact.js.map +1 -0
  50. package/dist/studio/browser.d.ts +7 -0
  51. package/dist/studio/browser.d.ts.map +1 -0
  52. package/dist/studio/browser.js +67 -0
  53. package/dist/studio/browser.js.map +1 -0
  54. package/dist/studio/install.d.ts +4 -0
  55. package/dist/studio/install.d.ts.map +1 -0
  56. package/dist/studio/install.js +60 -0
  57. package/dist/studio/install.js.map +1 -0
  58. package/dist/tools/apps-api-tools.d.ts +4 -0
  59. package/dist/tools/apps-api-tools.d.ts.map +1 -0
  60. package/dist/tools/apps-api-tools.js +96 -0
  61. package/dist/tools/apps-api-tools.js.map +1 -0
  62. package/dist/tools/educational-templates.d.ts +33 -0
  63. package/dist/tools/educational-templates.d.ts.map +1 -0
  64. package/dist/tools/educational-templates.js +261 -0
  65. package/dist/tools/educational-templates.js.map +1 -0
  66. package/dist/tools/export-tools.d.ts +3 -0
  67. package/dist/tools/export-tools.d.ts.map +1 -0
  68. package/dist/tools/export-tools.js +118 -0
  69. package/dist/tools/export-tools.js.map +1 -0
  70. package/dist/tools/geogebra-tools.d.ts +15 -0
  71. package/dist/tools/geogebra-tools.d.ts.map +1 -0
  72. package/dist/tools/geogebra-tools.js +3442 -0
  73. package/dist/tools/geogebra-tools.js.map +1 -0
  74. package/dist/tools/index.d.ts +43 -0
  75. package/dist/tools/index.d.ts.map +1 -0
  76. package/dist/tools/index.js +183 -0
  77. package/dist/tools/index.js.map +1 -0
  78. package/dist/tools/performance-tools.d.ts +7 -0
  79. package/dist/tools/performance-tools.d.ts.map +1 -0
  80. package/dist/tools/performance-tools.js +312 -0
  81. package/dist/tools/performance-tools.js.map +1 -0
  82. package/dist/tools/templates/algebra-templates.d.ts +7 -0
  83. package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
  84. package/dist/tools/templates/algebra-templates.js +568 -0
  85. package/dist/tools/templates/algebra-templates.js.map +1 -0
  86. package/dist/tools/templates/geometry-templates.d.ts +7 -0
  87. package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
  88. package/dist/tools/templates/geometry-templates.js +492 -0
  89. package/dist/tools/templates/geometry-templates.js.map +1 -0
  90. package/dist/types/geogebra.d.ts +103 -0
  91. package/dist/types/geogebra.d.ts.map +1 -0
  92. package/dist/types/geogebra.js +34 -0
  93. package/dist/types/geogebra.js.map +1 -0
  94. package/dist/types/mcp.d.ts +125 -0
  95. package/dist/types/mcp.d.ts.map +1 -0
  96. package/dist/types/mcp.js +19 -0
  97. package/dist/types/mcp.js.map +1 -0
  98. package/dist/utils/app-info.d.ts +12 -0
  99. package/dist/utils/app-info.d.ts.map +1 -0
  100. package/dist/utils/app-info.js +30 -0
  101. package/dist/utils/app-info.js.map +1 -0
  102. package/dist/utils/errors.d.ts +37 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +72 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/gemini-compatibility.d.ts +39 -0
  107. package/dist/utils/gemini-compatibility.d.ts.map +1 -0
  108. package/dist/utils/gemini-compatibility.js +154 -0
  109. package/dist/utils/gemini-compatibility.js.map +1 -0
  110. package/dist/utils/geogebra-instance.d.ts +252 -0
  111. package/dist/utils/geogebra-instance.d.ts.map +1 -0
  112. package/dist/utils/geogebra-instance.js +1560 -0
  113. package/dist/utils/geogebra-instance.js.map +1 -0
  114. package/dist/utils/geogebra-mock.d.ts +172 -0
  115. package/dist/utils/geogebra-mock.d.ts.map +1 -0
  116. package/dist/utils/geogebra-mock.js +732 -0
  117. package/dist/utils/geogebra-mock.js.map +1 -0
  118. package/dist/utils/logger.d.ts +4 -0
  119. package/dist/utils/logger.d.ts.map +1 -0
  120. package/dist/utils/logger.js +46 -0
  121. package/dist/utils/logger.js.map +1 -0
  122. package/dist/utils/performance/index.d.ts +76 -0
  123. package/dist/utils/performance/index.d.ts.map +1 -0
  124. package/dist/utils/performance/index.js +163 -0
  125. package/dist/utils/performance/index.js.map +1 -0
  126. package/dist/utils/performance/instance-pool.d.ts +78 -0
  127. package/dist/utils/performance/instance-pool.d.ts.map +1 -0
  128. package/dist/utils/performance/instance-pool.js +268 -0
  129. package/dist/utils/performance/instance-pool.js.map +1 -0
  130. package/dist/utils/validation.d.ts +92 -0
  131. package/dist/utils/validation.d.ts.map +1 -0
  132. package/dist/utils/validation.js +557 -0
  133. package/dist/utils/validation.js.map +1 -0
  134. package/dist/widget.html +110 -0
  135. package/docs/APPS-API-BRIDGE.md +28 -0
  136. package/docs/MODERNIZATION.md +15 -0
  137. package/docs/TANGENT-REGRESSION.md +34 -0
  138. package/docs/VALIDATION.md +26 -0
  139. package/docs/VISUAL-STANDARD.md +26 -0
  140. package/docs/images/native-construction.png +0 -0
  141. package/examples/tangent-construction.json +26 -0
  142. package/gikz/LICENSE +339 -0
  143. package/gikz/PROVENANCE.md +8 -0
  144. package/gikz/browser.cjs +2 -0
  145. package/gikz/cli.cjs +195 -0
  146. package/gikz/core.cjs +806 -0
  147. package/mcp.json +20 -0
  148. package/package.json +107 -4
  149. package/plugin.json +35 -0
  150. package/runtime/package.json +4 -0
  151. package/scripts/build-plugin.cjs +15 -0
  152. package/scripts/build-widget.cjs +7 -0
  153. package/skills/geogebra-construct/SKILL.md +40 -0
  154. package/skills/geogebra-setup/SKILL.md +37 -0
  155. package/skills/geometry-export/SKILL.md +31 -0
  156. package/src/cli.ts +212 -0
  157. package/src/export/files.ts +26 -0
  158. package/src/export/gikz.ts +22 -0
  159. package/src/export/html.ts +108 -0
  160. package/src/export/semantic.ts +180 -0
  161. package/src/export/viewer-themes.ts +165 -0
  162. package/src/export/workspace.ts +15 -0
  163. package/src/index.ts +71 -0
  164. package/src/server.ts +168 -0
  165. package/src/studio/artifact.ts +50 -0
  166. package/src/studio/browser.ts +38 -0
  167. package/src/studio/install.ts +43 -0
  168. package/src/tools/apps-api-tools.ts +96 -0
  169. package/src/tools/educational-templates.ts +299 -0
  170. package/src/tools/export-tools.ts +110 -0
  171. package/src/tools/geogebra-tools.ts +3836 -0
  172. package/src/tools/index.ts +192 -0
  173. package/src/tools/performance-tools.ts +322 -0
  174. package/src/tools/templates/algebra-templates.ts +619 -0
  175. package/src/tools/templates/geometry-templates.ts +550 -0
  176. package/src/types/geogebra.ts +140 -0
  177. package/src/types/global.d.ts +31 -0
  178. package/src/types/mcp.ts +141 -0
  179. package/src/utils/app-info.ts +35 -0
  180. package/src/utils/errors.ts +97 -0
  181. package/src/utils/gemini-compatibility.ts +193 -0
  182. package/src/utils/geogebra-instance.ts +1712 -0
  183. package/src/utils/geogebra-mock.ts +867 -0
  184. package/src/utils/logger.ts +60 -0
  185. package/src/utils/performance/index.ts +211 -0
  186. package/src/utils/performance/instance-pool.ts +323 -0
  187. package/src/utils/validation.ts +647 -0
  188. package/tsconfig.json +35 -0
  189. package/widget/main.ts +12 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Global type declarations for GeoGebra integration
3
+ */
4
+
5
+ declare global {
6
+ interface Window {
7
+ ggbApplet: {
8
+ evalCommand(command: string): boolean;
9
+ evalCommandGetLabels(command: string): string;
10
+ deleteObject(objName: string): void;
11
+ exists(objName: string): boolean;
12
+ isDefined(objName: string): boolean;
13
+ getAllObjectNames(type?: string): string[];
14
+ getObjectType(objName: string): string;
15
+ getValue(objName: string): number;
16
+ getValueString(objName: string): string;
17
+ getVisible(objName: string): boolean;
18
+ getXcoord(objName: string): number;
19
+ getYcoord(objName: string): number;
20
+ getZcoord(objName: string): number;
21
+ getColor(objName: string): string;
22
+ newConstruction(): void;
23
+ reset(): void;
24
+ refreshViews(): void;
25
+ };
26
+ ggbReady: boolean;
27
+ ggbOnInit: () => void;
28
+ }
29
+ }
30
+
31
+ export {};
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Model Context Protocol (MCP) Types
3
+ * Following JSON-RPC 2.0 specification
4
+ */
5
+
6
+ // JSON-RPC 2.0 Base Types
7
+ export interface JsonRpcRequest {
8
+ jsonrpc: '2.0';
9
+ method: string;
10
+ params?: Record<string, unknown> | unknown[];
11
+ id?: string | number | null;
12
+ }
13
+
14
+ export interface JsonRpcResponse {
15
+ jsonrpc: '2.0';
16
+ result?: unknown;
17
+ error?: JsonRpcError;
18
+ id: string | number | null;
19
+ }
20
+
21
+ export interface JsonRpcError {
22
+ code: number;
23
+ message: string;
24
+ data?: unknown;
25
+ }
26
+
27
+ // MCP Protocol - Initialize
28
+ export interface McpInitializeRequest extends JsonRpcRequest {
29
+ method: 'initialize';
30
+ params: {
31
+ protocolVersion: string;
32
+ capabilities: {
33
+ tools?: {};
34
+ [key: string]: unknown;
35
+ };
36
+ clientInfo: {
37
+ name: string;
38
+ version: string;
39
+ };
40
+ };
41
+ }
42
+
43
+ export interface McpInitializeResponse extends JsonRpcResponse {
44
+ result?: {
45
+ protocolVersion: string;
46
+ capabilities: {
47
+ tools?: {
48
+ listChanged?: boolean;
49
+ };
50
+ [key: string]: unknown;
51
+ };
52
+ serverInfo: {
53
+ name: string;
54
+ version: string;
55
+ };
56
+ };
57
+ error?: JsonRpcError;
58
+ }
59
+
60
+ // MCP Protocol - Initialized Notification
61
+ export interface McpInitializedNotification extends JsonRpcRequest {
62
+ method: 'notifications/initialized';
63
+ params?: Record<string, never>;
64
+ }
65
+
66
+ // MCP Specific Types
67
+ export interface McpTool {
68
+ name: string;
69
+ description: string;
70
+ annotations?: { readOnlyHint: boolean; destructiveHint: boolean; idempotentHint: boolean; openWorldHint: boolean };
71
+ outputSchema?: Record<string, unknown>;
72
+ _meta?: Record<string, unknown>;
73
+ inputSchema: {
74
+ type: 'object';
75
+ properties: Record<string, unknown>;
76
+ required?: string[];
77
+ [key: string]: unknown; // Allow additional JSON Schema properties
78
+ };
79
+ }
80
+
81
+ export interface McpToolsListRequest extends JsonRpcRequest {
82
+ method: 'tools/list';
83
+ params?: Record<string, never>;
84
+ }
85
+
86
+ export interface McpToolsListResponse extends JsonRpcResponse {
87
+ result?: {
88
+ tools: McpTool[];
89
+ };
90
+ error?: JsonRpcError;
91
+ }
92
+
93
+ export interface McpToolCallRequest extends JsonRpcRequest {
94
+ method: 'tools/call';
95
+ params: {
96
+ name: string;
97
+ arguments?: Record<string, unknown>;
98
+ };
99
+ }
100
+
101
+ export interface McpToolCallResponse extends JsonRpcResponse {
102
+ result?: {
103
+ content: Array<{
104
+ type: 'text' | 'image' | 'resource';
105
+ text?: string;
106
+ data?: string;
107
+ mimeType?: string;
108
+ }>;
109
+ structuredContent?: Record<string, unknown>;
110
+ _meta?: Record<string, unknown>;
111
+ isError?: boolean;
112
+ };
113
+ error?: JsonRpcError;
114
+ }
115
+
116
+ // Error Codes (following JSON-RPC 2.0 and MCP conventions)
117
+ export enum McpErrorCode {
118
+ ParseError = -32700,
119
+ InvalidRequest = -32600,
120
+ MethodNotFound = -32601,
121
+ InvalidParams = -32602,
122
+ InternalError = -32603,
123
+ ToolNotFound = -32000,
124
+ ToolExecutionError = -32001,
125
+ }
126
+
127
+ // Server Configuration
128
+ export interface McpServerConfig {
129
+ name: string;
130
+ version: string;
131
+ description: string;
132
+ logLevel?: 'error' | 'warn' | 'info' | 'debug';
133
+ }
134
+
135
+ // Tool Registry Types
136
+ export type ToolHandler = (params: Record<string, unknown>) => Promise<NonNullable<McpToolCallResponse['result']>>;
137
+
138
+ export interface ToolDefinition {
139
+ tool: McpTool;
140
+ handler: ToolHandler;
141
+ }
@@ -0,0 +1,35 @@
1
+ type AppInfo = {
2
+ name: string;
3
+ version: string;
4
+ description: string;
5
+ homepage?: string;
6
+ };
7
+
8
+ let cachedAppInfo: AppInfo | undefined;
9
+
10
+ /**
11
+ * Load package metadata in one place so CLI/server/tools report the same version.
12
+ */
13
+ export function getAppInfo(): AppInfo {
14
+ if (cachedAppInfo) {
15
+ return cachedAppInfo;
16
+ }
17
+
18
+ try {
19
+ const packageJson = require('../../package.json');
20
+ cachedAppInfo = {
21
+ name: packageJson.name || 'GeoGebra Studio',
22
+ version: packageJson.version || '0.0.0',
23
+ description: packageJson.description || 'Model Context Protocol server for GeoGebra mathematical visualization',
24
+ homepage: packageJson.homepage
25
+ };
26
+ } catch (_error) {
27
+ cachedAppInfo = {
28
+ name: 'GeoGebra Studio',
29
+ version: '0.0.0',
30
+ description: 'Model Context Protocol server for GeoGebra mathematical visualization'
31
+ };
32
+ }
33
+
34
+ return cachedAppInfo;
35
+ }
@@ -0,0 +1,97 @@
1
+ import { JsonRpcError, McpErrorCode } from '../types/mcp';
2
+ import logger from './logger';
3
+
4
+ /**
5
+ * Custom error class for MCP-specific errors
6
+ */
7
+ export class McpError extends Error {
8
+ public readonly code: number;
9
+ public readonly data?: unknown;
10
+
11
+ constructor(code: McpErrorCode, message: string, data?: unknown) {
12
+ super(message);
13
+ this.name = 'McpError';
14
+ this.code = code;
15
+ this.data = data;
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Create a JSON-RPC error response
21
+ */
22
+ export function createJsonRpcError(
23
+ code: McpErrorCode,
24
+ message: string,
25
+ data?: unknown
26
+ ): JsonRpcError {
27
+ return {
28
+ code,
29
+ message,
30
+ data
31
+ };
32
+ }
33
+
34
+ /**
35
+ * Handle and format errors for JSON-RPC responses
36
+ */
37
+ export function handleError(error: unknown): JsonRpcError {
38
+ logger.error('Error occurred:', error);
39
+
40
+ if (error instanceof McpError) {
41
+ return createJsonRpcError(error.code, error.message, error.data);
42
+ }
43
+
44
+ if (error instanceof Error) {
45
+ return createJsonRpcError(
46
+ McpErrorCode.InternalError,
47
+ error.message,
48
+ { stack: error.stack }
49
+ );
50
+ }
51
+
52
+ return createJsonRpcError(
53
+ McpErrorCode.InternalError,
54
+ 'Unknown error occurred',
55
+ { error: String(error) }
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Validate JSON-RPC request structure
61
+ */
62
+ export function validateJsonRpcRequest(request: unknown): request is { jsonrpc: '2.0'; method: string; id?: string | number | null } {
63
+ if (typeof request !== 'object' || request === null) {
64
+ return false;
65
+ }
66
+
67
+ const req = request as Record<string, unknown>;
68
+
69
+ return (
70
+ req['jsonrpc'] === '2.0' &&
71
+ typeof req['method'] === 'string' &&
72
+ (req['id'] === undefined || typeof req['id'] === 'string' || typeof req['id'] === 'number' || req['id'] === null)
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Common error creators
78
+ */
79
+ export const errors = {
80
+ parseError: (data?: unknown) =>
81
+ new McpError(McpErrorCode.ParseError, 'Parse error', data),
82
+
83
+ invalidRequest: (data?: unknown) =>
84
+ new McpError(McpErrorCode.InvalidRequest, 'Invalid Request', data),
85
+
86
+ methodNotFound: (method: string) =>
87
+ new McpError(McpErrorCode.MethodNotFound, `Method not found: ${method}`),
88
+
89
+ invalidParams: (message: string = 'Invalid params') =>
90
+ new McpError(McpErrorCode.InvalidParams, message),
91
+
92
+ toolNotFound: (toolName: string) =>
93
+ new McpError(McpErrorCode.ToolNotFound, `Tool not found: ${toolName}`),
94
+
95
+ toolExecutionError: (toolName: string, message: string) =>
96
+ new McpError(McpErrorCode.ToolExecutionError, `Tool execution failed for ${toolName}: ${message}`)
97
+ };
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Gemini Compatibility Utilities
3
+ *
4
+ * Gemini 2.5 Pro Preview requires stricter JSON Schema compliance:
5
+ * - All properties MUST have explicit "type" fields
6
+ * - No support for oneOf/anyOf/allOf constructs
7
+ * - Type must be specified for all parameter properties
8
+ */
9
+
10
+ export interface GeminiCompatibleSchema {
11
+ type: 'object';
12
+ properties: Record<string, {
13
+ type: 'string' | 'number' | 'boolean' | 'integer' | 'array' | 'object';
14
+ description?: string;
15
+ minimum?: number;
16
+ maximum?: number;
17
+ items?: any;
18
+ properties?: any;
19
+ required?: string[];
20
+ [key: string]: any;
21
+ }>;
22
+ required?: string[];
23
+ [key: string]: any;
24
+ }
25
+
26
+ /**
27
+ * Transform a schema to be compatible with Gemini 2.5 Pro Preview
28
+ */
29
+ export function makeGeminiCompatible(schema: any): GeminiCompatibleSchema {
30
+ if (!schema || typeof schema !== 'object') {
31
+ return {
32
+ type: 'object',
33
+ properties: {},
34
+ required: []
35
+ };
36
+ }
37
+
38
+ const result: GeminiCompatibleSchema = {
39
+ type: 'object',
40
+ properties: {},
41
+ required: schema.required || []
42
+ };
43
+
44
+ // Ensure all properties have explicit types
45
+ if (schema.properties && typeof schema.properties === 'object') {
46
+ for (const [key, prop] of Object.entries(schema.properties as Record<string, any>)) {
47
+ if (!prop || typeof prop !== 'object') {
48
+ continue;
49
+ }
50
+
51
+ const transformedProp: any = { ...prop };
52
+
53
+ // Ensure type is explicitly set
54
+ if (!transformedProp.type) {
55
+ // Infer type from other properties or default to string
56
+ if (transformedProp.minimum !== undefined || transformedProp.maximum !== undefined) {
57
+ transformedProp.type = 'number';
58
+ } else if (transformedProp.items !== undefined) {
59
+ transformedProp.type = 'array';
60
+ } else if (transformedProp.properties !== undefined) {
61
+ transformedProp.type = 'object';
62
+ } else {
63
+ transformedProp.type = 'string';
64
+ }
65
+ }
66
+
67
+ // Remove any oneOf/anyOf/allOf constructs as Gemini doesn't support them
68
+ delete transformedProp.oneOf;
69
+ delete transformedProp.anyOf;
70
+ delete transformedProp.allOf;
71
+
72
+ // Recursively transform nested objects
73
+ if (transformedProp.type === 'object' && transformedProp.properties) {
74
+ transformedProp.properties = makeGeminiCompatible({
75
+ type: 'object',
76
+ properties: transformedProp.properties,
77
+ required: transformedProp.required
78
+ }).properties;
79
+ }
80
+
81
+ // Transform array items if present
82
+ if (transformedProp.type === 'array' && transformedProp.items) {
83
+ if (typeof transformedProp.items === 'object' && !transformedProp.items.type) {
84
+ transformedProp.items = makeGeminiCompatible(transformedProp.items);
85
+ }
86
+ }
87
+
88
+ result.properties[key] = transformedProp;
89
+ }
90
+ }
91
+
92
+ return result;
93
+ }
94
+
95
+ /**
96
+ * Check if a schema needs Gemini compatibility fixes
97
+ */
98
+ export function needsGeminiCompatibility(schema: any): boolean {
99
+ if (!schema || typeof schema !== 'object') {
100
+ return false;
101
+ }
102
+
103
+ // Check for missing type at root level
104
+ if (!schema.type) {
105
+ return true;
106
+ }
107
+
108
+ // Check for oneOf/anyOf/allOf constructs
109
+ if (schema.oneOf || schema.anyOf || schema.allOf) {
110
+ return true;
111
+ }
112
+
113
+ // Check properties for missing types
114
+ if (schema.properties && typeof schema.properties === 'object') {
115
+ for (const prop of Object.values(schema.properties as Record<string, any>)) {
116
+ if (prop && typeof prop === 'object' && !prop.type) {
117
+ return true;
118
+ }
119
+
120
+ // Check for oneOf/anyOf/allOf in properties
121
+ if (prop && (prop.oneOf || prop.anyOf || prop.allOf)) {
122
+ return true;
123
+ }
124
+
125
+ // Recursively check nested objects
126
+ if (prop && prop.type === 'object' && prop.properties && needsGeminiCompatibility(prop)) {
127
+ return true;
128
+ }
129
+ }
130
+ }
131
+
132
+ return false;
133
+ }
134
+
135
+ /**
136
+ * Validate that a schema is Gemini-compatible
137
+ */
138
+ export function validateGeminiCompatibility(schema: any): {
139
+ isCompatible: boolean;
140
+ issues: string[];
141
+ } {
142
+ const issues: string[] = [];
143
+
144
+ if (!schema || typeof schema !== 'object') {
145
+ issues.push('Schema is not an object');
146
+ return { isCompatible: false, issues };
147
+ }
148
+
149
+ if (!schema.type) {
150
+ issues.push('Root schema missing type field');
151
+ }
152
+
153
+ if (schema.oneOf) {
154
+ issues.push('Root schema uses oneOf (not supported by Gemini)');
155
+ }
156
+
157
+ if (schema.anyOf) {
158
+ issues.push('Root schema uses anyOf (not supported by Gemini)');
159
+ }
160
+
161
+ if (schema.allOf) {
162
+ issues.push('Root schema uses allOf (not supported by Gemini)');
163
+ }
164
+
165
+ if (schema.properties && typeof schema.properties === 'object') {
166
+ for (const [key, prop] of Object.entries(schema.properties as Record<string, any>)) {
167
+ if (!prop || typeof prop !== 'object') {
168
+ continue;
169
+ }
170
+
171
+ if (!prop.type) {
172
+ issues.push(`Property "${key}" missing type field`);
173
+ }
174
+
175
+ if (prop.oneOf) {
176
+ issues.push(`Property "${key}" uses oneOf (not supported by Gemini)`);
177
+ }
178
+
179
+ if (prop.anyOf) {
180
+ issues.push(`Property "${key}" uses anyOf (not supported by Gemini)`);
181
+ }
182
+
183
+ if (prop.allOf) {
184
+ issues.push(`Property "${key}" uses allOf (not supported by Gemini)`);
185
+ }
186
+ }
187
+ }
188
+
189
+ return {
190
+ isCompatible: issues.length === 0,
191
+ issues
192
+ };
193
+ }