@nanocollective/nanocoder 1.17.2 → 1.18.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.
- package/README.md +3 -5
- package/assets/nanocoder-vscode.vsix +0 -0
- package/dist/ai-sdk-client-empty-message.spec.d.ts +2 -0
- package/dist/ai-sdk-client-empty-message.spec.d.ts.map +1 -0
- package/dist/ai-sdk-client-empty-message.spec.js +124 -0
- package/dist/ai-sdk-client-empty-message.spec.js.map +1 -0
- package/dist/ai-sdk-client-error-handling.spec.d.ts +2 -0
- package/dist/ai-sdk-client-error-handling.spec.d.ts.map +1 -0
- package/dist/ai-sdk-client-error-handling.spec.js +108 -0
- package/dist/ai-sdk-client-error-handling.spec.js.map +1 -0
- package/dist/ai-sdk-client-maxretries.spec.d.ts +2 -0
- package/dist/ai-sdk-client-maxretries.spec.d.ts.map +1 -0
- package/dist/ai-sdk-client-maxretries.spec.js +96 -0
- package/dist/ai-sdk-client-maxretries.spec.js.map +1 -0
- package/dist/ai-sdk-client.d.ts +25 -2
- package/dist/ai-sdk-client.d.ts.map +1 -1
- package/dist/ai-sdk-client.js +187 -124
- package/dist/ai-sdk-client.js.map +1 -1
- package/dist/app/utils/appUtils.js +3 -3
- package/dist/app/utils/appUtils.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +22 -11
- package/dist/app.js.map +1 -1
- package/dist/commands/debugging.d.ts +3 -0
- package/dist/commands/debugging.d.ts.map +1 -0
- package/dist/commands/debugging.js +23 -0
- package/dist/commands/debugging.js.map +1 -0
- package/dist/commands/index.d.ts +3 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +3 -2
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/lsp.d.ts +15 -0
- package/dist/commands/lsp.d.ts.map +1 -0
- package/dist/commands/lsp.js +45 -0
- package/dist/commands/lsp.js.map +1 -0
- package/dist/commands/model-database.d.ts +8 -0
- package/dist/commands/model-database.d.ts.map +1 -0
- package/dist/commands/model-database.js +193 -0
- package/dist/commands/model-database.js.map +1 -0
- package/dist/commands/usage.d.ts.map +1 -1
- package/dist/commands/usage.js +1 -1
- package/dist/commands/usage.js.map +1 -1
- package/dist/components/assistant-message.d.ts.map +1 -1
- package/dist/components/assistant-message.js +3 -2
- package/dist/components/assistant-message.js.map +1 -1
- package/dist/components/status.d.ts +3 -0
- package/dist/components/status.d.ts.map +1 -1
- package/dist/components/status.js +24 -3
- package/dist/components/status.js.map +1 -1
- package/dist/components/user-input.d.ts.map +1 -1
- package/dist/components/user-input.js +2 -1
- package/dist/components/user-input.js.map +1 -1
- package/dist/config/preferences.d.ts +2 -2
- package/dist/config/preferences.js +5 -5
- package/dist/config/preferences.js.map +1 -1
- package/dist/context/mode-context.d.ts +12 -0
- package/dist/context/mode-context.d.ts.map +1 -0
- package/dist/context/mode-context.js +21 -0
- package/dist/context/mode-context.js.map +1 -0
- package/dist/context/mode-context.spec.d.ts +2 -0
- package/dist/context/mode-context.spec.d.ts.map +1 -0
- package/dist/context/mode-context.spec.js +61 -0
- package/dist/context/mode-context.spec.js.map +1 -0
- package/dist/hooks/useAppInitialization.d.ts +4 -2
- package/dist/hooks/useAppInitialization.d.ts.map +1 -1
- package/dist/hooks/useAppInitialization.js +102 -26
- package/dist/hooks/useAppInitialization.js.map +1 -1
- package/dist/hooks/useAppState.d.ts +7 -5
- package/dist/hooks/useAppState.d.ts.map +1 -1
- package/dist/hooks/useAppState.js +11 -7
- package/dist/hooks/useAppState.js.map +1 -1
- package/dist/hooks/useChatHandler.d.ts +2 -2
- package/dist/hooks/useChatHandler.d.ts.map +1 -1
- package/dist/hooks/useChatHandler.js +186 -111
- package/dist/hooks/useChatHandler.js.map +1 -1
- package/dist/hooks/useModeHandlers.d.ts +4 -4
- package/dist/hooks/useModeHandlers.d.ts.map +1 -1
- package/dist/hooks/useModeHandlers.js +9 -9
- package/dist/hooks/useModeHandlers.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +16 -6
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/message-handler.js +1 -1
- package/dist/message-handler.js.map +1 -1
- package/dist/model-database/database-engine.d.ts +25 -0
- package/dist/model-database/database-engine.d.ts.map +1 -0
- package/dist/model-database/database-engine.js +37 -0
- package/dist/model-database/database-engine.js.map +1 -0
- package/dist/model-database/database-engine.spec.d.ts +2 -0
- package/dist/model-database/database-engine.spec.d.ts.map +1 -0
- package/dist/model-database/database-engine.spec.js +413 -0
- package/dist/model-database/database-engine.spec.js.map +1 -0
- package/dist/model-database/model-database.d.ts +30 -0
- package/dist/model-database/model-database.d.ts.map +1 -0
- package/dist/model-database/model-database.js +82 -0
- package/dist/model-database/model-database.js.map +1 -0
- package/dist/model-database/model-database.spec.d.ts +2 -0
- package/dist/model-database/model-database.spec.d.ts.map +1 -0
- package/dist/model-database/model-database.spec.js +322 -0
- package/dist/model-database/model-database.spec.js.map +1 -0
- package/dist/model-database/model-engine.d.ts +25 -0
- package/dist/model-database/model-engine.d.ts.map +1 -0
- package/dist/model-database/model-engine.js +49 -0
- package/dist/model-database/model-engine.js.map +1 -0
- package/dist/model-database/model-engine.spec.d.ts +2 -0
- package/dist/model-database/model-engine.spec.d.ts.map +1 -0
- package/dist/model-database/model-engine.spec.js +381 -0
- package/dist/model-database/model-engine.spec.js.map +1 -0
- package/dist/model-database/model-fetcher.d.ts +14 -0
- package/dist/model-database/model-fetcher.d.ts.map +1 -0
- package/dist/model-database/model-fetcher.js +248 -0
- package/dist/model-database/model-fetcher.js.map +1 -0
- package/dist/model-database/model-fetcher.spec.d.ts +2 -0
- package/dist/model-database/model-fetcher.spec.d.ts.map +1 -0
- package/dist/model-database/model-fetcher.spec.js +498 -0
- package/dist/model-database/model-fetcher.spec.js.map +1 -0
- package/dist/models/models-dev-client.d.ts.map +1 -1
- package/dist/models/models-dev-client.js +8 -0
- package/dist/models/models-dev-client.js.map +1 -1
- package/dist/tool-calling/json-parser.d.ts.map +1 -1
- package/dist/tool-calling/json-parser.js +10 -4
- package/dist/tool-calling/json-parser.js.map +1 -1
- package/dist/tool-calling/tool-parser.d.ts.map +1 -1
- package/dist/tool-calling/tool-parser.js +37 -9
- package/dist/tool-calling/tool-parser.js.map +1 -1
- package/dist/tool-calling/tool-parser.spec.js +79 -1
- package/dist/tool-calling/tool-parser.spec.js.map +1 -1
- package/dist/tool-calling/xml-parser.d.ts.map +1 -1
- package/dist/tool-calling/xml-parser.js +21 -23
- package/dist/tool-calling/xml-parser.js.map +1 -1
- package/dist/tool-calling/xml-parser.spec.js +23 -3
- package/dist/tool-calling/xml-parser.spec.js.map +1 -1
- package/dist/tools/create-file.d.ts +24 -2
- package/dist/tools/create-file.d.ts.map +1 -1
- package/dist/tools/create-file.js +14 -10
- package/dist/tools/create-file.js.map +1 -1
- package/dist/tools/delete-lines.d.ts +18 -2
- package/dist/tools/delete-lines.d.ts.map +1 -1
- package/dist/tools/delete-lines.js +14 -9
- package/dist/tools/delete-lines.js.map +1 -1
- package/dist/tools/execute-bash.d.ts +2 -2
- package/dist/tools/execute-bash.d.ts.map +1 -1
- package/dist/tools/execute-bash.js +10 -9
- package/dist/tools/execute-bash.js.map +1 -1
- package/dist/tools/execute-function.spec.d.ts +2 -0
- package/dist/tools/execute-function.spec.d.ts.map +1 -0
- package/dist/tools/execute-function.spec.js +141 -0
- package/dist/tools/execute-function.spec.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +16 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +10 -10
- package/dist/tools/fetch-url.js.map +1 -1
- package/dist/tools/find-files.d.ts +18 -2
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +7 -5
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/index.d.ts +2 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +30 -20
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/insert-lines.d.ts +18 -2
- package/dist/tools/insert-lines.d.ts.map +1 -1
- package/dist/tools/insert-lines.js +14 -9
- package/dist/tools/insert-lines.js.map +1 -1
- package/dist/tools/lsp-get-diagnostics.d.ts +10 -2
- package/dist/tools/lsp-get-diagnostics.d.ts.map +1 -1
- package/dist/tools/lsp-get-diagnostics.js +8 -6
- package/dist/tools/lsp-get-diagnostics.js.map +1 -1
- package/dist/tools/needs-approval.spec.d.ts +2 -0
- package/dist/tools/needs-approval.spec.d.ts.map +1 -0
- package/dist/tools/needs-approval.spec.js +308 -0
- package/dist/tools/needs-approval.spec.js.map +1 -0
- package/dist/tools/read-file.d.ts +2 -2
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +10 -12
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/replace-lines.d.ts +19 -2
- package/dist/tools/replace-lines.d.ts.map +1 -1
- package/dist/tools/replace-lines.js +14 -9
- package/dist/tools/replace-lines.js.map +1 -1
- package/dist/tools/search-file-contents.d.ts +20 -2
- package/dist/tools/search-file-contents.d.ts.map +1 -1
- package/dist/tools/search-file-contents.js +11 -8
- package/dist/tools/search-file-contents.js.map +1 -1
- package/dist/tools/web-search.d.ts +2 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +10 -10
- package/dist/tools/web-search.js.map +1 -1
- package/dist/types/app.d.ts +1 -1
- package/dist/types/app.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core-connection-status.spec.d.ts +2 -0
- package/dist/types/core-connection-status.spec.d.ts.map +1 -0
- package/dist/types/core-connection-status.spec.js +52 -0
- package/dist/types/core-connection-status.spec.js.map +1 -0
- package/dist/types/core.d.ts +33 -28
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js.map +1 -1
- package/dist/types/system.d.ts +5 -30
- package/dist/types/system.d.ts.map +1 -1
- package/dist/utils/prompt-processor.d.ts +2 -3
- package/dist/utils/prompt-processor.d.ts.map +1 -1
- package/dist/utils/prompt-processor.js +2 -50
- package/dist/utils/prompt-processor.js.map +1 -1
- package/dist/wizard/templates/provider-templates.d.ts.map +1 -1
- package/dist/wizard/templates/provider-templates.js +34 -2
- package/dist/wizard/templates/provider-templates.js.map +1 -1
- package/package.json +6 -5
- package/source/app/prompts/main-prompt.md +29 -96
- package/dist/commands/recommendations.d.ts +0 -8
- package/dist/commands/recommendations.d.ts.map +0 -1
- package/dist/commands/recommendations.js +0 -311
- package/dist/commands/recommendations.js.map +0 -1
- package/dist/commands/streaming.d.ts +0 -3
- package/dist/commands/streaming.d.ts.map +0 -1
- package/dist/commands/streaming.js +0 -23
- package/dist/commands/streaming.js.map +0 -1
- package/dist/components/thinking-indicator.d.ts +0 -3
- package/dist/components/thinking-indicator.d.ts.map +0 -1
- package/dist/components/thinking-indicator.js +0 -69
- package/dist/components/thinking-indicator.js.map +0 -1
- package/dist/recommendations/model-database.d.ts +0 -8
- package/dist/recommendations/model-database.d.ts.map +0 -1
- package/dist/recommendations/model-database.js +0 -514
- package/dist/recommendations/model-database.js.map +0 -1
- package/dist/recommendations/model-engine.d.ts +0 -16
- package/dist/recommendations/model-engine.d.ts.map +0 -1
- package/dist/recommendations/model-engine.js +0 -185
- package/dist/recommendations/model-engine.js.map +0 -1
- package/dist/recommendations/recommendation-engine.d.ts +0 -39
- package/dist/recommendations/recommendation-engine.d.ts.map +0 -1
- package/dist/recommendations/recommendation-engine.js +0 -144
- package/dist/recommendations/recommendation-engine.js.map +0 -1
- package/dist/system/detector.d.ts +0 -18
- package/dist/system/detector.d.ts.map +0 -1
- package/dist/system/detector.js +0 -140
- package/dist/system/detector.js.map +0 -1
package/README.md
CHANGED
|
@@ -423,7 +423,6 @@ Preferences follow the same location hierarchy as configuration files:
|
|
|
423
423
|
- **Last model per provider**: Your preferred model for each provider
|
|
424
424
|
- **Session continuity**: Automatically switches back to your preferred provider/model when restarting
|
|
425
425
|
- **Last theme used**: The theme you last selected
|
|
426
|
-
- **Streaming preference**: Whether response streaming is enabled (toggle with `/streaming` command)
|
|
427
426
|
|
|
428
427
|
**Manual management:**
|
|
429
428
|
|
|
@@ -451,8 +450,7 @@ You can override this directory using `NANOCODER_DATA_DIR`.
|
|
|
451
450
|
- `/model` - Switch between available models
|
|
452
451
|
- `/provider` - Switch between configured AI providers
|
|
453
452
|
- `/status` - Display current status (CWD, provider, model, theme, available updates, AGENTS setup)
|
|
454
|
-
- `/
|
|
455
|
-
- `/recommendations` - Get AI model recommendations based on your system capabilities (RAM, GPU, network)
|
|
453
|
+
- `/model-database` - Browse coding models from OpenRouter (searchable, filterable by open/proprietary)
|
|
456
454
|
- `/mcp` - Show connected MCP servers and their tools
|
|
457
455
|
- `/custom-commands` - List all custom commands
|
|
458
456
|
- `/exit` - Exit the application
|
|
@@ -460,6 +458,7 @@ You can override this directory using `NANOCODER_DATA_DIR`.
|
|
|
460
458
|
- `/theme` - Select a theme for the Nanocoder CLI
|
|
461
459
|
- `/update` - Update Nanocoder to the latest version
|
|
462
460
|
- `/usage` – Get current model context usage visually
|
|
461
|
+
- `/lsp` – List connected LSP servers
|
|
463
462
|
- `!command` - Execute bash commands directly without leaving Nanocoder (output becomes context for the LLM)
|
|
464
463
|
- `@file` - Include file contents in messages automatically via fuzzy search as you type
|
|
465
464
|
|
|
@@ -535,7 +534,7 @@ Generate comprehensive unit tests for {{component}}. Include:
|
|
|
535
534
|
- **Smart autocomplete**: Tab completion for commands with real-time suggestions
|
|
536
535
|
- **Colorized output**: Syntax highlighting and structured display
|
|
537
536
|
- **Session persistence**: Maintains context and preferences across sessions
|
|
538
|
-
- **Real-time streaming**: Live token-by-token streaming of AI responses
|
|
537
|
+
- **Real-time streaming**: Live token-by-token streaming of AI responses
|
|
539
538
|
- **Real-time indicators**: Shows token usage, timing, and processing status
|
|
540
539
|
- **First-time directory security disclaimer**: Prompts on first run and stores a per-project trust decision to prevent accidental exposure of local code or secrets.
|
|
541
540
|
- **Development modes**: Three modes to control tool execution behavior (toggle with Shift+Tab)
|
|
@@ -587,6 +586,5 @@ Nanocoder could benefit from help all across the board. Such as:
|
|
|
587
586
|
- Reporting bugs or suggesting features
|
|
588
587
|
- Marketing and getting the word out
|
|
589
588
|
- Design and building more great software
|
|
590
|
-
- Model cards for our recommendations database
|
|
591
589
|
|
|
592
590
|
All contributions and community participation are welcome!
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-empty-message.spec.d.ts","sourceRoot":"","sources":["../source/ai-sdk-client-empty-message.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { isEmptyAssistantMessage } from './ai-sdk-client.js';
|
|
3
|
+
// Tests for isEmptyAssistantMessage function
|
|
4
|
+
// This function is used to filter out empty assistant messages that would cause API errors:
|
|
5
|
+
// "400 Bad Request: Assistant message must have either content or tool_calls, but not none."
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Non-assistant messages should never be considered empty
|
|
8
|
+
// ============================================================================
|
|
9
|
+
test('isEmptyAssistantMessage - user message is not empty', t => {
|
|
10
|
+
const message = {
|
|
11
|
+
role: 'user',
|
|
12
|
+
content: '',
|
|
13
|
+
};
|
|
14
|
+
t.false(isEmptyAssistantMessage(message));
|
|
15
|
+
});
|
|
16
|
+
test('isEmptyAssistantMessage - system message is not empty', t => {
|
|
17
|
+
const message = {
|
|
18
|
+
role: 'system',
|
|
19
|
+
content: '',
|
|
20
|
+
};
|
|
21
|
+
t.false(isEmptyAssistantMessage(message));
|
|
22
|
+
});
|
|
23
|
+
test('isEmptyAssistantMessage - tool message is not empty', t => {
|
|
24
|
+
const message = {
|
|
25
|
+
role: 'tool',
|
|
26
|
+
content: '',
|
|
27
|
+
};
|
|
28
|
+
t.false(isEmptyAssistantMessage(message));
|
|
29
|
+
});
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Empty assistant messages (should be filtered out)
|
|
32
|
+
// ============================================================================
|
|
33
|
+
test('isEmptyAssistantMessage - assistant with empty string content is empty', t => {
|
|
34
|
+
const message = {
|
|
35
|
+
role: 'assistant',
|
|
36
|
+
content: '',
|
|
37
|
+
};
|
|
38
|
+
t.true(isEmptyAssistantMessage(message));
|
|
39
|
+
});
|
|
40
|
+
test('isEmptyAssistantMessage - assistant with whitespace-only content is empty', t => {
|
|
41
|
+
const message = {
|
|
42
|
+
role: 'assistant',
|
|
43
|
+
content: ' \n\t ',
|
|
44
|
+
};
|
|
45
|
+
t.true(isEmptyAssistantMessage(message));
|
|
46
|
+
});
|
|
47
|
+
test('isEmptyAssistantMessage - assistant with empty array content is empty', t => {
|
|
48
|
+
const message = {
|
|
49
|
+
role: 'assistant',
|
|
50
|
+
content: [],
|
|
51
|
+
};
|
|
52
|
+
t.true(isEmptyAssistantMessage(message));
|
|
53
|
+
});
|
|
54
|
+
test('isEmptyAssistantMessage - assistant with empty content and empty toolCalls is empty', t => {
|
|
55
|
+
const message = {
|
|
56
|
+
role: 'assistant',
|
|
57
|
+
content: '',
|
|
58
|
+
toolCalls: [],
|
|
59
|
+
};
|
|
60
|
+
t.true(isEmptyAssistantMessage(message));
|
|
61
|
+
});
|
|
62
|
+
test('isEmptyAssistantMessage - assistant with undefined toolCalls is empty', t => {
|
|
63
|
+
const message = {
|
|
64
|
+
role: 'assistant',
|
|
65
|
+
content: '',
|
|
66
|
+
toolCalls: undefined,
|
|
67
|
+
};
|
|
68
|
+
t.true(isEmptyAssistantMessage(message));
|
|
69
|
+
});
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Valid assistant messages (should NOT be filtered out)
|
|
72
|
+
// ============================================================================
|
|
73
|
+
test('isEmptyAssistantMessage - assistant with text content is not empty', t => {
|
|
74
|
+
const message = {
|
|
75
|
+
role: 'assistant',
|
|
76
|
+
content: 'Hello, how can I help you?',
|
|
77
|
+
};
|
|
78
|
+
t.false(isEmptyAssistantMessage(message));
|
|
79
|
+
});
|
|
80
|
+
test('isEmptyAssistantMessage - assistant with single character content is not empty', t => {
|
|
81
|
+
const message = {
|
|
82
|
+
role: 'assistant',
|
|
83
|
+
content: 'a',
|
|
84
|
+
};
|
|
85
|
+
t.false(isEmptyAssistantMessage(message));
|
|
86
|
+
});
|
|
87
|
+
test('isEmptyAssistantMessage - assistant with array content is not empty', t => {
|
|
88
|
+
const message = {
|
|
89
|
+
role: 'assistant',
|
|
90
|
+
content: [{ type: 'text', text: 'Hello' }],
|
|
91
|
+
};
|
|
92
|
+
t.false(isEmptyAssistantMessage(message));
|
|
93
|
+
});
|
|
94
|
+
test('isEmptyAssistantMessage - assistant with toolCalls is not empty', t => {
|
|
95
|
+
const message = {
|
|
96
|
+
role: 'assistant',
|
|
97
|
+
content: '',
|
|
98
|
+
toolCalls: [
|
|
99
|
+
{ toolName: 'read_file', toolCallId: '123', input: { path: 'test.txt' } },
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
t.false(isEmptyAssistantMessage(message));
|
|
103
|
+
});
|
|
104
|
+
test('isEmptyAssistantMessage - assistant with content and toolCalls is not empty', t => {
|
|
105
|
+
const message = {
|
|
106
|
+
role: 'assistant',
|
|
107
|
+
content: 'Let me read that file for you.',
|
|
108
|
+
toolCalls: [
|
|
109
|
+
{ toolName: 'read_file', toolCallId: '123', input: { path: 'test.txt' } },
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
t.false(isEmptyAssistantMessage(message));
|
|
113
|
+
});
|
|
114
|
+
test('isEmptyAssistantMessage - assistant with whitespace content but toolCalls is not empty', t => {
|
|
115
|
+
const message = {
|
|
116
|
+
role: 'assistant',
|
|
117
|
+
content: ' ',
|
|
118
|
+
toolCalls: [
|
|
119
|
+
{ toolName: 'read_file', toolCallId: '123', input: { path: 'test.txt' } },
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
t.false(isEmptyAssistantMessage(message));
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=ai-sdk-client-empty-message.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-empty-message.spec.js","sourceRoot":"","sources":["../source/ai-sdk-client-empty-message.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-error-handling.spec.d.ts","sourceRoot":"","sources":["../source/ai-sdk-client-error-handling.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { parseAPIError } from './ai-sdk-client.js';
|
|
3
|
+
// Tests for parseAPIError function
|
|
4
|
+
// Now using the actual exported function instead of a duplicated copy
|
|
5
|
+
test('parseAPIError - handles Ollama unmarshal error from issue #87', t => {
|
|
6
|
+
const error = new Error("RetryError [AI_RetryError]: Failed after 3 attempts. Last error: unmarshal: invalid character '{' after top-level value");
|
|
7
|
+
const result = parseAPIError(error);
|
|
8
|
+
t.true(result.includes('Ollama server error'));
|
|
9
|
+
t.true(result.includes('malformed JSON'));
|
|
10
|
+
t.true(result.includes('Restart Ollama'));
|
|
11
|
+
t.true(result.includes('Re-pull the model'));
|
|
12
|
+
t.true(result.includes('Check Ollama logs'));
|
|
13
|
+
t.true(result.includes('Try a different model'));
|
|
14
|
+
t.true(result.includes('Original error:'));
|
|
15
|
+
});
|
|
16
|
+
test('parseAPIError - handles unmarshal error without retry wrapper', t => {
|
|
17
|
+
const error = new Error("unmarshal: invalid character '{' after top-level value");
|
|
18
|
+
const result = parseAPIError(error);
|
|
19
|
+
t.true(result.includes('Ollama server error'));
|
|
20
|
+
t.true(result.includes('malformed JSON'));
|
|
21
|
+
});
|
|
22
|
+
test('parseAPIError - handles 500 error with invalid character (status code takes precedence)', t => {
|
|
23
|
+
// This test verifies that HTTP status codes are parsed FIRST,
|
|
24
|
+
// so a 500 error with "invalid character" in the message is treated
|
|
25
|
+
// as a server error, not an Ollama-specific error
|
|
26
|
+
const error = new Error("500 Internal Server Error: invalid character 'x' after top-level value");
|
|
27
|
+
const result = parseAPIError(error);
|
|
28
|
+
// Status code parsing takes precedence over Ollama-specific pattern matching
|
|
29
|
+
t.is(result, "Server error: invalid character 'x' after top-level value");
|
|
30
|
+
});
|
|
31
|
+
test('parseAPIError - handles 500 error without JSON parsing issue', t => {
|
|
32
|
+
const error = new Error('500 Internal Server Error: database connection failed');
|
|
33
|
+
const result = parseAPIError(error);
|
|
34
|
+
t.is(result, 'Server error: database connection failed');
|
|
35
|
+
});
|
|
36
|
+
test('parseAPIError - handles 404 error', t => {
|
|
37
|
+
const error = new Error('404 Not Found: model not available');
|
|
38
|
+
const result = parseAPIError(error);
|
|
39
|
+
t.is(result, 'Model not found: The requested model may not exist or is unavailable');
|
|
40
|
+
});
|
|
41
|
+
test('parseAPIError - handles connection refused', t => {
|
|
42
|
+
const error = new Error('ECONNREFUSED: Connection refused');
|
|
43
|
+
const result = parseAPIError(error);
|
|
44
|
+
t.is(result, 'Connection failed: Unable to reach the model server');
|
|
45
|
+
});
|
|
46
|
+
test('parseAPIError - handles timeout error', t => {
|
|
47
|
+
const error = new Error('Request timeout: ETIMEDOUT');
|
|
48
|
+
const result = parseAPIError(error);
|
|
49
|
+
t.is(result, 'Request timed out: The model took too long to respond');
|
|
50
|
+
});
|
|
51
|
+
test('parseAPIError - handles non-Error objects', t => {
|
|
52
|
+
const result = parseAPIError('string error');
|
|
53
|
+
t.is(result, 'An unknown error occurred while communicating with the model');
|
|
54
|
+
});
|
|
55
|
+
test('parseAPIError - handles context length errors', t => {
|
|
56
|
+
const error = new Error('context length exceeded');
|
|
57
|
+
const result = parseAPIError(error);
|
|
58
|
+
// Use exact assertion instead of OR condition
|
|
59
|
+
t.is(result, 'Context too large: Please reduce the conversation length or message size');
|
|
60
|
+
});
|
|
61
|
+
test('parseAPIError - handles too many tokens errors', t => {
|
|
62
|
+
const error = new Error('too many tokens in the request');
|
|
63
|
+
const result = parseAPIError(error);
|
|
64
|
+
t.is(result, 'Context too large: Please reduce the conversation length or message size');
|
|
65
|
+
});
|
|
66
|
+
test('parseAPIError - handles 400 with context length in message', t => {
|
|
67
|
+
const error = new Error('400 Bad Request: context length exceeded');
|
|
68
|
+
const result = parseAPIError(error);
|
|
69
|
+
// The 400 status code pattern matches first, so we get the full message
|
|
70
|
+
t.is(result, 'Bad request: context length exceeded');
|
|
71
|
+
});
|
|
72
|
+
test('parseAPIError - handles 401 authentication error', t => {
|
|
73
|
+
const error = new Error('401 Unauthorized: Invalid API key');
|
|
74
|
+
const result = parseAPIError(error);
|
|
75
|
+
t.is(result, 'Authentication failed: Invalid API key or credentials');
|
|
76
|
+
});
|
|
77
|
+
test('parseAPIError - handles 403 forbidden error', t => {
|
|
78
|
+
const error = new Error('403 Forbidden: Access denied');
|
|
79
|
+
const result = parseAPIError(error);
|
|
80
|
+
t.is(result, 'Access forbidden: Check your API permissions');
|
|
81
|
+
});
|
|
82
|
+
test('parseAPIError - handles 429 rate limit error', t => {
|
|
83
|
+
const error = new Error('429 Too Many Requests: Rate limit exceeded');
|
|
84
|
+
const result = parseAPIError(error);
|
|
85
|
+
t.is(result, 'Rate limit exceeded: Too many requests. Please wait and try again');
|
|
86
|
+
});
|
|
87
|
+
test('parseAPIError - handles 502 bad gateway error', t => {
|
|
88
|
+
const error = new Error('502 Bad Gateway: upstream error');
|
|
89
|
+
const result = parseAPIError(error);
|
|
90
|
+
t.is(result, 'Server error: upstream error');
|
|
91
|
+
});
|
|
92
|
+
test('parseAPIError - handles 503 service unavailable error', t => {
|
|
93
|
+
const error = new Error('503 Service Unavailable: server overloaded');
|
|
94
|
+
const result = parseAPIError(error);
|
|
95
|
+
t.is(result, 'Server error: server overloaded');
|
|
96
|
+
});
|
|
97
|
+
test('parseAPIError - handles reduce tokens message', t => {
|
|
98
|
+
const error = new Error('Please reduce the number of tokens in your request');
|
|
99
|
+
const result = parseAPIError(error);
|
|
100
|
+
t.is(result, 'Too many tokens: Please shorten your message or clear conversation history');
|
|
101
|
+
});
|
|
102
|
+
test('parseAPIError - cleans up unknown errors', t => {
|
|
103
|
+
const error = new Error('Error: Something unexpected happened\nWith more details');
|
|
104
|
+
const result = parseAPIError(error);
|
|
105
|
+
// Should strip "Error: " prefix and only return first line
|
|
106
|
+
t.is(result, 'Something unexpected happened');
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=ai-sdk-client-error-handling.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-error-handling.spec.js","sourceRoot":"","sources":["../source/ai-sdk-client-error-handling.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-maxretries.spec.d.ts","sourceRoot":"","sources":["../source/ai-sdk-client-maxretries.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { AISDKClient } from './ai-sdk-client.js';
|
|
3
|
+
// Tests for maxRetries configuration
|
|
4
|
+
// Now tests actual AISDKClient instantiation and behavior
|
|
5
|
+
test('AISDKClient - maxRetries defaults to 2 when not specified', t => {
|
|
6
|
+
const config = {
|
|
7
|
+
name: 'TestProvider',
|
|
8
|
+
type: 'openai-compatible',
|
|
9
|
+
models: ['test-model'],
|
|
10
|
+
config: {
|
|
11
|
+
baseURL: 'http://localhost:11434/v1',
|
|
12
|
+
apiKey: 'test-key',
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const client = new AISDKClient(config);
|
|
16
|
+
// Verify the client's internal maxRetries is set to default of 2
|
|
17
|
+
t.is(client.getMaxRetries(), 2);
|
|
18
|
+
});
|
|
19
|
+
test('AISDKClient - maxRetries respects custom value', t => {
|
|
20
|
+
const config = {
|
|
21
|
+
name: 'TestProvider',
|
|
22
|
+
type: 'openai-compatible',
|
|
23
|
+
models: ['test-model'],
|
|
24
|
+
maxRetries: 5,
|
|
25
|
+
config: {
|
|
26
|
+
baseURL: 'http://localhost:11434/v1',
|
|
27
|
+
apiKey: 'test-key',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const client = new AISDKClient(config);
|
|
31
|
+
// Verify the client uses the custom maxRetries value
|
|
32
|
+
t.is(client.getMaxRetries(), 5);
|
|
33
|
+
});
|
|
34
|
+
test('AISDKClient - maxRetries can be set to 0 to disable retries', t => {
|
|
35
|
+
// Important: This test verifies that 0 is treated as a valid value,
|
|
36
|
+
// not as falsy (which would incorrectly default to 2)
|
|
37
|
+
const config = {
|
|
38
|
+
name: 'TestProvider',
|
|
39
|
+
type: 'openai-compatible',
|
|
40
|
+
models: ['test-model'],
|
|
41
|
+
maxRetries: 0,
|
|
42
|
+
config: {
|
|
43
|
+
baseURL: 'http://localhost:11434/v1',
|
|
44
|
+
apiKey: 'test-key',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const client = new AISDKClient(config);
|
|
48
|
+
// Verify that 0 is respected (nullish coalescing handles this correctly)
|
|
49
|
+
t.is(client.getMaxRetries(), 0);
|
|
50
|
+
});
|
|
51
|
+
test('AISDKClient - maxRetries handles value of 1', t => {
|
|
52
|
+
const config = {
|
|
53
|
+
name: 'TestProvider',
|
|
54
|
+
type: 'openai-compatible',
|
|
55
|
+
models: ['test-model'],
|
|
56
|
+
maxRetries: 1,
|
|
57
|
+
config: {
|
|
58
|
+
baseURL: 'http://localhost:11434/v1',
|
|
59
|
+
apiKey: 'test-key',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
const client = new AISDKClient(config);
|
|
63
|
+
t.is(client.getMaxRetries(), 1);
|
|
64
|
+
});
|
|
65
|
+
test('AIProviderConfig type - includes maxRetries in interface', t => {
|
|
66
|
+
// Compile-time test that maxRetries is part of the interface
|
|
67
|
+
const config = {
|
|
68
|
+
name: 'TestProvider',
|
|
69
|
+
type: 'openai-compatible',
|
|
70
|
+
models: ['test-model'],
|
|
71
|
+
maxRetries: 3,
|
|
72
|
+
config: {
|
|
73
|
+
baseURL: 'http://localhost:11434/v1',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
// TypeScript should not complain about maxRetries property
|
|
77
|
+
t.is(typeof config.maxRetries, 'number');
|
|
78
|
+
t.true('maxRetries' in config);
|
|
79
|
+
});
|
|
80
|
+
test('AISDKClient - undefined maxRetries uses default', t => {
|
|
81
|
+
// Explicitly set to undefined to test fallback behavior
|
|
82
|
+
const config = {
|
|
83
|
+
name: 'TestProvider',
|
|
84
|
+
type: 'openai-compatible',
|
|
85
|
+
models: ['test-model'],
|
|
86
|
+
maxRetries: undefined,
|
|
87
|
+
config: {
|
|
88
|
+
baseURL: 'http://localhost:11434/v1',
|
|
89
|
+
apiKey: 'test-key',
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const client = new AISDKClient(config);
|
|
93
|
+
// Verify undefined falls back to default of 2
|
|
94
|
+
t.is(client.getMaxRetries(), 2);
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=ai-sdk-client-maxretries.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sdk-client-maxretries.spec.js","sourceRoot":"","sources":["../source/ai-sdk-client-maxretries.spec.ts"],"names":[],"mappings":"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"}
|
package/dist/ai-sdk-client.d.ts
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import type { AIProviderConfig, LLMChatResponse, LLMClient, Message, AISDKCoreTool, StreamCallbacks } from './types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Message type used for testing the empty assistant message filter.
|
|
4
|
+
* This is a simplified version of the AI SDK's internal message format.
|
|
5
|
+
*/
|
|
6
|
+
export interface TestableMessage {
|
|
7
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
8
|
+
content: string | unknown[];
|
|
9
|
+
toolCalls?: unknown[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Checks if an assistant message is empty (no content and no tool calls).
|
|
13
|
+
* Empty assistant messages cause API errors:
|
|
14
|
+
* "400 Bad Request: Assistant message must have either content or tool_calls, but not none."
|
|
15
|
+
*
|
|
16
|
+
* Exported for testing purposes.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isEmptyAssistantMessage(message: TestableMessage): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Parses API errors into user-friendly messages.
|
|
21
|
+
* Exported for testing purposes.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseAPIError(error: unknown): string;
|
|
2
24
|
export declare class AISDKClient implements LLMClient {
|
|
3
25
|
private provider;
|
|
4
26
|
private currentModel;
|
|
@@ -6,6 +28,7 @@ export declare class AISDKClient implements LLMClient {
|
|
|
6
28
|
private providerConfig;
|
|
7
29
|
private undiciAgent;
|
|
8
30
|
private cachedContextSize;
|
|
31
|
+
private maxRetries;
|
|
9
32
|
constructor(providerConfig: AIProviderConfig);
|
|
10
33
|
/**
|
|
11
34
|
* Fetch and cache context size from models.dev
|
|
@@ -16,12 +39,12 @@ export declare class AISDKClient implements LLMClient {
|
|
|
16
39
|
setModel(model: string): void;
|
|
17
40
|
getCurrentModel(): string;
|
|
18
41
|
getContextSize(): number;
|
|
42
|
+
getMaxRetries(): number;
|
|
19
43
|
getAvailableModels(): Promise<string[]>;
|
|
20
|
-
chat(messages: Message[], tools: Record<string, AISDKCoreTool>, signal?: AbortSignal): Promise<LLMChatResponse>;
|
|
21
44
|
/**
|
|
22
45
|
* Stream chat with real-time token updates
|
|
23
46
|
*/
|
|
24
|
-
|
|
47
|
+
chat(messages: Message[], tools: Record<string, AISDKCoreTool>, callbacks: StreamCallbacks, signal?: AbortSignal): Promise<LLMChatResponse>;
|
|
25
48
|
clearContext(): Promise<void>;
|
|
26
49
|
}
|
|
27
50
|
//# sourceMappingURL=ai-sdk-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-sdk-client.d.ts","sourceRoot":"","sources":["../source/ai-sdk-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,OAAO,EAEP,aAAa,EACb,eAAe,EACf,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-sdk-client.d.ts","sourceRoot":"","sources":["../source/ai-sdk-client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,OAAO,EAEP,aAAa,EACb,eAAe,EACf,MAAM,eAAe,CAAC;AAIvB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAczE;AAgBD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAyJpD;AAmDD,qBAAa,WAAY,YAAW,SAAS;IAC5C,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,UAAU,CAAS;gBAEf,cAAc,EAAE,gBAAgB;IAgC5C;;OAEG;YACW,iBAAiB;IAU/B,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAKrE,OAAO,CAAC,cAAc;IAgCtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM7B,eAAe,IAAI,MAAM;IAIzB,cAAc,IAAI,MAAM;IAIxB,aAAa,IAAI,MAAM;IAIvB,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIvC;;OAEG;IACG,IAAI,CACT,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,SAAS,EAAE,eAAe,EAC1B,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,eAAe,CAAC;IAyLrB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
|