lynkr 8.0.0 → 8.0.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.
Files changed (102) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/api/openai-router.js +34 -2
  4. package/src/clients/standard-tools.js +23 -0
  5. package/src/config/index.js +20 -0
  6. package/src/orchestrator/index.js +2 -2
  7. package/src/server.js +2 -12
  8. package/src/tools/index.js +4 -0
  9. package/src/tools/lazy-loader.js +7 -0
  10. package/src/tools/tinyfish.js +358 -0
  11. package/src/tools/truncate.js +1 -0
  12. package/.github/FUNDING.yml +0 -15
  13. package/.github/workflows/README.md +0 -215
  14. package/.github/workflows/ci.yml +0 -69
  15. package/.github/workflows/index.yml +0 -62
  16. package/.github/workflows/web-tools-tests.yml +0 -56
  17. package/CITATIONS.bib +0 -6
  18. package/DEPLOYMENT.md +0 -1001
  19. package/LYNKR-TUI-PLAN.md +0 -984
  20. package/PERFORMANCE-REPORT.md +0 -866
  21. package/PLAN-per-client-model-routing.md +0 -252
  22. package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
  23. package/docs/BingSiteAuth.xml +0 -4
  24. package/docs/docs-style.css +0 -478
  25. package/docs/docs.html +0 -198
  26. package/docs/google5be250e608e6da39.html +0 -1
  27. package/docs/index.html +0 -577
  28. package/docs/index.md +0 -584
  29. package/docs/robots.txt +0 -4
  30. package/docs/sitemap.xml +0 -44
  31. package/docs/style.css +0 -1223
  32. package/docs/toon-integration-spec.md +0 -130
  33. package/documentation/README.md +0 -101
  34. package/documentation/api.md +0 -806
  35. package/documentation/claude-code-cli.md +0 -679
  36. package/documentation/codex-cli.md +0 -397
  37. package/documentation/contributing.md +0 -571
  38. package/documentation/cursor-integration.md +0 -734
  39. package/documentation/docker.md +0 -874
  40. package/documentation/embeddings.md +0 -762
  41. package/documentation/faq.md +0 -713
  42. package/documentation/features.md +0 -403
  43. package/documentation/headroom.md +0 -519
  44. package/documentation/installation.md +0 -758
  45. package/documentation/memory-system.md +0 -476
  46. package/documentation/production.md +0 -636
  47. package/documentation/providers.md +0 -1009
  48. package/documentation/routing.md +0 -476
  49. package/documentation/testing.md +0 -629
  50. package/documentation/token-optimization.md +0 -325
  51. package/documentation/tools.md +0 -697
  52. package/documentation/troubleshooting.md +0 -969
  53. package/final-test.js +0 -33
  54. package/headroom-sidecar/config.py +0 -93
  55. package/headroom-sidecar/requirements.txt +0 -14
  56. package/headroom-sidecar/server.py +0 -451
  57. package/monitor-agents.sh +0 -31
  58. package/scripts/audit-log-reader.js +0 -399
  59. package/scripts/compact-dictionary.js +0 -204
  60. package/scripts/test-deduplication.js +0 -448
  61. package/src/db/database.sqlite +0 -0
  62. package/te +0 -11622
  63. package/test/README.md +0 -212
  64. package/test/azure-openai-config.test.js +0 -213
  65. package/test/azure-openai-error-resilience.test.js +0 -238
  66. package/test/azure-openai-format-conversion.test.js +0 -354
  67. package/test/azure-openai-integration.test.js +0 -287
  68. package/test/azure-openai-routing.test.js +0 -175
  69. package/test/azure-openai-streaming.test.js +0 -171
  70. package/test/bedrock-integration.test.js +0 -457
  71. package/test/comprehensive-test-suite.js +0 -928
  72. package/test/config-validation.test.js +0 -207
  73. package/test/cursor-integration.test.js +0 -484
  74. package/test/format-conversion.test.js +0 -578
  75. package/test/hybrid-routing-integration.test.js +0 -269
  76. package/test/hybrid-routing-performance.test.js +0 -428
  77. package/test/llamacpp-integration.test.js +0 -882
  78. package/test/lmstudio-integration.test.js +0 -347
  79. package/test/memory/extractor.test.js +0 -398
  80. package/test/memory/retriever.test.js +0 -613
  81. package/test/memory/retriever.test.js.bak +0 -585
  82. package/test/memory/search.test.js +0 -537
  83. package/test/memory/search.test.js.bak +0 -389
  84. package/test/memory/store.test.js +0 -344
  85. package/test/memory/store.test.js.bak +0 -312
  86. package/test/memory/surprise.test.js +0 -300
  87. package/test/memory-performance.test.js +0 -472
  88. package/test/openai-integration.test.js +0 -683
  89. package/test/openrouter-error-resilience.test.js +0 -418
  90. package/test/passthrough-mode.test.js +0 -385
  91. package/test/performance-benchmark.js +0 -351
  92. package/test/performance-tests.js +0 -528
  93. package/test/routing.test.js +0 -225
  94. package/test/toon-compression.test.js +0 -131
  95. package/test/web-tools.test.js +0 -329
  96. package/test-agents-simple.js +0 -43
  97. package/test-cli-connection.sh +0 -33
  98. package/test-learning-unit.js +0 -126
  99. package/test-learning.js +0 -112
  100. package/test-parallel-agents.sh +0 -124
  101. package/test-parallel-direct.js +0 -155
  102. package/test-subagents.sh +0 -117
