@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.
- package/.agents/plugins/marketplace.json +21 -0
- package/.codex-plugin/plugin.json +21 -0
- package/.mcp.json +18 -0
- package/LICENSE +339 -0
- package/LICENSE-MIT +21 -0
- package/README.md +108 -2
- package/README.zh-CN.md +89 -0
- package/THIRD_PARTY_NOTICES.md +35 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/export/files.d.ts +4 -0
- package/dist/export/files.d.ts.map +1 -0
- package/dist/export/files.js +44 -0
- package/dist/export/files.js.map +1 -0
- package/dist/export/gikz.d.ts +11 -0
- package/dist/export/gikz.d.ts.map +1 -0
- package/dist/export/gikz.js +28 -0
- package/dist/export/gikz.js.map +1 -0
- package/dist/export/html.d.ts +14 -0
- package/dist/export/html.d.ts.map +1 -0
- package/dist/export/html.js +97 -0
- package/dist/export/html.js.map +1 -0
- package/dist/export/semantic.d.ts +43 -0
- package/dist/export/semantic.d.ts.map +1 -0
- package/dist/export/semantic.js +212 -0
- package/dist/export/semantic.js.map +1 -0
- package/dist/export/viewer-themes.d.ts +76 -0
- package/dist/export/viewer-themes.d.ts.map +1 -0
- package/dist/export/viewer-themes.js +169 -0
- package/dist/export/viewer-themes.js.map +1 -0
- package/dist/export/workspace.d.ts +4 -0
- package/dist/export/workspace.d.ts.map +1 -0
- package/dist/export/workspace.js +25 -0
- package/dist/export/workspace.js.map +1 -0
- package/dist/gikz-browser.js +770 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +187 -0
- package/dist/server.js.map +1 -0
- package/dist/studio/artifact.d.ts +37 -0
- package/dist/studio/artifact.d.ts.map +1 -0
- package/dist/studio/artifact.js +61 -0
- package/dist/studio/artifact.js.map +1 -0
- package/dist/studio/browser.d.ts +7 -0
- package/dist/studio/browser.d.ts.map +1 -0
- package/dist/studio/browser.js +67 -0
- package/dist/studio/browser.js.map +1 -0
- package/dist/studio/install.d.ts +4 -0
- package/dist/studio/install.d.ts.map +1 -0
- package/dist/studio/install.js +60 -0
- package/dist/studio/install.js.map +1 -0
- package/dist/tools/apps-api-tools.d.ts +4 -0
- package/dist/tools/apps-api-tools.d.ts.map +1 -0
- package/dist/tools/apps-api-tools.js +96 -0
- package/dist/tools/apps-api-tools.js.map +1 -0
- package/dist/tools/educational-templates.d.ts +33 -0
- package/dist/tools/educational-templates.d.ts.map +1 -0
- package/dist/tools/educational-templates.js +261 -0
- package/dist/tools/educational-templates.js.map +1 -0
- package/dist/tools/export-tools.d.ts +3 -0
- package/dist/tools/export-tools.d.ts.map +1 -0
- package/dist/tools/export-tools.js +118 -0
- package/dist/tools/export-tools.js.map +1 -0
- package/dist/tools/geogebra-tools.d.ts +15 -0
- package/dist/tools/geogebra-tools.d.ts.map +1 -0
- package/dist/tools/geogebra-tools.js +3442 -0
- package/dist/tools/geogebra-tools.js.map +1 -0
- package/dist/tools/index.d.ts +43 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +183 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/performance-tools.d.ts +7 -0
- package/dist/tools/performance-tools.d.ts.map +1 -0
- package/dist/tools/performance-tools.js +312 -0
- package/dist/tools/performance-tools.js.map +1 -0
- package/dist/tools/templates/algebra-templates.d.ts +7 -0
- package/dist/tools/templates/algebra-templates.d.ts.map +1 -0
- package/dist/tools/templates/algebra-templates.js +568 -0
- package/dist/tools/templates/algebra-templates.js.map +1 -0
- package/dist/tools/templates/geometry-templates.d.ts +7 -0
- package/dist/tools/templates/geometry-templates.d.ts.map +1 -0
- package/dist/tools/templates/geometry-templates.js +492 -0
- package/dist/tools/templates/geometry-templates.js.map +1 -0
- package/dist/types/geogebra.d.ts +103 -0
- package/dist/types/geogebra.d.ts.map +1 -0
- package/dist/types/geogebra.js +34 -0
- package/dist/types/geogebra.js.map +1 -0
- package/dist/types/mcp.d.ts +125 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +19 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/utils/app-info.d.ts +12 -0
- package/dist/utils/app-info.d.ts.map +1 -0
- package/dist/utils/app-info.js +30 -0
- package/dist/utils/app-info.js.map +1 -0
- package/dist/utils/errors.d.ts +37 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +72 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/gemini-compatibility.d.ts +39 -0
- package/dist/utils/gemini-compatibility.d.ts.map +1 -0
- package/dist/utils/gemini-compatibility.js +154 -0
- package/dist/utils/gemini-compatibility.js.map +1 -0
- package/dist/utils/geogebra-instance.d.ts +252 -0
- package/dist/utils/geogebra-instance.d.ts.map +1 -0
- package/dist/utils/geogebra-instance.js +1560 -0
- package/dist/utils/geogebra-instance.js.map +1 -0
- package/dist/utils/geogebra-mock.d.ts +172 -0
- package/dist/utils/geogebra-mock.d.ts.map +1 -0
- package/dist/utils/geogebra-mock.js +732 -0
- package/dist/utils/geogebra-mock.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +46 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/performance/index.d.ts +76 -0
- package/dist/utils/performance/index.d.ts.map +1 -0
- package/dist/utils/performance/index.js +163 -0
- package/dist/utils/performance/index.js.map +1 -0
- package/dist/utils/performance/instance-pool.d.ts +78 -0
- package/dist/utils/performance/instance-pool.d.ts.map +1 -0
- package/dist/utils/performance/instance-pool.js +268 -0
- package/dist/utils/performance/instance-pool.js.map +1 -0
- package/dist/utils/validation.d.ts +92 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +557 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/widget.html +110 -0
- package/docs/APPS-API-BRIDGE.md +28 -0
- package/docs/MODERNIZATION.md +15 -0
- package/docs/TANGENT-REGRESSION.md +34 -0
- package/docs/VALIDATION.md +26 -0
- package/docs/VISUAL-STANDARD.md +26 -0
- package/docs/images/native-construction.png +0 -0
- package/examples/tangent-construction.json +26 -0
- package/gikz/LICENSE +339 -0
- package/gikz/PROVENANCE.md +8 -0
- package/gikz/browser.cjs +2 -0
- package/gikz/cli.cjs +195 -0
- package/gikz/core.cjs +806 -0
- package/mcp.json +20 -0
- package/package.json +107 -4
- package/plugin.json +35 -0
- package/runtime/package.json +4 -0
- package/scripts/build-plugin.cjs +15 -0
- package/scripts/build-widget.cjs +7 -0
- package/skills/geogebra-construct/SKILL.md +40 -0
- package/skills/geogebra-setup/SKILL.md +37 -0
- package/skills/geometry-export/SKILL.md +31 -0
- package/src/cli.ts +212 -0
- package/src/export/files.ts +26 -0
- package/src/export/gikz.ts +22 -0
- package/src/export/html.ts +108 -0
- package/src/export/semantic.ts +180 -0
- package/src/export/viewer-themes.ts +165 -0
- package/src/export/workspace.ts +15 -0
- package/src/index.ts +71 -0
- package/src/server.ts +168 -0
- package/src/studio/artifact.ts +50 -0
- package/src/studio/browser.ts +38 -0
- package/src/studio/install.ts +43 -0
- package/src/tools/apps-api-tools.ts +96 -0
- package/src/tools/educational-templates.ts +299 -0
- package/src/tools/export-tools.ts +110 -0
- package/src/tools/geogebra-tools.ts +3836 -0
- package/src/tools/index.ts +192 -0
- package/src/tools/performance-tools.ts +322 -0
- package/src/tools/templates/algebra-templates.ts +619 -0
- package/src/tools/templates/geometry-templates.ts +550 -0
- package/src/types/geogebra.ts +140 -0
- package/src/types/global.d.ts +31 -0
- package/src/types/mcp.ts +141 -0
- package/src/utils/app-info.ts +35 -0
- package/src/utils/errors.ts +97 -0
- package/src/utils/gemini-compatibility.ts +193 -0
- package/src/utils/geogebra-instance.ts +1712 -0
- package/src/utils/geogebra-mock.ts +867 -0
- package/src/utils/logger.ts +60 -0
- package/src/utils/performance/index.ts +211 -0
- package/src/utils/performance/instance-pool.ts +323 -0
- package/src/utils/validation.ts +647 -0
- package/tsconfig.json +35 -0
- 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 {};
|
package/src/types/mcp.ts
ADDED
|
@@ -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
|
+
}
|