lynkr 8.0.0 → 9.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 (128) hide show
  1. package/.lynkr/telemetry.db +0 -0
  2. package/.lynkr/telemetry.db-shm +0 -0
  3. package/.lynkr/telemetry.db-wal +0 -0
  4. package/README.md +196 -322
  5. package/lynkr-skill.tar.gz +0 -0
  6. package/package.json +4 -3
  7. package/src/api/openai-router.js +64 -13
  8. package/src/api/providers-handler.js +171 -3
  9. package/src/api/router.js +9 -2
  10. package/src/clients/circuit-breaker.js +10 -247
  11. package/src/clients/codex-process.js +342 -0
  12. package/src/clients/codex-utils.js +143 -0
  13. package/src/clients/databricks.js +210 -63
  14. package/src/clients/resilience.js +540 -0
  15. package/src/clients/retry.js +22 -167
  16. package/src/clients/standard-tools.js +23 -0
  17. package/src/config/index.js +77 -0
  18. package/src/context/compression.js +42 -9
  19. package/src/context/distill.js +492 -0
  20. package/src/orchestrator/index.js +48 -8
  21. package/src/routing/complexity-analyzer.js +258 -5
  22. package/src/routing/index.js +12 -2
  23. package/src/routing/latency-tracker.js +148 -0
  24. package/src/routing/model-tiers.js +2 -0
  25. package/src/routing/quality-scorer.js +113 -0
  26. package/src/routing/telemetry.js +464 -0
  27. package/src/server.js +13 -12
  28. package/src/tools/code-graph.js +538 -0
  29. package/src/tools/code-mode.js +304 -0
  30. package/src/tools/index.js +4 -0
  31. package/src/tools/lazy-loader.js +18 -0
  32. package/src/tools/mcp-remote.js +7 -0
  33. package/src/tools/smart-selection.js +11 -0
  34. package/src/tools/tinyfish.js +358 -0
  35. package/src/tools/truncate.js +1 -0
  36. package/src/utils/payload.js +206 -0
  37. package/src/utils/perf-timer.js +80 -0
  38. package/.github/FUNDING.yml +0 -15
  39. package/.github/workflows/README.md +0 -215
  40. package/.github/workflows/ci.yml +0 -69
  41. package/.github/workflows/index.yml +0 -62
  42. package/.github/workflows/web-tools-tests.yml +0 -56
  43. package/CITATIONS.bib +0 -6
  44. package/DEPLOYMENT.md +0 -1001
  45. package/LYNKR-TUI-PLAN.md +0 -984
  46. package/PERFORMANCE-REPORT.md +0 -866
  47. package/PLAN-per-client-model-routing.md +0 -252
  48. package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
  49. package/docs/BingSiteAuth.xml +0 -4
  50. package/docs/docs-style.css +0 -478
  51. package/docs/docs.html +0 -198
  52. package/docs/google5be250e608e6da39.html +0 -1
  53. package/docs/index.html +0 -577
  54. package/docs/index.md +0 -584
  55. package/docs/robots.txt +0 -4
  56. package/docs/sitemap.xml +0 -44
  57. package/docs/style.css +0 -1223
  58. package/docs/toon-integration-spec.md +0 -130
  59. package/documentation/README.md +0 -101
  60. package/documentation/api.md +0 -806
  61. package/documentation/claude-code-cli.md +0 -679
  62. package/documentation/codex-cli.md +0 -397
  63. package/documentation/contributing.md +0 -571
  64. package/documentation/cursor-integration.md +0 -734
  65. package/documentation/docker.md +0 -874
  66. package/documentation/embeddings.md +0 -762
  67. package/documentation/faq.md +0 -713
  68. package/documentation/features.md +0 -403
  69. package/documentation/headroom.md +0 -519
  70. package/documentation/installation.md +0 -758
  71. package/documentation/memory-system.md +0 -476
  72. package/documentation/production.md +0 -636
  73. package/documentation/providers.md +0 -1009
  74. package/documentation/routing.md +0 -476
  75. package/documentation/testing.md +0 -629
  76. package/documentation/token-optimization.md +0 -325
  77. package/documentation/tools.md +0 -697
  78. package/documentation/troubleshooting.md +0 -969
  79. package/final-test.js +0 -33
  80. package/headroom-sidecar/config.py +0 -93
  81. package/headroom-sidecar/requirements.txt +0 -14
  82. package/headroom-sidecar/server.py +0 -451
  83. package/monitor-agents.sh +0 -31
  84. package/scripts/audit-log-reader.js +0 -399
  85. package/scripts/compact-dictionary.js +0 -204
  86. package/scripts/test-deduplication.js +0 -448
  87. package/src/db/database.sqlite +0 -0
  88. package/te +0 -11622
  89. package/test/README.md +0 -212
  90. package/test/azure-openai-config.test.js +0 -213
  91. package/test/azure-openai-error-resilience.test.js +0 -238
  92. package/test/azure-openai-format-conversion.test.js +0 -354
  93. package/test/azure-openai-integration.test.js +0 -287
  94. package/test/azure-openai-routing.test.js +0 -175
  95. package/test/azure-openai-streaming.test.js +0 -171
  96. package/test/bedrock-integration.test.js +0 -457
  97. package/test/comprehensive-test-suite.js +0 -928
  98. package/test/config-validation.test.js +0 -207
  99. package/test/cursor-integration.test.js +0 -484
  100. package/test/format-conversion.test.js +0 -578
  101. package/test/hybrid-routing-integration.test.js +0 -269
  102. package/test/hybrid-routing-performance.test.js +0 -428
  103. package/test/llamacpp-integration.test.js +0 -882
  104. package/test/lmstudio-integration.test.js +0 -347
  105. package/test/memory/extractor.test.js +0 -398
  106. package/test/memory/retriever.test.js +0 -613
  107. package/test/memory/retriever.test.js.bak +0 -585
  108. package/test/memory/search.test.js +0 -537
  109. package/test/memory/search.test.js.bak +0 -389
  110. package/test/memory/store.test.js +0 -344
  111. package/test/memory/store.test.js.bak +0 -312
  112. package/test/memory/surprise.test.js +0 -300
  113. package/test/memory-performance.test.js +0 -472
  114. package/test/openai-integration.test.js +0 -683
  115. package/test/openrouter-error-resilience.test.js +0 -418
  116. package/test/passthrough-mode.test.js +0 -385
  117. package/test/performance-benchmark.js +0 -351
  118. package/test/performance-tests.js +0 -528
  119. package/test/routing.test.js +0 -225
  120. package/test/toon-compression.test.js +0 -131
  121. package/test/web-tools.test.js +0 -329
  122. package/test-agents-simple.js +0 -43
  123. package/test-cli-connection.sh +0 -33
  124. package/test-learning-unit.js +0 -126
  125. package/test-learning.js +0 -112
  126. package/test-parallel-agents.sh +0 -124
  127. package/test-parallel-direct.js +0 -155
  128. package/test-subagents.sh +0 -117
