@pedrofariasx/qwenproxy 1.1.0

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 (59) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +292 -0
  3. package/bin/qwenproxy.mjs +11 -0
  4. package/package.json +56 -0
  5. package/src/api/models.ts +183 -0
  6. package/src/api/server.ts +126 -0
  7. package/src/cache/memory-cache.ts +186 -0
  8. package/src/core/account-manager.ts +132 -0
  9. package/src/core/accounts.ts +78 -0
  10. package/src/core/config.ts +91 -0
  11. package/src/core/database.ts +92 -0
  12. package/src/core/logger.ts +96 -0
  13. package/src/core/metrics.ts +169 -0
  14. package/src/core/model-registry.ts +30 -0
  15. package/src/core/stream-registry.ts +40 -0
  16. package/src/core/watchdog.ts +130 -0
  17. package/src/index.ts +7 -0
  18. package/src/linter/extraction-engine.ts +165 -0
  19. package/src/linter/index.ts +258 -0
  20. package/src/linter/repair-normalize.ts +245 -0
  21. package/src/linter/safety-gate.ts +219 -0
  22. package/src/linter/streaming-state-machine.ts +252 -0
  23. package/src/linter/structural-parser.ts +352 -0
  24. package/src/linter/types.ts +74 -0
  25. package/src/login.ts +228 -0
  26. package/src/routes/chat.ts +801 -0
  27. package/src/routes/upload.ts +700 -0
  28. package/src/services/playwright.ts +778 -0
  29. package/src/services/qwen.ts +500 -0
  30. package/src/tests/advanced.test.ts +227 -0
  31. package/src/tests/agenticStress.test.ts +360 -0
  32. package/src/tests/concurrency.test.ts +103 -0
  33. package/src/tests/concurrentChat.test.ts +71 -0
  34. package/src/tests/delta.test.ts +63 -0
  35. package/src/tests/index.test.ts +356 -0
  36. package/src/tests/jsonFix.test.ts +98 -0
  37. package/src/tests/linter.test.ts +151 -0
  38. package/src/tests/parallel.test.ts +42 -0
  39. package/src/tests/parser.test.ts +89 -0
  40. package/src/tests/rotation.test.ts +45 -0
  41. package/src/tests/streamingOptimizations.test.ts +328 -0
  42. package/src/tests/structureVerification.test.ts +176 -0
  43. package/src/tools/ast.ts +15 -0
  44. package/src/tools/coercion.ts +67 -0
  45. package/src/tools/confidence.ts +48 -0
  46. package/src/tools/detector.ts +40 -0
  47. package/src/tools/executor.ts +236 -0
  48. package/src/tools/parser.ts +446 -0
  49. package/src/tools/pipeline.ts +122 -0
  50. package/src/tools/registry-runtime.ts +34 -0
  51. package/src/tools/registry.ts +142 -0
  52. package/src/tools/repair.ts +42 -0
  53. package/src/tools/schema.ts +285 -0
  54. package/src/tools/types.ts +104 -0
  55. package/src/tools/validator.ts +33 -0
  56. package/src/utils/context-truncation.ts +61 -0
  57. package/src/utils/json.ts +114 -0
  58. package/src/utils/qwen-stream-parser.ts +286 -0
  59. package/src/utils/types.ts +101 -0
