tarsk 0.2.5 → 0.3.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 +1 -7
- package/dist/index.d.ts +3 -0
- package/dist/index.js +92 -32
- package/dist/lib/response-builder.d.ts +50 -0
- package/dist/lib/response-builder.js +56 -0
- package/dist/lib/stream-helper.d.ts +39 -0
- package/dist/lib/stream-helper.js +43 -0
- package/dist/managers/ConversationManager.d.ts +83 -0
- package/dist/managers/ConversationManager.js +129 -0
- package/dist/managers/GitManager.d.ts +133 -0
- package/dist/managers/GitManager.js +330 -0
- package/dist/managers/MetadataManager.d.ts +139 -0
- package/dist/managers/MetadataManager.js +309 -0
- package/dist/managers/ModelManager.d.ts +57 -0
- package/dist/managers/ModelManager.js +129 -0
- package/dist/managers/NeovateExecutor.d.ts +40 -0
- package/dist/managers/NeovateExecutor.js +138 -0
- package/dist/managers/ProjectManager.d.ts +162 -0
- package/dist/managers/ProjectManager.js +353 -0
- package/dist/managers/ThreadManager.d.ts +181 -0
- package/dist/managers/ThreadManager.js +325 -0
- package/dist/managers/conversation-manager.d.ts +83 -0
- package/dist/managers/conversation-manager.js +129 -0
- package/dist/managers/git-manager.d.ts +133 -0
- package/dist/managers/git-manager.js +330 -0
- package/dist/managers/metadata-manager.d.ts +139 -0
- package/dist/managers/metadata-manager.js +305 -0
- package/dist/managers/model-manager.d.ts +59 -0
- package/dist/managers/model-manager.js +144 -0
- package/dist/managers/neovate-executor.d.ts +43 -0
- package/dist/managers/neovate-executor.js +205 -0
- package/dist/managers/processing-state-manager.d.ts +40 -0
- package/dist/managers/processing-state-manager.js +27 -0
- package/dist/managers/project-manager.d.ts +199 -0
- package/dist/managers/project-manager.js +465 -0
- package/dist/managers/thread-manager.d.ts +193 -0
- package/dist/managers/thread-manager.js +368 -0
- package/dist/model-info-aihubmix.d.ts +25 -0
- package/dist/model-info-aihubmix.js +117 -0
- package/dist/model-info-openai.d.ts +17 -0
- package/dist/model-info-openai.js +59 -0
- package/dist/model-info-openrouter.d.ts +25 -0
- package/dist/model-info-openrouter.js +101 -0
- package/dist/model-info.d.ts +37 -0
- package/dist/model-info.js +39 -0
- package/dist/provider-data.d.ts +101 -0
- package/dist/provider-data.js +471 -0
- package/dist/provider.d.ts +10 -0
- package/dist/provider.js +192 -0
- package/dist/public/android-chrome-192x192.png +0 -0
- package/dist/public/android-chrome-512x512.png +0 -0
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/assets/index-B443aj9k.js +8506 -0
- package/dist/public/assets/index-CjXGVbI7.css +1 -0
- package/dist/public/assets/index-DJC-p914.js +8506 -0
- package/dist/public/favicon-16x16.png +0 -0
- package/dist/public/favicon-32x32.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/index.html +28 -0
- package/dist/public/manifest.json +82 -0
- package/dist/public/placeholder-logo.svg +1 -0
- package/dist/public/placeholder.svg +1 -0
- package/dist/public/snpro.woff2 +0 -0
- package/dist/public/tarsk-color.svg +12 -0
- package/dist/public/tarsk.png +0 -0
- package/dist/public/tarsk.svg +12 -0
- package/dist/public/zalando-sans.woff2 +0 -0
- package/dist/routes/chat-old.d.ts +21 -0
- package/dist/routes/chat-old.js +251 -0
- package/dist/routes/chat.d.ts +21 -0
- package/dist/routes/chat.js +217 -0
- package/dist/routes/git.d.ts +4 -0
- package/dist/routes/git.js +668 -0
- package/dist/routes/models.d.ts +18 -0
- package/dist/routes/models.js +128 -0
- package/dist/routes/projects-old.d.ts +20 -0
- package/dist/routes/projects-old.js +297 -0
- package/dist/routes/projects.d.ts +20 -0
- package/dist/routes/projects.js +365 -0
- package/dist/routes/providers.d.ts +15 -0
- package/dist/routes/providers.js +130 -0
- package/dist/routes/threads-old.d.ts +14 -0
- package/dist/routes/threads-old.js +393 -0
- package/dist/routes/threads.d.ts +14 -0
- package/dist/routes/threads.js +352 -0
- package/dist/types/models.d.ts +315 -0
- package/dist/types/models.js +11 -0
- package/dist/utils/env-manager.d.ts +3 -0
- package/dist/utils/env-manager.js +60 -0
- package/dist/utils/open-router-models.d.ts +45 -0
- package/dist/utils/open-router-models.js +103 -0
- package/dist/utils/openai-models.d.ts +63 -0
- package/dist/utils/openai-models.js +152 -0
- package/dist/utils/openai-pricing-scraper.d.ts +17 -0
- package/dist/utils/openai-pricing-scraper.js +185 -0
- package/dist/utils/validation.d.ts +10 -0
- package/dist/utils/validation.js +20 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +12 -0
- package/package.json +36 -22
- package/LICENSE.md +0 -7
- package/dist/agent/agent.js +0 -131
- package/dist/agent/interfaces.js +0 -1
- package/dist/api/encryption.js +0 -41
- package/dist/api/models.js +0 -169
- package/dist/api/prompt.js +0 -12
- package/dist/api/settings.js +0 -43
- package/dist/api/test.js +0 -29
- package/dist/api/tools.js +0 -287
- package/dist/api/utils.js +0 -18
- package/dist/interfaces/meta.js +0 -1
- package/dist/interfaces/model.js +0 -1
- package/dist/interfaces/settings.js +0 -1
- package/dist/log/log.js +0 -33
- package/dist/prompt.js +0 -49
- package/dist/tools.js +0 -84
- package/dist/utils/files.js +0 -14
- package/dist/utils/json-file.js +0 -28
- package/dist/utils/strip-markdown.js +0 -5
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetadataManager handles persistence of project and thread metadata
|
|
3
|
+
*
|
|
4
|
+
* This manager provides JSON file-based storage with atomic writes
|
|
5
|
+
* to ensure data consistency even if the process crashes during write operations.
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from "fs";
|
|
8
|
+
import { join, dirname } from "path";
|
|
9
|
+
export class MetadataManager {
|
|
10
|
+
projectsFile;
|
|
11
|
+
threadsFile;
|
|
12
|
+
stateFile;
|
|
13
|
+
metadataDir;
|
|
14
|
+
/**
|
|
15
|
+
* Create a new MetadataManager
|
|
16
|
+
* @param rootFolder - Base directory where metadata will be stored
|
|
17
|
+
*/
|
|
18
|
+
constructor(rootFolder) {
|
|
19
|
+
this.metadataDir = join(rootFolder, ".metadata");
|
|
20
|
+
this.projectsFile = join(this.metadataDir, "projects.json");
|
|
21
|
+
this.threadsFile = join(this.metadataDir, "threads.json");
|
|
22
|
+
this.stateFile = join(this.metadataDir, "state.json");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Initialize metadata directory if it doesn't exist
|
|
26
|
+
*/
|
|
27
|
+
async initialize() {
|
|
28
|
+
try {
|
|
29
|
+
await fs.mkdir(this.metadataDir, { recursive: true });
|
|
30
|
+
// Create empty files if they don't exist
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(this.projectsFile);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
await this.saveProjects([]);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await fs.access(this.threadsFile);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
await this.saveThreads([]);
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await fs.access(this.stateFile);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
await this.saveState({
|
|
48
|
+
selectedThreadId: null,
|
|
49
|
+
providerKeys: {},
|
|
50
|
+
enabledModels: {},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
throw new Error(`Failed to initialize metadata directory: ${error}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Save projects to disk using atomic write
|
|
60
|
+
* @param projects - Array of projects to save
|
|
61
|
+
*/
|
|
62
|
+
async saveProjects(projects) {
|
|
63
|
+
await this.atomicWrite(this.projectsFile, projects);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Load projects from disk
|
|
67
|
+
* @returns Array of projects
|
|
68
|
+
*/
|
|
69
|
+
async loadProjects() {
|
|
70
|
+
try {
|
|
71
|
+
const data = await fs.readFile(this.projectsFile, "utf-8");
|
|
72
|
+
const projects = JSON.parse(data);
|
|
73
|
+
// Convert date strings back to Date objects
|
|
74
|
+
return projects.map((project) => ({
|
|
75
|
+
...project,
|
|
76
|
+
createdAt: new Date(project.createdAt),
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (error.code === "ENOENT") {
|
|
81
|
+
// File doesn't exist yet, return empty array
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Failed to load projects: ${error}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Save threads to disk using atomic write
|
|
89
|
+
* @param threads - Array of threads to save
|
|
90
|
+
*/
|
|
91
|
+
async saveThreads(threads) {
|
|
92
|
+
await this.atomicWrite(this.threadsFile, threads);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Load threads from disk
|
|
96
|
+
* @returns Array of threads
|
|
97
|
+
*/
|
|
98
|
+
async loadThreads() {
|
|
99
|
+
try {
|
|
100
|
+
const data = await fs.readFile(this.threadsFile, "utf-8");
|
|
101
|
+
const threads = JSON.parse(data);
|
|
102
|
+
// Convert date strings back to Date objects
|
|
103
|
+
const result = threads.map((thread) => ({
|
|
104
|
+
...thread,
|
|
105
|
+
createdAt: new Date(thread.createdAt),
|
|
106
|
+
}));
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error.code === "ENOENT") {
|
|
111
|
+
// File doesn't exist yet, return empty array
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Failed to load threads: ${error}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Perform atomic write using temp file
|
|
119
|
+
*
|
|
120
|
+
* This ensures that if the process crashes during write,
|
|
121
|
+
* we don't end up with corrupted or partial data.
|
|
122
|
+
*
|
|
123
|
+
* @param filePath - Target file path
|
|
124
|
+
* @param data - Data to write
|
|
125
|
+
*/
|
|
126
|
+
async atomicWrite(filePath, data) {
|
|
127
|
+
const tempFile = `${filePath}.tmp`;
|
|
128
|
+
try {
|
|
129
|
+
// Ensure directory exists
|
|
130
|
+
await fs.mkdir(dirname(filePath), { recursive: true });
|
|
131
|
+
// Write to temp file
|
|
132
|
+
const jsonData = JSON.stringify(data, null, 2);
|
|
133
|
+
await fs.writeFile(tempFile, jsonData, "utf-8");
|
|
134
|
+
// Atomic rename (overwrites target file)
|
|
135
|
+
await fs.rename(tempFile, filePath);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
// Clean up temp file if it exists
|
|
139
|
+
try {
|
|
140
|
+
await fs.unlink(tempFile);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Ignore cleanup errors
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`Failed to write ${filePath}: ${error}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get the metadata directory path
|
|
150
|
+
*/
|
|
151
|
+
getMetadataDir() {
|
|
152
|
+
return this.metadataDir;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the projects file path
|
|
156
|
+
*/
|
|
157
|
+
getProjectsFile() {
|
|
158
|
+
return this.projectsFile;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get the threads file path
|
|
162
|
+
*/
|
|
163
|
+
getThreadsFile() {
|
|
164
|
+
return this.threadsFile;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Save application state to disk
|
|
168
|
+
* @param state - Application state to save
|
|
169
|
+
*/
|
|
170
|
+
async saveState(state) {
|
|
171
|
+
await this.atomicWrite(this.stateFile, state);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Load application state from disk
|
|
175
|
+
* @returns Application state
|
|
176
|
+
*/
|
|
177
|
+
async loadState() {
|
|
178
|
+
try {
|
|
179
|
+
const data = await fs.readFile(this.stateFile, "utf-8");
|
|
180
|
+
const state = JSON.parse(data);
|
|
181
|
+
// Ensure providerKeys exists
|
|
182
|
+
if (!state.providerKeys) {
|
|
183
|
+
state.providerKeys = {};
|
|
184
|
+
}
|
|
185
|
+
// Ensure enabledModels exists
|
|
186
|
+
if (!state.enabledModels) {
|
|
187
|
+
state.enabledModels = {};
|
|
188
|
+
}
|
|
189
|
+
return state;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error.code === "ENOENT") {
|
|
193
|
+
return { selectedThreadId: null, providerKeys: {}, enabledModels: {} };
|
|
194
|
+
}
|
|
195
|
+
throw new Error(`Failed to load state: ${error}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Update all provider keys at once
|
|
200
|
+
* @param keys - Object mapping provider names to API keys
|
|
201
|
+
*/
|
|
202
|
+
async saveAllProviderKeys(keys) {
|
|
203
|
+
const state = await this.loadState();
|
|
204
|
+
state.providerKeys = { ...state.providerKeys, ...keys };
|
|
205
|
+
await this.saveState(state);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Update provider keys
|
|
209
|
+
* @param providerName - Name of the provider
|
|
210
|
+
* @param apiKey - API key to save
|
|
211
|
+
*/
|
|
212
|
+
async saveProviderKey(providerName, apiKey) {
|
|
213
|
+
const state = await this.loadState();
|
|
214
|
+
state.providerKeys[providerName] = apiKey;
|
|
215
|
+
await this.saveState(state);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get all provider keys
|
|
219
|
+
* @returns Record of provider names to API keys
|
|
220
|
+
*/
|
|
221
|
+
async getProviderKeys() {
|
|
222
|
+
const state = await this.loadState();
|
|
223
|
+
return state.providerKeys;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Set the selected thread ID
|
|
227
|
+
* @param threadId - Thread ID to select (or null to deselect)
|
|
228
|
+
*/
|
|
229
|
+
async setSelectedThread(threadId) {
|
|
230
|
+
const state = await this.loadState();
|
|
231
|
+
state.selectedThreadId = threadId;
|
|
232
|
+
await this.saveState(state);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get the selected thread ID
|
|
236
|
+
* @returns The selected thread ID or null
|
|
237
|
+
*/
|
|
238
|
+
async getSelectedThread() {
|
|
239
|
+
const state = await this.loadState();
|
|
240
|
+
return state.selectedThreadId;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Enable a model for a provider
|
|
244
|
+
* @param provider - Provider name
|
|
245
|
+
* @param modelId - Model ID to enable
|
|
246
|
+
*/
|
|
247
|
+
async enableModel(provider, modelId) {
|
|
248
|
+
const state = await this.loadState();
|
|
249
|
+
if (!state.enabledModels[provider]) {
|
|
250
|
+
state.enabledModels[provider] = [];
|
|
251
|
+
}
|
|
252
|
+
if (!state.enabledModels[provider].includes(modelId)) {
|
|
253
|
+
state.enabledModels[provider].push(modelId);
|
|
254
|
+
}
|
|
255
|
+
await this.saveState(state);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Disable a model for a provider
|
|
259
|
+
* @param provider - Provider name
|
|
260
|
+
* @param modelId - Model ID to disable
|
|
261
|
+
*/
|
|
262
|
+
async disableModel(provider, modelId) {
|
|
263
|
+
const state = await this.loadState();
|
|
264
|
+
if (state.enabledModels[provider]) {
|
|
265
|
+
state.enabledModels[provider] = state.enabledModels[provider].filter((id) => id !== modelId);
|
|
266
|
+
if (state.enabledModels[provider].length === 0) {
|
|
267
|
+
delete state.enabledModels[provider];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
await this.saveState(state);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get enabled models for a provider
|
|
274
|
+
* @param provider - Provider name
|
|
275
|
+
* @returns Array of enabled model IDs
|
|
276
|
+
*/
|
|
277
|
+
async getEnabledModels(provider) {
|
|
278
|
+
const state = await this.loadState();
|
|
279
|
+
return state.enabledModels[provider] || [];
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get all enabled models across all providers
|
|
283
|
+
* @returns Object mapping provider to array of model IDs
|
|
284
|
+
*/
|
|
285
|
+
async getAllEnabledModels() {
|
|
286
|
+
const state = await this.loadState();
|
|
287
|
+
return state.enabledModels;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Set enabled models for a provider
|
|
291
|
+
* @param provider - Provider name
|
|
292
|
+
* @param modelIds - Array of model IDs to enable
|
|
293
|
+
*/
|
|
294
|
+
async setEnabledModels(provider, modelIds) {
|
|
295
|
+
const state = await this.loadState();
|
|
296
|
+
if (modelIds.length === 0) {
|
|
297
|
+
delete state.enabledModels[provider];
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
state.enabledModels[provider] = modelIds;
|
|
301
|
+
}
|
|
302
|
+
await this.saveState(state);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=metadata-manager.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelManager
|
|
3
|
+
*
|
|
4
|
+
* Manages available and enabled models across different providers.
|
|
5
|
+
* Enriches models with pricing (and name/description) from model-info when available (e.g. OpenRouter).
|
|
6
|
+
*/
|
|
7
|
+
import { Model } from '../types/models.js';
|
|
8
|
+
import { MetadataManager } from './metadata-manager.js';
|
|
9
|
+
/**
|
|
10
|
+
* ModelManager handles model availability and selection
|
|
11
|
+
*/
|
|
12
|
+
export declare class ModelManager {
|
|
13
|
+
private metadataManager;
|
|
14
|
+
/**
|
|
15
|
+
* Create a new ModelManager
|
|
16
|
+
* @param metadataManager - MetadataManager instance for persistence
|
|
17
|
+
*/
|
|
18
|
+
constructor(metadataManager: MetadataManager);
|
|
19
|
+
/**
|
|
20
|
+
* Get available models for a provider
|
|
21
|
+
* Enriches with pricing (and name/description) from model-info when available (e.g. OpenRouter).
|
|
22
|
+
* @param provider - Provider name (e.g., "openrouter", "openai")
|
|
23
|
+
* @returns Array of Model objects
|
|
24
|
+
* @throws Error if provider is not supported
|
|
25
|
+
*/
|
|
26
|
+
getAvailableModels(provider: string): Promise<Model[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Get enabled models for a provider
|
|
29
|
+
* @param provider - Provider name
|
|
30
|
+
* @returns Array of Model objects that are enabled
|
|
31
|
+
*/
|
|
32
|
+
getEnabledModels(provider: string): Promise<Model[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get a specific model by ID from a provider
|
|
35
|
+
* @param provider - Provider name
|
|
36
|
+
* @param modelId - Model ID
|
|
37
|
+
* @returns Model object or null if not found
|
|
38
|
+
*/
|
|
39
|
+
getModel(provider: string, modelId: string): Promise<Model | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Enable a model for a provider
|
|
42
|
+
* @param provider - Provider name
|
|
43
|
+
* @param modelId - Model ID to enable
|
|
44
|
+
* @throws Error if model is not found
|
|
45
|
+
*/
|
|
46
|
+
enableModel(provider: string, modelId: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Disable a model for a provider
|
|
49
|
+
* @param provider - Provider name
|
|
50
|
+
* @param modelId - Model ID to disable
|
|
51
|
+
*/
|
|
52
|
+
disableModel(provider: string, modelId: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Get all enabled models across all providers
|
|
55
|
+
* @returns Object mapping provider to array of enabled Models
|
|
56
|
+
*/
|
|
57
|
+
getAllEnabledModels(): Promise<Record<string, Model[]>>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=model-manager.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelManager
|
|
3
|
+
*
|
|
4
|
+
* Manages available and enabled models across different providers.
|
|
5
|
+
* Enriches models with pricing (and name/description) from model-info when available (e.g. OpenRouter).
|
|
6
|
+
*/
|
|
7
|
+
import { PROVIDER_DATA } from '../provider-data.js';
|
|
8
|
+
import { getModelInfoForProvider } from '../model-info.js';
|
|
9
|
+
import { PROVIDERS } from '../provider.js';
|
|
10
|
+
/**
|
|
11
|
+
* ModelManager handles model availability and selection
|
|
12
|
+
*/
|
|
13
|
+
export class ModelManager {
|
|
14
|
+
metadataManager;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new ModelManager
|
|
17
|
+
* @param metadataManager - MetadataManager instance for persistence
|
|
18
|
+
*/
|
|
19
|
+
constructor(metadataManager) {
|
|
20
|
+
this.metadataManager = metadataManager;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get available models for a provider
|
|
24
|
+
* Enriches with pricing (and name/description) from model-info when available (e.g. OpenRouter).
|
|
25
|
+
* @param provider - Provider name (e.g., "openrouter", "openai")
|
|
26
|
+
* @returns Array of Model objects
|
|
27
|
+
* @throws Error if provider is not supported
|
|
28
|
+
*/
|
|
29
|
+
async getAvailableModels(provider) {
|
|
30
|
+
const providerId = provider.toLowerCase();
|
|
31
|
+
const providerData = PROVIDER_DATA.find((p) => p.id === providerId);
|
|
32
|
+
if (!providerData) {
|
|
33
|
+
throw new Error(`Provider "${provider}" is not supported`);
|
|
34
|
+
}
|
|
35
|
+
const modelIds = [...providerData.models];
|
|
36
|
+
// Resolve API key for providers that fetch model info from their API (OpenRouter, AIHubMix)
|
|
37
|
+
let apiKey;
|
|
38
|
+
if (providerId === 'openrouter') {
|
|
39
|
+
const keys = await this.metadataManager.getProviderKeys();
|
|
40
|
+
const openRouterProvider = PROVIDERS.find((p) => p.name === 'OpenRouter');
|
|
41
|
+
apiKey =
|
|
42
|
+
keys['OpenRouter'] ??
|
|
43
|
+
(openRouterProvider?.keyName ? process.env[openRouterProvider.keyName] : undefined);
|
|
44
|
+
}
|
|
45
|
+
else if (providerId === 'aihubmix') {
|
|
46
|
+
const keys = await this.metadataManager.getProviderKeys();
|
|
47
|
+
const aiHubMixProvider = PROVIDERS.find((p) => p.name === 'AIHubMix');
|
|
48
|
+
apiKey =
|
|
49
|
+
keys['AIHubMix'] ??
|
|
50
|
+
(aiHubMixProvider?.keyName ? process.env[aiHubMixProvider.keyName] : undefined);
|
|
51
|
+
}
|
|
52
|
+
const infoMap = await getModelInfoForProvider(providerId, modelIds, apiKey);
|
|
53
|
+
return modelIds.map((modelId) => {
|
|
54
|
+
const info = infoMap.get(modelId);
|
|
55
|
+
return {
|
|
56
|
+
id: modelId,
|
|
57
|
+
name: info?.name ?? modelId,
|
|
58
|
+
description: info?.description ?? `${provider} model: ${modelId}`,
|
|
59
|
+
provider: providerId,
|
|
60
|
+
pricing: info?.pricing,
|
|
61
|
+
supportedParameters: info?.supportedParameters,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get enabled models for a provider
|
|
67
|
+
* @param provider - Provider name
|
|
68
|
+
* @returns Array of Model objects that are enabled
|
|
69
|
+
*/
|
|
70
|
+
async getEnabledModels(provider) {
|
|
71
|
+
const enabledModelIds = await this.metadataManager.getEnabledModels(provider);
|
|
72
|
+
if (enabledModelIds.length === 0) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const availableModels = await this.getAvailableModels(provider);
|
|
77
|
+
return availableModels.filter((model) => enabledModelIds.includes(model.id));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// If we can't fetch available models, return empty
|
|
81
|
+
console.error(`Failed to get enabled models for ${provider}:`, error);
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get a specific model by ID from a provider
|
|
87
|
+
* @param provider - Provider name
|
|
88
|
+
* @param modelId - Model ID
|
|
89
|
+
* @returns Model object or null if not found
|
|
90
|
+
*/
|
|
91
|
+
async getModel(provider, modelId) {
|
|
92
|
+
try {
|
|
93
|
+
const availableModels = await this.getAvailableModels(provider);
|
|
94
|
+
return availableModels.find((m) => m.id === modelId) || null;
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error(`Failed to get model ${modelId} from ${provider}:`, error);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Enable a model for a provider
|
|
103
|
+
* @param provider - Provider name
|
|
104
|
+
* @param modelId - Model ID to enable
|
|
105
|
+
* @throws Error if model is not found
|
|
106
|
+
*/
|
|
107
|
+
async enableModel(provider, modelId) {
|
|
108
|
+
// Verify the model exists
|
|
109
|
+
const model = await this.getModel(provider, modelId);
|
|
110
|
+
if (!model) {
|
|
111
|
+
throw new Error(`Model "${modelId}" not found in provider "${provider}"`);
|
|
112
|
+
}
|
|
113
|
+
await this.metadataManager.enableModel(provider, modelId);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Disable a model for a provider
|
|
117
|
+
* @param provider - Provider name
|
|
118
|
+
* @param modelId - Model ID to disable
|
|
119
|
+
*/
|
|
120
|
+
async disableModel(provider, modelId) {
|
|
121
|
+
await this.metadataManager.disableModel(provider, modelId);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all enabled models across all providers
|
|
125
|
+
* @returns Object mapping provider to array of enabled Models
|
|
126
|
+
*/
|
|
127
|
+
async getAllEnabledModels() {
|
|
128
|
+
const enabledByProvider = await this.metadataManager.getAllEnabledModels();
|
|
129
|
+
const result = {};
|
|
130
|
+
for (const provider of Object.keys(enabledByProvider)) {
|
|
131
|
+
try {
|
|
132
|
+
const models = await this.getEnabledModels(provider);
|
|
133
|
+
if (models.length > 0) {
|
|
134
|
+
result[provider] = models;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
console.error(`Failed to get enabled models for ${provider}:`, error);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=model-manager.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeovateExecutor handles execution of neovate commands via the @neovate/code SDK
|
|
3
|
+
*
|
|
4
|
+
* This manager is responsible for:
|
|
5
|
+
* - Executing streaming sessions via the SDK
|
|
6
|
+
* - Streaming result messages back to the caller
|
|
7
|
+
* - Handling execution errors
|
|
8
|
+
*/
|
|
9
|
+
import { NeovateEvent, ExecutionContext } from "../types/models.js";
|
|
10
|
+
import { MetadataManager } from "./metadata-manager.js";
|
|
11
|
+
/**
|
|
12
|
+
* NeovateExecutor interface defines the contract for neovate command execution
|
|
13
|
+
*/
|
|
14
|
+
export interface NeovateExecutor {
|
|
15
|
+
/**
|
|
16
|
+
* Executes a neovate command with the given prompt and context
|
|
17
|
+
* @param prompt - The user's message/prompt to send to neovate
|
|
18
|
+
* @param context - ExecutionContext containing thread info and options
|
|
19
|
+
* @yields NeovateEvent objects for system, message, result, and error events
|
|
20
|
+
*/
|
|
21
|
+
execute(prompt: string, context: ExecutionContext): AsyncGenerator<NeovateEvent>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* NeovateExecutorImpl provides the implementation for neovate command execution
|
|
25
|
+
* using the @neovate/code SDK with streaming sessions.
|
|
26
|
+
*/
|
|
27
|
+
export declare class NeovateExecutorImpl implements NeovateExecutor {
|
|
28
|
+
private metadataManager;
|
|
29
|
+
constructor(metadataManager: MetadataManager);
|
|
30
|
+
/**
|
|
31
|
+
* Executes a neovate prompt using the SDK via streaming sessions
|
|
32
|
+
*
|
|
33
|
+
* @param userPrompt - The user's message/prompt to send to neovate
|
|
34
|
+
* @param context - ExecutionContext with threadId, threadPath, model, and attachments
|
|
35
|
+
* @yields NeovateEvent objects for message, result, and error events
|
|
36
|
+
*
|
|
37
|
+
* Requirements:
|
|
38
|
+
* - 5.2 - WHEN the CLI receives a chat message, THE CLI SHALL execute the Neovate command
|
|
39
|
+
* - 5.4 - WHEN the Neovate command executes, THE CLI SHALL stream the output back to the App
|
|
40
|
+
*/
|
|
41
|
+
execute(userPrompt: string, context: ExecutionContext): AsyncGenerator<NeovateEvent>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=neovate-executor.d.ts.map
|