@kb-labs/adapters-vibeproxy 0.2.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 +159 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +307 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +60 -0
- package/dist/llm.js +265 -0
- package/dist/llm.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# @kb-labs/adapters-vibeproxy
|
|
2
|
+
|
|
3
|
+
> Part of [KB Labs](https://github.com/KirillBaranov/kb-labs) ecosystem. Works exclusively within KB Labs platform.
|
|
4
|
+
|
|
5
|
+
VibeProxy local adapter supporting multiple LLM providers (Claude, GPT, etc.) through a unified interface.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
| Property | Value |
|
|
10
|
+
|----------|-------|
|
|
11
|
+
| **Implements** | `ILLM` |
|
|
12
|
+
| **Type** | `core` |
|
|
13
|
+
| **Requires** | None |
|
|
14
|
+
| **Category** | AI |
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Multi-Provider** - Claude, GPT, Gemini, and more via single interface
|
|
19
|
+
- **Local Proxy** - Route through local VibeProxy server
|
|
20
|
+
- **Function Calling** - Native tool support for all providers
|
|
21
|
+
- **Model Switching** - Change provider by just changing model name
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @kb-labs/adapters-vibeproxy
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
Add to your `kb.config.json`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"platform": {
|
|
36
|
+
"adapters": {
|
|
37
|
+
"llm": "@kb-labs/adapters-vibeproxy"
|
|
38
|
+
},
|
|
39
|
+
"adapterOptions": {
|
|
40
|
+
"llm": {
|
|
41
|
+
"baseURL": "http://localhost:8317",
|
|
42
|
+
"apiKey": "any-string",
|
|
43
|
+
"model": "claude-sonnet-4-20250514",
|
|
44
|
+
"timeout": 120000
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Options
|
|
52
|
+
|
|
53
|
+
| Option | Type | Default | Description |
|
|
54
|
+
|--------|------|---------|-------------|
|
|
55
|
+
| `baseURL` | `string` | `"http://localhost:8317"` | VibeProxy server URL |
|
|
56
|
+
| `apiKey` | `string` | `"any-string"` | API key (any string works for local) |
|
|
57
|
+
| `model` | `string` | `"claude-sonnet-4-20250514"` | Model to use |
|
|
58
|
+
| `timeout` | `number` | `120000` | Request timeout in ms |
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
### Via Platform (Recommended)
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { usePlatform } from '@kb-labs/sdk';
|
|
66
|
+
|
|
67
|
+
const platform = usePlatform();
|
|
68
|
+
|
|
69
|
+
// Chat with Claude
|
|
70
|
+
const response = await platform.llm.chat([
|
|
71
|
+
{ role: 'user', content: 'Hello!' }
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
// Switch to GPT by changing model
|
|
75
|
+
const gptResponse = await platform.llm.chat(
|
|
76
|
+
[{ role: 'user', content: 'Hello!' }],
|
|
77
|
+
{ model: 'gpt-4-turbo' }
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Function calling
|
|
81
|
+
const result = await platform.llm.chatWithTools(
|
|
82
|
+
[{ role: 'user', content: 'What time is it?' }],
|
|
83
|
+
[{ name: 'getTime', parameters: { ... } }]
|
|
84
|
+
);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Standalone (Testing/Development)
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { createAdapter } from '@kb-labs/adapters-vibeproxy';
|
|
91
|
+
|
|
92
|
+
const llm = createAdapter({
|
|
93
|
+
baseURL: 'http://localhost:8317',
|
|
94
|
+
model: 'claude-sonnet-4-20250514'
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const response = await llm.chat([
|
|
98
|
+
{ role: 'user', content: 'Hello!' }
|
|
99
|
+
]);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Adapter Manifest
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
{
|
|
106
|
+
id: 'vibeproxy-llm',
|
|
107
|
+
name: 'VibeProxy LLM',
|
|
108
|
+
version: '0.1.0',
|
|
109
|
+
implements: 'ILLM',
|
|
110
|
+
capabilities: {
|
|
111
|
+
streaming: false, // TODO: implement SSE streaming
|
|
112
|
+
custom: {
|
|
113
|
+
functionCalling: true,
|
|
114
|
+
multiProvider: true,
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Supported Models
|
|
121
|
+
|
|
122
|
+
| Provider | Model Examples |
|
|
123
|
+
|----------|---------------|
|
|
124
|
+
| **Anthropic** | `claude-sonnet-4-20250514`, `claude-3-opus-*` |
|
|
125
|
+
| **OpenAI** | `gpt-4-turbo`, `gpt-3.5-turbo` |
|
|
126
|
+
| **Google** | `gemini-pro`, `gemini-ultra` |
|
|
127
|
+
|
|
128
|
+
## FAQ
|
|
129
|
+
|
|
130
|
+
<details>
|
|
131
|
+
<summary><strong>Q: How do I start VibeProxy locally?</strong></summary>
|
|
132
|
+
|
|
133
|
+
See VibeProxy documentation for setup instructions. Default port is 8317.
|
|
134
|
+
</details>
|
|
135
|
+
|
|
136
|
+
<details>
|
|
137
|
+
<summary><strong>Q: Why use VibeProxy instead of direct API?</strong></summary>
|
|
138
|
+
|
|
139
|
+
- Single interface for multiple providers
|
|
140
|
+
- Local caching and rate limiting
|
|
141
|
+
- Request logging and analytics
|
|
142
|
+
- Cost tracking across providers
|
|
143
|
+
</details>
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary><strong>Q: Is streaming supported?</strong></summary>
|
|
147
|
+
|
|
148
|
+
Not yet. Streaming (SSE) is planned for a future release.
|
|
149
|
+
</details>
|
|
150
|
+
|
|
151
|
+
## Related Adapters
|
|
152
|
+
|
|
153
|
+
| Adapter | Use Case |
|
|
154
|
+
|---------|----------|
|
|
155
|
+
| `@kb-labs/adapters-openai` | Direct OpenAI API access |
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
[KB Public License v1.1](../../LICENSE) - KB Labs Team
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { VibeProxyLLM, VibeProxyLLMConfig, default as createAdapter, default } from './llm.js';
|
|
2
|
+
import { AdapterManifest } from '@kb-labs/core-platform';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @module @kb-labs/adapters-vibeproxy/manifest
|
|
6
|
+
* Adapter manifest for VibeProxy LLM.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Adapter manifest for VibeProxy LLM.
|
|
11
|
+
*/
|
|
12
|
+
declare const manifest: AdapterManifest;
|
|
13
|
+
|
|
14
|
+
export { manifest };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// src/llm.ts
|
|
2
|
+
var DEFAULT_MAX_TOKENS = 16384;
|
|
3
|
+
var VibeProxyLLM = class {
|
|
4
|
+
baseURL;
|
|
5
|
+
apiKey;
|
|
6
|
+
defaultModel;
|
|
7
|
+
timeout;
|
|
8
|
+
defaultMaxTokens;
|
|
9
|
+
constructor(config = {}) {
|
|
10
|
+
this.baseURL = config.baseURL ?? process.env.VIBEPROXY_URL ?? "http://localhost:8317";
|
|
11
|
+
this.apiKey = config.apiKey ?? process.env.VIBEPROXY_API_KEY ?? "any-string";
|
|
12
|
+
this.defaultModel = config.defaultModel ?? process.env.VIBEPROXY_MODEL ?? "claude-sonnet-4-20250514";
|
|
13
|
+
this.timeout = config.timeout ?? 12e4;
|
|
14
|
+
this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
|
|
15
|
+
}
|
|
16
|
+
getProtocolCapabilities() {
|
|
17
|
+
return {
|
|
18
|
+
cache: {
|
|
19
|
+
supported: true,
|
|
20
|
+
protocol: "explicit_handle",
|
|
21
|
+
scopes: ["prefix", "segments", "full_request"]
|
|
22
|
+
},
|
|
23
|
+
// Current implementation yields complete() as one chunk (not true streaming)
|
|
24
|
+
stream: { supported: false }
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Make a request to VibeProxy.
|
|
29
|
+
*/
|
|
30
|
+
async request(endpoint, body, headers) {
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
"x-api-key": this.apiKey,
|
|
39
|
+
...headers
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify(body),
|
|
42
|
+
signal: controller.signal
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorBody = await response.json().catch(() => ({ error: { message: response.statusText } }));
|
|
46
|
+
throw new Error(
|
|
47
|
+
`VibeProxy error: ${errorBody.error?.message ?? response.statusText}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return response.json();
|
|
51
|
+
} finally {
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
buildExecutionHeaders(execution) {
|
|
56
|
+
const headers = {};
|
|
57
|
+
const cache = execution?.cache;
|
|
58
|
+
if (!cache) {
|
|
59
|
+
return headers;
|
|
60
|
+
}
|
|
61
|
+
headers["x-kb-cache-mode"] = cache.mode ?? "prefer";
|
|
62
|
+
if (cache.scope) {
|
|
63
|
+
headers["x-kb-cache-scope"] = cache.scope;
|
|
64
|
+
}
|
|
65
|
+
if (typeof cache.ttlSec === "number") {
|
|
66
|
+
headers["x-kb-cache-ttl-sec"] = String(cache.ttlSec);
|
|
67
|
+
}
|
|
68
|
+
if (cache.key) {
|
|
69
|
+
headers["x-kb-cache-key"] = cache.key;
|
|
70
|
+
}
|
|
71
|
+
return headers;
|
|
72
|
+
}
|
|
73
|
+
buildTraceHeaders(options) {
|
|
74
|
+
const trace = options?.metadata?.cacheDecisionTrace;
|
|
75
|
+
if (!trace) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
"x-kb-cache-decision": JSON.stringify(trace)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
extractTextContent(response) {
|
|
83
|
+
return response.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
84
|
+
}
|
|
85
|
+
convertMessagesForTools(messages) {
|
|
86
|
+
const vibeProxyMessages = [];
|
|
87
|
+
let systemPrompt;
|
|
88
|
+
for (const msg of messages) {
|
|
89
|
+
if (msg.role === "system") {
|
|
90
|
+
systemPrompt = msg.content;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (msg.role === "tool") {
|
|
94
|
+
vibeProxyMessages.push({
|
|
95
|
+
role: "user",
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "tool_result",
|
|
99
|
+
tool_use_id: msg.toolCallId || "",
|
|
100
|
+
content: msg.content
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) {
|
|
107
|
+
vibeProxyMessages.push({
|
|
108
|
+
role: "assistant",
|
|
109
|
+
content: this.toAssistantToolContent(msg)
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
vibeProxyMessages.push({
|
|
114
|
+
role: msg.role,
|
|
115
|
+
content: msg.content
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return { messages: vibeProxyMessages, systemPrompt };
|
|
119
|
+
}
|
|
120
|
+
toAssistantToolContent(message) {
|
|
121
|
+
const contentBlocks = [];
|
|
122
|
+
if (message.content && message.content.trim()) {
|
|
123
|
+
contentBlocks.push({
|
|
124
|
+
type: "text",
|
|
125
|
+
text: message.content
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
for (const toolCall of message.toolCalls ?? []) {
|
|
129
|
+
contentBlocks.push({
|
|
130
|
+
type: "tool_use",
|
|
131
|
+
id: toolCall.id,
|
|
132
|
+
name: toolCall.name,
|
|
133
|
+
input: toolCall.input
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return contentBlocks;
|
|
137
|
+
}
|
|
138
|
+
buildToolChoice(toolChoice) {
|
|
139
|
+
if (toolChoice === "auto") {
|
|
140
|
+
return { type: "auto" };
|
|
141
|
+
}
|
|
142
|
+
if (toolChoice === "required") {
|
|
143
|
+
return { type: "any" };
|
|
144
|
+
}
|
|
145
|
+
if (toolChoice && typeof toolChoice === "object") {
|
|
146
|
+
return { type: "tool", name: toolChoice.function.name };
|
|
147
|
+
}
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
extractToolCalls(response) {
|
|
151
|
+
return response.content.filter(
|
|
152
|
+
(c) => c.type === "tool_use"
|
|
153
|
+
).map((tc) => ({
|
|
154
|
+
id: tc.id,
|
|
155
|
+
name: tc.name,
|
|
156
|
+
input: tc.input
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
async complete(prompt, options) {
|
|
160
|
+
const model = options?.model ?? this.defaultModel;
|
|
161
|
+
const requestBody = {
|
|
162
|
+
model,
|
|
163
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
164
|
+
messages: [{ role: "user", content: prompt }]
|
|
165
|
+
};
|
|
166
|
+
if (options?.systemPrompt) {
|
|
167
|
+
requestBody.system = options.systemPrompt;
|
|
168
|
+
}
|
|
169
|
+
if (options?.temperature !== void 0) {
|
|
170
|
+
requestBody.temperature = options.temperature;
|
|
171
|
+
}
|
|
172
|
+
if (options?.stop) {
|
|
173
|
+
requestBody.stop_sequences = options.stop;
|
|
174
|
+
}
|
|
175
|
+
const response = await this.request(
|
|
176
|
+
"/v1/messages",
|
|
177
|
+
requestBody,
|
|
178
|
+
{
|
|
179
|
+
...this.buildExecutionHeaders(options?.execution),
|
|
180
|
+
...this.buildTraceHeaders(options)
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
content: this.extractTextContent(response),
|
|
185
|
+
usage: {
|
|
186
|
+
promptTokens: response.usage.input_tokens,
|
|
187
|
+
completionTokens: response.usage.output_tokens,
|
|
188
|
+
cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
|
|
189
|
+
cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,
|
|
190
|
+
providerUsage: {
|
|
191
|
+
stopReason: response.stop_reason
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
model: response.model
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async *stream(prompt, options) {
|
|
198
|
+
const response = await this.complete(prompt, options);
|
|
199
|
+
yield response.content;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Chat with native tool calling support.
|
|
203
|
+
*/
|
|
204
|
+
async chatWithTools(messages, options) {
|
|
205
|
+
const model = options?.model ?? this.defaultModel;
|
|
206
|
+
const converted = this.convertMessagesForTools(messages);
|
|
207
|
+
const tools = options.tools.map(
|
|
208
|
+
(tool) => ({
|
|
209
|
+
name: tool.name,
|
|
210
|
+
description: tool.description,
|
|
211
|
+
input_schema: tool.inputSchema
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
const toolChoice = this.buildToolChoice(options.toolChoice);
|
|
215
|
+
const requestBody = {
|
|
216
|
+
model,
|
|
217
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
218
|
+
messages: converted.messages,
|
|
219
|
+
tools: options.toolChoice !== "none" ? tools : void 0,
|
|
220
|
+
tool_choice: options.toolChoice !== "none" ? toolChoice : void 0
|
|
221
|
+
};
|
|
222
|
+
if (converted.systemPrompt || options?.systemPrompt) {
|
|
223
|
+
requestBody.system = converted.systemPrompt ?? options.systemPrompt;
|
|
224
|
+
}
|
|
225
|
+
if (options?.temperature !== void 0) {
|
|
226
|
+
requestBody.temperature = options.temperature;
|
|
227
|
+
}
|
|
228
|
+
if (options?.stop) {
|
|
229
|
+
requestBody.stop_sequences = options.stop;
|
|
230
|
+
}
|
|
231
|
+
const response = await this.request(
|
|
232
|
+
"/v1/messages",
|
|
233
|
+
requestBody,
|
|
234
|
+
{
|
|
235
|
+
...this.buildExecutionHeaders(options?.execution),
|
|
236
|
+
...this.buildTraceHeaders(options)
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
const textContent = this.extractTextContent(response);
|
|
240
|
+
const toolCalls = this.extractToolCalls(response);
|
|
241
|
+
return {
|
|
242
|
+
content: textContent,
|
|
243
|
+
usage: {
|
|
244
|
+
promptTokens: response.usage.input_tokens,
|
|
245
|
+
completionTokens: response.usage.output_tokens,
|
|
246
|
+
cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
|
|
247
|
+
cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,
|
|
248
|
+
providerUsage: {
|
|
249
|
+
stopReason: response.stop_reason
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
model: response.model,
|
|
253
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
254
|
+
stopReason: response.stop_reason
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
function createAdapter(config) {
|
|
259
|
+
return new VibeProxyLLM(config);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// src/manifest.ts
|
|
263
|
+
var manifest = {
|
|
264
|
+
manifestVersion: "1.0.0",
|
|
265
|
+
id: "vibeproxy-llm",
|
|
266
|
+
name: "VibeProxy LLM",
|
|
267
|
+
version: "0.1.0",
|
|
268
|
+
description: "VibeProxy local adapter supporting multiple LLM providers (Claude, GPT, etc.)",
|
|
269
|
+
author: "KB Labs Team",
|
|
270
|
+
license: "KBPL-1.1",
|
|
271
|
+
type: "core",
|
|
272
|
+
implements: "ILLM",
|
|
273
|
+
capabilities: {
|
|
274
|
+
streaming: false,
|
|
275
|
+
// TODO: implement SSE streaming
|
|
276
|
+
custom: {
|
|
277
|
+
functionCalling: true,
|
|
278
|
+
multiProvider: true
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
configSchema: {
|
|
282
|
+
baseURL: {
|
|
283
|
+
type: "string",
|
|
284
|
+
default: "http://localhost:8317",
|
|
285
|
+
description: "VibeProxy server URL"
|
|
286
|
+
},
|
|
287
|
+
apiKey: {
|
|
288
|
+
type: "string",
|
|
289
|
+
default: "any-string",
|
|
290
|
+
description: "API key (any string works for local VibeProxy)"
|
|
291
|
+
},
|
|
292
|
+
model: {
|
|
293
|
+
type: "string",
|
|
294
|
+
default: "claude-sonnet-4-20250514",
|
|
295
|
+
description: "Model to use (claude-*, gpt-*, etc.)"
|
|
296
|
+
},
|
|
297
|
+
timeout: {
|
|
298
|
+
type: "number",
|
|
299
|
+
default: 12e4,
|
|
300
|
+
description: "Request timeout in milliseconds"
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
export { VibeProxyLLM, createAdapter, createAdapter as default, manifest };
|
|
306
|
+
//# sourceMappingURL=index.js.map
|
|
307
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/infra/kb-labs-adapters/packages/adapters-vibeproxy/src/llm.ts","../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/infra/kb-labs-adapters/packages/adapters-vibeproxy/src/manifest.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/adapters-vibeproxy/llm\n * VibeProxy implementation of ILLM interface.\n * Connects to local VibeProxy server (supports Claude, GPT, and other models).\n */\n\nimport type {\n ILLM,\n LLMOptions,\n LLMResponse,\n LLMMessage,\n LLMToolCallOptions,\n LLMToolCallResponse,\n LLMTool,\n LLMToolCall,\n LLMProtocolCapabilities,\n LLMExecutionPolicy,\n} from \"@kb-labs/core-platform\";\n\n/**\n * Configuration for VibeProxy LLM adapter.\n */\nexport interface VibeProxyLLMConfig {\n /** Base URL for VibeProxy (defaults to http://localhost:8317) */\n baseURL?: string;\n /** API key (can be any string for VibeProxy) */\n apiKey?: string;\n /** Default model to use */\n defaultModel?: string;\n /** Request timeout in ms (defaults to 120000) */\n timeout?: number;\n /** Default max output tokens when caller does not specify. Overrides the hardcoded 4096. */\n defaultMaxTokens?: number;\n}\n\n/** Default max output tokens — avoids hitting the 4096 hardcoded limit mid-response. */\nconst DEFAULT_MAX_TOKENS = 16_384;\n\n/**\n * VibeProxy Messages API request format.\n */\ninterface VibeProxyMessagesRequest {\n model: string;\n max_tokens: number;\n messages: Array<{\n role: \"user\" | \"assistant\";\n content:\n | string\n | Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n | { type: \"tool_result\"; tool_use_id: string; content: string }\n >;\n }>;\n system?: string;\n temperature?: number;\n stop_sequences?: string[];\n tools?: Array<{\n name: string;\n description: string;\n input_schema: Record<string, unknown>;\n }>;\n tool_choice?:\n | { type: \"auto\" }\n | { type: \"any\" }\n | { type: \"tool\"; name: string };\n}\n\n/**\n * VibeProxy Messages API response format.\n */\ninterface VibeProxyMessagesResponse {\n id: string;\n type: \"message\";\n role: \"assistant\";\n model: string;\n content: Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n >;\n stop_reason: \"end_turn\" | \"max_tokens\" | \"stop_sequence\" | \"tool_use\";\n stop_sequence: string | null;\n usage: {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n}\n\n/**\n * VibeProxy implementation of ILLM interface.\n * Supports multiple model providers through local VibeProxy server.\n */\nexport class VibeProxyLLM implements ILLM {\n private baseURL: string;\n private apiKey: string;\n private defaultModel: string;\n private timeout: number;\n private defaultMaxTokens: number;\n\n constructor(config: VibeProxyLLMConfig = {}) {\n this.baseURL =\n config.baseURL ?? process.env.VIBEPROXY_URL ?? \"http://localhost:8317\";\n this.apiKey =\n config.apiKey ?? process.env.VIBEPROXY_API_KEY ?? \"any-string\";\n this.defaultModel =\n config.defaultModel ??\n process.env.VIBEPROXY_MODEL ??\n \"claude-sonnet-4-20250514\";\n this.timeout = config.timeout ?? 120000;\n this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;\n }\n\n getProtocolCapabilities(): LLMProtocolCapabilities {\n return {\n cache: {\n supported: true,\n protocol: \"explicit_handle\",\n scopes: [\"prefix\", \"segments\", \"full_request\"],\n },\n // Current implementation yields complete() as one chunk (not true streaming)\n stream: { supported: false },\n };\n }\n\n /**\n * Make a request to VibeProxy.\n */\n private async request<T>(\n endpoint: string,\n body: unknown,\n headers?: Record<string, string>,\n ): Promise<T> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseURL}${endpoint}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n ...headers,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = (await response\n .json()\n .catch(() => ({ error: { message: response.statusText } }))) as {\n error?: { message?: string };\n };\n throw new Error(\n `VibeProxy error: ${errorBody.error?.message ?? response.statusText}`,\n );\n }\n\n return response.json() as Promise<T>;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private buildExecutionHeaders(execution?: LLMExecutionPolicy): Record<string, string> {\n const headers: Record<string, string> = {};\n const cache = execution?.cache;\n if (!cache) {\n return headers;\n }\n\n headers[\"x-kb-cache-mode\"] = cache.mode ?? \"prefer\";\n if (cache.scope) {\n headers[\"x-kb-cache-scope\"] = cache.scope;\n }\n if (typeof cache.ttlSec === \"number\") {\n headers[\"x-kb-cache-ttl-sec\"] = String(cache.ttlSec);\n }\n if (cache.key) {\n headers[\"x-kb-cache-key\"] = cache.key;\n }\n\n return headers;\n }\n\n private buildTraceHeaders(options?: LLMOptions): Record<string, string> {\n const trace = options?.metadata?.cacheDecisionTrace;\n if (!trace) {\n return {};\n }\n return {\n \"x-kb-cache-decision\": JSON.stringify(trace),\n };\n }\n\n private extractTextContent(response: VibeProxyMessagesResponse): string {\n return response.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n }\n\n private convertMessagesForTools(\n messages: LLMMessage[],\n ): {\n messages: VibeProxyMessagesRequest[\"messages\"];\n systemPrompt?: string;\n } {\n const vibeProxyMessages: VibeProxyMessagesRequest[\"messages\"] = [];\n let systemPrompt: string | undefined;\n\n for (const msg of messages) {\n if (msg.role === \"system\") {\n systemPrompt = msg.content;\n continue;\n }\n if (msg.role === \"tool\") {\n vibeProxyMessages.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.toolCallId || \"\",\n content: msg.content,\n },\n ],\n });\n continue;\n }\n if (msg.role === \"assistant\" && msg.toolCalls && msg.toolCalls.length > 0) {\n vibeProxyMessages.push({\n role: \"assistant\",\n content: this.toAssistantToolContent(msg),\n });\n continue;\n }\n vibeProxyMessages.push({\n role: msg.role as \"user\" | \"assistant\",\n content: msg.content,\n });\n }\n\n return { messages: vibeProxyMessages, systemPrompt };\n }\n\n private toAssistantToolContent(\n message: LLMMessage,\n ): Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n > {\n const contentBlocks: Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n > = [];\n\n if (message.content && message.content.trim()) {\n contentBlocks.push({\n type: \"text\",\n text: message.content,\n });\n }\n\n for (const toolCall of message.toolCalls ?? []) {\n contentBlocks.push({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.input,\n });\n }\n return contentBlocks;\n }\n\n private buildToolChoice(\n toolChoice: LLMToolCallOptions[\"toolChoice\"],\n ): VibeProxyMessagesRequest[\"tool_choice\"] {\n if (toolChoice === \"auto\") {\n return { type: \"auto\" };\n }\n if (toolChoice === \"required\") {\n return { type: \"any\" };\n }\n if (toolChoice && typeof toolChoice === \"object\") {\n return { type: \"tool\", name: toolChoice.function.name };\n }\n return undefined;\n }\n\n private extractToolCalls(response: VibeProxyMessagesResponse): LLMToolCall[] {\n return response.content\n .filter(\n (\n c,\n ): c is {\n type: \"tool_use\";\n id: string;\n name: string;\n input: unknown;\n } => c.type === \"tool_use\",\n )\n .map((tc) => ({\n id: tc.id,\n name: tc.name,\n input: tc.input,\n }));\n }\n\n async complete(prompt: string, options?: LLMOptions): Promise<LLMResponse> {\n const model = options?.model ?? this.defaultModel;\n\n const requestBody: VibeProxyMessagesRequest = {\n model,\n max_tokens: options?.maxTokens ?? this.defaultMaxTokens,\n messages: [{ role: \"user\", content: prompt }],\n };\n\n if (options?.systemPrompt) {\n requestBody.system = options.systemPrompt;\n }\n if (options?.temperature !== undefined) {\n requestBody.temperature = options.temperature;\n }\n if (options?.stop) {\n requestBody.stop_sequences = options.stop;\n }\n\n const response = await this.request<VibeProxyMessagesResponse>(\n \"/v1/messages\",\n requestBody,\n {\n ...this.buildExecutionHeaders(options?.execution),\n ...this.buildTraceHeaders(options),\n },\n );\n\n return {\n content: this.extractTextContent(response),\n usage: {\n promptTokens: response.usage.input_tokens,\n completionTokens: response.usage.output_tokens,\n cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,\n cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,\n providerUsage: {\n stopReason: response.stop_reason,\n },\n },\n model: response.model,\n };\n }\n\n async *stream(prompt: string, options?: LLMOptions): AsyncIterable<string> {\n // VibeProxy supports streaming via SSE, but for simplicity we'll use non-streaming\n // and yield the full response. Can be enhanced later with proper SSE support.\n const response = await this.complete(prompt, options);\n yield response.content;\n }\n\n /**\n * Chat with native tool calling support.\n */\n async chatWithTools(\n messages: LLMMessage[],\n options: LLMToolCallOptions,\n ): Promise<LLMToolCallResponse> {\n const model = options?.model ?? this.defaultModel;\n const converted = this.convertMessagesForTools(messages);\n\n // Convert LLMTool[] to VibeProxy tools format\n const tools: VibeProxyMessagesRequest[\"tools\"] = options.tools.map(\n (tool: LLMTool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: tool.inputSchema,\n }),\n );\n const toolChoice = this.buildToolChoice(options.toolChoice);\n\n const requestBody: VibeProxyMessagesRequest = {\n model,\n max_tokens: options?.maxTokens ?? this.defaultMaxTokens,\n messages: converted.messages,\n tools: options.toolChoice !== \"none\" ? tools : undefined,\n tool_choice: options.toolChoice !== \"none\" ? toolChoice : undefined,\n };\n\n if (converted.systemPrompt || options?.systemPrompt) {\n requestBody.system = converted.systemPrompt ?? options.systemPrompt;\n }\n if (options?.temperature !== undefined) {\n requestBody.temperature = options.temperature;\n }\n if (options?.stop) {\n requestBody.stop_sequences = options.stop;\n }\n\n const response = await this.request<VibeProxyMessagesResponse>(\n \"/v1/messages\",\n requestBody,\n {\n ...this.buildExecutionHeaders(options?.execution),\n ...this.buildTraceHeaders(options),\n },\n );\n const textContent = this.extractTextContent(response);\n const toolCalls = this.extractToolCalls(response);\n\n return {\n content: textContent,\n usage: {\n promptTokens: response.usage.input_tokens,\n completionTokens: response.usage.output_tokens,\n cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,\n cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,\n providerUsage: {\n stopReason: response.stop_reason,\n },\n },\n model: response.model,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n stopReason: response.stop_reason,\n };\n }\n}\n\n/**\n * Create VibeProxy LLM adapter.\n * This is the factory function called by initPlatform() when loading adapters.\n */\nexport function createAdapter(config?: VibeProxyLLMConfig): VibeProxyLLM {\n return new VibeProxyLLM(config);\n}\n\n// Default export for direct import\nexport default createAdapter;\n","/**\n * @module @kb-labs/adapters-vibeproxy/manifest\n * Adapter manifest for VibeProxy LLM.\n */\n\nimport type { AdapterManifest } from \"@kb-labs/core-platform\";\n\n/**\n * Adapter manifest for VibeProxy LLM.\n */\nexport const manifest: AdapterManifest = {\n manifestVersion: \"1.0.0\",\n id: \"vibeproxy-llm\",\n name: \"VibeProxy LLM\",\n version: \"0.1.0\",\n description:\n \"VibeProxy local adapter supporting multiple LLM providers (Claude, GPT, etc.)\",\n author: \"KB Labs Team\",\n license: \"KBPL-1.1\",\n type: \"core\",\n implements: \"ILLM\",\n capabilities: {\n streaming: false, // TODO: implement SSE streaming\n custom: {\n functionCalling: true,\n multiProvider: true,\n },\n },\n configSchema: {\n baseURL: {\n type: \"string\",\n default: \"http://localhost:8317\",\n description: \"VibeProxy server URL\",\n },\n apiKey: {\n type: \"string\",\n default: \"any-string\",\n description: \"API key (any string works for local VibeProxy)\",\n },\n model: {\n type: \"string\",\n default: \"claude-sonnet-4-20250514\",\n description: \"Model to use (claude-*, gpt-*, etc.)\",\n },\n timeout: {\n type: \"number\",\n default: 120000,\n description: \"Request timeout in milliseconds\",\n },\n },\n};\n"]}
|
package/dist/llm.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ILLM, LLMProtocolCapabilities, LLMOptions, LLMResponse, LLMMessage, LLMToolCallOptions, LLMToolCallResponse } from '@kb-labs/core-platform';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module @kb-labs/adapters-vibeproxy/llm
|
|
5
|
+
* VibeProxy implementation of ILLM interface.
|
|
6
|
+
* Connects to local VibeProxy server (supports Claude, GPT, and other models).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configuration for VibeProxy LLM adapter.
|
|
11
|
+
*/
|
|
12
|
+
interface VibeProxyLLMConfig {
|
|
13
|
+
/** Base URL for VibeProxy (defaults to http://localhost:8317) */
|
|
14
|
+
baseURL?: string;
|
|
15
|
+
/** API key (can be any string for VibeProxy) */
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
/** Default model to use */
|
|
18
|
+
defaultModel?: string;
|
|
19
|
+
/** Request timeout in ms (defaults to 120000) */
|
|
20
|
+
timeout?: number;
|
|
21
|
+
/** Default max output tokens when caller does not specify. Overrides the hardcoded 4096. */
|
|
22
|
+
defaultMaxTokens?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* VibeProxy implementation of ILLM interface.
|
|
26
|
+
* Supports multiple model providers through local VibeProxy server.
|
|
27
|
+
*/
|
|
28
|
+
declare class VibeProxyLLM implements ILLM {
|
|
29
|
+
private baseURL;
|
|
30
|
+
private apiKey;
|
|
31
|
+
private defaultModel;
|
|
32
|
+
private timeout;
|
|
33
|
+
private defaultMaxTokens;
|
|
34
|
+
constructor(config?: VibeProxyLLMConfig);
|
|
35
|
+
getProtocolCapabilities(): LLMProtocolCapabilities;
|
|
36
|
+
/**
|
|
37
|
+
* Make a request to VibeProxy.
|
|
38
|
+
*/
|
|
39
|
+
private request;
|
|
40
|
+
private buildExecutionHeaders;
|
|
41
|
+
private buildTraceHeaders;
|
|
42
|
+
private extractTextContent;
|
|
43
|
+
private convertMessagesForTools;
|
|
44
|
+
private toAssistantToolContent;
|
|
45
|
+
private buildToolChoice;
|
|
46
|
+
private extractToolCalls;
|
|
47
|
+
complete(prompt: string, options?: LLMOptions): Promise<LLMResponse>;
|
|
48
|
+
stream(prompt: string, options?: LLMOptions): AsyncIterable<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Chat with native tool calling support.
|
|
51
|
+
*/
|
|
52
|
+
chatWithTools(messages: LLMMessage[], options: LLMToolCallOptions): Promise<LLMToolCallResponse>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create VibeProxy LLM adapter.
|
|
56
|
+
* This is the factory function called by initPlatform() when loading adapters.
|
|
57
|
+
*/
|
|
58
|
+
declare function createAdapter(config?: VibeProxyLLMConfig): VibeProxyLLM;
|
|
59
|
+
|
|
60
|
+
export { VibeProxyLLM, type VibeProxyLLMConfig, createAdapter, createAdapter as default };
|
package/dist/llm.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// src/llm.ts
|
|
2
|
+
var DEFAULT_MAX_TOKENS = 16384;
|
|
3
|
+
var VibeProxyLLM = class {
|
|
4
|
+
baseURL;
|
|
5
|
+
apiKey;
|
|
6
|
+
defaultModel;
|
|
7
|
+
timeout;
|
|
8
|
+
defaultMaxTokens;
|
|
9
|
+
constructor(config = {}) {
|
|
10
|
+
this.baseURL = config.baseURL ?? process.env.VIBEPROXY_URL ?? "http://localhost:8317";
|
|
11
|
+
this.apiKey = config.apiKey ?? process.env.VIBEPROXY_API_KEY ?? "any-string";
|
|
12
|
+
this.defaultModel = config.defaultModel ?? process.env.VIBEPROXY_MODEL ?? "claude-sonnet-4-20250514";
|
|
13
|
+
this.timeout = config.timeout ?? 12e4;
|
|
14
|
+
this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
|
|
15
|
+
}
|
|
16
|
+
getProtocolCapabilities() {
|
|
17
|
+
return {
|
|
18
|
+
cache: {
|
|
19
|
+
supported: true,
|
|
20
|
+
protocol: "explicit_handle",
|
|
21
|
+
scopes: ["prefix", "segments", "full_request"]
|
|
22
|
+
},
|
|
23
|
+
// Current implementation yields complete() as one chunk (not true streaming)
|
|
24
|
+
stream: { supported: false }
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Make a request to VibeProxy.
|
|
29
|
+
*/
|
|
30
|
+
async request(endpoint, body, headers) {
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
33
|
+
try {
|
|
34
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
"x-api-key": this.apiKey,
|
|
39
|
+
...headers
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify(body),
|
|
42
|
+
signal: controller.signal
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const errorBody = await response.json().catch(() => ({ error: { message: response.statusText } }));
|
|
46
|
+
throw new Error(
|
|
47
|
+
`VibeProxy error: ${errorBody.error?.message ?? response.statusText}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return response.json();
|
|
51
|
+
} finally {
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
buildExecutionHeaders(execution) {
|
|
56
|
+
const headers = {};
|
|
57
|
+
const cache = execution?.cache;
|
|
58
|
+
if (!cache) {
|
|
59
|
+
return headers;
|
|
60
|
+
}
|
|
61
|
+
headers["x-kb-cache-mode"] = cache.mode ?? "prefer";
|
|
62
|
+
if (cache.scope) {
|
|
63
|
+
headers["x-kb-cache-scope"] = cache.scope;
|
|
64
|
+
}
|
|
65
|
+
if (typeof cache.ttlSec === "number") {
|
|
66
|
+
headers["x-kb-cache-ttl-sec"] = String(cache.ttlSec);
|
|
67
|
+
}
|
|
68
|
+
if (cache.key) {
|
|
69
|
+
headers["x-kb-cache-key"] = cache.key;
|
|
70
|
+
}
|
|
71
|
+
return headers;
|
|
72
|
+
}
|
|
73
|
+
buildTraceHeaders(options) {
|
|
74
|
+
const trace = options?.metadata?.cacheDecisionTrace;
|
|
75
|
+
if (!trace) {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
"x-kb-cache-decision": JSON.stringify(trace)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
extractTextContent(response) {
|
|
83
|
+
return response.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
84
|
+
}
|
|
85
|
+
convertMessagesForTools(messages) {
|
|
86
|
+
const vibeProxyMessages = [];
|
|
87
|
+
let systemPrompt;
|
|
88
|
+
for (const msg of messages) {
|
|
89
|
+
if (msg.role === "system") {
|
|
90
|
+
systemPrompt = msg.content;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (msg.role === "tool") {
|
|
94
|
+
vibeProxyMessages.push({
|
|
95
|
+
role: "user",
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "tool_result",
|
|
99
|
+
tool_use_id: msg.toolCallId || "",
|
|
100
|
+
content: msg.content
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) {
|
|
107
|
+
vibeProxyMessages.push({
|
|
108
|
+
role: "assistant",
|
|
109
|
+
content: this.toAssistantToolContent(msg)
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
vibeProxyMessages.push({
|
|
114
|
+
role: msg.role,
|
|
115
|
+
content: msg.content
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return { messages: vibeProxyMessages, systemPrompt };
|
|
119
|
+
}
|
|
120
|
+
toAssistantToolContent(message) {
|
|
121
|
+
const contentBlocks = [];
|
|
122
|
+
if (message.content && message.content.trim()) {
|
|
123
|
+
contentBlocks.push({
|
|
124
|
+
type: "text",
|
|
125
|
+
text: message.content
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
for (const toolCall of message.toolCalls ?? []) {
|
|
129
|
+
contentBlocks.push({
|
|
130
|
+
type: "tool_use",
|
|
131
|
+
id: toolCall.id,
|
|
132
|
+
name: toolCall.name,
|
|
133
|
+
input: toolCall.input
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return contentBlocks;
|
|
137
|
+
}
|
|
138
|
+
buildToolChoice(toolChoice) {
|
|
139
|
+
if (toolChoice === "auto") {
|
|
140
|
+
return { type: "auto" };
|
|
141
|
+
}
|
|
142
|
+
if (toolChoice === "required") {
|
|
143
|
+
return { type: "any" };
|
|
144
|
+
}
|
|
145
|
+
if (toolChoice && typeof toolChoice === "object") {
|
|
146
|
+
return { type: "tool", name: toolChoice.function.name };
|
|
147
|
+
}
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
extractToolCalls(response) {
|
|
151
|
+
return response.content.filter(
|
|
152
|
+
(c) => c.type === "tool_use"
|
|
153
|
+
).map((tc) => ({
|
|
154
|
+
id: tc.id,
|
|
155
|
+
name: tc.name,
|
|
156
|
+
input: tc.input
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
async complete(prompt, options) {
|
|
160
|
+
const model = options?.model ?? this.defaultModel;
|
|
161
|
+
const requestBody = {
|
|
162
|
+
model,
|
|
163
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
164
|
+
messages: [{ role: "user", content: prompt }]
|
|
165
|
+
};
|
|
166
|
+
if (options?.systemPrompt) {
|
|
167
|
+
requestBody.system = options.systemPrompt;
|
|
168
|
+
}
|
|
169
|
+
if (options?.temperature !== void 0) {
|
|
170
|
+
requestBody.temperature = options.temperature;
|
|
171
|
+
}
|
|
172
|
+
if (options?.stop) {
|
|
173
|
+
requestBody.stop_sequences = options.stop;
|
|
174
|
+
}
|
|
175
|
+
const response = await this.request(
|
|
176
|
+
"/v1/messages",
|
|
177
|
+
requestBody,
|
|
178
|
+
{
|
|
179
|
+
...this.buildExecutionHeaders(options?.execution),
|
|
180
|
+
...this.buildTraceHeaders(options)
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
content: this.extractTextContent(response),
|
|
185
|
+
usage: {
|
|
186
|
+
promptTokens: response.usage.input_tokens,
|
|
187
|
+
completionTokens: response.usage.output_tokens,
|
|
188
|
+
cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
|
|
189
|
+
cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,
|
|
190
|
+
providerUsage: {
|
|
191
|
+
stopReason: response.stop_reason
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
model: response.model
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async *stream(prompt, options) {
|
|
198
|
+
const response = await this.complete(prompt, options);
|
|
199
|
+
yield response.content;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Chat with native tool calling support.
|
|
203
|
+
*/
|
|
204
|
+
async chatWithTools(messages, options) {
|
|
205
|
+
const model = options?.model ?? this.defaultModel;
|
|
206
|
+
const converted = this.convertMessagesForTools(messages);
|
|
207
|
+
const tools = options.tools.map(
|
|
208
|
+
(tool) => ({
|
|
209
|
+
name: tool.name,
|
|
210
|
+
description: tool.description,
|
|
211
|
+
input_schema: tool.inputSchema
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
const toolChoice = this.buildToolChoice(options.toolChoice);
|
|
215
|
+
const requestBody = {
|
|
216
|
+
model,
|
|
217
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
218
|
+
messages: converted.messages,
|
|
219
|
+
tools: options.toolChoice !== "none" ? tools : void 0,
|
|
220
|
+
tool_choice: options.toolChoice !== "none" ? toolChoice : void 0
|
|
221
|
+
};
|
|
222
|
+
if (converted.systemPrompt || options?.systemPrompt) {
|
|
223
|
+
requestBody.system = converted.systemPrompt ?? options.systemPrompt;
|
|
224
|
+
}
|
|
225
|
+
if (options?.temperature !== void 0) {
|
|
226
|
+
requestBody.temperature = options.temperature;
|
|
227
|
+
}
|
|
228
|
+
if (options?.stop) {
|
|
229
|
+
requestBody.stop_sequences = options.stop;
|
|
230
|
+
}
|
|
231
|
+
const response = await this.request(
|
|
232
|
+
"/v1/messages",
|
|
233
|
+
requestBody,
|
|
234
|
+
{
|
|
235
|
+
...this.buildExecutionHeaders(options?.execution),
|
|
236
|
+
...this.buildTraceHeaders(options)
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
const textContent = this.extractTextContent(response);
|
|
240
|
+
const toolCalls = this.extractToolCalls(response);
|
|
241
|
+
return {
|
|
242
|
+
content: textContent,
|
|
243
|
+
usage: {
|
|
244
|
+
promptTokens: response.usage.input_tokens,
|
|
245
|
+
completionTokens: response.usage.output_tokens,
|
|
246
|
+
cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,
|
|
247
|
+
cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,
|
|
248
|
+
providerUsage: {
|
|
249
|
+
stopReason: response.stop_reason
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
model: response.model,
|
|
253
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
254
|
+
stopReason: response.stop_reason
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
function createAdapter(config) {
|
|
259
|
+
return new VibeProxyLLM(config);
|
|
260
|
+
}
|
|
261
|
+
var llm_default = createAdapter;
|
|
262
|
+
|
|
263
|
+
export { VibeProxyLLM, createAdapter, llm_default as default };
|
|
264
|
+
//# sourceMappingURL=llm.js.map
|
|
265
|
+
//# sourceMappingURL=llm.js.map
|
package/dist/llm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../Users/kirillbaranov/Desktop/kb-labs-workspace/infra/kb-labs-adapters/packages/adapters-vibeproxy/src/llm.ts"],"names":[],"mappings":"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","file":"llm.js","sourcesContent":["/**\n * @module @kb-labs/adapters-vibeproxy/llm\n * VibeProxy implementation of ILLM interface.\n * Connects to local VibeProxy server (supports Claude, GPT, and other models).\n */\n\nimport type {\n ILLM,\n LLMOptions,\n LLMResponse,\n LLMMessage,\n LLMToolCallOptions,\n LLMToolCallResponse,\n LLMTool,\n LLMToolCall,\n LLMProtocolCapabilities,\n LLMExecutionPolicy,\n} from \"@kb-labs/core-platform\";\n\n/**\n * Configuration for VibeProxy LLM adapter.\n */\nexport interface VibeProxyLLMConfig {\n /** Base URL for VibeProxy (defaults to http://localhost:8317) */\n baseURL?: string;\n /** API key (can be any string for VibeProxy) */\n apiKey?: string;\n /** Default model to use */\n defaultModel?: string;\n /** Request timeout in ms (defaults to 120000) */\n timeout?: number;\n /** Default max output tokens when caller does not specify. Overrides the hardcoded 4096. */\n defaultMaxTokens?: number;\n}\n\n/** Default max output tokens — avoids hitting the 4096 hardcoded limit mid-response. */\nconst DEFAULT_MAX_TOKENS = 16_384;\n\n/**\n * VibeProxy Messages API request format.\n */\ninterface VibeProxyMessagesRequest {\n model: string;\n max_tokens: number;\n messages: Array<{\n role: \"user\" | \"assistant\";\n content:\n | string\n | Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n | { type: \"tool_result\"; tool_use_id: string; content: string }\n >;\n }>;\n system?: string;\n temperature?: number;\n stop_sequences?: string[];\n tools?: Array<{\n name: string;\n description: string;\n input_schema: Record<string, unknown>;\n }>;\n tool_choice?:\n | { type: \"auto\" }\n | { type: \"any\" }\n | { type: \"tool\"; name: string };\n}\n\n/**\n * VibeProxy Messages API response format.\n */\ninterface VibeProxyMessagesResponse {\n id: string;\n type: \"message\";\n role: \"assistant\";\n model: string;\n content: Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n >;\n stop_reason: \"end_turn\" | \"max_tokens\" | \"stop_sequence\" | \"tool_use\";\n stop_sequence: string | null;\n usage: {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n };\n}\n\n/**\n * VibeProxy implementation of ILLM interface.\n * Supports multiple model providers through local VibeProxy server.\n */\nexport class VibeProxyLLM implements ILLM {\n private baseURL: string;\n private apiKey: string;\n private defaultModel: string;\n private timeout: number;\n private defaultMaxTokens: number;\n\n constructor(config: VibeProxyLLMConfig = {}) {\n this.baseURL =\n config.baseURL ?? process.env.VIBEPROXY_URL ?? \"http://localhost:8317\";\n this.apiKey =\n config.apiKey ?? process.env.VIBEPROXY_API_KEY ?? \"any-string\";\n this.defaultModel =\n config.defaultModel ??\n process.env.VIBEPROXY_MODEL ??\n \"claude-sonnet-4-20250514\";\n this.timeout = config.timeout ?? 120000;\n this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;\n }\n\n getProtocolCapabilities(): LLMProtocolCapabilities {\n return {\n cache: {\n supported: true,\n protocol: \"explicit_handle\",\n scopes: [\"prefix\", \"segments\", \"full_request\"],\n },\n // Current implementation yields complete() as one chunk (not true streaming)\n stream: { supported: false },\n };\n }\n\n /**\n * Make a request to VibeProxy.\n */\n private async request<T>(\n endpoint: string,\n body: unknown,\n headers?: Record<string, string>,\n ): Promise<T> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseURL}${endpoint}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.apiKey,\n ...headers,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorBody = (await response\n .json()\n .catch(() => ({ error: { message: response.statusText } }))) as {\n error?: { message?: string };\n };\n throw new Error(\n `VibeProxy error: ${errorBody.error?.message ?? response.statusText}`,\n );\n }\n\n return response.json() as Promise<T>;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private buildExecutionHeaders(execution?: LLMExecutionPolicy): Record<string, string> {\n const headers: Record<string, string> = {};\n const cache = execution?.cache;\n if (!cache) {\n return headers;\n }\n\n headers[\"x-kb-cache-mode\"] = cache.mode ?? \"prefer\";\n if (cache.scope) {\n headers[\"x-kb-cache-scope\"] = cache.scope;\n }\n if (typeof cache.ttlSec === \"number\") {\n headers[\"x-kb-cache-ttl-sec\"] = String(cache.ttlSec);\n }\n if (cache.key) {\n headers[\"x-kb-cache-key\"] = cache.key;\n }\n\n return headers;\n }\n\n private buildTraceHeaders(options?: LLMOptions): Record<string, string> {\n const trace = options?.metadata?.cacheDecisionTrace;\n if (!trace) {\n return {};\n }\n return {\n \"x-kb-cache-decision\": JSON.stringify(trace),\n };\n }\n\n private extractTextContent(response: VibeProxyMessagesResponse): string {\n return response.content\n .filter((c): c is { type: \"text\"; text: string } => c.type === \"text\")\n .map((c) => c.text)\n .join(\"\");\n }\n\n private convertMessagesForTools(\n messages: LLMMessage[],\n ): {\n messages: VibeProxyMessagesRequest[\"messages\"];\n systemPrompt?: string;\n } {\n const vibeProxyMessages: VibeProxyMessagesRequest[\"messages\"] = [];\n let systemPrompt: string | undefined;\n\n for (const msg of messages) {\n if (msg.role === \"system\") {\n systemPrompt = msg.content;\n continue;\n }\n if (msg.role === \"tool\") {\n vibeProxyMessages.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.toolCallId || \"\",\n content: msg.content,\n },\n ],\n });\n continue;\n }\n if (msg.role === \"assistant\" && msg.toolCalls && msg.toolCalls.length > 0) {\n vibeProxyMessages.push({\n role: \"assistant\",\n content: this.toAssistantToolContent(msg),\n });\n continue;\n }\n vibeProxyMessages.push({\n role: msg.role as \"user\" | \"assistant\",\n content: msg.content,\n });\n }\n\n return { messages: vibeProxyMessages, systemPrompt };\n }\n\n private toAssistantToolContent(\n message: LLMMessage,\n ): Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n > {\n const contentBlocks: Array<\n | { type: \"text\"; text: string }\n | { type: \"tool_use\"; id: string; name: string; input: unknown }\n > = [];\n\n if (message.content && message.content.trim()) {\n contentBlocks.push({\n type: \"text\",\n text: message.content,\n });\n }\n\n for (const toolCall of message.toolCalls ?? []) {\n contentBlocks.push({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.input,\n });\n }\n return contentBlocks;\n }\n\n private buildToolChoice(\n toolChoice: LLMToolCallOptions[\"toolChoice\"],\n ): VibeProxyMessagesRequest[\"tool_choice\"] {\n if (toolChoice === \"auto\") {\n return { type: \"auto\" };\n }\n if (toolChoice === \"required\") {\n return { type: \"any\" };\n }\n if (toolChoice && typeof toolChoice === \"object\") {\n return { type: \"tool\", name: toolChoice.function.name };\n }\n return undefined;\n }\n\n private extractToolCalls(response: VibeProxyMessagesResponse): LLMToolCall[] {\n return response.content\n .filter(\n (\n c,\n ): c is {\n type: \"tool_use\";\n id: string;\n name: string;\n input: unknown;\n } => c.type === \"tool_use\",\n )\n .map((tc) => ({\n id: tc.id,\n name: tc.name,\n input: tc.input,\n }));\n }\n\n async complete(prompt: string, options?: LLMOptions): Promise<LLMResponse> {\n const model = options?.model ?? this.defaultModel;\n\n const requestBody: VibeProxyMessagesRequest = {\n model,\n max_tokens: options?.maxTokens ?? this.defaultMaxTokens,\n messages: [{ role: \"user\", content: prompt }],\n };\n\n if (options?.systemPrompt) {\n requestBody.system = options.systemPrompt;\n }\n if (options?.temperature !== undefined) {\n requestBody.temperature = options.temperature;\n }\n if (options?.stop) {\n requestBody.stop_sequences = options.stop;\n }\n\n const response = await this.request<VibeProxyMessagesResponse>(\n \"/v1/messages\",\n requestBody,\n {\n ...this.buildExecutionHeaders(options?.execution),\n ...this.buildTraceHeaders(options),\n },\n );\n\n return {\n content: this.extractTextContent(response),\n usage: {\n promptTokens: response.usage.input_tokens,\n completionTokens: response.usage.output_tokens,\n cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,\n cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,\n providerUsage: {\n stopReason: response.stop_reason,\n },\n },\n model: response.model,\n };\n }\n\n async *stream(prompt: string, options?: LLMOptions): AsyncIterable<string> {\n // VibeProxy supports streaming via SSE, but for simplicity we'll use non-streaming\n // and yield the full response. Can be enhanced later with proper SSE support.\n const response = await this.complete(prompt, options);\n yield response.content;\n }\n\n /**\n * Chat with native tool calling support.\n */\n async chatWithTools(\n messages: LLMMessage[],\n options: LLMToolCallOptions,\n ): Promise<LLMToolCallResponse> {\n const model = options?.model ?? this.defaultModel;\n const converted = this.convertMessagesForTools(messages);\n\n // Convert LLMTool[] to VibeProxy tools format\n const tools: VibeProxyMessagesRequest[\"tools\"] = options.tools.map(\n (tool: LLMTool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: tool.inputSchema,\n }),\n );\n const toolChoice = this.buildToolChoice(options.toolChoice);\n\n const requestBody: VibeProxyMessagesRequest = {\n model,\n max_tokens: options?.maxTokens ?? this.defaultMaxTokens,\n messages: converted.messages,\n tools: options.toolChoice !== \"none\" ? tools : undefined,\n tool_choice: options.toolChoice !== \"none\" ? toolChoice : undefined,\n };\n\n if (converted.systemPrompt || options?.systemPrompt) {\n requestBody.system = converted.systemPrompt ?? options.systemPrompt;\n }\n if (options?.temperature !== undefined) {\n requestBody.temperature = options.temperature;\n }\n if (options?.stop) {\n requestBody.stop_sequences = options.stop;\n }\n\n const response = await this.request<VibeProxyMessagesResponse>(\n \"/v1/messages\",\n requestBody,\n {\n ...this.buildExecutionHeaders(options?.execution),\n ...this.buildTraceHeaders(options),\n },\n );\n const textContent = this.extractTextContent(response);\n const toolCalls = this.extractToolCalls(response);\n\n return {\n content: textContent,\n usage: {\n promptTokens: response.usage.input_tokens,\n completionTokens: response.usage.output_tokens,\n cacheReadTokens: response.usage.cache_read_input_tokens ?? 0,\n cacheWriteTokens: response.usage.cache_creation_input_tokens ?? 0,\n providerUsage: {\n stopReason: response.stop_reason,\n },\n },\n model: response.model,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n stopReason: response.stop_reason,\n };\n }\n}\n\n/**\n * Create VibeProxy LLM adapter.\n * This is the factory function called by initPlatform() when loading adapters.\n */\nexport function createAdapter(config?: VibeProxyLLMConfig): VibeProxyLLM {\n return new VibeProxyLLM(config);\n}\n\n// Default export for direct import\nexport default createAdapter;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/adapters-vibeproxy",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "VibeProxy adapter implementing ILLM interface for local Anthropic API proxy",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./llm": {
|
|
14
|
+
"import": "./dist/llm.js",
|
|
15
|
+
"types": "./dist/llm.d.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"scripts": {
|
|
24
|
+
"clean": "rimraf dist",
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"type-check": "tsc --noEmit",
|
|
28
|
+
"test": "vitest run --passWithNoTests",
|
|
29
|
+
"test:watch": "vitest",
|
|
30
|
+
"lint": "eslint src --ext .ts",
|
|
31
|
+
"lint:fix": "eslint . --fix"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@kb-labs/core-platform": "*"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@kb-labs/core-platform": "link:../../../../platform/kb-labs-core/packages/core-platform",
|
|
39
|
+
"@types/node": "^24.3.3",
|
|
40
|
+
"eslint": "^9",
|
|
41
|
+
"rimraf": "^6.0.1",
|
|
42
|
+
"tsup": "^8.5.0",
|
|
43
|
+
"typescript": "^5.6.3",
|
|
44
|
+
"vitest": "^3.2.4",
|
|
45
|
+
"@kb-labs/devkit": "link:../../../kb-labs-devkit"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20.0.0",
|
|
49
|
+
"pnpm": ">=9.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|