@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,192 @@
|
|
|
1
|
+
import { McpTool, ToolDefinition } from '../types/mcp';
|
|
2
|
+
import { errors } from '../utils/errors';
|
|
3
|
+
import logger from '../utils/logger';
|
|
4
|
+
import { getAppInfo } from '../utils/app-info';
|
|
5
|
+
import { geogebraTools } from './geogebra-tools';
|
|
6
|
+
import { exportTools } from './export-tools';
|
|
7
|
+
import { educationalTemplateTools } from './educational-templates';
|
|
8
|
+
import { performanceTools } from './performance-tools';
|
|
9
|
+
import { appsApiTools } from './apps-api-tools';
|
|
10
|
+
|
|
11
|
+
// Check if we're in MCP mode (stdio communication)
|
|
12
|
+
// When piping input, process.stdin.isTTY is undefined, not false
|
|
13
|
+
const isMcpMode = !process.stdin.isTTY;
|
|
14
|
+
const appInfo = getAppInfo();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Tool Registry for managing MCP tools
|
|
18
|
+
*/
|
|
19
|
+
export class ToolRegistry {
|
|
20
|
+
private tools: Map<string, ToolDefinition> = new Map();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Register a new tool
|
|
24
|
+
*/
|
|
25
|
+
register(definition: ToolDefinition): void {
|
|
26
|
+
const name = definition.tool.name;
|
|
27
|
+
const readOnly = ['echo', 'ping', 'server_info', 'geogebra_get_objects',
|
|
28
|
+
'geogebra_instance_status', 'geogebra_get_prompt_framework', 'geogebra_get_semantic_scene'].includes(name);
|
|
29
|
+
definition.tool.annotations ??= {
|
|
30
|
+
readOnlyHint: readOnly,
|
|
31
|
+
destructiveHint: !readOnly,
|
|
32
|
+
idempotentHint: readOnly,
|
|
33
|
+
openWorldHint: name.startsWith('geogebra_') && !['geogebra_create_html', 'geogebra_clean_tikz'].includes(name),
|
|
34
|
+
};
|
|
35
|
+
this.tools.set(name, definition);
|
|
36
|
+
if (!isMcpMode) {
|
|
37
|
+
logger.info(`Registered tool: ${definition.tool.name}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get all registered tools
|
|
43
|
+
*/
|
|
44
|
+
getTools(): McpTool[] {
|
|
45
|
+
return Array.from(this.tools.values()).map(def => def.tool);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get a specific tool by name
|
|
50
|
+
*/
|
|
51
|
+
getTool(name: string): ToolDefinition | undefined {
|
|
52
|
+
return this.tools.get(name);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Execute a tool by name with given parameters
|
|
57
|
+
*/
|
|
58
|
+
async executeTool(name: string, params: Record<string, unknown> = {}) {
|
|
59
|
+
const toolDef = this.tools.get(name);
|
|
60
|
+
|
|
61
|
+
if (!toolDef) {
|
|
62
|
+
throw errors.toolNotFound(name);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
if (!isMcpMode) {
|
|
67
|
+
logger.info(`Executing tool: ${name}`, { params });
|
|
68
|
+
}
|
|
69
|
+
const result = await toolDef.handler(params);
|
|
70
|
+
if (!isMcpMode) {
|
|
71
|
+
logger.info(`Tool execution completed: ${name}`);
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
logger.error(`Tool execution failed: ${name}`, error);
|
|
76
|
+
throw errors.toolExecutionError(name, error instanceof Error ? error.message : String(error));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if a tool exists
|
|
82
|
+
*/
|
|
83
|
+
hasTool(name: string): boolean {
|
|
84
|
+
return this.tools.has(name);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get the number of registered tools
|
|
89
|
+
*/
|
|
90
|
+
getToolCount(): number {
|
|
91
|
+
return this.tools.size;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Create global tool registry instance
|
|
96
|
+
export const toolRegistry = new ToolRegistry();
|
|
97
|
+
|
|
98
|
+
// Example tools for testing and demonstration
|
|
99
|
+
const exampleTools: ToolDefinition[] = [
|
|
100
|
+
{
|
|
101
|
+
tool: {
|
|
102
|
+
name: 'echo',
|
|
103
|
+
description: 'Echo back the provided message',
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
message: {
|
|
108
|
+
type: 'string',
|
|
109
|
+
description: 'The message to echo back'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
required: ['message']
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
handler: async (params: Record<string, unknown>) => {
|
|
116
|
+
const message = params['message'] as string;
|
|
117
|
+
return {
|
|
118
|
+
content: [{
|
|
119
|
+
type: 'text' as const,
|
|
120
|
+
text: `Echo: ${message}`
|
|
121
|
+
}]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
tool: {
|
|
127
|
+
name: 'ping',
|
|
128
|
+
description: 'Simple ping tool that returns pong',
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: 'object',
|
|
131
|
+
properties: {},
|
|
132
|
+
required: []
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
handler: async () => {
|
|
136
|
+
return {
|
|
137
|
+
content: [{
|
|
138
|
+
type: 'text' as const,
|
|
139
|
+
text: 'pong'
|
|
140
|
+
}]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
tool: {
|
|
146
|
+
name: 'server_info',
|
|
147
|
+
description: 'Get information about the MCP server',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {},
|
|
151
|
+
required: []
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
handler: async () => {
|
|
155
|
+
return {
|
|
156
|
+
content: [{
|
|
157
|
+
type: 'text' as const,
|
|
158
|
+
text: JSON.stringify({
|
|
159
|
+
name: 'GeoGebra Studio',
|
|
160
|
+
version: appInfo.version,
|
|
161
|
+
description: appInfo.description,
|
|
162
|
+
toolCount: toolRegistry.getToolCount(),
|
|
163
|
+
timestamp: new Date().toISOString()
|
|
164
|
+
}, null, 2)
|
|
165
|
+
}]
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
// Register example tools
|
|
172
|
+
exampleTools.forEach(tool => {
|
|
173
|
+
toolRegistry.register(tool);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Register GeoGebra tools
|
|
177
|
+
geogebraTools.forEach(tool => {
|
|
178
|
+
toolRegistry.register(tool);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Register Educational Template tools
|
|
182
|
+
educationalTemplateTools.forEach(tool => {
|
|
183
|
+
toolRegistry.register(tool);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Register Performance tools
|
|
187
|
+
performanceTools.forEach(tool => {
|
|
188
|
+
toolRegistry.register(tool);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
exportTools.forEach(tool => toolRegistry.register(tool));
|
|
192
|
+
appsApiTools.forEach(tool => toolRegistry.register(tool));
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance Optimization Tools
|
|
3
|
+
* GEB-9: Performance Optimization: Response Time and Resource Management
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ToolDefinition } from '../types/mcp';
|
|
7
|
+
import { performanceMonitor } from '../utils/performance';
|
|
8
|
+
import { optimizedInstancePool } from '../utils/performance/instance-pool';
|
|
9
|
+
import logger from '../utils/logger';
|
|
10
|
+
|
|
11
|
+
export const performanceTools: ToolDefinition[] = [
|
|
12
|
+
{
|
|
13
|
+
tool: {
|
|
14
|
+
name: 'performance_get_stats',
|
|
15
|
+
description: 'Get performance statistics for operations',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
operationName: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'Specific operation name to get stats for (optional - if not provided, gets overall stats)'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
handler: async (params) => {
|
|
27
|
+
try {
|
|
28
|
+
const operationName = params['operationName'] as string | undefined;
|
|
29
|
+
const stats = performanceMonitor.getStats(operationName);
|
|
30
|
+
const operationNames = performanceMonitor.getOperationNames();
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
content: [{
|
|
34
|
+
type: 'text' as const,
|
|
35
|
+
text: JSON.stringify({
|
|
36
|
+
success: true,
|
|
37
|
+
operationName: operationName || 'overall',
|
|
38
|
+
stats,
|
|
39
|
+
availableOperations: operationNames,
|
|
40
|
+
summary: {
|
|
41
|
+
totalOperations: stats.count,
|
|
42
|
+
averageResponseTime: `${stats.averageDuration.toFixed(2)}ms`,
|
|
43
|
+
successRate: `${(stats.successRate * 100).toFixed(1)}%`,
|
|
44
|
+
p95ResponseTime: `${stats.p95Duration.toFixed(2)}ms`,
|
|
45
|
+
performanceStatus: stats.p95Duration < 2000 ? 'GOOD' : 'NEEDS_ATTENTION'
|
|
46
|
+
}
|
|
47
|
+
}, null, 2)
|
|
48
|
+
}]
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
logger.error('Failed to get performance stats', error);
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: 'text' as const,
|
|
55
|
+
text: JSON.stringify({
|
|
56
|
+
success: false,
|
|
57
|
+
error: error instanceof Error ? error.message : String(error)
|
|
58
|
+
}, null, 2)
|
|
59
|
+
}],
|
|
60
|
+
isError: true
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
tool: {
|
|
68
|
+
name: 'performance_get_pool_stats',
|
|
69
|
+
description: 'Get instance pool performance and resource statistics',
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
handler: async () => {
|
|
76
|
+
try {
|
|
77
|
+
const poolStats = optimizedInstancePool.getStats();
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: [{
|
|
81
|
+
type: 'text' as const,
|
|
82
|
+
text: JSON.stringify({
|
|
83
|
+
success: true,
|
|
84
|
+
poolStats,
|
|
85
|
+
resourceStatus: {
|
|
86
|
+
memoryUsage: `${poolStats.memoryEstimate}MB estimated`,
|
|
87
|
+
efficiency: poolStats.averageUsage > 5 ? 'HIGH' : 'NORMAL',
|
|
88
|
+
poolUtilization: `${((poolStats.activeInstances / poolStats.totalInstances) * 100).toFixed(1)}%`,
|
|
89
|
+
recommendation: poolStats.totalInstances === 0
|
|
90
|
+
? 'Pool empty - instances will be created on demand'
|
|
91
|
+
: poolStats.averageUsage > 10
|
|
92
|
+
? 'Consider increasing pool size for high usage'
|
|
93
|
+
: 'Pool size appropriate for current usage'
|
|
94
|
+
}
|
|
95
|
+
}, null, 2)
|
|
96
|
+
}]
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
logger.error('Failed to get pool stats', error);
|
|
100
|
+
return {
|
|
101
|
+
content: [{
|
|
102
|
+
type: 'text' as const,
|
|
103
|
+
text: JSON.stringify({
|
|
104
|
+
success: false,
|
|
105
|
+
error: error instanceof Error ? error.message : String(error)
|
|
106
|
+
}, null, 2)
|
|
107
|
+
}],
|
|
108
|
+
isError: true
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
tool: {
|
|
116
|
+
name: 'performance_warm_up_pool',
|
|
117
|
+
description: 'Pre-warm the instance pool for better performance',
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
count: {
|
|
122
|
+
type: 'number',
|
|
123
|
+
description: 'Number of instances to pre-create (default: 1, max: 3)',
|
|
124
|
+
minimum: 1,
|
|
125
|
+
maximum: 3
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
handler: async (params) => {
|
|
131
|
+
try {
|
|
132
|
+
const count = Math.min((params['count'] as number) || 1, 3);
|
|
133
|
+
|
|
134
|
+
const startTime = Date.now();
|
|
135
|
+
await optimizedInstancePool.warmUp(count);
|
|
136
|
+
const duration = Date.now() - startTime;
|
|
137
|
+
|
|
138
|
+
const poolStats = optimizedInstancePool.getStats();
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
content: [{
|
|
142
|
+
type: 'text' as const,
|
|
143
|
+
text: JSON.stringify({
|
|
144
|
+
success: true,
|
|
145
|
+
message: `Pool warmed up with ${count} instances`,
|
|
146
|
+
warmUpTime: `${duration}ms`,
|
|
147
|
+
poolStats: {
|
|
148
|
+
totalInstances: poolStats.totalInstances,
|
|
149
|
+
memoryEstimate: `${poolStats.memoryEstimate}MB`
|
|
150
|
+
}
|
|
151
|
+
}, null, 2)
|
|
152
|
+
}]
|
|
153
|
+
};
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logger.error('Failed to warm up pool', error);
|
|
156
|
+
return {
|
|
157
|
+
content: [{
|
|
158
|
+
type: 'text' as const,
|
|
159
|
+
text: JSON.stringify({
|
|
160
|
+
success: false,
|
|
161
|
+
error: error instanceof Error ? error.message : String(error)
|
|
162
|
+
}, null, 2)
|
|
163
|
+
}],
|
|
164
|
+
isError: true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
{
|
|
171
|
+
tool: {
|
|
172
|
+
name: 'performance_clear_metrics',
|
|
173
|
+
description: 'Clear all performance metrics (useful for testing)',
|
|
174
|
+
inputSchema: {
|
|
175
|
+
type: 'object',
|
|
176
|
+
properties: {}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
handler: async () => {
|
|
180
|
+
try {
|
|
181
|
+
performanceMonitor.clearMetrics();
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
content: [{
|
|
185
|
+
type: 'text' as const,
|
|
186
|
+
text: JSON.stringify({
|
|
187
|
+
success: true,
|
|
188
|
+
message: 'All performance metrics cleared'
|
|
189
|
+
}, null, 2)
|
|
190
|
+
}]
|
|
191
|
+
};
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logger.error('Failed to clear metrics', error);
|
|
194
|
+
return {
|
|
195
|
+
content: [{
|
|
196
|
+
type: 'text' as const,
|
|
197
|
+
text: JSON.stringify({
|
|
198
|
+
success: false,
|
|
199
|
+
error: error instanceof Error ? error.message : String(error)
|
|
200
|
+
}, null, 2)
|
|
201
|
+
}],
|
|
202
|
+
isError: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
{
|
|
209
|
+
tool: {
|
|
210
|
+
name: 'performance_benchmark',
|
|
211
|
+
description: 'Run performance benchmark tests',
|
|
212
|
+
inputSchema: {
|
|
213
|
+
type: 'object',
|
|
214
|
+
properties: {
|
|
215
|
+
testType: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
description: 'Type of benchmark to run',
|
|
218
|
+
enum: ['basic', 'command_execution', 'export_operations', 'all']
|
|
219
|
+
},
|
|
220
|
+
iterations: {
|
|
221
|
+
type: 'number',
|
|
222
|
+
description: 'Number of iterations to run (default: 5)',
|
|
223
|
+
minimum: 1,
|
|
224
|
+
maximum: 20
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
required: ['testType']
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
handler: async (params) => {
|
|
231
|
+
try {
|
|
232
|
+
const testType = params['testType'] as string;
|
|
233
|
+
const iterations = Math.min((params['iterations'] as number) || 5, 20);
|
|
234
|
+
|
|
235
|
+
const benchmarkResults: any = {
|
|
236
|
+
testType,
|
|
237
|
+
iterations,
|
|
238
|
+
results: [],
|
|
239
|
+
summary: {}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const instance = await optimizedInstancePool.getInstance();
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
if (testType === 'basic' || testType === 'all') {
|
|
246
|
+
// Basic command execution benchmark
|
|
247
|
+
const durations: number[] = [];
|
|
248
|
+
for (let i = 0; i < iterations; i++) {
|
|
249
|
+
const startTime = Date.now();
|
|
250
|
+
await instance.evalCommand(`TestPoint${i} = (${i}, ${i})`);
|
|
251
|
+
durations.push(Date.now() - startTime);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
benchmarkResults.results.push({
|
|
255
|
+
operation: 'basic_command_execution',
|
|
256
|
+
durations,
|
|
257
|
+
average: durations.reduce((a, b) => a + b, 0) / durations.length,
|
|
258
|
+
min: Math.min(...durations),
|
|
259
|
+
max: Math.max(...durations)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (testType === 'export_operations' || testType === 'all') {
|
|
264
|
+
// Export benchmark
|
|
265
|
+
await instance.evalCommand('A = (0, 0)');
|
|
266
|
+
await instance.evalCommand('B = (1, 1)');
|
|
267
|
+
await instance.evalCommand('line1 = Line(A, B)');
|
|
268
|
+
|
|
269
|
+
const exportDurations: number[] = [];
|
|
270
|
+
for (let i = 0; i < Math.min(iterations, 3); i++) { // Limit export tests
|
|
271
|
+
const startTime = Date.now();
|
|
272
|
+
await instance.exportSVG();
|
|
273
|
+
exportDurations.push(Date.now() - startTime);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
benchmarkResults.results.push({
|
|
277
|
+
operation: 'svg_export',
|
|
278
|
+
durations: exportDurations,
|
|
279
|
+
average: exportDurations.reduce((a, b) => a + b, 0) / exportDurations.length,
|
|
280
|
+
min: Math.min(...exportDurations),
|
|
281
|
+
max: Math.max(...exportDurations)
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Calculate overall summary
|
|
286
|
+
benchmarkResults.summary = {
|
|
287
|
+
totalTests: benchmarkResults.results.length,
|
|
288
|
+
allTestsPassed: benchmarkResults.results.every((r: any) => r.average < 2000),
|
|
289
|
+
recommendedAction: benchmarkResults.results.some((r: any) => r.average > 1500)
|
|
290
|
+
? 'Consider pool warm-up or optimization'
|
|
291
|
+
: 'Performance is within acceptable range'
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
} finally {
|
|
295
|
+
await optimizedInstancePool.releaseInstance(instance);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
content: [{
|
|
300
|
+
type: 'text' as const,
|
|
301
|
+
text: JSON.stringify({
|
|
302
|
+
success: true,
|
|
303
|
+
benchmark: benchmarkResults
|
|
304
|
+
}, null, 2)
|
|
305
|
+
}]
|
|
306
|
+
};
|
|
307
|
+
} catch (error) {
|
|
308
|
+
logger.error('Failed to run benchmark', error);
|
|
309
|
+
return {
|
|
310
|
+
content: [{
|
|
311
|
+
type: 'text' as const,
|
|
312
|
+
text: JSON.stringify({
|
|
313
|
+
success: false,
|
|
314
|
+
error: error instanceof Error ? error.message : String(error)
|
|
315
|
+
}, null, 2)
|
|
316
|
+
}],
|
|
317
|
+
isError: true
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
];
|