@decido/kernel-bridge 1.0.0 → 4.0.2
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 +31 -0
- package/dist/index.js +2593 -0
- package/dist/index.mjs +2518 -0
- package/package.json +13 -7
- package/.turbo/turbo-build.log +0 -13
- package/.turbo/turbo-lint.log +0 -30
- package/src/ai/components/PeerNetworkPanel.tsx +0 -219
- package/src/ai/components/TokenWalletPanel.tsx +0 -172
- package/src/ai/hooks/usePeerMesh.ts +0 -79
- package/src/ai/hooks/useTokenWallet.ts +0 -35
- package/src/ai/index.ts +0 -96
- package/src/ai/services/EmbeddingService.ts +0 -119
- package/src/ai/services/InferenceRouter.ts +0 -347
- package/src/ai/services/LocalAgentResponder.ts +0 -199
- package/src/ai/services/MLXBridge.ts +0 -278
- package/src/ai/services/OllamaService.ts +0 -326
- package/src/ai/services/PeerMesh.ts +0 -373
- package/src/ai/services/TokenWallet.ts +0 -237
- package/src/ai/services/providers/AnthropicProvider.ts +0 -229
- package/src/ai/services/providers/GeminiProvider.ts +0 -121
- package/src/ai/services/providers/LLMProvider.ts +0 -72
- package/src/ai/services/providers/OllamaProvider.ts +0 -84
- package/src/ai/services/providers/OpenAIProvider.ts +0 -178
- package/src/crypto.ts +0 -54
- package/src/index.ts +0 -4
- package/src/kernel.ts +0 -376
- package/src/rehydration.ts +0 -52
- package/tsconfig.json +0 -18
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OllamaProvider — Local Ollama LLM provider
|
|
3
|
-
*
|
|
4
|
-
* Wraps Ollama's REST API (localhost:11434) as an LLMProvider.
|
|
5
|
-
* Supports tool-calling via <tool_call> blocks in system prompt.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { LLMProvider, ChatMessage, ChatOptions, ChatResult, ProviderStatus } from './LLMProvider';
|
|
9
|
-
|
|
10
|
-
// ─── Config ─────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
const OLLAMA_BASE_URL = 'http://localhost:11434';
|
|
13
|
-
const DEFAULT_MODEL = 'qwen2:latest';
|
|
14
|
-
|
|
15
|
-
// ─── Provider Implementation ────────────────────────────────
|
|
16
|
-
|
|
17
|
-
export class OllamaProvider implements LLMProvider {
|
|
18
|
-
readonly id = 'ollama';
|
|
19
|
-
readonly name = 'Ollama (Local)';
|
|
20
|
-
readonly requiresApiKey = false;
|
|
21
|
-
readonly defaultModel = DEFAULT_MODEL;
|
|
22
|
-
|
|
23
|
-
async listModels(): Promise<string[]> {
|
|
24
|
-
try {
|
|
25
|
-
const res = await fetch(`${OLLAMA_BASE_URL}/api/tags`);
|
|
26
|
-
if (!res.ok) return [];
|
|
27
|
-
const data = await res.json();
|
|
28
|
-
return (data.models || []).map((m: { name: string }) => m.name);
|
|
29
|
-
} catch {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async checkStatus(): Promise<ProviderStatus> {
|
|
35
|
-
try {
|
|
36
|
-
const res = await fetch(`${OLLAMA_BASE_URL}/api/tags`, {
|
|
37
|
-
signal: AbortSignal.timeout(2000),
|
|
38
|
-
});
|
|
39
|
-
return res.ok ? 'available' : 'error';
|
|
40
|
-
} catch {
|
|
41
|
-
return 'unavailable';
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResult> {
|
|
46
|
-
const model = options?.model || this.defaultModel;
|
|
47
|
-
const start = Date.now();
|
|
48
|
-
|
|
49
|
-
const ollamaMessages = messages.map(m => ({
|
|
50
|
-
role: m.role,
|
|
51
|
-
content: m.content,
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
const res = await fetch(`${OLLAMA_BASE_URL}/api/chat`, {
|
|
55
|
-
method: 'POST',
|
|
56
|
-
headers: { 'Content-Type': 'application/json' },
|
|
57
|
-
body: JSON.stringify({
|
|
58
|
-
model,
|
|
59
|
-
messages: ollamaMessages,
|
|
60
|
-
stream: false,
|
|
61
|
-
options: {
|
|
62
|
-
temperature: options?.temperature ?? 0.7,
|
|
63
|
-
num_predict: options?.maxTokens ?? 512,
|
|
64
|
-
},
|
|
65
|
-
}),
|
|
66
|
-
signal: options?.signal ?? AbortSignal.timeout(30000),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
if (!res.ok) {
|
|
70
|
-
const errorText = await res.text();
|
|
71
|
-
throw new Error(`Ollama API error ${res.status}: ${errorText}`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const data = await res.json();
|
|
75
|
-
const latencyMs = Date.now() - start;
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
text: data.message?.content || '(sin respuesta)',
|
|
79
|
-
model,
|
|
80
|
-
latencyMs,
|
|
81
|
-
tokensUsed: data.eval_count,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenAIProvider — GPT-4o / GPT-4 / GPT-3.5 LLM provider
|
|
3
|
-
*
|
|
4
|
-
* Supports chat completion with streaming via SSE.
|
|
5
|
-
* Compatible with OpenAI API and OpenAI-compatible endpoints (e.g., LM Studio).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { LLMProvider, ChatMessage, ChatOptions, ChatResult, ProviderStatus } from './LLMProvider';
|
|
9
|
-
|
|
10
|
-
// ─── Config ─────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
const OPENAI_API_BASE = 'https://api.openai.com/v1';
|
|
13
|
-
const DEFAULT_MODEL = 'gpt-4o';
|
|
14
|
-
|
|
15
|
-
const AVAILABLE_MODELS = [
|
|
16
|
-
'gpt-4o',
|
|
17
|
-
'gpt-4o-mini',
|
|
18
|
-
'gpt-4-turbo',
|
|
19
|
-
'gpt-4',
|
|
20
|
-
'gpt-3.5-turbo',
|
|
21
|
-
'o3-mini',
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
// ─── Provider Implementation ────────────────────────────────
|
|
25
|
-
|
|
26
|
-
export class OpenAIProvider implements LLMProvider {
|
|
27
|
-
readonly id = 'openai';
|
|
28
|
-
readonly name = 'OpenAI';
|
|
29
|
-
readonly requiresApiKey = true;
|
|
30
|
-
readonly defaultModel = DEFAULT_MODEL;
|
|
31
|
-
|
|
32
|
-
private apiKey: string | null = null;
|
|
33
|
-
private baseUrl: string = OPENAI_API_BASE;
|
|
34
|
-
|
|
35
|
-
setApiKey(key: string): void {
|
|
36
|
-
this.apiKey = key;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Override base URL for OpenAI-compatible endpoints */
|
|
40
|
-
setBaseUrl(url: string): void {
|
|
41
|
-
this.baseUrl = url.replace(/\/$/, '');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async listModels(): Promise<string[]> {
|
|
45
|
-
if (!this.apiKey) return AVAILABLE_MODELS;
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const res = await fetch(`${this.baseUrl}/models`, {
|
|
49
|
-
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
50
|
-
signal: AbortSignal.timeout(5000),
|
|
51
|
-
});
|
|
52
|
-
if (!res.ok) return AVAILABLE_MODELS;
|
|
53
|
-
const data = await res.json();
|
|
54
|
-
const models = (data.data || [])
|
|
55
|
-
.map((m: { id: string }) => m.id)
|
|
56
|
-
.filter((id: string) => id.startsWith('gpt-') || id.startsWith('o'));
|
|
57
|
-
return models.length > 0 ? models : AVAILABLE_MODELS;
|
|
58
|
-
} catch {
|
|
59
|
-
return AVAILABLE_MODELS;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async checkStatus(): Promise<ProviderStatus> {
|
|
64
|
-
if (!this.apiKey) return 'unconfigured';
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const res = await fetch(`${this.baseUrl}/models`, {
|
|
68
|
-
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
69
|
-
signal: AbortSignal.timeout(5000),
|
|
70
|
-
});
|
|
71
|
-
return res.ok ? 'available' : 'error';
|
|
72
|
-
} catch {
|
|
73
|
-
return 'unavailable';
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResult> {
|
|
78
|
-
if (!this.apiKey) {
|
|
79
|
-
throw new Error('OpenAI API key not configured. Set it in Settings → Providers.');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const model = options?.model || this.defaultModel;
|
|
83
|
-
const start = Date.now();
|
|
84
|
-
|
|
85
|
-
const body: Record<string, unknown> = {
|
|
86
|
-
model,
|
|
87
|
-
messages: messages.map(m => ({ role: m.role, content: m.content })),
|
|
88
|
-
temperature: options?.temperature ?? 0.7,
|
|
89
|
-
max_tokens: options?.maxTokens ?? 2048,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const res = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
93
|
-
method: 'POST',
|
|
94
|
-
headers: {
|
|
95
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
96
|
-
'Content-Type': 'application/json',
|
|
97
|
-
},
|
|
98
|
-
body: JSON.stringify(body),
|
|
99
|
-
signal: options?.signal ?? AbortSignal.timeout(60000),
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
if (!res.ok) {
|
|
103
|
-
const errorBody = await res.text();
|
|
104
|
-
throw new Error(`OpenAI API error ${res.status}: ${errorBody}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const data = await res.json();
|
|
108
|
-
const latencyMs = Date.now() - start;
|
|
109
|
-
|
|
110
|
-
const text = data.choices?.[0]?.message?.content || '(sin respuesta)';
|
|
111
|
-
const tokensUsed =
|
|
112
|
-
(data.usage?.prompt_tokens || 0) + (data.usage?.completion_tokens || 0);
|
|
113
|
-
|
|
114
|
-
return { text, model, latencyMs, tokensUsed };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Stream chat completion — yields text chunks */
|
|
118
|
-
async *chatStream(
|
|
119
|
-
messages: ChatMessage[],
|
|
120
|
-
options?: ChatOptions,
|
|
121
|
-
): AsyncGenerator<string, void, unknown> {
|
|
122
|
-
if (!this.apiKey) {
|
|
123
|
-
throw new Error('OpenAI API key not configured.');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const model = options?.model || this.defaultModel;
|
|
127
|
-
|
|
128
|
-
const body: Record<string, unknown> = {
|
|
129
|
-
model,
|
|
130
|
-
messages: messages.map(m => ({ role: m.role, content: m.content })),
|
|
131
|
-
temperature: options?.temperature ?? 0.7,
|
|
132
|
-
max_tokens: options?.maxTokens ?? 2048,
|
|
133
|
-
stream: true,
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const res = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
137
|
-
method: 'POST',
|
|
138
|
-
headers: {
|
|
139
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
140
|
-
'Content-Type': 'application/json',
|
|
141
|
-
},
|
|
142
|
-
body: JSON.stringify(body),
|
|
143
|
-
signal: options?.signal ?? AbortSignal.timeout(120000),
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
if (!res.ok) {
|
|
147
|
-
const errorBody = await res.text();
|
|
148
|
-
throw new Error(`OpenAI stream error ${res.status}: ${errorBody}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const reader = res.body?.getReader();
|
|
152
|
-
if (!reader) return;
|
|
153
|
-
|
|
154
|
-
const decoder = new TextDecoder();
|
|
155
|
-
let buffer = '';
|
|
156
|
-
|
|
157
|
-
while (true) {
|
|
158
|
-
const { done, value } = await reader.read();
|
|
159
|
-
if (done) break;
|
|
160
|
-
|
|
161
|
-
buffer += decoder.decode(value, { stream: true });
|
|
162
|
-
const lines = buffer.split('\n');
|
|
163
|
-
buffer = lines.pop() || '';
|
|
164
|
-
|
|
165
|
-
for (const line of lines) {
|
|
166
|
-
if (!line.startsWith('data: ')) continue;
|
|
167
|
-
const data = line.slice(6).trim();
|
|
168
|
-
if (data === '[DONE]') return;
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
const chunk = JSON.parse(data);
|
|
172
|
-
const delta = chunk.choices?.[0]?.delta?.content;
|
|
173
|
-
if (delta) yield delta;
|
|
174
|
-
} catch { /* skip malformed */ }
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
package/src/crypto.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility functions for decrypting the Zero-Trust encrypted Swarm Bus messages
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Decrypts a base64 encoded payload that contains [12-byte Nonce][Ciphertext]
|
|
7
|
-
* using AES-256-GCM and the provided Swarm Key
|
|
8
|
-
*
|
|
9
|
-
* @param base64Payload The encrypted base64 string from Redis
|
|
10
|
-
* @param base64Key The base64 string representing the 32-byte Swarm Key
|
|
11
|
-
* @returns The parsed JSON object of the event
|
|
12
|
-
*/
|
|
13
|
-
export async function decryptEvent(base64Payload: string, base64Key: string): Promise<any> {
|
|
14
|
-
try {
|
|
15
|
-
// 1. Decode base64 key
|
|
16
|
-
const keyBuffer = Uint8Array.from(atob(base64Key), c => c.charCodeAt(0));
|
|
17
|
-
|
|
18
|
-
// 2. Decode base64 payload
|
|
19
|
-
const payloadBuffer = Uint8Array.from(atob(base64Payload), c => c.charCodeAt(0));
|
|
20
|
-
|
|
21
|
-
if (payloadBuffer.byteLength < 12) {
|
|
22
|
-
throw new Error("Payload too short to contain a valid nonce");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 3. Extract Nonce (first 12 bytes) and Ciphertext (the rest)
|
|
26
|
-
const nonce = payloadBuffer.slice(0, 12);
|
|
27
|
-
const ciphertext = payloadBuffer.slice(12);
|
|
28
|
-
|
|
29
|
-
// 4. Import the key for subtle crypto
|
|
30
|
-
const cryptoKey = await crypto.subtle.importKey(
|
|
31
|
-
"raw",
|
|
32
|
-
keyBuffer,
|
|
33
|
-
{ name: "AES-GCM" },
|
|
34
|
-
false,
|
|
35
|
-
["decrypt"]
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
// 5. Decrypt
|
|
39
|
-
const decryptedBuffer = await crypto.subtle.decrypt(
|
|
40
|
-
{ name: "AES-GCM", iv: nonce },
|
|
41
|
-
cryptoKey,
|
|
42
|
-
ciphertext
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
// 6. Parse JSON
|
|
46
|
-
const decoder = new TextDecoder();
|
|
47
|
-
const jsonString = decoder.decode(decryptedBuffer);
|
|
48
|
-
|
|
49
|
-
return JSON.parse(jsonString);
|
|
50
|
-
} catch (e) {
|
|
51
|
-
console.error("[Crypto Bridge] Failed to decrypt secure event:", e);
|
|
52
|
-
throw e;
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/index.ts
DELETED