@mandujs/core 0.45.1 → 0.46.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/package.json +2 -2
- package/src/brain/adapters/__tests__/resolver.test.ts +37 -21
- package/src/brain/adapters/base.ts +4 -3
- package/src/brain/adapters/index.ts +319 -333
- package/src/brain/adapters/openai-oauth.ts +3 -5
- package/src/brain/brain.ts +8 -11
- package/src/brain/consent.ts +1 -1
- package/src/brain/index.ts +4 -1
- package/src/config/mandu.ts +12 -14
- package/src/config/validate.ts +3 -10
- package/src/deploy/cache.ts +139 -0
- package/src/deploy/index.ts +62 -0
- package/src/deploy/inference/context.ts +173 -0
- package/src/deploy/inference/heuristic.ts +182 -0
- package/src/deploy/intent.ts +173 -0
- package/src/deploy/plan.ts +178 -0
- package/src/brain/adapters/ollama.ts +0 -235
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Brain v0.1 - Ollama LLM Adapter
|
|
3
|
-
*
|
|
4
|
-
* Default adapter for local sLLM via Ollama.
|
|
5
|
-
* Uses official ollama npm package for reliable API integration.
|
|
6
|
-
* Recommended models: ministral-3:3b, llama3.2, codellama, mistral
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Ollama } from "ollama";
|
|
10
|
-
import { BaseLLMAdapter } from "./base";
|
|
11
|
-
import type {
|
|
12
|
-
AdapterConfig,
|
|
13
|
-
AdapterStatus,
|
|
14
|
-
ChatMessage,
|
|
15
|
-
CompletionOptions,
|
|
16
|
-
CompletionResult,
|
|
17
|
-
} from "../types";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Default Ollama configuration
|
|
21
|
-
*
|
|
22
|
-
* Ministral 3B: 저사양 PC에서도 동작하는 경량 모델
|
|
23
|
-
* - 2GB VRAM 이하에서도 CPU 모드로 동작
|
|
24
|
-
* - 코드 분석/제안에 충분한 성능
|
|
25
|
-
*/
|
|
26
|
-
export const DEFAULT_OLLAMA_CONFIG: AdapterConfig = {
|
|
27
|
-
baseUrl: "http://localhost:11434",
|
|
28
|
-
model: "ministral-3:3b", // Mistral's lightweight 3B model (3.0GB)
|
|
29
|
-
timeout: 30000, // 30 seconds
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Ollama LLM Adapter
|
|
34
|
-
*
|
|
35
|
-
* Connects to a local Ollama instance for sLLM inference.
|
|
36
|
-
* Falls back gracefully if Ollama is not available.
|
|
37
|
-
*/
|
|
38
|
-
export class OllamaAdapter extends BaseLLMAdapter {
|
|
39
|
-
readonly name = "ollama";
|
|
40
|
-
private client: Ollama;
|
|
41
|
-
|
|
42
|
-
constructor(config: Partial<AdapterConfig> = {}) {
|
|
43
|
-
super({
|
|
44
|
-
...DEFAULT_OLLAMA_CONFIG,
|
|
45
|
-
...config,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
this.client = new Ollama({
|
|
49
|
-
host: this.baseUrl,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Check if Ollama is running and the model is available
|
|
55
|
-
*/
|
|
56
|
-
async checkStatus(): Promise<AdapterStatus> {
|
|
57
|
-
try {
|
|
58
|
-
const response = await this.client.list();
|
|
59
|
-
const models = response.models || [];
|
|
60
|
-
|
|
61
|
-
// Check if configured model is available
|
|
62
|
-
const modelAvailable = models.some(
|
|
63
|
-
(m) =>
|
|
64
|
-
m.name === this.config.model ||
|
|
65
|
-
m.name.startsWith(`${this.config.model}:`)
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
if (!modelAvailable) {
|
|
69
|
-
// Check if any model is available
|
|
70
|
-
if (models.length > 0) {
|
|
71
|
-
return {
|
|
72
|
-
available: true,
|
|
73
|
-
model: models[0].name,
|
|
74
|
-
error: `Configured model '${this.config.model}' not found. Using '${models[0].name}' instead.`,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
available: false,
|
|
80
|
-
model: null,
|
|
81
|
-
error: `No models available. Run: ollama pull ${this.config.model}`,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
available: true,
|
|
87
|
-
model: this.config.model,
|
|
88
|
-
};
|
|
89
|
-
} catch (error) {
|
|
90
|
-
const errorMessage =
|
|
91
|
-
error instanceof Error ? error.message : "Unknown error";
|
|
92
|
-
|
|
93
|
-
// Check for common connection errors
|
|
94
|
-
if (
|
|
95
|
-
errorMessage.includes("ECONNREFUSED") ||
|
|
96
|
-
errorMessage.includes("fetch failed") ||
|
|
97
|
-
errorMessage.includes("Unable to connect")
|
|
98
|
-
) {
|
|
99
|
-
return {
|
|
100
|
-
available: false,
|
|
101
|
-
model: null,
|
|
102
|
-
error: "Ollama is not running. Start with: ollama serve",
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
available: false,
|
|
108
|
-
model: null,
|
|
109
|
-
error: `Ollama check failed: ${errorMessage}`,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Complete a chat conversation using Ollama's chat API
|
|
116
|
-
*/
|
|
117
|
-
async complete(
|
|
118
|
-
messages: ChatMessage[],
|
|
119
|
-
options: CompletionOptions = {}
|
|
120
|
-
): Promise<CompletionResult> {
|
|
121
|
-
const { temperature = 0.7, maxTokens = 2048 } = options;
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const response = await this.client.chat({
|
|
125
|
-
model: this.config.model,
|
|
126
|
-
messages: messages.map((m) => ({
|
|
127
|
-
role: m.role,
|
|
128
|
-
content: m.content,
|
|
129
|
-
})),
|
|
130
|
-
stream: false,
|
|
131
|
-
options: {
|
|
132
|
-
temperature,
|
|
133
|
-
num_predict: maxTokens,
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
content: response.message?.content || "",
|
|
139
|
-
usage: {
|
|
140
|
-
promptTokens: response.prompt_eval_count || 0,
|
|
141
|
-
completionTokens: response.eval_count || 0,
|
|
142
|
-
totalTokens:
|
|
143
|
-
(response.prompt_eval_count || 0) + (response.eval_count || 0),
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
} catch (error) {
|
|
147
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
148
|
-
throw new Error("Ollama request timeout", { cause: error });
|
|
149
|
-
}
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Pull a model from Ollama registry with progress callback
|
|
156
|
-
*/
|
|
157
|
-
async pullModel(
|
|
158
|
-
modelName?: string,
|
|
159
|
-
onProgress?: (status: string, completed?: number, total?: number) => void
|
|
160
|
-
): Promise<{ success: boolean; error?: string }> {
|
|
161
|
-
const model = modelName ?? this.config.model;
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const stream = await this.client.pull({
|
|
165
|
-
model,
|
|
166
|
-
stream: true,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
for await (const progress of stream) {
|
|
170
|
-
if (onProgress && progress.status) {
|
|
171
|
-
onProgress(
|
|
172
|
-
progress.status,
|
|
173
|
-
progress.completed,
|
|
174
|
-
progress.total
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return { success: true };
|
|
180
|
-
} catch (error) {
|
|
181
|
-
return {
|
|
182
|
-
success: false,
|
|
183
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Check if Ollama server is reachable
|
|
190
|
-
*/
|
|
191
|
-
async isServerRunning(): Promise<boolean> {
|
|
192
|
-
try {
|
|
193
|
-
await this.client.list();
|
|
194
|
-
return true;
|
|
195
|
-
} catch {
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* List all available models
|
|
202
|
-
*/
|
|
203
|
-
async listModels(): Promise<string[]> {
|
|
204
|
-
try {
|
|
205
|
-
const response = await this.client.list();
|
|
206
|
-
return (response.models || []).map((m) => m.name);
|
|
207
|
-
} catch {
|
|
208
|
-
return [];
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Generate embeddings for text
|
|
214
|
-
*/
|
|
215
|
-
async embed(text: string, model?: string): Promise<number[] | null> {
|
|
216
|
-
try {
|
|
217
|
-
const response = await this.client.embed({
|
|
218
|
-
model: model ?? this.config.model,
|
|
219
|
-
input: text,
|
|
220
|
-
});
|
|
221
|
-
return response.embeddings?.[0] ?? null;
|
|
222
|
-
} catch {
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Create an Ollama adapter with optional configuration
|
|
230
|
-
*/
|
|
231
|
-
export function createOllamaAdapter(
|
|
232
|
-
config?: Partial<AdapterConfig>
|
|
233
|
-
): OllamaAdapter {
|
|
234
|
-
return new OllamaAdapter(config);
|
|
235
|
-
}
|