@@ -0,0 +1,71 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert';
3
+ import net from 'node:net';
4
+ import { serve } from '@hono/node-server';
5
+ import { app } from '../api/server.js';
6
+ import { initPlaywright, closePlaywright } from '../services/playwright.ts';
7
+
8
+ function isPortAvailable(port: number): Promise<boolean> {
9
+ return new Promise((resolve) => {
10
+ const server = net.createServer();
11
+ server.once('error', () => resolve(false));
12
+ server.once('listening', () => {
13
+ server.close(() => resolve(true));
14
+ });
15
+ server.listen(port);
16
+ });
17
+ }
18
+
19
+ async function getFreePort(startPort: number): Promise<number> {
20
+ let port = startPort;
21
+ while (true) {
22
+ const available = await isPortAvailable(port);
23
+ if (available) return port;
24
+ port++;
25
+ }
26
+ }
27
+
28
+ test('Concurrent chat requests check for "chat is in progress"', { skip: process.env.CI ? 'Requires real accounts - skipped in CI' : false }, async () => {
29
+ const port = await getFreePort(3100);
30
+ const server = serve({ fetch: app.fetch, port });
31
+ console.log(`[ConcurrentTest] Server started on port ${port}`);
32
+
33
+ await initPlaywright(true);
34
+
35
+ try {
36
+ const requestPayload = {
37
+ model: 'qwen3.6-plus',
38
+ messages: [{ role: 'user', content: 'Say "hello" and nothing else.' }],
39
+ stream: false
40
+ };
41
+
42
+ console.log('[ConcurrentTest] Sending 2 requests concurrently...');
43
+
44
+ const p1 = fetch(`http://localhost:${port}/v1/chat/completions`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify(requestPayload)
48
+ });
49
+
50
+ const p2 = fetch(`http://localhost:${port}/v1/chat/completions`, {
51
+ method: 'POST',
52
+ headers: { 'Content-Type': 'application/json' },
53
+ body: JSON.stringify(requestPayload)
54
+ });
55
+
56
+ const [res1, res2] = await Promise.all([p1, p2]);
57
+
58
+ const data1 = await res1.json();
59
+ const data2 = await res2.json();
60
+
61
+ console.log('[ConcurrentTest] Result 1:', res1.status, JSON.stringify(data1).substring(0, 200));
62
+ console.log('[ConcurrentTest] Result 2:', res2.status, JSON.stringify(data2).substring(0, 200));
63
+
64
+ assert.strictEqual(res1.status, 200, `Request 1 failed: ${JSON.stringify(data1)}`);
65
+ assert.strictEqual(res2.status, 200, `Request 2 failed: ${JSON.stringify(data2)}`);
66
+
67
+ } finally {
68
+ await closePlaywright();
69
+ server.close();
70
+ }
71
+ });
@@ -0,0 +1,63 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { getIncrementalDelta } from '../routes/chat.ts';
4
+
5
+ test('getIncrementalDelta: handles strictly cumulative stream correctly', () => {
6
+ let accumulated = '';
7
+
8
+ // Step 1
9
+ let chunk1 = 'const x = 1;';
10
+ let res1 = getIncrementalDelta(accumulated, chunk1);
11
+ assert.strictEqual(res1.delta, 'const x = 1;');
12
+ accumulated = res1.matchedContent;
13
+
14
+ // Step 2
15
+ let chunk2 = 'const x = 1;\nconst y = 2;';
16
+ let res2 = getIncrementalDelta(accumulated, chunk2);
17
+ assert.strictEqual(res2.delta, '\nconst y = 2;');
18
+ accumulated = res2.matchedContent;
19
+
20
+ // Step 3
21
+ let chunk3 = 'const x = 1;\nconst y = 2;\nconst z = 3;';
22
+ let res3 = getIncrementalDelta(accumulated, chunk3);
23
+ assert.strictEqual(res3.delta, '\nconst z = 3;');
24
+ accumulated = res3.matchedContent;
25
+
26
+ assert.strictEqual(accumulated, 'const x = 1;\nconst y = 2;\nconst z = 3;');
27
+ });
28
+
29
+ test('getIncrementalDelta: handles strictly incremental stream correctly', () => {
30
+ let accumulated = '';
31
+
32
+ // Step 1
33
+ let chunk1 = 'const x = 1;';
34
+ let res1 = getIncrementalDelta(accumulated, chunk1);
35
+ assert.strictEqual(res1.delta, 'const x = 1;');
36
+ accumulated = res1.matchedContent;
37
+
38
+ // Step 2
39
+ let chunk2 = '\nconst y = 2;';
40
+ let res2 = getIncrementalDelta(accumulated, chunk2);
41
+ assert.strictEqual(res2.delta, '\nconst y = 2;');
42
+ accumulated = res2.matchedContent;
43
+
44
+ // Step 3
45
+ let chunk3 = '\nconst z = 3;';
46
+ let res3 = getIncrementalDelta(accumulated, chunk3);
47
+ assert.strictEqual(res3.delta, '\nconst z = 3;');
48
+ accumulated = res3.matchedContent;
49
+
50
+ assert.strictEqual(accumulated, 'const x = 1;\nconst y = 2;\nconst z = 3;');
51
+ });
52
+
53
+ test('getIncrementalDelta: does not suffer from false-positive repetitive word overlap bugs', () => {
54
+ // Previously, if oldStr ended in a common keyword and newStr started/contained the same keyword,
55
+ // it would incorrectly match them and strip them. Let's verify this is fixed.
56
+ let accumulated = 'import { useState } from \'react\';\nimport {';
57
+ let nextChunk = ' Button } from \'@/components/ui/button\';';
58
+
59
+ let res = getIncrementalDelta(accumulated, nextChunk);
60
+ // It should treat the next chunk as strictly incremental and return it unchanged.
61
+ assert.strictEqual(res.delta, ' Button } from \'@/components/ui/button\';');
62
+ assert.strictEqual(res.matchedContent, 'import { useState } from \'react\';\nimport { Button } from \'@/components/ui/button\';');
63
+ });
@@ -0,0 +1,356 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert';
3
+
4
+ process.env.TEST_MOCK_PLAYWRIGHT = 'true';
5
+ // Ensure API_KEY is empty by default for existing tests
6
+ process.env.API_KEY = '';
7
+
8
+ import { app } from '../api/server.js';
9
+ import { initPlaywright, closePlaywright } from '../services/playwright.ts';
10
+
11
+ test('Health check endpoint returns 200', async () => {
12
+ const req = new Request('http://localhost/health');
13
+ const res = await app.fetch(req);
14
+
15
+ assert.strictEqual(res.status, 200);
16
+
17
+ const body = await res.json();
18
+ assert.ok(body.status === 'ok' || body.status === 'unknown');
19
+ assert.ok(body.timestamp);
20
+ });
21
+
22
+ test('Models endpoint returns qwen3.6-plus and qwen3.6-plus-no-thinking', async () => {
23
+ const originalFetch = globalThis.fetch;
24
+ globalThis.fetch = async (input: any) => {
25
+ const url = typeof input === 'string' ? input : input.url;
26
+ if (url.includes('/api/models')) {
27
+ return new Response(JSON.stringify({ data: [{ id: 'qwen3.6-plus', owned_by: 'qwen' }] }), { status: 200 });
28
+ }
29
+ return originalFetch(input);
30
+ };
31
+
32
+ try {
33
+ const req = new Request('http://localhost/v1/models');
34
+ const res = await app.fetch(req);
35
+
36
+ assert.strictEqual(res.status, 200);
37
+
38
+ const body = await res.json();
39
+ assert.strictEqual(body.object, 'list');
40
+ assert.ok(Array.isArray(body.data));
41
+ assert.ok(body.data.some((m: any) => m.id === 'qwen3.6-plus'));
42
+ assert.ok(body.data.some((m: any) => m.id === 'qwen3.6-plus-no-thinking'));
43
+ } finally {
44
+ globalThis.fetch = originalFetch;
45
+ }
46
+ });
47
+
48
+ test('Chat Completions endpoint with qwen3.6-plus (thinking enabled)', async () => {
49
+ const originalFetch = globalThis.fetch;
50
+ globalThis.fetch = async (input: any) => {
51
+ const url = typeof input === 'string' ? input : input.url;
52
+ if (url.includes('/api/models')) {
53
+ return new Response(JSON.stringify({ data: [{ id: 'qwen3.6-plus', owned_by: 'qwen' }] }), { status: 200 });
54
+ }
55
+ if (url.includes('/api/v2/chat/completions')) {
56
+ const stream = new ReadableStream({
57
+ start(c) {
58
+ c.enqueue(new TextEncoder().encode('data: {"choices": [{"delta": {"phase": "thinking_summary", "extra": {"summary_thought": {"content": ["Thinking..."]}}}}]}\n\n'));
59
+ c.enqueue(new TextEncoder().encode('data: {"choices": [{"delta": {"phase": "answer", "content": "Hello"}}]}\n\n'));
60
+ c.enqueue(new TextEncoder().encode('data: [DONE]\n\n'));
61
+ c.close();
62
+ }
63
+ });
64
+ return new Response(stream, { status: 200 });
65
+ }
66
+ return originalFetch(input);
67
+ };
68
+
69
+ // Initialize playwright for this test
70
+ await initPlaywright(false);
71
+
72
+ try {
73
+ const payload = {
74
+ model: 'qwen3.6-plus',
75
+ messages: [{ role: 'user', content: 'What is 99 * 182? Please think step by step.' }],
76
+ stream: true
77
+ };
78
+
79
+ const req = new Request('http://localhost/v1/chat/completions', {
80
+ method: 'POST',
81
+ headers: { 'Content-Type': 'application/json' },
82
+ body: JSON.stringify(payload)
83
+ });
84
+
85
+ const res = await app.fetch(req);
86
+ assert.strictEqual(res.status, 200);
87
+ assert.strictEqual(res.headers.get('Content-Type'), 'text/event-stream');
88
+
89
+ const reader = res.body?.getReader();
90
+ assert.ok(reader, 'Response should have a readable body');
91
+
92
+ const decoder = new TextDecoder();
93
+ let hasReasoning = false;
94
+ let hasContent = false;
95
+
96
+ while (true) {
97
+ const { done, value } = await reader.read();
98
+ if (done) break;
99
+
100
+ const chunk = decoder.decode(value);
101
+ const lines = chunk.split('\n');
102
+
103
+ for (const line of lines) {
104
+ if (line.trim() === 'data: [DONE]') {
105
+ break;
106
+ }
107
+ if (line.startsWith('data: ')) {
108
+ try {
109
+ const dataStr = line.slice(6);
110
+ if (dataStr !== '[DONE]') {
111
+ const data = JSON.parse(dataStr);
112
+
113
+ if (data.choices && data.choices[0] && data.choices[0].delta) {
114
+ const delta = data.choices[0].delta;
115
+ if (delta.content) {
116
+ hasContent = true;
117
+ }
118
+ if (delta.reasoning_content) {
119
+ hasReasoning = true;
120
+ }
121
+ }
122
+ }
123
+ } catch (err) {
124
+ // Partial JSON ignored
125
+ // console.error("Parse error:", err);
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ assert.ok(hasReasoning, 'Should have received streamed chunks with reasoning_content (Thinking enabled)');
132
+ assert.ok(hasContent, 'Should have received streamed chunks with content');
133
+ } finally {
134
+ globalThis.fetch = originalFetch;
135
+ await closePlaywright();
136
+ }
137
+ });
138
+
139
+ test('Chat Completions returns explicit error for non-SSE upstream JSON errors', async () => {
140
+ const originalFetch = globalThis.fetch;
141
+ globalThis.fetch = async (input: any) => {
142
+ const url = typeof input === 'string' ? input : input.url;
143
+ if (url.includes('/api/v2/chat/completions')) {
144
+ return new Response(JSON.stringify({
145
+ success: false,
146
+ data: {
147
+ code: 'RateLimited',
148
+ details: "You've reached the upper limit for today's usage.",
149
+ num: 3
150
+ }
151
+ }), { status: 200, headers: { 'Content-Type': 'application/json' } });
152
+ }
153
+ return originalFetch(input);
154
+ };
155
+
156
+ await initPlaywright(false);
157
+
158
+ try {
159
+ const req = new Request('http://localhost/v1/chat/completions', {
160
+ method: 'POST',
161
+ headers: { 'Content-Type': 'application/json' },
162
+ body: JSON.stringify({
163
+ model: 'qwen3.6-plus',
164
+ messages: [{ role: 'user', content: 'hello' }],
165
+ stream: false
166
+ })
167
+ });
168
+
169
+ const res = await app.fetch(req);
170
+ assert.strictEqual(res.status, 429);
171
+
172
+ const body = await res.json();
173
+ assert.match(body.error.message, /Qwen upstream error: RateLimited/);
174
+ assert.match(body.error.message, /upper limit/);
175
+ } finally {
176
+ globalThis.fetch = originalFetch;
177
+ await closePlaywright();
178
+ }
179
+ });
180
+
181
+ test('Chat Completions returns a JSON chat.completion object for non-streaming requests', async () => {
182
+ const originalFetch = globalThis.fetch;
183
+ globalThis.fetch = async (input: any) => {
184
+ const url = typeof input === 'string' ? input : input.url;
185
+ if (url.includes('/api/v2/chat/completions')) {
186
+ const stream = new ReadableStream({
187
+ start(c) {
188
+ c.enqueue(new TextEncoder().encode('data: {"choices": [{"delta": {"phase": "answer", "content": "Hello"}}]}\n\n'));
189
+ c.enqueue(new TextEncoder().encode('data: [DONE]\n\n'));
190
+ c.close();
191
+ }
192
+ });
193
+ return new Response(stream, { status: 200 });
194
+ }
195
+ return originalFetch(input);
196
+ };
197
+
198
+ await initPlaywright(false);
199
+
200
+ try {
201
+ const req = new Request('http://localhost/v1/chat/completions', {
202
+ method: 'POST',
203
+ headers: { 'Content-Type': 'application/json' },
204
+ body: JSON.stringify({
205
+ model: 'qwen3.6-plus',
206
+ messages: [{ role: 'user', content: 'hello' }],
207
+ stream: false
208
+ })
209
+ });
210
+
211
+ const res = await app.fetch(req);
212
+ assert.strictEqual(res.status, 200);
213
+
214
+ const body = await res.json();
215
+ assert.strictEqual(body.object, 'chat.completion');
216
+ assert.strictEqual(body.choices[0].message.role, 'assistant');
217
+ assert.strictEqual(body.choices[0].message.content, 'Hello');
218
+ } finally {
219
+ globalThis.fetch = originalFetch;
220
+ await closePlaywright();
221
+ }
222
+ });
223
+
224
+ test('API Key protection', async () => {
225
+ const originalApiKey = process.env.API_KEY;
226
+ process.env.API_KEY = 'test-api-key';
227
+
228
+ try {
229
+ // 1. Test request without API Key
230
+ const req1 = new Request('http://localhost/v1/models');
231
+ const res1 = await app.fetch(req1);
232
+ assert.strictEqual(res1.status, 401, 'Should return 401 Unauthorized without API Key');
233
+
234
+ // 2. Test request with wrong API Key
235
+ const req2 = new Request('http://localhost/v1/models', {
236
+ headers: { 'Authorization': 'Bearer wrong-key' }
237
+ });
238
+ const res2 = await app.fetch(req2);
239
+ assert.strictEqual(res2.status, 401, 'Should return 401 Unauthorized with wrong API Key');
240
+
241
+ // 3. Test request with correct API Key
242
+ // Mock fetch for models list
243
+ const originalFetch = globalThis.fetch;
244
+ globalThis.fetch = async () => new Response(JSON.stringify({ data: [] }), { status: 200 });
245
+
246
+ try {
247
+ const req3 = new Request('http://localhost/v1/models', {
248
+ headers: { 'Authorization': 'Bearer test-api-key' }
249
+ });
250
+ const res3 = await app.fetch(req3);
251
+ assert.strictEqual(res3.status, 200, 'Should return 200 OK with correct API Key');
252
+ } finally {
253
+ globalThis.fetch = originalFetch;
254
+ }
255
+ } finally {
256
+ process.env.API_KEY = originalApiKey;
257
+ }
258
+ });
259
+
260
+ test('Chat Completions endpoint - Non-streaming (stream: false)', async () => {
261
+ const originalFetch = globalThis.fetch;
262
+ globalThis.fetch = async (input: any) => {
263
+ const url = typeof input === 'string' ? input : input.url;
264
+ if (url.includes('/api/models')) {
265
+ return new Response(JSON.stringify({ data: [{ id: 'qwen3.6-plus', owned_by: 'qwen' }] }), { status: 200 });
266
+ }
267
+ if (url.includes('/api/v2/chat/completions')) {
268
+ const stream = new ReadableStream({
269
+ start(c) {
270
+ c.enqueue(new TextEncoder().encode('data: {"choices": [{"delta": {"phase": "thinking_summary", "extra": {"summary_thought": {"content": ["Thinking non-stream..."]}}}}]}\n\n'));
271
+ c.enqueue(new TextEncoder().encode('data: {"choices": [{"delta": {"phase": "answer", "content": "Hello non-stream"}}]}\n\n'));
272
+ c.enqueue(new TextEncoder().encode('data: [DONE]\n\n'));
273
+ c.close();
274
+ }
275
+ });
276
+ return new Response(stream, { status: 200 });
277
+ }
278
+ return originalFetch(input);
279
+ };
280
+
281
+ // Initialize playwright for this test
282
+ await initPlaywright(false);
283
+
284
+ try {
285
+ const payload = {
286
+ model: 'qwen3.6-plus',
287
+ messages: [{ role: 'user', content: 'Hello' }],
288
+ stream: false
289
+ };
290
+
291
+ const req = new Request('http://localhost/v1/chat/completions', {
292
+ method: 'POST',
293
+ headers: { 'Content-Type': 'application/json' },
294
+ body: JSON.stringify(payload)
295
+ });
296
+
297
+ const res = await app.fetch(req);
298
+ assert.strictEqual(res.status, 200);
299
+ assert.ok(res.headers.get('Content-Type')?.includes('application/json'));
300
+
301
+ const body = await res.json();
302
+ assert.strictEqual(body.object, 'chat.completion');
303
+ assert.strictEqual(body.model, 'qwen3.6-plus');
304
+ assert.ok(body.choices);
305
+ assert.strictEqual(body.choices.length, 1);
306
+
307
+ const choice = body.choices[0];
308
+ assert.strictEqual(choice.message.role, 'assistant');
309
+ assert.strictEqual(choice.message.content, 'Hello non-stream');
310
+ assert.strictEqual(choice.message.reasoning_content, 'Thinking non-stream...');
311
+ assert.strictEqual(choice.finish_reason, 'stop');
312
+
313
+ assert.ok(body.usage);
314
+ assert.ok(body.usage.prompt_tokens > 0);
315
+ assert.ok(body.usage.completion_tokens >= 0);
316
+ } finally {
317
+ globalThis.fetch = originalFetch;
318
+ await closePlaywright();
319
+ }
320
+ });
321
+
322
+ test('Models endpoint caching: subsequent requests return cached models without fetch', async () => {
323
+ const originalFetch = globalThis.fetch;
324
+ let fetchCount = 0;
325
+ globalThis.fetch = async (input: any) => {
326
+ const url = typeof input === 'string' ? input : input.url;
327
+ if (url.includes('/api/models')) {
328
+ fetchCount++;
329
+ return new Response(JSON.stringify({ data: [{ id: 'qwen3.6-plus-cached-test', owned_by: 'qwen' }] }), { status: 200 });
330
+ }
331
+ return originalFetch(input);
332
+ };
333
+
334
+ try {
335
+ const { cache } = await import('../cache/memory-cache.js');
336
+ await cache.flush();
337
+
338
+ // First request
339
+ const req1 = new Request('http://localhost/v1/models');
340
+ const res1 = await app.fetch(req1);
341
+ assert.strictEqual(res1.status, 200);
342
+ const body1 = await res1.json();
343
+ assert.ok(body1.data.some((m: any) => m.id === 'qwen3.6-plus-cached-test'));
344
+ assert.strictEqual(fetchCount, 1);
345
+
346
+ // Second request
347
+ const req2 = new Request('http://localhost/v1/models');
348
+ const res2 = await app.fetch(req2);
349
+ assert.strictEqual(res2.status, 200);
350
+ const body2 = await res2.json();
351
+ assert.ok(body2.data.some((m: any) => m.id === 'qwen3.6-plus-cached-test'));
352
+ assert.strictEqual(fetchCount, 1);
353
+ } finally {
354
+ globalThis.fetch = originalFetch;
355
+ }
356
+ });
@@ -0,0 +1,98 @@
1
+ import { robustParseJSON } from '../utils/json.ts';
2
+
3
+ const problematicString = '{"name": "suggest", "arguments": {"suggest": "Landing page para escritório de advocacia criada em src/pages/Index.tsx", "actions": [{"label": "Revisar alterações", "description": "Executar review local das mudanças não commitadas", "prompt": "/local-review-uncommitted"}]})';
4
+
5
+ console.log('Testing problematic string...');
6
+ try {
7
+ const result = robustParseJSON(problematicString);
8
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
9
+ if (result.name === 'suggest' && result.arguments.actions.length === 1) {
10
+ console.log('✅ Problematic string test passed!');
11
+ } else {
12
+ console.error('❌ Result structure is incorrect');
13
+ }
14
+ } catch (e) {
15
+ console.error('❌ Failed to parse problematic string:', e);
16
+ }
17
+
18
+ const missingBraces = '{"name": "test", "arguments": {"foo": "bar"';
19
+ console.log('\nTesting missing braces...');
20
+ try {
21
+ const result = robustParseJSON(missingBraces);
22
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
23
+ if (result.arguments.foo === 'bar') {
24
+ console.log('✅ Missing braces test passed!');
25
+ } else {
26
+ console.error('❌ Result structure is incorrect');
27
+ }
28
+ } catch (e) {
29
+ console.error('❌ Failed to parse missing braces:', e);
30
+ }
31
+
32
+ const controlChars = '{"name": "control", "msg": "line 1\\nline 2"}';
33
+ console.log('\nTesting control characters in string...');
34
+ try {
35
+ // Note: in a real string from the model, it would be a literal newline
36
+ const literalNewline = '{"name": "control", "msg": "line 1\\nline 2"}'.replace('\\n', '\n');
37
+ const result = robustParseJSON(literalNewline);
38
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
39
+ if (result.msg.includes('line 1') && result.msg.includes('line 2')) {
40
+ console.log('✅ Control characters test passed!');
41
+ } else {
42
+ console.error('❌ Result content is incorrect');
43
+ }
44
+ } catch (e) {
45
+ console.error('❌ Failed to parse control characters:', e);
46
+ }
47
+
48
+ const crazyCase = `{"name": "suggest", "arguments": {"suggest": "Landing page criada para escritório de advocacia com design corporativo", "actions": [{"label": "Revisar código local", "description": "Exec<tool_call>\n{"name": "bashutar revisão local das", "arguments": alterações {"command": não commitadas", "npm run lint "prompt", "description":": "/local-review "Run lint-uncommitted"}] to verify code quality})"}}`;
49
+ console.log('\nTesting crazy nested hallucination case...');
50
+ try {
51
+ const result = robustParseJSON(crazyCase);
52
+ console.log('Successfully parsed (at least some of it):', JSON.stringify(result, null, 2));
53
+ console.log('✅ Crazy case handled without crashing!');
54
+ } catch (e: any) {
55
+ console.log('⚠️ Crazy case failed (too malformed), but error was:', e.message);
56
+ }
57
+
58
+ const invalidEscapes = '{"path": "C:\\\\Users\\\\name\\\\Documents"}';
59
+ console.log('\nTesting invalid backslash escapes in string...');
60
+ try {
61
+ const result = robustParseJSON(invalidEscapes);
62
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
63
+ if (result.path === 'C:\\\\Users\\\\name\\\\Documents' || result.path === 'C:\\Users\\name\\Documents') {
64
+ console.log('✅ Invalid backslash escapes test passed!');
65
+ } else {
66
+ console.error('❌ Result path is incorrect:', result.path);
67
+ }
68
+ } catch (e) {
69
+ console.error('❌ Failed to parse invalid backslash escapes:', e);
70
+ }
71
+
72
+ const doubleKey = '{"name": "name": "create_file", "arguments": {"path": "b.txt"}}';
73
+ console.log('\nTesting double key hallucination...');
74
+ try {
75
+ const result = robustParseJSON(doubleKey);
76
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
77
+ if (result.name === 'create_file') {
78
+ console.log('✅ Double key test passed!');
79
+ } else {
80
+ console.error('❌ Result name is incorrect:', result.name);
81
+ }
82
+ } catch (e) {
83
+ console.error('❌ Failed to parse double key:', e);
84
+ }
85
+
86
+ const unquotedArgs = '{"name":"Read",arguments:{"file_path":"test.ts","limit":100}}';
87
+ console.log('\nTesting unquoted arguments key...');
88
+ try {
89
+ const result = robustParseJSON(unquotedArgs);
90
+ console.log('Successfully parsed:', JSON.stringify(result, null, 2));
91
+ if (result.arguments && result.arguments.limit === 100) {
92
+ console.log('✅ Unquoted arguments test passed!');
93
+ } else {
94
+ console.error('❌ Result structure is incorrect');
95
+ }
96
+ } catch (e) {
97
+ console.error('❌ Failed to parse unquoted arguments:', e);
98
+ }