@@ -1,385 +0,0 @@
1
- const assert = require("assert");
2
- const { describe, it, beforeEach, afterEach, mock } = require("node:test");
3
-
4
- describe("Passthrough Mode (Client-Side Tool Execution)", () => {
5
- let originalEnv;
6
- let config;
7
- let orchestrator;
8
-
9
- beforeEach(() => {
10
- // Store original environment
11
- originalEnv = { ...process.env };
12
-
13
- // Ensure clean state for TOOL_EXECUTION_MODE
14
- delete process.env.TOOL_EXECUTION_MODE;
15
-
16
- // Set MODEL_PROVIDER to databricks for tests (not azure-openai from .env)
17
- process.env.MODEL_PROVIDER = "databricks";
18
- process.env.DATABRICKS_API_KEY = "test-key";
19
- process.env.DATABRICKS_API_BASE = "http://test.com";
20
-
21
- // Clear module cache
22
- delete require.cache[require.resolve("../src/config")];
23
- delete require.cache[require.resolve("../src/orchestrator/index")];
24
- });
25
-
26
- afterEach(() => {
27
- // Restore environment
28
- process.env = originalEnv;
29
- });
30
-
31
- describe("Configuration", () => {
32
- it("should accept 'client' mode", () => {
33
- process.env.TOOL_EXECUTION_MODE = "client";
34
- process.env.DATABRICKS_API_KEY = "test-key";
35
- process.env.DATABRICKS_API_BASE = "http://test.com";
36
- config = require("../src/config");
37
-
38
- assert.strictEqual(config.toolExecutionMode, "client");
39
- });
40
-
41
- it("should accept 'passthrough' mode (alias for client)", () => {
42
- process.env.TOOL_EXECUTION_MODE = "passthrough";
43
- process.env.DATABRICKS_API_KEY = "test-key";
44
- process.env.DATABRICKS_API_BASE = "http://test.com";
45
- config = require("../src/config");
46
-
47
- assert.strictEqual(config.toolExecutionMode, "passthrough");
48
- });
49
-
50
- it("should accept 'server' mode explicitly", () => {
51
- process.env.TOOL_EXECUTION_MODE = "server";
52
- process.env.DATABRICKS_API_KEY = "test-key";
53
- process.env.DATABRICKS_API_BASE = "http://test.com";
54
- config = require("../src/config");
55
-
56
- assert.strictEqual(config.toolExecutionMode, "server");
57
- });
58
- });
59
-
60
- describe("Response Format in Passthrough Mode", () => {
61
- it("should return Anthropic-formatted response with tool_use blocks", () => {
62
- // Mock response from provider with tool calls
63
- const mockProviderResponse = {
64
- ok: true,
65
- status: 200,
66
- json: {
67
- choices: [
68
- {
69
- message: {
70
- role: "assistant",
71
- content: "I'll create that file for you.",
72
- tool_calls: [
73
- {
74
- id: "call_123",
75
- type: "function",
76
- function: {
77
- name: "Write",
78
- arguments: JSON.stringify({
79
- file_path: "/tmp/test.txt",
80
- content: "Hello World"
81
- })
82
- }
83
- }
84
- ]
85
- },
86
- finish_reason: "tool_calls"
87
- }
88
- ],
89
- model: "openai/gpt-4o-mini",
90
- usage: {
91
- prompt_tokens: 10,
92
- completion_tokens: 20,
93
- total_tokens: 30
94
- }
95
- }
96
- };
97
-
98
- // Expected Anthropic format
99
- const expectedContent = [
100
- {
101
- type: "text",
102
- text: "I'll create that file for you."
103
- },
104
- {
105
- type: "tool_use",
106
- id: "call_123",
107
- name: "Write",
108
- input: {
109
- file_path: "/tmp/test.txt",
110
- content: "Hello World"
111
- }
112
- }
113
- ];
114
-
115
- // Test content conversion
116
- const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
117
- const anthropicResponse = convertOpenRouterResponseToAnthropic(
118
- mockProviderResponse.json,
119
- "claude-sonnet-4-5"
120
- );
121
-
122
- assert.strictEqual(anthropicResponse.role, "assistant");
123
- assert.strictEqual(anthropicResponse.stop_reason, "tool_use");
124
- assert.strictEqual(Array.isArray(anthropicResponse.content), true);
125
- assert.strictEqual(anthropicResponse.content.length, 2);
126
- assert.strictEqual(anthropicResponse.content[0].type, "text");
127
- assert.strictEqual(anthropicResponse.content[1].type, "tool_use");
128
- assert.strictEqual(anthropicResponse.content[1].name, "Write");
129
- assert.deepStrictEqual(anthropicResponse.content[1].input, {
130
- file_path: "/tmp/test.txt",
131
- content: "Hello World"
132
- });
133
- });
134
-
135
- it("should handle multiple tool calls in one response", () => {
136
- const mockProviderResponse = {
137
- choices: [
138
- {
139
- message: {
140
- role: "assistant",
141
- content: "I'll read the file and then write it.",
142
- tool_calls: [
143
- {
144
- id: "call_1",
145
- type: "function",
146
- function: {
147
- name: "Read",
148
- arguments: JSON.stringify({ file_path: "/tmp/input.txt" })
149
- }
150
- },
151
- {
152
- id: "call_2",
153
- type: "function",
154
- function: {
155
- name: "Write",
156
- arguments: JSON.stringify({
157
- file_path: "/tmp/output.txt",
158
- content: "Modified"
159
- })
160
- }
161
- }
162
- ]
163
- },
164
- finish_reason: "tool_calls"
165
- }
166
- ],
167
- model: "openai/gpt-4o-mini",
168
- usage: { prompt_tokens: 10, completion_tokens: 30, total_tokens: 40 }
169
- };
170
-
171
- const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
172
- const anthropicResponse = convertOpenRouterResponseToAnthropic(
173
- mockProviderResponse,
174
- "claude-sonnet-4-5"
175
- );
176
-
177
- assert.strictEqual(anthropicResponse.content.length, 3); // 1 text + 2 tool_use
178
- assert.strictEqual(anthropicResponse.content[1].type, "tool_use");
179
- assert.strictEqual(anthropicResponse.content[1].name, "Read");
180
- assert.strictEqual(anthropicResponse.content[2].type, "tool_use");
181
- assert.strictEqual(anthropicResponse.content[2].name, "Write");
182
- });
183
-
184
- it("should handle tool calls without text content", () => {
185
- const mockProviderResponse = {
186
- choices: [
187
- {
188
- message: {
189
- role: "assistant",
190
- content: null,
191
- tool_calls: [
192
- {
193
- id: "call_1",
194
- type: "function",
195
- function: {
196
- name: "Read",
197
- arguments: JSON.stringify({ file_path: "/tmp/test.txt" })
198
- }
199
- }
200
- ]
201
- },
202
- finish_reason: "tool_calls"
203
- }
204
- ],
205
- model: "openai/gpt-4o-mini",
206
- usage: { prompt_tokens: 10, completion_tokens: 15, total_tokens: 25 }
207
- };
208
-
209
- const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
210
- const anthropicResponse = convertOpenRouterResponseToAnthropic(
211
- mockProviderResponse,
212
- "claude-sonnet-4-5"
213
- );
214
-
215
- // Should only have tool_use block, no text block
216
- assert.strictEqual(anthropicResponse.content.length, 1);
217
- assert.strictEqual(anthropicResponse.content[0].type, "tool_use");
218
- });
219
- });
220
-
221
- describe("Tool Result Processing", () => {
222
- it("should accept tool_result blocks from CLI in next request", () => {
223
- // Simulate a conversation with tool results coming back from CLI
224
- const messagesWithToolResults = [
225
- {
226
- role: "user",
227
- content: "Create a file /tmp/test.txt"
228
- },
229
- {
230
- role: "assistant",
231
- content: [
232
- { type: "text", text: "I'll create that file." },
233
- {
234
- type: "tool_use",
235
- id: "toolu_123",
236
- name: "Write",
237
- input: {
238
- file_path: "/tmp/test.txt",
239
- content: "Hello"
240
- }
241
- }
242
- ]
243
- },
244
- {
245
- role: "user",
246
- content: [
247
- {
248
- type: "tool_result",
249
- tool_use_id: "toolu_123",
250
- content: "File created successfully"
251
- }
252
- ]
253
- }
254
- ];
255
-
256
- // Verify structure
257
- assert.strictEqual(messagesWithToolResults.length, 3);
258
- assert.strictEqual(messagesWithToolResults[2].role, "user");
259
- assert.strictEqual(Array.isArray(messagesWithToolResults[2].content), true);
260
- assert.strictEqual(messagesWithToolResults[2].content[0].type, "tool_result");
261
- assert.strictEqual(messagesWithToolResults[2].content[0].tool_use_id, "toolu_123");
262
- });
263
-
264
- it("should convert tool_result blocks to OpenRouter format", () => {
265
- // Must include assistant message with tool_use first
266
- const anthropicMessages = [
267
- {
268
- role: "assistant",
269
- content: [
270
- {
271
- type: "tool_use",
272
- id: "toolu_123",
273
- name: "Write",
274
- input: { file_path: "/tmp/test.txt", content: "Hello" }
275
- }
276
- ]
277
- },
278
- {
279
- role: "user",
280
- content: [
281
- {
282
- type: "tool_result",
283
- tool_use_id: "toolu_123",
284
- content: "File created successfully"
285
- }
286
- ]
287
- }
288
- ];
289
-
290
- const { convertAnthropicMessagesToOpenRouter } = require("../src/clients/openrouter-utils");
291
- const openRouterMessages = convertAnthropicMessagesToOpenRouter(anthropicMessages);
292
-
293
- // Should convert to tool role message for OpenRouter
294
- assert.strictEqual(openRouterMessages.length >= 2, true);
295
- // OpenRouter expects tool results as separate tool messages
296
- const toolMessage = openRouterMessages.find(m => m.role === "tool");
297
- assert.ok(toolMessage, "Tool message should be present");
298
- });
299
- });
300
-
301
- describe("Stop Reason Handling", () => {
302
- it("should set stop_reason to 'tool_use' when tools are present", () => {
303
- const mockResponse = {
304
- choices: [
305
- {
306
- message: {
307
- role: "assistant",
308
- content: "Using tool",
309
- tool_calls: [
310
- {
311
- id: "call_1",
312
- function: {
313
- name: "Read",
314
- arguments: "{}"
315
- }
316
- }
317
- ]
318
- },
319
- finish_reason: "tool_calls"
320
- }
321
- ],
322
- model: "test-model",
323
- usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 }
324
- };
325
-
326
- const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
327
- const result = convertOpenRouterResponseToAnthropic(mockResponse, "claude-sonnet-4-5");
328
-
329
- assert.strictEqual(result.stop_reason, "tool_use");
330
- });
331
-
332
- it("should set stop_reason to 'end_turn' when no tools", () => {
333
- const mockResponse = {
334
- choices: [
335
- {
336
- message: {
337
- role: "assistant",
338
- content: "Simple response"
339
- },
340
- finish_reason: "stop"
341
- }
342
- ],
343
- model: "test-model",
344
- usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 }
345
- };
346
-
347
- const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
348
- const result = convertOpenRouterResponseToAnthropic(mockResponse, "claude-sonnet-4-5");
349
-
350
- assert.strictEqual(result.stop_reason, "end_turn");
351
- });
352
- });
353
-
354
- describe("Session Storage Format", () => {
355
- it("should store tool_use blocks in Anthropic format for session", () => {
356
- // Session content should always be in Anthropic format
357
- // regardless of provider
358
- const sessionContent = [
359
- {
360
- type: "text",
361
- text: "I'll help with that."
362
- },
363
- {
364
- type: "tool_use",
365
- id: "toolu_abc",
366
- name: "Write",
367
- input: {
368
- file_path: "/tmp/test.txt",
369
- content: "data"
370
- }
371
- }
372
- ];
373
-
374
- // Verify all blocks have correct structure
375
- sessionContent.forEach(block => {
376
- assert.strictEqual(typeof block.type, "string");
377
- if (block.type === "tool_use") {
378
- assert.strictEqual(typeof block.id, "string");
379
- assert.strictEqual(typeof block.name, "string");
380
- assert.strictEqual(typeof block.input, "object");
381
- }
382
- });
383
- });
384
- });
385
- });