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.
- package/.lynkr/telemetry.db +0 -0
- package/.lynkr/telemetry.db-shm +0 -0
- package/.lynkr/telemetry.db-wal +0 -0
- package/README.md +196 -322
- package/lynkr-skill.tar.gz +0 -0
- package/package.json +4 -3
- package/src/api/openai-router.js +64 -13
- package/src/api/providers-handler.js +171 -3
- package/src/api/router.js +9 -2
- package/src/clients/circuit-breaker.js +10 -247
- package/src/clients/codex-process.js +342 -0
- package/src/clients/codex-utils.js +143 -0
- package/src/clients/databricks.js +210 -63
- package/src/clients/resilience.js +540 -0
- package/src/clients/retry.js +22 -167
- package/src/clients/standard-tools.js +23 -0
- package/src/config/index.js +77 -0
- package/src/context/compression.js +42 -9
- package/src/context/distill.js +492 -0
- package/src/orchestrator/index.js +48 -8
- package/src/routing/complexity-analyzer.js +258 -5
- package/src/routing/index.js +12 -2
- package/src/routing/latency-tracker.js +148 -0
- package/src/routing/model-tiers.js +2 -0
- package/src/routing/quality-scorer.js +113 -0
- package/src/routing/telemetry.js +464 -0
- package/src/server.js +13 -12
- package/src/tools/code-graph.js +538 -0
- package/src/tools/code-mode.js +304 -0
- package/src/tools/index.js +4 -0
- package/src/tools/lazy-loader.js +18 -0
- package/src/tools/mcp-remote.js +7 -0
- package/src/tools/smart-selection.js +11 -0
- package/src/tools/tinyfish.js +358 -0
- package/src/tools/truncate.js +1 -0
- package/src/utils/payload.js +206 -0
- package/src/utils/perf-timer.js +80 -0
- package/.github/FUNDING.yml +0 -15
- package/.github/workflows/README.md +0 -215
- package/.github/workflows/ci.yml +0 -69
- package/.github/workflows/index.yml +0 -62
- package/.github/workflows/web-tools-tests.yml +0 -56
- package/CITATIONS.bib +0 -6
- package/DEPLOYMENT.md +0 -1001
- package/LYNKR-TUI-PLAN.md +0 -984
- package/PERFORMANCE-REPORT.md +0 -866
- package/PLAN-per-client-model-routing.md +0 -252
- package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
- package/docs/BingSiteAuth.xml +0 -4
- package/docs/docs-style.css +0 -478
- package/docs/docs.html +0 -198
- package/docs/google5be250e608e6da39.html +0 -1
- package/docs/index.html +0 -577
- package/docs/index.md +0 -584
- package/docs/robots.txt +0 -4
- package/docs/sitemap.xml +0 -44
- package/docs/style.css +0 -1223
- package/docs/toon-integration-spec.md +0 -130
- package/documentation/README.md +0 -101
- package/documentation/api.md +0 -806
- package/documentation/claude-code-cli.md +0 -679
- package/documentation/codex-cli.md +0 -397
- package/documentation/contributing.md +0 -571
- package/documentation/cursor-integration.md +0 -734
- package/documentation/docker.md +0 -874
- package/documentation/embeddings.md +0 -762
- package/documentation/faq.md +0 -713
- package/documentation/features.md +0 -403
- package/documentation/headroom.md +0 -519
- package/documentation/installation.md +0 -758
- package/documentation/memory-system.md +0 -476
- package/documentation/production.md +0 -636
- package/documentation/providers.md +0 -1009
- package/documentation/routing.md +0 -476
- package/documentation/testing.md +0 -629
- package/documentation/token-optimization.md +0 -325
- package/documentation/tools.md +0 -697
- package/documentation/troubleshooting.md +0 -969
- package/final-test.js +0 -33
- package/headroom-sidecar/config.py +0 -93
- package/headroom-sidecar/requirements.txt +0 -14
- package/headroom-sidecar/server.py +0 -451
- package/monitor-agents.sh +0 -31
- package/scripts/audit-log-reader.js +0 -399
- package/scripts/compact-dictionary.js +0 -204
- package/scripts/test-deduplication.js +0 -448
- package/src/db/database.sqlite +0 -0
- package/te +0 -11622
- package/test/README.md +0 -212
- package/test/azure-openai-config.test.js +0 -213
- package/test/azure-openai-error-resilience.test.js +0 -238
- package/test/azure-openai-format-conversion.test.js +0 -354
- package/test/azure-openai-integration.test.js +0 -287
- package/test/azure-openai-routing.test.js +0 -175
- package/test/azure-openai-streaming.test.js +0 -171
- package/test/bedrock-integration.test.js +0 -457
- package/test/comprehensive-test-suite.js +0 -928
- package/test/config-validation.test.js +0 -207
- package/test/cursor-integration.test.js +0 -484
- package/test/format-conversion.test.js +0 -578
- package/test/hybrid-routing-integration.test.js +0 -269
- package/test/hybrid-routing-performance.test.js +0 -428
- package/test/llamacpp-integration.test.js +0 -882
- package/test/lmstudio-integration.test.js +0 -347
- package/test/memory/extractor.test.js +0 -398
- package/test/memory/retriever.test.js +0 -613
- package/test/memory/retriever.test.js.bak +0 -585
- package/test/memory/search.test.js +0 -537
- package/test/memory/search.test.js.bak +0 -389
- package/test/memory/store.test.js +0 -344
- package/test/memory/store.test.js.bak +0 -312
- package/test/memory/surprise.test.js +0 -300
- package/test/memory-performance.test.js +0 -472
- package/test/openai-integration.test.js +0 -683
- package/test/openrouter-error-resilience.test.js +0 -418
- package/test/passthrough-mode.test.js +0 -385
- package/test/performance-benchmark.js +0 -351
- package/test/performance-tests.js +0 -528
- package/test/routing.test.js +0 -225
- package/test/toon-compression.test.js +0 -131
- package/test/web-tools.test.js +0 -329
- package/test-agents-simple.js +0 -43
- package/test-cli-connection.sh +0 -33
- package/test-learning-unit.js +0 -126
- package/test-learning.js +0 -112
- package/test-parallel-agents.sh +0 -124
- package/test-parallel-direct.js +0 -155
- package/test-subagents.sh +0 -117
package/documentation/api.md
DELETED
|
@@ -1,806 +0,0 @@
|
|
|
1
|
-
# API Reference
|
|
2
|
-
|
|
3
|
-
Complete API reference for all Lynkr endpoints, including Claude Code CLI (Anthropic format) and Cursor IDE (OpenAI format) compatibility.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Base URL
|
|
8
|
-
|
|
9
|
-
**Development:**
|
|
10
|
-
```
|
|
11
|
-
http://localhost:8081
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
**Production:**
|
|
15
|
-
```
|
|
16
|
-
https://your-domain.com
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Authentication
|
|
22
|
-
|
|
23
|
-
Lynkr acts as a proxy, so authentication depends on the configured provider:
|
|
24
|
-
|
|
25
|
-
**For Claude Code CLI:**
|
|
26
|
-
```bash
|
|
27
|
-
export ANTHROPIC_API_KEY=dummy # Any value works
|
|
28
|
-
export ANTHROPIC_BASE_URL=http://localhost:8081
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**For Cursor IDE:**
|
|
32
|
-
```
|
|
33
|
-
API Key: sk-lynkr # Any value starting with "sk-" works
|
|
34
|
-
Base URL: http://localhost:8081/v1
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**Note:** Real authentication happens between Lynkr and the provider (Databricks, Bedrock, etc.).
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Endpoints
|
|
42
|
-
|
|
43
|
-
### Chat Completion (Anthropic Format)
|
|
44
|
-
|
|
45
|
-
#### POST /v1/messages
|
|
46
|
-
|
|
47
|
-
Create a message using Anthropic's Messages API format.
|
|
48
|
-
|
|
49
|
-
**Request:**
|
|
50
|
-
```bash
|
|
51
|
-
curl -X POST http://localhost:8081/v1/messages \
|
|
52
|
-
-H "Content-Type: application/json" \
|
|
53
|
-
-H "anthropic-version: 2023-06-01" \
|
|
54
|
-
-d '{
|
|
55
|
-
"model": "claude-3-5-sonnet-20241022",
|
|
56
|
-
"messages": [
|
|
57
|
-
{
|
|
58
|
-
"role": "user",
|
|
59
|
-
"content": "What is the capital of France?"
|
|
60
|
-
}
|
|
61
|
-
],
|
|
62
|
-
"max_tokens": 1024,
|
|
63
|
-
"temperature": 0.7
|
|
64
|
-
}'
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**Request Body:**
|
|
68
|
-
```typescript
|
|
69
|
-
{
|
|
70
|
-
model: string; // Model name (e.g., "claude-3-5-sonnet-20241022")
|
|
71
|
-
messages: Message[]; // Conversation history
|
|
72
|
-
max_tokens?: number; // Max tokens to generate (default: 4096)
|
|
73
|
-
temperature?: number; // 0.0-1.0 (default: 0.7)
|
|
74
|
-
top_p?: number; // 0.0-1.0 (default: 1.0)
|
|
75
|
-
top_k?: number; // Top-k sampling (default: null)
|
|
76
|
-
stop_sequences?: string[]; // Stop generation at these sequences
|
|
77
|
-
stream?: boolean; // Enable streaming (default: false)
|
|
78
|
-
tools?: Tool[]; // Available tools for the model
|
|
79
|
-
system?: string; // System prompt
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
interface Message {
|
|
83
|
-
role: "user" | "assistant";
|
|
84
|
-
content: string | Content[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface Content {
|
|
88
|
-
type: "text" | "image" | "tool_use" | "tool_result";
|
|
89
|
-
text?: string;
|
|
90
|
-
source?: ImageSource;
|
|
91
|
-
id?: string;
|
|
92
|
-
name?: string;
|
|
93
|
-
input?: object;
|
|
94
|
-
tool_use_id?: string;
|
|
95
|
-
content?: string | object;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
interface Tool {
|
|
99
|
-
name: string;
|
|
100
|
-
description: string;
|
|
101
|
-
input_schema: {
|
|
102
|
-
type: "object";
|
|
103
|
-
properties: object;
|
|
104
|
-
required?: string[];
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Response (Non-Streaming):**
|
|
110
|
-
```json
|
|
111
|
-
{
|
|
112
|
-
"id": "msg_01ABC123",
|
|
113
|
-
"type": "message",
|
|
114
|
-
"role": "assistant",
|
|
115
|
-
"content": [
|
|
116
|
-
{
|
|
117
|
-
"type": "text",
|
|
118
|
-
"text": "The capital of France is Paris."
|
|
119
|
-
}
|
|
120
|
-
],
|
|
121
|
-
"model": "claude-3-5-sonnet-20241022",
|
|
122
|
-
"stop_reason": "end_turn",
|
|
123
|
-
"stop_sequence": null,
|
|
124
|
-
"usage": {
|
|
125
|
-
"input_tokens": 15,
|
|
126
|
-
"output_tokens": 8
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Response (Streaming):**
|
|
132
|
-
```
|
|
133
|
-
event: message_start
|
|
134
|
-
data: {"type":"message_start","message":{"id":"msg_01ABC123","type":"message","role":"assistant","content":[],"model":"claude-3-5-sonnet-20241022","stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":15,"output_tokens":0}}}
|
|
135
|
-
|
|
136
|
-
event: content_block_start
|
|
137
|
-
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
|
|
138
|
-
|
|
139
|
-
event: content_block_delta
|
|
140
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"The"}}
|
|
141
|
-
|
|
142
|
-
event: content_block_delta
|
|
143
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" capital"}}
|
|
144
|
-
|
|
145
|
-
event: content_block_delta
|
|
146
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" of"}}
|
|
147
|
-
|
|
148
|
-
event: content_block_delta
|
|
149
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" France"}}
|
|
150
|
-
|
|
151
|
-
event: content_block_delta
|
|
152
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" is"}}
|
|
153
|
-
|
|
154
|
-
event: content_block_delta
|
|
155
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Paris"}}
|
|
156
|
-
|
|
157
|
-
event: content_block_delta
|
|
158
|
-
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}}
|
|
159
|
-
|
|
160
|
-
event: content_block_stop
|
|
161
|
-
data: {"type":"content_block_stop","index":0}
|
|
162
|
-
|
|
163
|
-
event: message_delta
|
|
164
|
-
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":8}}
|
|
165
|
-
|
|
166
|
-
event: message_stop
|
|
167
|
-
data: {"type":"message_stop"}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
### Chat Completion (OpenAI Format)
|
|
173
|
-
|
|
174
|
-
#### POST /v1/chat/completions
|
|
175
|
-
|
|
176
|
-
Create a chat completion using OpenAI's Chat Completions API format.
|
|
177
|
-
|
|
178
|
-
**Request:**
|
|
179
|
-
```bash
|
|
180
|
-
curl -X POST http://localhost:8081/v1/chat/completions \
|
|
181
|
-
-H "Content-Type: application/json" \
|
|
182
|
-
-H "Authorization: Bearer sk-lynkr" \
|
|
183
|
-
-d '{
|
|
184
|
-
"model": "claude-3.5-sonnet",
|
|
185
|
-
"messages": [
|
|
186
|
-
{
|
|
187
|
-
"role": "user",
|
|
188
|
-
"content": "What is the capital of France?"
|
|
189
|
-
}
|
|
190
|
-
],
|
|
191
|
-
"max_tokens": 1024,
|
|
192
|
-
"temperature": 0.7,
|
|
193
|
-
"stream": false
|
|
194
|
-
}'
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**Request Body:**
|
|
198
|
-
```typescript
|
|
199
|
-
{
|
|
200
|
-
model: string; // Model name
|
|
201
|
-
messages: Message[]; // Conversation history
|
|
202
|
-
max_tokens?: number; // Max tokens to generate
|
|
203
|
-
temperature?: number; // 0.0-2.0 (default: 0.7)
|
|
204
|
-
top_p?: number; // 0.0-1.0
|
|
205
|
-
n?: number; // Number of completions (default: 1)
|
|
206
|
-
stop?: string | string[]; // Stop sequences
|
|
207
|
-
stream?: boolean; // Enable streaming
|
|
208
|
-
tools?: Tool[]; // Function calling tools
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
interface Message {
|
|
212
|
-
role: "system" | "user" | "assistant" | "tool";
|
|
213
|
-
content: string;
|
|
214
|
-
name?: string; // For tool messages
|
|
215
|
-
tool_call_id?: string; // For tool result messages
|
|
216
|
-
tool_calls?: ToolCall[]; // For assistant tool call messages
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
interface ToolCall {
|
|
220
|
-
id: string;
|
|
221
|
-
type: "function";
|
|
222
|
-
function: {
|
|
223
|
-
name: string;
|
|
224
|
-
arguments: string; // JSON string
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
interface Tool {
|
|
229
|
-
type: "function";
|
|
230
|
-
function: {
|
|
231
|
-
name: string;
|
|
232
|
-
description: string;
|
|
233
|
-
parameters: object; // JSON Schema
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
**Response (Non-Streaming):**
|
|
239
|
-
```json
|
|
240
|
-
{
|
|
241
|
-
"id": "chatcmpl-ABC123",
|
|
242
|
-
"object": "chat.completion",
|
|
243
|
-
"created": 1677858242,
|
|
244
|
-
"model": "claude-3.5-sonnet",
|
|
245
|
-
"choices": [
|
|
246
|
-
{
|
|
247
|
-
"index": 0,
|
|
248
|
-
"message": {
|
|
249
|
-
"role": "assistant",
|
|
250
|
-
"content": "The capital of France is Paris."
|
|
251
|
-
},
|
|
252
|
-
"finish_reason": "stop"
|
|
253
|
-
}
|
|
254
|
-
],
|
|
255
|
-
"usage": {
|
|
256
|
-
"prompt_tokens": 15,
|
|
257
|
-
"completion_tokens": 8,
|
|
258
|
-
"total_tokens": 23
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
**Response (Streaming):**
|
|
264
|
-
```
|
|
265
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
|
|
266
|
-
|
|
267
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":"The"},"finish_reason":null}]}
|
|
268
|
-
|
|
269
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":" capital"},"finish_reason":null}]}
|
|
270
|
-
|
|
271
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":" of"},"finish_reason":null}]}
|
|
272
|
-
|
|
273
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":" France"},"finish_reason":null}]}
|
|
274
|
-
|
|
275
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":" is"},"finish_reason":null}]}
|
|
276
|
-
|
|
277
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":" Paris"},"finish_reason":null}]}
|
|
278
|
-
|
|
279
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{"content":"."},"finish_reason":null}]}
|
|
280
|
-
|
|
281
|
-
data: {"id":"chatcmpl-ABC123","object":"chat.completion.chunk","created":1677858242,"model":"claude-3.5-sonnet","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
|
|
282
|
-
|
|
283
|
-
data: [DONE]
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
---
|
|
287
|
-
|
|
288
|
-
### Embeddings
|
|
289
|
-
|
|
290
|
-
#### POST /v1/embeddings
|
|
291
|
-
|
|
292
|
-
Generate embeddings for text input.
|
|
293
|
-
|
|
294
|
-
**Request:**
|
|
295
|
-
```bash
|
|
296
|
-
curl -X POST http://localhost:8081/v1/embeddings \
|
|
297
|
-
-H "Content-Type: application/json" \
|
|
298
|
-
-d '{
|
|
299
|
-
"input": "function to sort array",
|
|
300
|
-
"model": "text-embedding-ada-002"
|
|
301
|
-
}'
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
**Request Body:**
|
|
305
|
-
```typescript
|
|
306
|
-
{
|
|
307
|
-
input: string | string[]; // Text to embed
|
|
308
|
-
model: string; // Embedding model name
|
|
309
|
-
}
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Supported Models:**
|
|
313
|
-
- `text-embedding-ada-002` (OpenAI)
|
|
314
|
-
- `text-embedding-3-small` (OpenAI)
|
|
315
|
-
- `text-embedding-3-large` (OpenAI)
|
|
316
|
-
- `nomic-embed-text` (Ollama)
|
|
317
|
-
- `all-minilm` (llama.cpp)
|
|
318
|
-
|
|
319
|
-
**Response:**
|
|
320
|
-
```json
|
|
321
|
-
{
|
|
322
|
-
"object": "list",
|
|
323
|
-
"data": [
|
|
324
|
-
{
|
|
325
|
-
"object": "embedding",
|
|
326
|
-
"embedding": [0.123, -0.456, 0.789, ...],
|
|
327
|
-
"index": 0
|
|
328
|
-
}
|
|
329
|
-
],
|
|
330
|
-
"model": "text-embedding-ada-002",
|
|
331
|
-
"usage": {
|
|
332
|
-
"prompt_tokens": 8,
|
|
333
|
-
"total_tokens": 8
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
**Configuration:**
|
|
339
|
-
```bash
|
|
340
|
-
# Ollama embeddings (local)
|
|
341
|
-
EMBEDDINGS_PROVIDER=ollama
|
|
342
|
-
OLLAMA_API_BASE=http://localhost:11434
|
|
343
|
-
OLLAMA_EMBEDDINGS_MODEL=nomic-embed-text
|
|
344
|
-
|
|
345
|
-
# OpenAI embeddings (cloud)
|
|
346
|
-
EMBEDDINGS_PROVIDER=openai
|
|
347
|
-
OPENAI_API_KEY=sk-...
|
|
348
|
-
OPENAI_EMBEDDINGS_MODEL=text-embedding-3-small
|
|
349
|
-
|
|
350
|
-
# OpenRouter embeddings (cloud)
|
|
351
|
-
EMBEDDINGS_PROVIDER=openrouter
|
|
352
|
-
OPENROUTER_API_KEY=sk-or-v1-...
|
|
353
|
-
OPENROUTER_EMBEDDINGS_MODEL=openai/text-embedding-3-small
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
---
|
|
357
|
-
|
|
358
|
-
### Models
|
|
359
|
-
|
|
360
|
-
#### GET /v1/models
|
|
361
|
-
|
|
362
|
-
List available models.
|
|
363
|
-
|
|
364
|
-
**Request:**
|
|
365
|
-
```bash
|
|
366
|
-
curl http://localhost:8081/v1/models
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
**Response:**
|
|
370
|
-
```json
|
|
371
|
-
{
|
|
372
|
-
"object": "list",
|
|
373
|
-
"data": [
|
|
374
|
-
{
|
|
375
|
-
"id": "claude-3-5-sonnet-20241022",
|
|
376
|
-
"object": "model",
|
|
377
|
-
"created": 1677649963,
|
|
378
|
-
"owned_by": "anthropic"
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
"id": "claude-3-opus-20240229",
|
|
382
|
-
"object": "model",
|
|
383
|
-
"created": 1677649963,
|
|
384
|
-
"owned_by": "anthropic"
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
"id": "qwen2.5-coder:7b",
|
|
388
|
-
"object": "model",
|
|
389
|
-
"created": 1677649963,
|
|
390
|
-
"owned_by": "ollama"
|
|
391
|
-
}
|
|
392
|
-
]
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
### Health Checks
|
|
399
|
-
|
|
400
|
-
#### GET /health/live
|
|
401
|
-
|
|
402
|
-
Liveness probe - checks if server is running.
|
|
403
|
-
|
|
404
|
-
**Request:**
|
|
405
|
-
```bash
|
|
406
|
-
curl http://localhost:8081/health/live
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**Response:**
|
|
410
|
-
```json
|
|
411
|
-
{
|
|
412
|
-
"status": "ok",
|
|
413
|
-
"provider": "databricks",
|
|
414
|
-
"timestamp": "2026-01-12T00:00:00.000Z"
|
|
415
|
-
}
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
**HTTP Status:**
|
|
419
|
-
- `200 OK` - Server is running
|
|
420
|
-
- `503 Service Unavailable` - Server is not ready
|
|
421
|
-
|
|
422
|
-
#### GET /health/ready
|
|
423
|
-
|
|
424
|
-
Readiness probe - checks if server can handle requests.
|
|
425
|
-
|
|
426
|
-
**Request:**
|
|
427
|
-
```bash
|
|
428
|
-
curl http://localhost:8081/health/ready
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
**Response:**
|
|
432
|
-
```json
|
|
433
|
-
{
|
|
434
|
-
"status": "ready",
|
|
435
|
-
"checks": {
|
|
436
|
-
"database": "ok",
|
|
437
|
-
"provider": "ok"
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
**HTTP Status:**
|
|
443
|
-
- `200 OK` - Server is ready
|
|
444
|
-
- `503 Service Unavailable` - Server is not ready
|
|
445
|
-
|
|
446
|
-
#### GET /health/ready?deep=true
|
|
447
|
-
|
|
448
|
-
Deep health check with detailed information.
|
|
449
|
-
|
|
450
|
-
**Request:**
|
|
451
|
-
```bash
|
|
452
|
-
curl "http://localhost:8081/health/ready?deep=true"
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
**Response:**
|
|
456
|
-
```json
|
|
457
|
-
{
|
|
458
|
-
"status": "ready",
|
|
459
|
-
"checks": {
|
|
460
|
-
"database": "ok",
|
|
461
|
-
"provider": "ok",
|
|
462
|
-
"memory": {
|
|
463
|
-
"used": "50%",
|
|
464
|
-
"status": "ok"
|
|
465
|
-
},
|
|
466
|
-
"circuit_breaker": {
|
|
467
|
-
"state": "closed",
|
|
468
|
-
"status": "ok"
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
---
|
|
475
|
-
|
|
476
|
-
### Metrics
|
|
477
|
-
|
|
478
|
-
#### GET /metrics
|
|
479
|
-
|
|
480
|
-
Prometheus-compatible metrics endpoint.
|
|
481
|
-
|
|
482
|
-
**Request:**
|
|
483
|
-
```bash
|
|
484
|
-
curl http://localhost:8081/metrics
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
**Response:**
|
|
488
|
-
```
|
|
489
|
-
# HELP lynkr_requests_total Total number of requests
|
|
490
|
-
# TYPE lynkr_requests_total counter
|
|
491
|
-
lynkr_requests_total{provider="databricks",status="200"} 1234
|
|
492
|
-
|
|
493
|
-
# HELP lynkr_request_duration_seconds Request duration in seconds
|
|
494
|
-
# TYPE lynkr_request_duration_seconds histogram
|
|
495
|
-
lynkr_request_duration_seconds_bucket{provider="databricks",le="0.5"} 980
|
|
496
|
-
lynkr_request_duration_seconds_bucket{provider="databricks",le="1"} 1200
|
|
497
|
-
lynkr_request_duration_seconds_bucket{provider="databricks",le="2"} 1230
|
|
498
|
-
lynkr_request_duration_seconds_bucket{provider="databricks",le="+Inf"} 1234
|
|
499
|
-
lynkr_request_duration_seconds_sum{provider="databricks"} 1234.5
|
|
500
|
-
lynkr_request_duration_seconds_count{provider="databricks"} 1234
|
|
501
|
-
|
|
502
|
-
# HELP lynkr_errors_total Total number of errors
|
|
503
|
-
# TYPE lynkr_errors_total counter
|
|
504
|
-
lynkr_errors_total{provider="databricks",type="timeout"} 12
|
|
505
|
-
|
|
506
|
-
# HELP lynkr_tokens_input_total Total input tokens
|
|
507
|
-
# TYPE lynkr_tokens_input_total counter
|
|
508
|
-
lynkr_tokens_input_total{provider="databricks"} 5000000
|
|
509
|
-
|
|
510
|
-
# HELP lynkr_tokens_output_total Total output tokens
|
|
511
|
-
# TYPE lynkr_tokens_output_total counter
|
|
512
|
-
lynkr_tokens_output_total{provider="databricks"} 500000
|
|
513
|
-
|
|
514
|
-
# HELP lynkr_tokens_cached_total Total cached tokens
|
|
515
|
-
# TYPE lynkr_tokens_cached_total counter
|
|
516
|
-
lynkr_tokens_cached_total 2000000
|
|
517
|
-
|
|
518
|
-
# HELP lynkr_cache_hits_total Total cache hits
|
|
519
|
-
# TYPE lynkr_cache_hits_total counter
|
|
520
|
-
lynkr_cache_hits_total 850
|
|
521
|
-
|
|
522
|
-
# HELP lynkr_cache_misses_total Total cache misses
|
|
523
|
-
# TYPE lynkr_cache_misses_total counter
|
|
524
|
-
lynkr_cache_misses_total 150
|
|
525
|
-
|
|
526
|
-
# HELP lynkr_circuit_breaker_state Circuit breaker state (1=open, 0=closed)
|
|
527
|
-
# TYPE lynkr_circuit_breaker_state gauge
|
|
528
|
-
lynkr_circuit_breaker_state{provider="databricks",state="closed"} 1
|
|
529
|
-
|
|
530
|
-
# HELP lynkr_active_requests Current active requests
|
|
531
|
-
# TYPE lynkr_active_requests gauge
|
|
532
|
-
lynkr_active_requests 42
|
|
533
|
-
|
|
534
|
-
# HELP process_resident_memory_bytes Resident memory size in bytes
|
|
535
|
-
# TYPE process_resident_memory_bytes gauge
|
|
536
|
-
process_resident_memory_bytes 104857600
|
|
537
|
-
|
|
538
|
-
# HELP nodejs_heap_size_used_bytes Heap size used in bytes
|
|
539
|
-
# TYPE nodejs_heap_size_used_bytes gauge
|
|
540
|
-
nodejs_heap_size_used_bytes 52428800
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
---
|
|
544
|
-
|
|
545
|
-
## Error Handling
|
|
546
|
-
|
|
547
|
-
### Error Response Format
|
|
548
|
-
|
|
549
|
-
**Anthropic Format:**
|
|
550
|
-
```json
|
|
551
|
-
{
|
|
552
|
-
"type": "error",
|
|
553
|
-
"error": {
|
|
554
|
-
"type": "invalid_request_error",
|
|
555
|
-
"message": "Missing required field: messages"
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
**OpenAI Format:**
|
|
561
|
-
```json
|
|
562
|
-
{
|
|
563
|
-
"error": {
|
|
564
|
-
"message": "Missing required field: messages",
|
|
565
|
-
"type": "invalid_request_error",
|
|
566
|
-
"code": "invalid_request"
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
### Error Types
|
|
572
|
-
|
|
573
|
-
| HTTP Status | Error Type | Description |
|
|
574
|
-
|-------------|------------|-------------|
|
|
575
|
-
| 400 | `invalid_request_error` | Invalid request parameters |
|
|
576
|
-
| 401 | `authentication_error` | Invalid or missing API key |
|
|
577
|
-
| 403 | `permission_error` | Insufficient permissions |
|
|
578
|
-
| 404 | `not_found_error` | Resource not found |
|
|
579
|
-
| 429 | `rate_limit_error` | Rate limit exceeded |
|
|
580
|
-
| 500 | `api_error` | Internal server error |
|
|
581
|
-
| 503 | `overloaded_error` | Server overloaded (load shedding) |
|
|
582
|
-
|
|
583
|
-
### Common Errors
|
|
584
|
-
|
|
585
|
-
**Missing API Key:**
|
|
586
|
-
```json
|
|
587
|
-
{
|
|
588
|
-
"type": "error",
|
|
589
|
-
"error": {
|
|
590
|
-
"type": "authentication_error",
|
|
591
|
-
"message": "Missing provider API key. Set DATABRICKS_API_KEY environment variable."
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
**Rate Limit:**
|
|
597
|
-
```json
|
|
598
|
-
{
|
|
599
|
-
"type": "error",
|
|
600
|
-
"error": {
|
|
601
|
-
"type": "rate_limit_error",
|
|
602
|
-
"message": "Rate limit exceeded. Retry after 60 seconds."
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
```
|
|
606
|
-
|
|
607
|
-
**Load Shedding:**
|
|
608
|
-
```json
|
|
609
|
-
{
|
|
610
|
-
"type": "error",
|
|
611
|
-
"error": {
|
|
612
|
-
"type": "overloaded_error",
|
|
613
|
-
"message": "Server overloaded. Please retry."
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
HTTP Response:
|
|
619
|
-
```
|
|
620
|
-
HTTP/1.1 503 Service Unavailable
|
|
621
|
-
Retry-After: 5
|
|
622
|
-
Content-Type: application/json
|
|
623
|
-
|
|
624
|
-
{"type":"error","error":{"type":"overloaded_error","message":"Server overloaded. Please retry."}}
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
---
|
|
628
|
-
|
|
629
|
-
## Rate Limiting
|
|
630
|
-
|
|
631
|
-
Lynkr does not implement rate limiting itself. Rate limits are enforced by the underlying provider:
|
|
632
|
-
|
|
633
|
-
| Provider | Rate Limit | Burst |
|
|
634
|
-
|----------|------------|-------|
|
|
635
|
-
| **Databricks** | Provider-specific | Provider-specific |
|
|
636
|
-
| **AWS Bedrock** | Provider-specific | Provider-specific |
|
|
637
|
-
| **OpenRouter** | Provider-specific | Provider-specific |
|
|
638
|
-
| **Ollama** | No limit | No limit |
|
|
639
|
-
| **llama.cpp** | No limit | No limit |
|
|
640
|
-
|
|
641
|
-
**Handle rate limits:**
|
|
642
|
-
```javascript
|
|
643
|
-
async function makeRequest(payload) {
|
|
644
|
-
try {
|
|
645
|
-
const response = await fetch("http://localhost:8081/v1/messages", {
|
|
646
|
-
method: "POST",
|
|
647
|
-
headers: { "Content-Type": "application/json" },
|
|
648
|
-
body: JSON.stringify(payload)
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
if (response.status === 429) {
|
|
652
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
653
|
-
console.log(`Rate limited. Retry after ${retryAfter}s`);
|
|
654
|
-
await sleep(parseInt(retryAfter) * 1000);
|
|
655
|
-
return makeRequest(payload); // Retry
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
return await response.json();
|
|
659
|
-
} catch (error) {
|
|
660
|
-
console.error("Request failed:", error);
|
|
661
|
-
throw error;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
```
|
|
665
|
-
|
|
666
|
-
---
|
|
667
|
-
|
|
668
|
-
## SDK Examples
|
|
669
|
-
|
|
670
|
-
### Node.js (Anthropic SDK)
|
|
671
|
-
|
|
672
|
-
```javascript
|
|
673
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
674
|
-
|
|
675
|
-
const client = new Anthropic({
|
|
676
|
-
apiKey: "dummy", // Any value works
|
|
677
|
-
baseURL: "http://localhost:8081"
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
// Non-streaming
|
|
681
|
-
const message = await client.messages.create({
|
|
682
|
-
model: "claude-3-5-sonnet-20241022",
|
|
683
|
-
max_tokens: 1024,
|
|
684
|
-
messages: [
|
|
685
|
-
{ role: "user", content: "What is the capital of France?" }
|
|
686
|
-
]
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
console.log(message.content[0].text);
|
|
690
|
-
|
|
691
|
-
// Streaming
|
|
692
|
-
const stream = await client.messages.create({
|
|
693
|
-
model: "claude-3-5-sonnet-20241022",
|
|
694
|
-
max_tokens: 1024,
|
|
695
|
-
messages: [
|
|
696
|
-
{ role: "user", content: "Tell me a story" }
|
|
697
|
-
],
|
|
698
|
-
stream: true
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
for await (const event of stream) {
|
|
702
|
-
if (event.type === "content_block_delta") {
|
|
703
|
-
process.stdout.write(event.delta.text);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
```
|
|
707
|
-
|
|
708
|
-
### Python (OpenAI SDK)
|
|
709
|
-
|
|
710
|
-
```python
|
|
711
|
-
from openai import OpenAI
|
|
712
|
-
|
|
713
|
-
client = OpenAI(
|
|
714
|
-
api_key="sk-lynkr",
|
|
715
|
-
base_url="http://localhost:8081/v1"
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
# Non-streaming
|
|
719
|
-
response = client.chat.completions.create(
|
|
720
|
-
model="claude-3.5-sonnet",
|
|
721
|
-
messages=[
|
|
722
|
-
{"role": "user", "content": "What is the capital of France?"}
|
|
723
|
-
],
|
|
724
|
-
max_tokens=1024
|
|
725
|
-
)
|
|
726
|
-
|
|
727
|
-
print(response.choices[0].message.content)
|
|
728
|
-
|
|
729
|
-
# Streaming
|
|
730
|
-
stream = client.chat.completions.create(
|
|
731
|
-
model="claude-3.5-sonnet",
|
|
732
|
-
messages=[
|
|
733
|
-
{"role": "user", "content": "Tell me a story"}
|
|
734
|
-
],
|
|
735
|
-
max_tokens=1024,
|
|
736
|
-
stream=True
|
|
737
|
-
)
|
|
738
|
-
|
|
739
|
-
for chunk in stream:
|
|
740
|
-
if chunk.choices[0].delta.content:
|
|
741
|
-
print(chunk.choices[0].delta.content, end="")
|
|
742
|
-
```
|
|
743
|
-
|
|
744
|
-
### cURL
|
|
745
|
-
|
|
746
|
-
```bash
|
|
747
|
-
# Non-streaming (Anthropic format)
|
|
748
|
-
curl -X POST http://localhost:8081/v1/messages \
|
|
749
|
-
-H "Content-Type: application/json" \
|
|
750
|
-
-H "anthropic-version: 2023-06-01" \
|
|
751
|
-
-d '{
|
|
752
|
-
"model": "claude-3-5-sonnet-20241022",
|
|
753
|
-
"messages": [{"role": "user", "content": "Hello"}],
|
|
754
|
-
"max_tokens": 1024
|
|
755
|
-
}'
|
|
756
|
-
|
|
757
|
-
# Streaming (Anthropic format)
|
|
758
|
-
curl -X POST http://localhost:8081/v1/messages \
|
|
759
|
-
-H "Content-Type: application/json" \
|
|
760
|
-
-H "anthropic-version: 2023-06-01" \
|
|
761
|
-
-d '{
|
|
762
|
-
"model": "claude-3-5-sonnet-20241022",
|
|
763
|
-
"messages": [{"role": "user", "content": "Hello"}],
|
|
764
|
-
"max_tokens": 1024,
|
|
765
|
-
"stream": true
|
|
766
|
-
}' \
|
|
767
|
-
--no-buffer
|
|
768
|
-
|
|
769
|
-
# Non-streaming (OpenAI format)
|
|
770
|
-
curl -X POST http://localhost:8081/v1/chat/completions \
|
|
771
|
-
-H "Content-Type: application/json" \
|
|
772
|
-
-H "Authorization: Bearer sk-lynkr" \
|
|
773
|
-
-d '{
|
|
774
|
-
"model": "claude-3.5-sonnet",
|
|
775
|
-
"messages": [{"role": "user", "content": "Hello"}],
|
|
776
|
-
"max_tokens": 1024
|
|
777
|
-
}'
|
|
778
|
-
|
|
779
|
-
# Streaming (OpenAI format)
|
|
780
|
-
curl -X POST http://localhost:8081/v1/chat/completions \
|
|
781
|
-
-H "Content-Type: application/json" \
|
|
782
|
-
-H "Authorization: Bearer sk-lynkr" \
|
|
783
|
-
-d '{
|
|
784
|
-
"model": "claude-3.5-sonnet",
|
|
785
|
-
"messages": [{"role": "user", "content": "Hello"}],
|
|
786
|
-
"max_tokens": 1024,
|
|
787
|
-
"stream": true
|
|
788
|
-
}' \
|
|
789
|
-
--no-buffer
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
---
|
|
793
|
-
|
|
794
|
-
## Next Steps
|
|
795
|
-
|
|
796
|
-
- **[Claude Code CLI Guide](claude-code-cli.md)** - Configure Claude Code CLI
|
|
797
|
-
- **[Cursor Integration](cursor-integration.md)** - Configure Cursor IDE
|
|
798
|
-
- **[Providers Guide](providers.md)** - Configure providers
|
|
799
|
-
- **[Troubleshooting](troubleshooting.md)** - Common issues
|
|
800
|
-
|
|
801
|
-
---
|
|
802
|
-
|
|
803
|
-
## Getting Help
|
|
804
|
-
|
|
805
|
-
- **[GitHub Discussions](https://github.com/vishalveerareddy123/Lynkr/discussions)** - Ask questions
|
|
806
|
-
- **[GitHub Issues](https://github.com/vishalveerareddy123/Lynkr/issues)** - Report issues
|