gthinking 1.3.0 → 2.1.1
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/.eslintrc.js +34 -0
- package/ANALYSIS_SUMMARY.md +363 -0
- package/README.md +230 -250
- package/dist/analysis/analysis-engine.d.ts +63 -0
- package/dist/analysis/analysis-engine.d.ts.map +1 -0
- package/dist/analysis/analysis-engine.js +322 -0
- package/dist/analysis/analysis-engine.js.map +1 -0
- package/dist/core/config.d.ts +1419 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +361 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/engine.d.ts +176 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +604 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/errors.d.ts +153 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +287 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/{types.js → core/index.js} +8 -4
- package/dist/core/index.js.map +1 -0
- package/dist/core/pipeline.d.ts +121 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +289 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +58 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +133 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/session-manager.d.ts +96 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +223 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/creativity/creativity-engine.d.ts +6 -0
- package/dist/creativity/creativity-engine.d.ts.map +1 -0
- package/dist/creativity/creativity-engine.js +17 -0
- package/dist/creativity/creativity-engine.js.map +1 -0
- package/dist/index.d.ts +24 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +130 -104
- package/dist/index.js.map +1 -1
- package/dist/learning/learning-engine.d.ts +6 -0
- package/dist/learning/learning-engine.d.ts.map +1 -0
- package/dist/learning/learning-engine.js +17 -0
- package/dist/learning/learning-engine.js.map +1 -0
- package/dist/llm/index.d.ts +10 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +26 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/llm-service.d.ts +109 -0
- package/dist/llm/llm-service.d.ts.map +1 -0
- package/dist/llm/llm-service.js +224 -0
- package/dist/llm/llm-service.js.map +1 -0
- package/dist/llm/providers/base.d.ts +85 -0
- package/dist/llm/providers/base.d.ts.map +1 -0
- package/dist/llm/providers/base.js +57 -0
- package/dist/llm/providers/base.js.map +1 -0
- package/dist/llm/providers/cli.d.ts +23 -0
- package/dist/llm/providers/cli.d.ts.map +1 -0
- package/dist/llm/providers/cli.js +158 -0
- package/dist/llm/providers/cli.js.map +1 -0
- package/dist/llm/providers/gemini.d.ts +30 -0
- package/dist/llm/providers/gemini.d.ts.map +1 -0
- package/dist/llm/providers/gemini.js +168 -0
- package/dist/llm/providers/gemini.js.map +1 -0
- package/dist/llm/sanitization.d.ts +50 -0
- package/dist/llm/sanitization.d.ts.map +1 -0
- package/dist/llm/sanitization.js +149 -0
- package/dist/llm/sanitization.js.map +1 -0
- package/dist/{server.d.ts.map → mcp/server.d.ts.map} +1 -1
- package/dist/mcp/server.js +108 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/planning/planning-engine.d.ts +6 -0
- package/dist/planning/planning-engine.d.ts.map +1 -0
- package/dist/planning/planning-engine.js +17 -0
- package/dist/planning/planning-engine.js.map +1 -0
- package/dist/reasoning/reasoning-engine.d.ts +6 -0
- package/dist/reasoning/reasoning-engine.d.ts.map +1 -0
- package/dist/reasoning/reasoning-engine.js +17 -0
- package/dist/reasoning/reasoning-engine.js.map +1 -0
- package/dist/search/search-engine.d.ts +99 -0
- package/dist/search/search-engine.d.ts.map +1 -0
- package/dist/search/search-engine.js +271 -0
- package/dist/search/search-engine.js.map +1 -0
- package/dist/synthesis/synthesis-engine.d.ts +6 -0
- package/dist/synthesis/synthesis-engine.d.ts.map +1 -0
- package/dist/synthesis/synthesis-engine.js +17 -0
- package/dist/synthesis/synthesis-engine.js.map +1 -0
- package/dist/types/analysis.d.ts +1534 -49
- package/dist/types/analysis.d.ts.map +1 -1
- package/dist/types/analysis.js +250 -0
- package/dist/types/analysis.js.map +1 -1
- package/dist/types/core.d.ts +257 -30
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +148 -18
- package/dist/types/core.js.map +1 -1
- package/dist/types/creativity.d.ts +2871 -56
- package/dist/types/creativity.d.ts.map +1 -1
- package/dist/types/creativity.js +195 -0
- package/dist/types/creativity.js.map +1 -1
- package/dist/types/index.d.ts +6 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +17 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/learning.d.ts +851 -61
- package/dist/types/learning.d.ts.map +1 -1
- package/dist/types/learning.js +155 -0
- package/dist/types/learning.js.map +1 -1
- package/dist/types/planning.d.ts +2223 -71
- package/dist/types/planning.d.ts.map +1 -1
- package/dist/types/planning.js +190 -0
- package/dist/types/planning.js.map +1 -1
- package/dist/types/reasoning.d.ts +2209 -72
- package/dist/types/reasoning.d.ts.map +1 -1
- package/dist/types/reasoning.js +200 -1
- package/dist/types/reasoning.js.map +1 -1
- package/dist/types/search.d.ts +981 -53
- package/dist/types/search.d.ts.map +1 -1
- package/dist/types/search.js +137 -0
- package/dist/types/search.js.map +1 -1
- package/dist/types/synthesis.d.ts +583 -38
- package/dist/types/synthesis.d.ts.map +1 -1
- package/dist/types/synthesis.js +138 -0
- package/dist/types/synthesis.js.map +1 -1
- package/dist/utils/cache.d.ts +144 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +288 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/id-generator.d.ts +89 -0
- package/dist/utils/id-generator.d.ts.map +1 -0
- package/dist/utils/id-generator.js +132 -0
- package/dist/utils/id-generator.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +33 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +142 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +248 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/metrics.d.ts +149 -0
- package/dist/utils/metrics.d.ts.map +1 -0
- package/dist/utils/metrics.js +296 -0
- package/dist/utils/metrics.js.map +1 -0
- package/dist/utils/timer.d.ts +7 -0
- package/dist/utils/timer.d.ts.map +1 -0
- package/dist/utils/timer.js +17 -0
- package/dist/utils/timer.js.map +1 -0
- package/dist/utils/validation.d.ts +147 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +275 -0
- package/dist/utils/validation.js.map +1 -0
- package/docs/API.md +411 -0
- package/docs/ARCHITECTURE.md +271 -0
- package/docs/CHANGELOG.md +283 -0
- package/jest.config.js +28 -0
- package/package.json +43 -30
- package/src/analysis/analysis-engine.ts +383 -0
- package/src/core/config.ts +406 -0
- package/src/core/engine.ts +785 -0
- package/src/core/errors.ts +349 -0
- package/src/core/index.ts +12 -0
- package/src/core/pipeline.ts +424 -0
- package/src/core/rate-limiter.ts +155 -0
- package/src/core/session-manager.ts +269 -0
- package/src/creativity/creativity-engine.ts +14 -0
- package/src/index.ts +178 -0
- package/src/learning/learning-engine.ts +14 -0
- package/src/llm/index.ts +10 -0
- package/src/llm/llm-service.ts +285 -0
- package/src/llm/providers/base.ts +146 -0
- package/src/llm/providers/cli.ts +186 -0
- package/src/llm/providers/gemini.ts +201 -0
- package/src/llm/sanitization.ts +178 -0
- package/src/mcp/server.ts +117 -0
- package/src/planning/planning-engine.ts +14 -0
- package/src/reasoning/reasoning-engine.ts +14 -0
- package/src/search/search-engine.ts +333 -0
- package/src/synthesis/synthesis-engine.ts +14 -0
- package/src/types/analysis.ts +337 -0
- package/src/types/core.ts +342 -0
- package/src/types/creativity.ts +268 -0
- package/src/types/index.ts +31 -0
- package/src/types/learning.ts +215 -0
- package/src/types/planning.ts +251 -0
- package/src/types/reasoning.ts +288 -0
- package/src/types/search.ts +192 -0
- package/src/types/synthesis.ts +187 -0
- package/src/utils/cache.ts +363 -0
- package/src/utils/id-generator.ts +135 -0
- package/src/utils/index.ts +22 -0
- package/src/utils/logger.ts +290 -0
- package/src/utils/metrics.ts +380 -0
- package/src/utils/timer.ts +15 -0
- package/src/utils/validation.ts +297 -0
- package/tests/setup.ts +22 -0
- package/tests/unit/cache.test.ts +189 -0
- package/tests/unit/engine.test.ts +179 -0
- package/tests/unit/validation.test.ts +218 -0
- package/tsconfig.json +17 -12
- package/GEMINI.md +0 -68
- package/analysis.ts +0 -1063
- package/creativity.ts +0 -1055
- package/dist/analysis.d.ts +0 -54
- package/dist/analysis.d.ts.map +0 -1
- package/dist/analysis.js +0 -866
- package/dist/analysis.js.map +0 -1
- package/dist/creativity.d.ts +0 -81
- package/dist/creativity.d.ts.map +0 -1
- package/dist/creativity.js +0 -828
- package/dist/creativity.js.map +0 -1
- package/dist/engine.d.ts +0 -90
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -720
- package/dist/engine.js.map +0 -1
- package/dist/examples.d.ts +0 -7
- package/dist/examples.d.ts.map +0 -1
- package/dist/examples.js +0 -506
- package/dist/examples.js.map +0 -1
- package/dist/learning.d.ts +0 -72
- package/dist/learning.d.ts.map +0 -1
- package/dist/learning.js +0 -615
- package/dist/learning.js.map +0 -1
- package/dist/llm-service.d.ts +0 -21
- package/dist/llm-service.d.ts.map +0 -1
- package/dist/llm-service.js +0 -100
- package/dist/llm-service.js.map +0 -1
- package/dist/planning.d.ts +0 -62
- package/dist/planning.d.ts.map +0 -1
- package/dist/planning.js +0 -886
- package/dist/planning.js.map +0 -1
- package/dist/reasoning.d.ts +0 -73
- package/dist/reasoning.d.ts.map +0 -1
- package/dist/reasoning.js +0 -845
- package/dist/reasoning.js.map +0 -1
- package/dist/search-discovery.d.ts +0 -73
- package/dist/search-discovery.d.ts.map +0 -1
- package/dist/search-discovery.js +0 -548
- package/dist/search-discovery.js.map +0 -1
- package/dist/server.js +0 -113
- package/dist/server.js.map +0 -1
- package/dist/types/engine.d.ts +0 -55
- package/dist/types/engine.d.ts.map +0 -1
- package/dist/types/engine.js +0 -3
- package/dist/types/engine.js.map +0 -1
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/engine.ts +0 -1009
- package/examples.ts +0 -717
- package/index.ts +0 -106
- package/learning.ts +0 -779
- package/llm-service.ts +0 -120
- package/planning.ts +0 -1101
- package/reasoning.ts +0 -1079
- package/search-discovery.ts +0 -700
- package/server.ts +0 -115
- package/types/analysis.ts +0 -69
- package/types/core.ts +0 -90
- package/types/creativity.ts +0 -72
- package/types/engine.ts +0 -60
- package/types/index.ts +0 -9
- package/types/learning.ts +0 -69
- package/types/planning.ts +0 -85
- package/types/reasoning.ts +0 -92
- package/types/search.ts +0 -58
- package/types/synthesis.ts +0 -43
- package/types.ts +0 -6
- /package/dist/{server.d.ts → mcp/server.d.ts} +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Gemini LLM Provider
|
|
3
|
+
*
|
|
4
|
+
* @module llm/providers/gemini
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import axios from 'axios';
|
|
8
|
+
import { BaseLLMProvider, type LLMMessage, type LLMRequestOptions, type LLMResponse, type LLMStreamChunk } from './base';
|
|
9
|
+
import { LLMError } from '../../core/errors';
|
|
10
|
+
import { logger } from '../../utils/logger';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gemini provider configuration
|
|
14
|
+
*/
|
|
15
|
+
export interface GeminiConfig {
|
|
16
|
+
apiKey: string;
|
|
17
|
+
model?: string;
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
maxRetries?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Gemini provider implementation
|
|
25
|
+
*/
|
|
26
|
+
export class GeminiProvider extends BaseLLMProvider {
|
|
27
|
+
readonly name = 'gemini';
|
|
28
|
+
readonly availableModels = [
|
|
29
|
+
'gemini-1.5-pro',
|
|
30
|
+
'gemini-1.5-flash',
|
|
31
|
+
'gemini-1.0-pro',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
constructor(config: GeminiConfig) {
|
|
35
|
+
super({
|
|
36
|
+
apiKey: config.apiKey,
|
|
37
|
+
baseUrl: config.baseUrl ?? 'https://generativelanguage.googleapis.com/v1beta',
|
|
38
|
+
defaultModel: config.model ?? 'gemini-1.5-pro',
|
|
39
|
+
timeoutMs: config.timeoutMs,
|
|
40
|
+
maxRetries: config.maxRetries,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async complete(
|
|
45
|
+
messages: LLMMessage[],
|
|
46
|
+
options: LLMRequestOptions = {}
|
|
47
|
+
): Promise<LLMResponse> {
|
|
48
|
+
return this.withRetry(async () => {
|
|
49
|
+
const model = this.getModel(options);
|
|
50
|
+
const url = `${this.baseUrl}/models/${model}:generateContent?key=${this.apiKey}`;
|
|
51
|
+
|
|
52
|
+
const requestBody = this.buildRequestBody(messages, options);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const response = await axios.post(url, requestBody, {
|
|
56
|
+
timeout: options.timeoutMs ?? this.timeoutMs,
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return this.parseResponse(response.data, model);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (axios.isAxiosError(error)) {
|
|
65
|
+
const statusCode = error.response?.status;
|
|
66
|
+
const errorMessage = error.response?.data?.error?.message ?? error.message;
|
|
67
|
+
|
|
68
|
+
logger.error('Gemini API error', { statusCode, errorMessage });
|
|
69
|
+
throw new LLMError(errorMessage, 'gemini', statusCode);
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async *stream(
|
|
77
|
+
messages: LLMMessage[],
|
|
78
|
+
options: LLMRequestOptions = {}
|
|
79
|
+
): AsyncGenerator<LLMStreamChunk> {
|
|
80
|
+
const model = this.getModel(options);
|
|
81
|
+
const url = `${this.baseUrl}/models/${model}:streamGenerateContent?key=${this.apiKey}`;
|
|
82
|
+
|
|
83
|
+
const requestBody = this.buildRequestBody(messages, options);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const response = await axios.post(url, requestBody, {
|
|
87
|
+
timeout: options.timeoutMs ?? this.timeoutMs,
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
},
|
|
91
|
+
responseType: 'stream',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const stream = response.data;
|
|
95
|
+
|
|
96
|
+
for await (const chunk of stream) {
|
|
97
|
+
const lines = chunk.toString().split('\n').filter((line: string) => line.trim());
|
|
98
|
+
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
try {
|
|
101
|
+
const data = JSON.parse(line);
|
|
102
|
+
const content = data.candidates?.[0]?.content?.parts?.[0]?.text ?? '';
|
|
103
|
+
|
|
104
|
+
if (content) {
|
|
105
|
+
yield {
|
|
106
|
+
content,
|
|
107
|
+
isComplete: false,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
// Ignore parse errors for non-JSON lines
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
yield {
|
|
117
|
+
content: '',
|
|
118
|
+
isComplete: true,
|
|
119
|
+
};
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (axios.isAxiosError(error)) {
|
|
122
|
+
const statusCode = error.response?.status;
|
|
123
|
+
const errorMessage = error.response?.data?.error?.message ?? error.message;
|
|
124
|
+
throw new LLMError(errorMessage, 'gemini', statusCode);
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private buildRequestBody(messages: LLMMessage[], options: LLMRequestOptions): Record<string, unknown> {
|
|
131
|
+
const contents = messages.map(msg => ({
|
|
132
|
+
role: msg.role === 'user' ? 'user' : 'model',
|
|
133
|
+
parts: [{ text: msg.content }],
|
|
134
|
+
}));
|
|
135
|
+
|
|
136
|
+
const body: Record<string, unknown> = {
|
|
137
|
+
contents,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
if (options.temperature !== undefined) {
|
|
141
|
+
body.generationConfig = {
|
|
142
|
+
...(body.generationConfig as Record<string, unknown>),
|
|
143
|
+
temperature: options.temperature,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (options.maxTokens !== undefined) {
|
|
148
|
+
body.generationConfig = {
|
|
149
|
+
...(body.generationConfig as Record<string, unknown>),
|
|
150
|
+
maxOutputTokens: options.maxTokens,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.topP !== undefined) {
|
|
155
|
+
body.generationConfig = {
|
|
156
|
+
...(body.generationConfig as Record<string, unknown>),
|
|
157
|
+
topP: options.topP,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (options.stopSequences !== undefined) {
|
|
162
|
+
body.generationConfig = {
|
|
163
|
+
...(body.generationConfig as Record<string, unknown>),
|
|
164
|
+
stopSequences: options.stopSequences,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return body;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private parseResponse(data: Record<string, unknown>, model: string): LLMResponse {
|
|
172
|
+
const candidate = (data.candidates as unknown[])?.[0] as Record<string, unknown> | undefined;
|
|
173
|
+
const content = candidate?.content as Record<string, unknown> | undefined;
|
|
174
|
+
const parts = content?.parts as Array<{ text?: string }> | undefined;
|
|
175
|
+
const text = parts?.[0]?.text ?? '';
|
|
176
|
+
|
|
177
|
+
const usage = data.usageMetadata as Record<string, number> | undefined;
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
content: text,
|
|
181
|
+
model,
|
|
182
|
+
usage: {
|
|
183
|
+
promptTokens: usage?.promptTokenCount ?? 0,
|
|
184
|
+
completionTokens: usage?.candidatesTokenCount ?? 0,
|
|
185
|
+
totalTokens: usage?.totalTokenCount ?? 0,
|
|
186
|
+
},
|
|
187
|
+
finishReason: (candidate?.finishReason as string) ?? 'stop',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected override isNonRetryableError(error: unknown): boolean {
|
|
192
|
+
if (axios.isAxiosError(error)) {
|
|
193
|
+
const statusCode = error.response?.status;
|
|
194
|
+
// Don't retry on client errors (4xx except 429)
|
|
195
|
+
if (statusCode !== undefined && statusCode >= 400 && statusCode < 500 && statusCode !== 429) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Sanitization for LLM Service
|
|
3
|
+
*
|
|
4
|
+
* Provides security-focused sanitization to prevent prompt injection
|
|
5
|
+
* and other LLM-related security vulnerabilities.
|
|
6
|
+
*
|
|
7
|
+
* @module llm/sanitization
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { logger } from '../utils/logger';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sanitization options
|
|
14
|
+
*/
|
|
15
|
+
export interface SanitizationOptions {
|
|
16
|
+
maxLength?: number;
|
|
17
|
+
allowCode?: boolean;
|
|
18
|
+
allowHTML?: boolean;
|
|
19
|
+
allowedTags?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default sanitization options
|
|
24
|
+
*/
|
|
25
|
+
const DEFAULT_OPTIONS: SanitizationOptions = {
|
|
26
|
+
maxLength: 10000,
|
|
27
|
+
allowCode: false,
|
|
28
|
+
allowHTML: false,
|
|
29
|
+
allowedTags: [],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Dangerous patterns that could indicate prompt injection
|
|
34
|
+
*/
|
|
35
|
+
const DANGEROUS_PATTERNS = [
|
|
36
|
+
// System prompt injection attempts
|
|
37
|
+
/ignore\s+(previous|prior|above)\s+instructions?/gi,
|
|
38
|
+
/disregard\s+(all\s+)?(previous|prior)\s+instructions?/gi,
|
|
39
|
+
/forget\s+(everything|all)\s+(you\s+)?(were\s+)?told/gi,
|
|
40
|
+
/system\s*:\s*/gi,
|
|
41
|
+
/user\s*:\s*/gi,
|
|
42
|
+
/assistant\s*:\s*/gi,
|
|
43
|
+
/\[system\s+prompt\]/gi,
|
|
44
|
+
/\[instructions\]/gi,
|
|
45
|
+
|
|
46
|
+
// Jailbreak attempts
|
|
47
|
+
/DAN\s*\(|do\s+anything\s+now/gi,
|
|
48
|
+
/jailbreak/gi,
|
|
49
|
+
/\bmode\s*:\s*\w+\s+unfiltered/gi,
|
|
50
|
+
/no\s+(restrictions?|limits?|filter)/gi,
|
|
51
|
+
|
|
52
|
+
// Delimiter manipulation
|
|
53
|
+
/```\s*system/gi,
|
|
54
|
+
/<\|system\|>/gi,
|
|
55
|
+
/<\|im_start\|>/gi,
|
|
56
|
+
/<\|im_end\|>/gi,
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Sanitize a prompt for LLM use
|
|
61
|
+
*
|
|
62
|
+
* @param input - Raw input string
|
|
63
|
+
* @param options - Sanitization options
|
|
64
|
+
* @returns Sanitized string
|
|
65
|
+
*/
|
|
66
|
+
export function sanitizePrompt(input: string, options: SanitizationOptions = {}): string {
|
|
67
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
68
|
+
|
|
69
|
+
// Check for dangerous patterns
|
|
70
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
71
|
+
if (pattern.test(input)) {
|
|
72
|
+
logger.warn('Potentially dangerous pattern detected in prompt', { pattern: pattern.source });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let sanitized = input;
|
|
77
|
+
|
|
78
|
+
// Remove null bytes and control characters
|
|
79
|
+
sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
|
|
80
|
+
|
|
81
|
+
// Remove potential prompt injection markers
|
|
82
|
+
sanitized = sanitized.replace(/^(system|user|assistant)\s*:\s*/gim, '');
|
|
83
|
+
|
|
84
|
+
// Remove system prompt markers
|
|
85
|
+
sanitized = sanitized.replace(/\[system\s+prompt\]/gi, '');
|
|
86
|
+
sanitized = sanitized.replace(/\[instructions?\]/gi, '');
|
|
87
|
+
|
|
88
|
+
// Handle code blocks
|
|
89
|
+
if (!opts.allowCode) {
|
|
90
|
+
// Escape code block markers
|
|
91
|
+
sanitized = sanitized.replace(/```/g, '` ` `');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Handle HTML
|
|
95
|
+
if (!opts.allowHTML) {
|
|
96
|
+
// Remove or escape HTML tags
|
|
97
|
+
sanitized = sanitized.replace(/</g, '<').replace(/>/g, '>');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Trim whitespace
|
|
101
|
+
sanitized = sanitized.trim();
|
|
102
|
+
|
|
103
|
+
// Enforce length limit
|
|
104
|
+
if (sanitized.length > opts.maxLength!) {
|
|
105
|
+
logger.warn('Prompt truncated due to length limit', {
|
|
106
|
+
originalLength: sanitized.length,
|
|
107
|
+
maxLength: opts.maxLength
|
|
108
|
+
});
|
|
109
|
+
sanitized = sanitized.substring(0, opts.maxLength);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return sanitized;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Validate that a prompt is safe to use
|
|
117
|
+
*
|
|
118
|
+
* @param input - Input to validate
|
|
119
|
+
* @returns Validation result
|
|
120
|
+
*/
|
|
121
|
+
export function validatePrompt(input: string): { safe: boolean; issues: string[] } {
|
|
122
|
+
const issues: string[] = [];
|
|
123
|
+
|
|
124
|
+
// Check for dangerous patterns
|
|
125
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
126
|
+
if (pattern.test(input)) {
|
|
127
|
+
issues.push(`Suspicious pattern detected: ${pattern.source}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check length
|
|
132
|
+
if (input.length > 10000) {
|
|
133
|
+
issues.push('Input exceeds maximum length of 10000 characters');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check for null bytes
|
|
137
|
+
if (/\x00/.test(input)) {
|
|
138
|
+
issues.push('Input contains null bytes');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
safe: issues.length === 0,
|
|
143
|
+
issues,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Escape special characters for safe inclusion in prompts
|
|
149
|
+
*
|
|
150
|
+
* @param input - Input to escape
|
|
151
|
+
* @returns Escaped string
|
|
152
|
+
*/
|
|
153
|
+
export function escapeSpecialChars(input: string): string {
|
|
154
|
+
return input
|
|
155
|
+
.replace(/\\/g, '\\\\')
|
|
156
|
+
.replace(/"/g, '\\"')
|
|
157
|
+
.replace(/\n/g, '\\n')
|
|
158
|
+
.replace(/\r/g, '\\r')
|
|
159
|
+
.replace(/\t/g, '\\t');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Sanitize LLM response to remove any system-like content
|
|
164
|
+
*
|
|
165
|
+
* @param response - LLM response
|
|
166
|
+
* @returns Sanitized response
|
|
167
|
+
*/
|
|
168
|
+
export function sanitizeResponse(response: string): string {
|
|
169
|
+
let sanitized = response;
|
|
170
|
+
|
|
171
|
+
// Remove system-like prefixes
|
|
172
|
+
sanitized = sanitized.replace(/^(system|user|assistant)\s*:\s*/gim, '');
|
|
173
|
+
|
|
174
|
+
// Remove any embedded instructions
|
|
175
|
+
sanitized = sanitized.replace(/\[system\s+prompt\].*?\[\/system\s+prompt\]/gis, '');
|
|
176
|
+
|
|
177
|
+
return sanitized.trim();
|
|
178
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { SequentialThinkingEngine } from "../core/engine";
|
|
10
|
+
import { Logger } from "../utils/logger";
|
|
11
|
+
|
|
12
|
+
const logger = new Logger('MCPServer');
|
|
13
|
+
const engine = new SequentialThinkingEngine();
|
|
14
|
+
|
|
15
|
+
const server = new Server(
|
|
16
|
+
{
|
|
17
|
+
name: "gthinking",
|
|
18
|
+
version: "2.0.0",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
capabilities: {
|
|
22
|
+
tools: {},
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
+
return {
|
|
29
|
+
tools: [
|
|
30
|
+
{
|
|
31
|
+
name: "think",
|
|
32
|
+
description: "Execute full thinking pipeline",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
query: { type: "string" },
|
|
37
|
+
preferredStages: {
|
|
38
|
+
type: "array",
|
|
39
|
+
items: { type: "string" }
|
|
40
|
+
},
|
|
41
|
+
options: { type: "object" }
|
|
42
|
+
},
|
|
43
|
+
required: ["query"]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "quick_search",
|
|
48
|
+
description: "Execute quick search",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
query: { type: "string" }
|
|
53
|
+
},
|
|
54
|
+
required: ["query"]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "creative_solve",
|
|
59
|
+
description: "Solve problem creatively",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
challenge: { type: "string" },
|
|
64
|
+
techniques: {
|
|
65
|
+
type: "array",
|
|
66
|
+
items: { type: "string" }
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
required: ["challenge"]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
77
|
+
const { name, arguments: args } = request.params;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
if (name === "think") {
|
|
81
|
+
const result = await engine.think(args);
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
84
|
+
};
|
|
85
|
+
} else if (name === "quick_search") {
|
|
86
|
+
const query = (args as any).query;
|
|
87
|
+
const result = await engine.quickSearch(query);
|
|
88
|
+
return {
|
|
89
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
90
|
+
};
|
|
91
|
+
} else if (name === "creative_solve") {
|
|
92
|
+
const challenge = (args as any).challenge;
|
|
93
|
+
const result = await engine.creativeSolve(challenge);
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: `Error: ${(error as Error).message}` }],
|
|
103
|
+
isError: true
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
async function run() {
|
|
109
|
+
const transport = new StdioServerTransport();
|
|
110
|
+
await server.connect(transport);
|
|
111
|
+
logger.info("MCP Server running on stdio");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
run().catch((error) => {
|
|
115
|
+
console.error("Fatal error running server:", error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Logger } from '../utils/logger';
|
|
3
|
+
|
|
4
|
+
const logger = new Logger('PlanningEngine');
|
|
5
|
+
|
|
6
|
+
export class PlanningEngine extends EventEmitter {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createPlanningEngine(): PlanningEngine {
|
|
13
|
+
return new PlanningEngine();
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Logger } from '../utils/logger';
|
|
3
|
+
|
|
4
|
+
const logger = new Logger('ReasoningEngine');
|
|
5
|
+
|
|
6
|
+
export class ReasoningEngine extends EventEmitter {
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createReasoningEngine(): ReasoningEngine {
|
|
13
|
+
return new ReasoningEngine();
|
|
14
|
+
}
|