package/test/README.md DELETED
@@ -1,212 +0,0 @@
1
- # Test Suite Documentation
2
-
3
- All tests for the Lynkr project are consolidated in this `test/` directory.
4
-
5
- ## Test Files
6
-
7
- ### Unit Tests
8
- **File**: `routing.test.js`
9
- **Purpose**: Tests the hybrid routing logic in isolation
10
- **Run**: `DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/routing.test.js`
11
- **Coverage**: 10 tests
12
- - Routing with tier-based routing disabled (no TIER_* vars set)
13
- - Simple requests → Ollama
14
- - Complex requests → Cloud
15
- - Tool capability checks
16
- - Fallback configuration
17
-
18
- ---
19
-
20
- ### Integration Tests
21
- **File**: `hybrid-routing-integration.test.js`
22
- **Purpose**: Tests configuration validation and metrics recording
23
- **Run**: `node --test test/hybrid-routing-integration.test.js`
24
- **Coverage**: 13 tests
25
- - Configuration validation (5 tests)
26
- - Metrics recording (6 tests)
27
- - Helper functions (2 tests)
28
-
29
- ---
30
-
31
- ### Hybrid Routing Performance Tests
32
- **File**: `hybrid-routing-performance.test.js`
33
- **Purpose**: Measures performance overhead of hybrid routing
34
- **Run**: `node test/hybrid-routing-performance.test.js`
35
- **Key Metrics**:
36
- - Routing decision: <0.01ms (36.8M decisions/sec)
37
- - Metrics overhead: <0.01ms (43.6M ops/sec)
38
- - Combined overhead: <0.02ms (15.6M ops/sec)
39
-
40
- ---
41
-
42
- ### System Performance Tests
43
- **File**: `performance-tests.js`
44
- **Purpose**: Tests system-wide performance optimizations
45
- **Run**: `DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/performance-tests.js`
46
- **Coverage**:
47
- - Database indexes (100% complete)
48
- - Persistent prompt cache
49
- - Regex pattern caching (4.5x faster)
50
- - Lazy loading
51
- - HTTP connection pooling
52
- - Response compression
53
-
54
- ---
55
-
56
- ### Middleware Benchmarks
57
- **File**: `performance-benchmark.js`
58
- **Purpose**: Benchmarks middleware overhead
59
- **Run**: `DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/performance-benchmark.js`
60
- **Coverage**:
61
- - Metrics collection (3.4M ops/sec)
62
- - Circuit breakers (3.9M ops/sec)
63
- - Input validation (5.7M ops/sec)
64
- - Load shedding
65
- - Combined middleware stack
66
-
67
- ---
68
-
69
- ## Running All Tests
70
-
71
- ### Using npm scripts (Recommended)
72
-
73
- **Run all tests (unit + performance):**
74
- ```bash
75
- npm test
76
- ```
77
-
78
- **Run only unit/integration tests:**
79
- ```bash
80
- npm run test:unit
81
- ```
82
-
83
- **Run only performance tests:**
84
- ```bash
85
- npm run test:performance
86
- ```
87
-
88
- **Run only benchmarks:**
89
- ```bash
90
- npm run test:benchmark
91
- ```
92
-
93
- **Run quick smoke test (routing only):**
94
- ```bash
95
- npm run test:quick
96
- ```
97
-
98
- **Run everything including benchmarks:**
99
- ```bash
100
- npm run test:all
101
- ```
102
-
103
- ### Manual execution (if needed)
104
-
105
- **Quick Test:**
106
- Run all unit and integration tests:
107
- ```bash
108
- DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/
109
- ```
110
-
111
- **Full Test Suite:**
112
- Run everything including performance tests:
113
- ```bash
114
- # Unit + Integration tests
115
- DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/routing.test.js
116
- DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/hybrid-routing-integration.test.js
117
-
118
- # Performance tests
119
- node test/hybrid-routing-performance.test.js
120
- DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/performance-tests.js
121
- DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/performance-benchmark.js
122
- ```
123
-
124
- ---
125
-
126
- ## Test Organization
127
-
128
- ```
129
- test/
130
- ├── README.md ← This file
131
- ├── routing.test.js ← Unit tests (10 tests)
132
- ├── hybrid-routing-integration.test.js ← Integration tests (13 tests)
133
- ├── hybrid-routing-performance.test.js ← Routing performance benchmarks
134
- ├── performance-tests.js ← System performance tests
135
- └── performance-benchmark.js ← Middleware benchmarks
136
- ```
137
-
138
- ---
139
-
140
- ## Important Notes
141
-
142
- ### Not Test Files
143
- - `src/tests/` - This is **application code**, not tests! It provides test execution functionality as a feature.
144
-
145
- ### Environment Variables
146
- Most tests require Databricks credentials (even though they're not used in actual API calls):
147
- ```bash
148
- export DATABRICKS_API_KEY=test-key
149
- export DATABRICKS_API_BASE=http://test.com
150
- ```
151
-
152
- ### Test Results Summary
153
-
154
- | Test Type | Status | Count |
155
- |-----------|--------|-------|
156
- | Unit Tests | ✅ Passing | 10/10 |
157
- | Integration Tests | ✅ Passing | 13/13 |
158
- | Routing Performance | ✅ Complete | <0.02ms overhead |
159
- | System Performance | ✅ Complete | 100% optimizations |
160
- | Middleware Benchmarks | ✅ Complete | Acceptable overhead |
161
-
162
- ---
163
-
164
- ## CI/CD Integration
165
-
166
- To run in CI/CD pipelines:
167
-
168
- ```bash
169
- #!/bin/bash
170
- set -e
171
-
172
- # Run all tests using npm
173
- echo "Running test suite..."
174
- npm run test:all
175
-
176
- echo "All tests passed!"
177
- ```
178
-
179
- Or for a faster CI pipeline (skip benchmarks):
180
-
181
- ```bash
182
- #!/bin/bash
183
- set -e
184
-
185
- echo "Running tests..."
186
- npm test
187
-
188
- echo "Tests passed!"
189
- ```
190
-
191
- ---
192
-
193
- ## Adding New Tests
194
-
195
- When adding new tests, follow these conventions:
196
-
197
- 1. **Unit tests**: Test individual functions in isolation
198
- - Place in `test/`
199
- - Use `node:test` framework
200
- - Name: `feature-name.test.js`
201
-
202
- 2. **Integration tests**: Test multiple components together
203
- - Place in `test/`
204
- - Use `node:test` framework
205
- - Name: `feature-name-integration.test.js`
206
-
207
- 3. **Performance tests**: Benchmark specific features
208
- - Place in `test/`
209
- - Use custom benchmark utilities
210
- - Name: `feature-name-performance.test.js`
211
-
212
- 4. **Always**: Document in this README!
@@ -1,213 +0,0 @@
1
- const assert = require("assert");
2
- const { describe, it, beforeEach, afterEach } = require("node:test");
3
-
4
- describe("Azure OpenAI Configuration Tests", () => {
5
- let originalConfig;
6
-
7
- beforeEach(() => {
8
- // Clear module cache
9
- delete require.cache[require.resolve("../src/config")];
10
-
11
- // Store original config
12
- originalConfig = { ...process.env };
13
-
14
- // Set Azure OpenAI environment variables to empty strings to override .env values
15
- // (deleting them would cause dotenv to reload from .env file)
16
- process.env.AZURE_OPENAI_ENDPOINT = "";
17
- process.env.AZURE_OPENAI_API_KEY = "";
18
- process.env.AZURE_OPENAI_DEPLOYMENT = "";
19
- process.env.AZURE_OPENAI_API_VERSION = "";
20
-
21
- // Prevent .env TIER_* values from being picked up by dotenv
22
- process.env.TIER_SIMPLE = "";
23
- process.env.TIER_MEDIUM = "";
24
- process.env.TIER_COMPLEX = "";
25
- process.env.TIER_REASONING = "";
26
- });
27
-
28
- afterEach(() => {
29
- // Restore original environment
30
- process.env = originalConfig;
31
- });
32
-
33
- describe("Configuration Loading", () => {
34
- it("should load Azure OpenAI configuration with all values set", () => {
35
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
36
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
37
- process.env.AZURE_OPENAI_DEPLOYMENT = "gpt-4o";
38
- process.env.AZURE_OPENAI_API_VERSION = "2024-08-01-preview";
39
- process.env.MODEL_PROVIDER = "databricks";
40
- process.env.DATABRICKS_API_KEY = "test-key";
41
- process.env.DATABRICKS_API_BASE = "http://test.com";
42
-
43
- const config = require("../src/config");
44
-
45
- assert.strictEqual(config.azureOpenAI.endpoint, "https://test-resource.openai.azure.com");
46
- assert.strictEqual(config.azureOpenAI.apiKey, "test-api-key");
47
- assert.strictEqual(config.azureOpenAI.deployment, "gpt-4o");
48
- assert.strictEqual(config.azureOpenAI.apiVersion, "2024-08-01-preview");
49
- });
50
-
51
- it("should use default values when optional fields not set", () => {
52
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
53
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
54
- // Keep as empty strings (don't delete) to prevent dotenv from reloading
55
- process.env.AZURE_OPENAI_DEPLOYMENT = "";
56
- process.env.AZURE_OPENAI_API_VERSION = "";
57
- process.env.MODEL_PROVIDER = "databricks";
58
- process.env.DATABRICKS_API_KEY = "test-key";
59
- process.env.DATABRICKS_API_BASE = "http://test.com";
60
-
61
- const config = require("../src/config");
62
-
63
- assert.strictEqual(config.azureOpenAI.deployment, "gpt-4o");
64
- assert.strictEqual(config.azureOpenAI.apiVersion, "2024-08-01-preview");
65
- });
66
-
67
- it("should load null values when Azure OpenAI not configured", () => {
68
- // Keep as empty strings (don't delete) to prevent dotenv from reloading
69
- process.env.AZURE_OPENAI_ENDPOINT = "";
70
- process.env.AZURE_OPENAI_API_KEY = "";
71
- process.env.MODEL_PROVIDER = "databricks";
72
- process.env.DATABRICKS_API_KEY = "test-key";
73
- process.env.DATABRICKS_API_BASE = "http://test.com";
74
-
75
- const config = require("../src/config");
76
-
77
- assert.strictEqual(config.azureOpenAI.endpoint, null);
78
- assert.strictEqual(config.azureOpenAI.apiKey, null);
79
- assert.strictEqual(config.azureOpenAI.deployment, "gpt-4o"); // default
80
- assert.strictEqual(config.azureOpenAI.apiVersion, "2024-08-01-preview"); // default
81
- });
82
- });
83
-
84
- describe("Primary Provider Validation", () => {
85
- it("should accept azure-openai as MODEL_PROVIDER", () => {
86
- process.env.MODEL_PROVIDER = "azure-openai";
87
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
88
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
89
-
90
- const config = require("../src/config");
91
-
92
- assert.strictEqual(config.modelProvider.type, "azure-openai");
93
- });
94
-
95
- it("should throw error when azure-openai is primary provider without endpoint", () => {
96
- process.env.MODEL_PROVIDER = "azure-openai";
97
- process.env.AZURE_OPENAI_ENDPOINT = ""; // Empty string, not deleted
98
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
99
-
100
- assert.throws(() => {
101
- require("../src/config");
102
- }, /AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY/);
103
- });
104
-
105
- it("should throw error when azure-openai is primary provider without API key", () => {
106
- process.env.MODEL_PROVIDER = "azure-openai";
107
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
108
- process.env.AZURE_OPENAI_API_KEY = ""; // Empty string, not deleted
109
-
110
- assert.throws(() => {
111
- require("../src/config");
112
- }, /AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY/);
113
- });
114
-
115
- it("should throw error when azure-openai is primary provider without both", () => {
116
- process.env.MODEL_PROVIDER = "azure-openai";
117
- process.env.AZURE_OPENAI_ENDPOINT = ""; // Empty string, not deleted
118
- process.env.AZURE_OPENAI_API_KEY = ""; // Empty string, not deleted
119
-
120
- assert.throws(() => {
121
- require("../src/config");
122
- }, /AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY/);
123
- });
124
- });
125
-
126
- describe("Fallback Provider Validation", () => {
127
- it("should accept azure-openai as fallback provider with credentials", () => {
128
- process.env.MODEL_PROVIDER = "ollama";
129
- process.env.OLLAMA_ENDPOINT = "http://localhost:11434";
130
- process.env.OLLAMA_MODEL = "qwen2.5-coder:latest";
131
- process.env.FALLBACK_ENABLED = "true";
132
- process.env.FALLBACK_PROVIDER = "azure-openai";
133
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
134
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
135
- process.env.DATABRICKS_API_KEY = "test-key";
136
- process.env.DATABRICKS_API_BASE = "http://test.com";
137
-
138
- const config = require("../src/config");
139
-
140
- assert.strictEqual(config.modelProvider.fallbackProvider, "azure-openai");
141
- });
142
-
143
- it("should warn when azure-openai is fallback but credentials missing", () => {
144
- process.env.MODEL_PROVIDER = "ollama";
145
- process.env.OLLAMA_ENDPOINT = "http://localhost:11434";
146
- process.env.OLLAMA_MODEL = "qwen2.5-coder:latest";
147
- process.env.FALLBACK_ENABLED = "true";
148
- process.env.FALLBACK_PROVIDER = "azure-openai";
149
- // Set to empty strings instead of deleting (dotenv.config() in config module would reload from .env)
150
- process.env.AZURE_OPENAI_ENDPOINT = "";
151
- process.env.AZURE_OPENAI_API_KEY = "";
152
- process.env.DATABRICKS_API_KEY = "test-key";
153
- process.env.DATABRICKS_API_BASE = "http://test.com";
154
- // Enable tier routing so fallback validation runs
155
- process.env.TIER_SIMPLE = "ollama:llama3.2";
156
- process.env.TIER_MEDIUM = "ollama:llama3.2";
157
- process.env.TIER_COMPLEX = "ollama:llama3.2";
158
- process.env.TIER_REASONING = "ollama:llama3.2";
159
-
160
- // Should warn but not throw (fallback misconfigured warning)
161
- const config = require("../src/config");
162
- assert.strictEqual(config.modelProvider.fallbackProvider, "azure-openai");
163
- });
164
- });
165
-
166
- describe("Deployment and API Version Defaults", () => {
167
- it("should use gpt-4o as default deployment", () => {
168
- // Keep as empty string (don't delete) to prevent dotenv from reloading from .env
169
- process.env.AZURE_OPENAI_DEPLOYMENT = "";
170
- process.env.MODEL_PROVIDER = "azure-openai";
171
- process.env.AZURE_OPENAI_ENDPOINT = "https://test-resource.openai.azure.com";
172
- process.env.AZURE_OPENAI_API_KEY = "test-api-key";
173
-
174
- const config = require("../src/config");
175
-
176
- assert.strictEqual(config.azureOpenAI.deployment, "gpt-4o");
177
- });
178
-
179
- it("should use custom deployment when specified", () => {
180
- process.env.AZURE_OPENAI_DEPLOYMENT = "gpt-5";
181
- process.env.MODEL_PROVIDER = "databricks";
182
- process.env.DATABRICKS_API_KEY = "test-key";
183
- process.env.DATABRICKS_API_BASE = "http://test.com";
184
-
185
- const config = require("../src/config");
186
-
187
- assert.strictEqual(config.azureOpenAI.deployment, "gpt-5");
188
- });
189
-
190
- it("should use 2024-08-01-preview as default API version", () => {
191
- // Keep as empty string (don't delete) to prevent dotenv from reloading from .env
192
- process.env.AZURE_OPENAI_API_VERSION = "";
193
- process.env.MODEL_PROVIDER = "databricks";
194
- process.env.DATABRICKS_API_KEY = "test-key";
195
- process.env.DATABRICKS_API_BASE = "http://test.com";
196
-
197
- const config = require("../src/config");
198
-
199
- assert.strictEqual(config.azureOpenAI.apiVersion, "2024-08-01-preview");
200
- });
201
-
202
- it("should use custom API version when specified", () => {
203
- process.env.AZURE_OPENAI_API_VERSION = "2025-01-01-preview";
204
- process.env.MODEL_PROVIDER = "databricks";
205
- process.env.DATABRICKS_API_KEY = "test-key";
206
- process.env.DATABRICKS_API_BASE = "http://test.com";
207
-
208
- const config = require("../src/config");
209
-
210
- assert.strictEqual(config.azureOpenAI.apiVersion, "2025-01-01-preview");
211
- });
212
- });
213
- });
@@ -1,238 +0,0 @@
1
- const assert = require("assert");
2
- const { describe, it } = require("node:test");
3
-
4
- describe("Azure OpenAI Error Resilience Tests", () => {
5
- describe("Error Response Structure", () => {
6
- it("should recognize 401 authentication error", () => {
7
- const errorResponse = {
8
- status: 401,
9
- json: {
10
- error: {
11
- message: "Incorrect API key provided",
12
- type: "invalid_request_error",
13
- code: "invalid_api_key"
14
- }
15
- }
16
- };
17
-
18
- assert.strictEqual(errorResponse.status, 401);
19
- assert.strictEqual(errorResponse.json.error.code, "invalid_api_key");
20
- });
21
-
22
- it("should recognize 403 permission denied error", () => {
23
- const errorResponse = {
24
- status: 403,
25
- json: {
26
- error: {
27
- message: "The API deployment for this resource does not exist",
28
- type: "invalid_request_error",
29
- code: "DeploymentNotFound"
30
- }
31
- }
32
- };
33
-
34
- assert.strictEqual(errorResponse.status, 403);
35
- });
36
-
37
- it("should recognize 404 deployment not found error", () => {
38
- const errorResponse = {
39
- status: 404,
40
- json: {
41
- error: {
42
- message: "The API deployment for this resource does not exist",
43
- type: "invalid_request_error",
44
- code: "DeploymentNotFound"
45
- }
46
- }
47
- };
48
-
49
- assert.strictEqual(errorResponse.status, 404);
50
- assert.strictEqual(errorResponse.json.error.code, "DeploymentNotFound");
51
- });
52
-
53
- it("should recognize 429 rate limit error with Retry-After header", () => {
54
- const errorResponse = {
55
- status: 429,
56
- headers: {
57
- "retry-after": "2",
58
- "x-ratelimit-remaining-tokens": "0",
59
- "x-ratelimit-remaining-requests": "0"
60
- },
61
- json: {
62
- error: {
63
- message: "Rate limit reached",
64
- type: "rate_limit_error",
65
- code: "rate_limit_exceeded"
66
- }
67
- }
68
- };
69
-
70
- assert.strictEqual(errorResponse.status, 429);
71
- assert.strictEqual(errorResponse.headers["retry-after"], "2");
72
- assert.strictEqual(errorResponse.json.error.code, "rate_limit_exceeded");
73
- });
74
-
75
- it("should recognize 400 content filter error", () => {
76
- const errorResponse = {
77
- status: 400,
78
- json: {
79
- error: {
80
- message: "The response was filtered due to the prompt triggering Azure OpenAI's content management policy",
81
- type: "invalid_request_error",
82
- code: "content_filter"
83
- }
84
- }
85
- };
86
-
87
- assert.strictEqual(errorResponse.status, 400);
88
- assert.strictEqual(errorResponse.json.error.code, "content_filter");
89
- });
90
-
91
- it("should recognize 500 internal server error", () => {
92
- const errorResponse = {
93
- status: 500,
94
- json: {
95
- error: {
96
- message: "The server had an error while processing your request",
97
- type: "server_error",
98
- code: "internal_error"
99
- }
100
- }
101
- };
102
-
103
- assert.strictEqual(errorResponse.status, 500);
104
- assert.strictEqual(errorResponse.json.error.type, "server_error");
105
- });
106
-
107
- it("should recognize 503 service unavailable error", () => {
108
- const errorResponse = {
109
- status: 503,
110
- json: {
111
- error: {
112
- message: "The service is temporarily unavailable",
113
- type: "server_error",
114
- code: "service_unavailable"
115
- }
116
- }
117
- };
118
-
119
- assert.strictEqual(errorResponse.status, 503);
120
- });
121
- });
122
-
123
- describe("Missing Choices Array Validation", () => {
124
- it("should detect missing choices array", () => {
125
- const invalidResponse = {
126
- id: "chatcmpl-123",
127
- object: "chat.completion",
128
- model: "gpt-4o"
129
- // choices array missing
130
- };
131
-
132
- assert.strictEqual(invalidResponse.choices, undefined);
133
- });
134
-
135
- it("should detect empty choices array", () => {
136
- const invalidResponse = {
137
- id: "chatcmpl-123",
138
- object: "chat.completion",
139
- model: "gpt-4o",
140
- choices: []
141
- };
142
-
143
- assert.strictEqual(invalidResponse.choices.length, 0);
144
- });
145
-
146
- it("should validate valid choices array", () => {
147
- const validResponse = {
148
- choices: [
149
- {
150
- message: {
151
- role: "assistant",
152
- content: "Hello"
153
- },
154
- finish_reason: "stop"
155
- }
156
- ]
157
- };
158
-
159
- assert.ok(validResponse.choices?.length > 0);
160
- assert.ok(validResponse.choices[0].message);
161
- });
162
- });
163
-
164
- describe("Network Error Categorization", () => {
165
- it("should categorize ETIMEDOUT as timeout error", () => {
166
- const error = new Error("Request timeout");
167
- error.code = "ETIMEDOUT";
168
-
169
- assert.strictEqual(error.code, "ETIMEDOUT");
170
- });
171
-
172
- it("should categorize ECONNREFUSED as connection error", () => {
173
- const error = new Error("Connection refused");
174
- error.code = "ECONNREFUSED";
175
-
176
- assert.strictEqual(error.code, "ECONNREFUSED");
177
- });
178
-
179
- it("should categorize ENOTFOUND as DNS error", () => {
180
- const error = new Error("DNS lookup failed");
181
- error.code = "ENOTFOUND";
182
-
183
- assert.strictEqual(error.code, "ENOTFOUND");
184
- });
185
- });
186
-
187
- describe("Retry Strategy", () => {
188
- it("should identify retryable 5xx errors", () => {
189
- const retryableStatuses = [500, 502, 503, 504];
190
-
191
- for (const status of retryableStatuses) {
192
- assert.ok(status >= 500 && status < 600);
193
- }
194
- });
195
-
196
- it("should identify non-retryable 4xx errors", () => {
197
- const nonRetryableStatuses = [400, 401, 403, 404];
198
-
199
- for (const status of nonRetryableStatuses) {
200
- assert.ok(status >= 400 && status < 500);
201
- assert.notStrictEqual(status, 429); // 429 is retryable
202
- }
203
- });
204
-
205
- it("should treat 429 as retryable with backoff", () => {
206
- const status = 429;
207
-
208
- assert.strictEqual(status, 429);
209
- assert.ok(status === 429); // Special handling for rate limits
210
- });
211
- });
212
-
213
- describe("Malformed JSON Response", () => {
214
- it("should handle truncated JSON response", () => {
215
- const truncatedJSON = '{"choices":[{"message":{"role":"assistant","content":"Hello';
216
-
217
- assert.throws(() => {
218
- JSON.parse(truncatedJSON);
219
- }, SyntaxError);
220
- });
221
-
222
- it("should handle empty response body", () => {
223
- const emptyBody = "";
224
-
225
- assert.throws(() => {
226
- JSON.parse(emptyBody);
227
- }, SyntaxError);
228
- });
229
-
230
- it("should handle non-JSON response", () => {
231
- const htmlError = "<html><body>Error 503</body></html>";
232
-
233
- assert.throws(() => {
234
- JSON.parse(htmlError);
235
- }, SyntaxError);
236
- });
237
- });
238
- });