nova-terminal-assistant 0.1.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.
Potentially problematic release.
This version of nova-terminal-assistant might be problematic. Click here for more details.
- package/README.md +358 -0
- package/bin/nova +38 -0
- package/bin/nova.js +12 -0
- package/package.json +67 -0
- package/src/cli/commands/SmartCompletion.ts +458 -0
- package/src/cli/index.ts +5 -0
- package/src/cli/startup/IFlowRepl.ts +212 -0
- package/src/cli/startup/InkBasedRepl.ts +1056 -0
- package/src/cli/startup/InteractiveRepl.ts +2833 -0
- package/src/cli/startup/NovaApp.ts +1861 -0
- package/src/cli/startup/index.ts +4 -0
- package/src/cli/startup/parseArgs.ts +293 -0
- package/src/cli/test-modules.ts +27 -0
- package/src/cli/ui/IFlowDropdown.ts +425 -0
- package/src/cli/ui/ModernReplUI.ts +276 -0
- package/src/cli/ui/SimpleSelector2.ts +215 -0
- package/src/cli/ui/components/ConfirmDialog.ts +176 -0
- package/src/cli/ui/components/ErrorPanel.ts +364 -0
- package/src/cli/ui/components/InkAppRunner.tsx +67 -0
- package/src/cli/ui/components/InkComponents.tsx +613 -0
- package/src/cli/ui/components/NovaInkApp.tsx +312 -0
- package/src/cli/ui/components/ProgressBar.ts +177 -0
- package/src/cli/ui/components/ProgressIndicator.ts +298 -0
- package/src/cli/ui/components/QuickActions.ts +396 -0
- package/src/cli/ui/components/SimpleErrorPanel.ts +231 -0
- package/src/cli/ui/components/StatusBar.ts +194 -0
- package/src/cli/ui/components/ThinkingBlockRenderer.ts +401 -0
- package/src/cli/ui/components/index.ts +27 -0
- package/src/cli/ui/ink-prototype.tsx +347 -0
- package/src/cli/utils/CliUI.ts +336 -0
- package/src/cli/utils/CompletionHelper.ts +388 -0
- package/src/cli/utils/EnhancedCompleter.test.ts +226 -0
- package/src/cli/utils/EnhancedCompleter.ts +513 -0
- package/src/cli/utils/ErrorEnhancer.ts +429 -0
- package/src/cli/utils/OutputFormatter.ts +193 -0
- package/src/cli/utils/index.ts +9 -0
- package/src/core/agents/AgentOrchestrator.ts +515 -0
- package/src/core/agents/index.ts +17 -0
- package/src/core/audit/AuditLogger.ts +509 -0
- package/src/core/audit/index.ts +11 -0
- package/src/core/auth/AuthManager.d.ts.map +1 -0
- package/src/core/auth/AuthManager.ts +138 -0
- package/src/core/auth/index.d.ts.map +1 -0
- package/src/core/auth/index.ts +2 -0
- package/src/core/config/ConfigManager.d.ts.map +1 -0
- package/src/core/config/ConfigManager.test.ts +183 -0
- package/src/core/config/ConfigManager.ts +1219 -0
- package/src/core/config/index.d.ts.map +1 -0
- package/src/core/config/index.ts +1 -0
- package/src/core/context/ContextBuilder.d.ts.map +1 -0
- package/src/core/context/ContextBuilder.ts +171 -0
- package/src/core/context/ContextCompressor.d.ts.map +1 -0
- package/src/core/context/ContextCompressor.ts +642 -0
- package/src/core/context/LayeredMemoryManager.ts +657 -0
- package/src/core/context/MemoryDiscovery.d.ts.map +1 -0
- package/src/core/context/MemoryDiscovery.ts +175 -0
- package/src/core/context/defaultSystemPrompt.d.ts.map +1 -0
- package/src/core/context/defaultSystemPrompt.ts +35 -0
- package/src/core/context/index.d.ts.map +1 -0
- package/src/core/context/index.ts +22 -0
- package/src/core/extensions/SkillGenerator.ts +421 -0
- package/src/core/extensions/SkillInstaller.d.ts.map +1 -0
- package/src/core/extensions/SkillInstaller.ts +257 -0
- package/src/core/extensions/SkillRegistry.d.ts.map +1 -0
- package/src/core/extensions/SkillRegistry.ts +361 -0
- package/src/core/extensions/SkillValidator.ts +525 -0
- package/src/core/extensions/index.ts +15 -0
- package/src/core/index.d.ts.map +1 -0
- package/src/core/index.ts +42 -0
- package/src/core/mcp/McpManager.d.ts.map +1 -0
- package/src/core/mcp/McpManager.ts +632 -0
- package/src/core/mcp/index.d.ts.map +1 -0
- package/src/core/mcp/index.ts +2 -0
- package/src/core/model/ModelClient.d.ts.map +1 -0
- package/src/core/model/ModelClient.ts +217 -0
- package/src/core/model/ModelConnectionTester.ts +363 -0
- package/src/core/model/ModelValidator.ts +348 -0
- package/src/core/model/index.d.ts.map +1 -0
- package/src/core/model/index.ts +6 -0
- package/src/core/model/providers/AnthropicProvider.d.ts.map +1 -0
- package/src/core/model/providers/AnthropicProvider.ts +279 -0
- package/src/core/model/providers/CodingPlanProvider.d.ts.map +1 -0
- package/src/core/model/providers/CodingPlanProvider.ts +210 -0
- package/src/core/model/providers/OllamaCloudProvider.d.ts.map +1 -0
- package/src/core/model/providers/OllamaCloudProvider.ts +405 -0
- package/src/core/model/providers/OllamaManager.d.ts.map +1 -0
- package/src/core/model/providers/OllamaManager.ts +201 -0
- package/src/core/model/providers/OllamaProvider.d.ts.map +1 -0
- package/src/core/model/providers/OllamaProvider.ts +73 -0
- package/src/core/model/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/src/core/model/providers/OpenAICompatibleProvider.ts +327 -0
- package/src/core/model/providers/OpenAIProvider.d.ts.map +1 -0
- package/src/core/model/providers/OpenAIProvider.ts +29 -0
- package/src/core/model/providers/index.d.ts.map +1 -0
- package/src/core/model/providers/index.ts +12 -0
- package/src/core/model/types.d.ts.map +1 -0
- package/src/core/model/types.ts +77 -0
- package/src/core/security/ApprovalManager.d.ts.map +1 -0
- package/src/core/security/ApprovalManager.ts +174 -0
- package/src/core/security/FileFilter.d.ts.map +1 -0
- package/src/core/security/FileFilter.ts +141 -0
- package/src/core/security/HookExecutor.d.ts.map +1 -0
- package/src/core/security/HookExecutor.ts +178 -0
- package/src/core/security/SandboxExecutor.ts +447 -0
- package/src/core/security/index.d.ts.map +1 -0
- package/src/core/security/index.ts +8 -0
- package/src/core/session/AgentLoop.d.ts.map +1 -0
- package/src/core/session/AgentLoop.ts +501 -0
- package/src/core/session/SessionManager.d.ts.map +1 -0
- package/src/core/session/SessionManager.test.ts +183 -0
- package/src/core/session/SessionManager.ts +460 -0
- package/src/core/session/index.d.ts.map +1 -0
- package/src/core/session/index.ts +3 -0
- package/src/core/telemetry/Telemetry.d.ts.map +1 -0
- package/src/core/telemetry/Telemetry.ts +90 -0
- package/src/core/telemetry/TelemetryService.ts +531 -0
- package/src/core/telemetry/index.d.ts.map +1 -0
- package/src/core/telemetry/index.ts +12 -0
- package/src/core/testing/AutoFixer.ts +385 -0
- package/src/core/testing/ErrorAnalyzer.ts +499 -0
- package/src/core/testing/TestRunner.ts +265 -0
- package/src/core/testing/agent-cli-tests.ts +538 -0
- package/src/core/testing/index.ts +11 -0
- package/src/core/tools/ToolRegistry.d.ts.map +1 -0
- package/src/core/tools/ToolRegistry.test.ts +206 -0
- package/src/core/tools/ToolRegistry.ts +260 -0
- package/src/core/tools/impl/EditFileTool.d.ts.map +1 -0
- package/src/core/tools/impl/EditFileTool.ts +97 -0
- package/src/core/tools/impl/ListDirectoryTool.d.ts.map +1 -0
- package/src/core/tools/impl/ListDirectoryTool.ts +142 -0
- package/src/core/tools/impl/MemoryTool.d.ts.map +1 -0
- package/src/core/tools/impl/MemoryTool.ts +102 -0
- package/src/core/tools/impl/ReadFileTool.d.ts.map +1 -0
- package/src/core/tools/impl/ReadFileTool.ts +58 -0
- package/src/core/tools/impl/SearchContentTool.d.ts.map +1 -0
- package/src/core/tools/impl/SearchContentTool.ts +94 -0
- package/src/core/tools/impl/SearchFileTool.d.ts.map +1 -0
- package/src/core/tools/impl/SearchFileTool.ts +61 -0
- package/src/core/tools/impl/ShellTool.d.ts.map +1 -0
- package/src/core/tools/impl/ShellTool.ts +118 -0
- package/src/core/tools/impl/TaskTool.d.ts.map +1 -0
- package/src/core/tools/impl/TaskTool.ts +207 -0
- package/src/core/tools/impl/TodoTool.d.ts.map +1 -0
- package/src/core/tools/impl/TodoTool.ts +122 -0
- package/src/core/tools/impl/WebFetchTool.d.ts.map +1 -0
- package/src/core/tools/impl/WebFetchTool.ts +103 -0
- package/src/core/tools/impl/WebSearchTool.d.ts.map +1 -0
- package/src/core/tools/impl/WebSearchTool.ts +89 -0
- package/src/core/tools/impl/WriteFileTool.d.ts.map +1 -0
- package/src/core/tools/impl/WriteFileTool.ts +49 -0
- package/src/core/tools/impl/index.d.ts.map +1 -0
- package/src/core/tools/impl/index.ts +16 -0
- package/src/core/tools/index.d.ts.map +1 -0
- package/src/core/tools/index.ts +7 -0
- package/src/core/tools/schemas/execution.d.ts.map +1 -0
- package/src/core/tools/schemas/execution.ts +42 -0
- package/src/core/tools/schemas/file.d.ts.map +1 -0
- package/src/core/tools/schemas/file.ts +119 -0
- package/src/core/tools/schemas/index.d.ts.map +1 -0
- package/src/core/tools/schemas/index.ts +11 -0
- package/src/core/tools/schemas/memory.d.ts.map +1 -0
- package/src/core/tools/schemas/memory.ts +52 -0
- package/src/core/tools/schemas/orchestration.d.ts.map +1 -0
- package/src/core/tools/schemas/orchestration.ts +44 -0
- package/src/core/tools/schemas/search.d.ts.map +1 -0
- package/src/core/tools/schemas/search.ts +112 -0
- package/src/core/tools/schemas/todo.d.ts.map +1 -0
- package/src/core/tools/schemas/todo.ts +32 -0
- package/src/core/tools/schemas/web.d.ts.map +1 -0
- package/src/core/tools/schemas/web.ts +86 -0
- package/src/core/types/config.d.ts.map +1 -0
- package/src/core/types/config.ts +200 -0
- package/src/core/types/errors.d.ts.map +1 -0
- package/src/core/types/errors.ts +204 -0
- package/src/core/types/index.d.ts.map +1 -0
- package/src/core/types/index.ts +8 -0
- package/src/core/types/session.d.ts.map +1 -0
- package/src/core/types/session.ts +216 -0
- package/src/core/types/tools.d.ts.map +1 -0
- package/src/core/types/tools.ts +157 -0
- package/src/core/utils/CheckpointManager.d.ts.map +1 -0
- package/src/core/utils/CheckpointManager.ts +327 -0
- package/src/core/utils/Logger.d.ts.map +1 -0
- package/src/core/utils/Logger.ts +98 -0
- package/src/core/utils/RetryManager.ts +471 -0
- package/src/core/utils/TokenCounter.d.ts.map +1 -0
- package/src/core/utils/TokenCounter.ts +414 -0
- package/src/core/utils/VectorMemoryStore.ts +440 -0
- package/src/core/utils/helpers.d.ts.map +1 -0
- package/src/core/utils/helpers.ts +89 -0
- package/src/core/utils/index.d.ts.map +1 -0
- package/src/core/utils/index.ts +19 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// OllamaManager - Ollama native API wrapper for model management
|
|
3
|
+
// ============================================================================
|
|
4
|
+
//
|
|
5
|
+
// Wraps Ollama's REST API for operations beyond simple chat completion:
|
|
6
|
+
// - List/pull/delete/show local models
|
|
7
|
+
// - Check Ollama server status and version
|
|
8
|
+
// - Runtime model discovery and auto-registration
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
import type { ModelConfig } from '../../types/config.js';
|
|
12
|
+
|
|
13
|
+
/** A model entry from Ollama's /api/tags */
|
|
14
|
+
export interface OllamaModel {
|
|
15
|
+
name: string;
|
|
16
|
+
model: string;
|
|
17
|
+
modified_at: string;
|
|
18
|
+
size: number;
|
|
19
|
+
digest: string;
|
|
20
|
+
details: {
|
|
21
|
+
parent_model?: string;
|
|
22
|
+
format: string;
|
|
23
|
+
family: string;
|
|
24
|
+
families?: string[];
|
|
25
|
+
parameter_size: string;
|
|
26
|
+
quantization_level: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Progress info for model pull operations */
|
|
31
|
+
export interface OllamaPullProgress {
|
|
32
|
+
status: string;
|
|
33
|
+
digest?: string;
|
|
34
|
+
total?: number;
|
|
35
|
+
completed?: number;
|
|
36
|
+
percent?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Model info from Ollama's /api/show */
|
|
40
|
+
export interface OllamaModelInfo {
|
|
41
|
+
license?: string;
|
|
42
|
+
modelfile?: string;
|
|
43
|
+
parameters?: string;
|
|
44
|
+
template?: string;
|
|
45
|
+
details: {
|
|
46
|
+
parent_model?: string;
|
|
47
|
+
format: string;
|
|
48
|
+
family: string;
|
|
49
|
+
families?: string[];
|
|
50
|
+
parameter_size: string;
|
|
51
|
+
quantization_level: string;
|
|
52
|
+
};
|
|
53
|
+
model_info?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Result from Ollama's /api/version */
|
|
57
|
+
export interface OllamaVersion {
|
|
58
|
+
version: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class OllamaManager {
|
|
62
|
+
private baseUrl: string;
|
|
63
|
+
private timeout: number;
|
|
64
|
+
|
|
65
|
+
constructor(baseUrl?: string, timeoutMs = 30000) {
|
|
66
|
+
this.baseUrl = (baseUrl || 'http://localhost:11434').replace(/\/+$/, '');
|
|
67
|
+
this.timeout = timeoutMs;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Check if Ollama server is running */
|
|
71
|
+
async ping(): Promise<boolean> {
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch(`${this.baseUrl}/api/tags`, {
|
|
74
|
+
signal: AbortSignal.timeout(5000),
|
|
75
|
+
});
|
|
76
|
+
return res.ok;
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Get Ollama server version */
|
|
83
|
+
async version(): Promise<string> {
|
|
84
|
+
const res = await this.request<{ version: string }>('/api/version', undefined, 'GET');
|
|
85
|
+
return res.version;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** List all locally installed models */
|
|
89
|
+
async listModels(): Promise<OllamaModel[]> {
|
|
90
|
+
const res = await this.request<{ models: OllamaModel[] }>('/api/tags', undefined, 'GET');
|
|
91
|
+
return res.models || [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Show detailed info about a model */
|
|
95
|
+
async showModel(name: string): Promise<OllamaModelInfo> {
|
|
96
|
+
return this.request<OllamaModelInfo>('/api/show', { name }, 'POST');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Pull a model from Ollama Hub. Calls onProgress periodically with download status.
|
|
101
|
+
* Returns when the pull is complete.
|
|
102
|
+
*/
|
|
103
|
+
async pullModel(name: string, onProgress?: (progress: OllamaPullProgress) => void): Promise<void> {
|
|
104
|
+
const res = await fetch(`${this.baseUrl}/api/pull`, {
|
|
105
|
+
method: 'POST',
|
|
106
|
+
headers: { 'Content-Type': 'application/json' },
|
|
107
|
+
body: JSON.stringify({ name, stream: true }),
|
|
108
|
+
signal: AbortSignal.timeout(this.timeout * 60), // Pull can take a long time
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!res.ok) {
|
|
112
|
+
throw new Error(`Ollama pull failed: ${res.status} ${res.statusText}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const reader = res.body?.getReader();
|
|
116
|
+
if (!reader) throw new Error('No response body');
|
|
117
|
+
|
|
118
|
+
const decoder = new TextDecoder();
|
|
119
|
+
let buffer = '';
|
|
120
|
+
|
|
121
|
+
while (true) {
|
|
122
|
+
const { done, value } = await reader.read();
|
|
123
|
+
if (done) break;
|
|
124
|
+
|
|
125
|
+
buffer += decoder.decode(value, { stream: true });
|
|
126
|
+
const lines = buffer.split('\n');
|
|
127
|
+
buffer = lines.pop() || '';
|
|
128
|
+
|
|
129
|
+
for (const line of lines) {
|
|
130
|
+
if (!line.trim()) continue;
|
|
131
|
+
try {
|
|
132
|
+
const progress: OllamaPullProgress = JSON.parse(line);
|
|
133
|
+
if (onProgress) onProgress(progress);
|
|
134
|
+
} catch {
|
|
135
|
+
// Skip malformed lines
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Delete a locally installed model */
|
|
142
|
+
async deleteModel(name: string): Promise<void> {
|
|
143
|
+
const res = await this.request<{ status: string }>('/api/delete', { name }, 'DELETE');
|
|
144
|
+
// Some Ollama versions return empty body for DELETE
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Convert Ollama models to Nova ModelConfig for auto-registration.
|
|
149
|
+
* Attempts to infer capabilities from model metadata.
|
|
150
|
+
*/
|
|
151
|
+
toModelConfig(model: OllamaModel): ModelConfig {
|
|
152
|
+
const paramSize = model.details?.parameter_size || '';
|
|
153
|
+
const isLarge = paramSize.includes('70B') || paramSize.includes('72B') || paramSize.includes('65B');
|
|
154
|
+
const isMedium = paramSize.includes('32B') || paramSize.includes('34B') || paramSize.includes('14B');
|
|
155
|
+
|
|
156
|
+
// Estimate context window from model family
|
|
157
|
+
let contextTokens = 8192;
|
|
158
|
+
const family = (model.details?.family || '').toLowerCase();
|
|
159
|
+
if (family.includes('qwen')) contextTokens = 131072;
|
|
160
|
+
else if (family.includes('llama')) contextTokens = isLarge ? 131072 : 128000;
|
|
161
|
+
else if (family.includes('deepseek')) contextTokens = 128000;
|
|
162
|
+
else if (family.includes('mistral')) contextTokens = isLarge ? 131072 : 32768;
|
|
163
|
+
else if (family.includes('gemma')) contextTokens = isMedium ? 8192 : 128000;
|
|
164
|
+
else contextTokens = isLarge ? 131072 : 32768;
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
name: model.name,
|
|
168
|
+
maxContextTokens: contextTokens,
|
|
169
|
+
maxOutputTokens: Math.min(contextTokens, isLarge ? 8192 : 4096),
|
|
170
|
+
supportsVision: family.includes('llava') || family.includes('qwen-vl'),
|
|
171
|
+
supportsTools: true, // Most models support tools via Ollama's OpenAI compat
|
|
172
|
+
supportsStreaming: true,
|
|
173
|
+
supportsThinking: false,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// --- Private helpers ---
|
|
178
|
+
|
|
179
|
+
private async request<T>(path: string, body?: Record<string, unknown>, method = 'POST'): Promise<T> {
|
|
180
|
+
const url = `${this.baseUrl}${path}`;
|
|
181
|
+
const options: RequestInit = {
|
|
182
|
+
method,
|
|
183
|
+
headers: { 'Content-Type': 'application/json' },
|
|
184
|
+
signal: AbortSignal.timeout(this.timeout),
|
|
185
|
+
};
|
|
186
|
+
if (body && method !== 'GET') {
|
|
187
|
+
options.body = JSON.stringify(body);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const res = await fetch(url, options);
|
|
191
|
+
if (!res.ok) {
|
|
192
|
+
const text = await res.text().catch(() => '');
|
|
193
|
+
throw new Error(`Ollama API error ${res.status}: ${text || res.statusText}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Some endpoints return empty body (e.g., DELETE)
|
|
197
|
+
const text = await res.text();
|
|
198
|
+
if (!text) return {} as T;
|
|
199
|
+
return JSON.parse(text);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OllamaProvider.d.ts","sourceRoot":"","sources":["OllamaProvider.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,qBAAa,cAAe,SAAQ,wBAAwB;IAC1D,QAAQ,CAAC,IAAI,YAAY;gBAEb,MAAM,EAAE,oBAAoB;IAUxC;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE;IAiBjF,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK;IAS5E,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO;CAQzC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Ollama Provider - Local LLM via Ollama OpenAI-compatible API
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Refactored: now extends OpenAICompatibleProvider base class.
|
|
5
|
+
// Handles Ollama-specific concerns: no API key, /v1 suffix, friendly error hints.
|
|
6
|
+
// ============================================================================
|
|
7
|
+
|
|
8
|
+
import type { OpenAICompatibleConfig } from './OpenAICompatibleProvider.js';
|
|
9
|
+
import { OpenAICompatibleProvider } from './OpenAICompatibleProvider.js';
|
|
10
|
+
import type { ToolDefinition } from '../../types/tools.js';
|
|
11
|
+
|
|
12
|
+
export interface OllamaProviderConfig {
|
|
13
|
+
/** Base URL for Ollama, defaults to http://localhost:11434 */
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/** Model name (e.g., llama3, codellama, mistral) */
|
|
16
|
+
model: string;
|
|
17
|
+
/** Custom headers */
|
|
18
|
+
headers?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class OllamaProvider extends OpenAICompatibleProvider {
|
|
22
|
+
readonly name = 'Ollama';
|
|
23
|
+
|
|
24
|
+
constructor(config: OllamaProviderConfig) {
|
|
25
|
+
super({
|
|
26
|
+
apiKey: 'ollama', // Ollama doesn't require a real API key
|
|
27
|
+
baseUrl: config.baseUrl || 'http://localhost:11434',
|
|
28
|
+
model: config.model,
|
|
29
|
+
headers: config.headers,
|
|
30
|
+
appendV1Suffix: true, // Ollama needs /v1 appended to baseUrl
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Ollama: whitelist-based tools filtering.
|
|
36
|
+
* Many Ollama models (e.g., deepseek-r1) do not support function calling.
|
|
37
|
+
* Only well-known tool-capable model families get tools passed through.
|
|
38
|
+
*/
|
|
39
|
+
protected filterTools(tools: ToolDefinition[], modelId: string): ToolDefinition[] {
|
|
40
|
+
if (tools.length === 0) return tools;
|
|
41
|
+
|
|
42
|
+
const modelLower = modelId.toLowerCase();
|
|
43
|
+
const toolCapable = [
|
|
44
|
+
'llama3', 'llama3.1', 'llama3.2', 'llama3.3',
|
|
45
|
+
'qwen2.5', 'qwen2', 'mistral', 'mixtral',
|
|
46
|
+
'gemma2', 'gemma3', 'codellama',
|
|
47
|
+
'phi3', 'phi4', 'command-r',
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (!toolCapable.some(p => modelLower.includes(p))) {
|
|
51
|
+
return []; // Strip tools for unknown/unsupported models
|
|
52
|
+
}
|
|
53
|
+
return tools;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected handleError(err: unknown, operation: 'complete' | 'stream'): never {
|
|
57
|
+
const msg = (err as Error).message || String(err);
|
|
58
|
+
const hint = msg.includes('ECONNREFUSED') || msg.includes('connect')
|
|
59
|
+
? ' Is Ollama running? Try `ollama serve` or check https://ollama.com for installation.'
|
|
60
|
+
: '';
|
|
61
|
+
const enhanced = new Error(`${msg}.${hint}`);
|
|
62
|
+
super.handleError(enhanced, operation);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected handleStreamError(err: unknown) {
|
|
66
|
+
const msg = (err as Error).message || String(err);
|
|
67
|
+
const hint = msg.includes('ECONNREFUSED') || msg.includes('connect')
|
|
68
|
+
? ' Is Ollama running? Try `ollama serve` or check https://ollama.com for installation.'
|
|
69
|
+
: '';
|
|
70
|
+
const enhanced = new Error(`${msg}.${hint}`);
|
|
71
|
+
return super.handleStreamError(enhanced);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAICompatibleProvider.d.ts","sourceRoot":"","sources":["OpenAICompatibleProvider.ts"],"names":[],"mappings":"AAWA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAqC,MAAM,wBAAwB,CAAC;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI9G,sEAAsE;AACtE,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,8BAAsB,wBAAyB,YAAW,aAAa;IACrE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE,sBAAsB;IAe1C;;;OAGG;IACH,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK;IAgB5E,2DAA2D;IAC3D,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW;IAetD;;;;;;OAMG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE;IAM3E,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IA+BlF,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,mBAAmB,GAAG,cAAc,CAAC,WAAW,CAAC;IA4DvF,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAYvD,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,0BAA0B,EAAE;IAsD1G,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,kBAAkB,EAAE;IAW5E,SAAS,CAAC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,YAAY,EAAE;IA2BtF,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,eAAe,GAAG,SAAS,GAAG,UAAU;IAO7E,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,CAAC,YAAY,CAAC;IAU3F;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAatC"}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// OpenAICompatibleProvider - Base class for all OpenAI-compatible providers
|
|
3
|
+
// ============================================================================
|
|
4
|
+
//
|
|
5
|
+
// This base class handles all shared logic for providers that use the OpenAI
|
|
6
|
+
// SDK with an OpenAI-compatible API endpoint. Subclasses only need to define:
|
|
7
|
+
// - Provider name
|
|
8
|
+
// - Constructor (how to create the OpenAI client)
|
|
9
|
+
// - Error handling specifics (provider name in error messages)
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
import OpenAI from 'openai';
|
|
13
|
+
import type { Message, ContentBlock, ToolUseContent, ToolResultContent } from '../../types/session.js';
|
|
14
|
+
import type { ToolDefinition } from '../../types/tools.js';
|
|
15
|
+
import type { ModelProvider, ModelRequestOptions, ModelResponse, TokenUsage, StreamEvent } from '../types.js';
|
|
16
|
+
import { ModelError, RateLimitError } from '../../types/errors.js';
|
|
17
|
+
import { createToolCallId } from '../../types/session.js';
|
|
18
|
+
|
|
19
|
+
/** Configuration options shared by all OpenAI-compatible providers */
|
|
20
|
+
export interface OpenAICompatibleConfig {
|
|
21
|
+
apiKey?: string;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
model: string;
|
|
24
|
+
organizationId?: string;
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
/** Append /v1 suffix to baseUrl (needed by Ollama) */
|
|
27
|
+
appendV1Suffix?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export abstract class OpenAICompatibleProvider implements ModelProvider {
|
|
31
|
+
abstract readonly name: string;
|
|
32
|
+
protected client: OpenAI;
|
|
33
|
+
|
|
34
|
+
constructor(config: OpenAICompatibleConfig) {
|
|
35
|
+
let baseURL = config.baseUrl;
|
|
36
|
+
if (baseURL && config.appendV1Suffix) {
|
|
37
|
+
baseURL = baseURL.replace(/\/+$/, '') + '/v1';
|
|
38
|
+
}
|
|
39
|
+
this.client = new OpenAI({
|
|
40
|
+
apiKey: config.apiKey || 'no-key-required',
|
|
41
|
+
baseURL,
|
|
42
|
+
...(config.organizationId && { organization: config.organizationId }),
|
|
43
|
+
...(config.headers && { defaultHeaders: config.headers }),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- Provider-specific hooks ---
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Override to customize the error handling in complete()
|
|
51
|
+
* Subclasses should call super.handleError(err, operation) after wrapping the error.
|
|
52
|
+
*/
|
|
53
|
+
protected handleError(err: unknown, operation: 'complete' | 'stream'): never {
|
|
54
|
+
if (err instanceof OpenAI.APIError) {
|
|
55
|
+
if (err.status === 429) {
|
|
56
|
+
const retryAfter = parseInt(err.headers?.['retry-after'] || '60', 10) * 1000;
|
|
57
|
+
throw new RateLimitError(err.message, retryAfter, this.name);
|
|
58
|
+
}
|
|
59
|
+
throw new ModelError(err.message, err.status, this.name, err);
|
|
60
|
+
}
|
|
61
|
+
throw new ModelError(
|
|
62
|
+
`${this.name} ${operation} failed: ${(err as Error).message}`,
|
|
63
|
+
undefined,
|
|
64
|
+
this.name,
|
|
65
|
+
{ originalError: err }
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Override to customize the error handling in stream() */
|
|
70
|
+
protected handleStreamError(err: unknown): StreamEvent {
|
|
71
|
+
if (err instanceof OpenAI.APIError) {
|
|
72
|
+
return { type: 'error', error: new ModelError(err.message, err.status, this.name, err) };
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
type: 'error',
|
|
76
|
+
error: new ModelError(
|
|
77
|
+
`${this.name} stream failed: ${(err as Error).message}`,
|
|
78
|
+
undefined,
|
|
79
|
+
this.name,
|
|
80
|
+
{ originalError: err }
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Hook to filter or disable tools before sending to the API.
|
|
87
|
+
* Override in subclasses to conditionally disable tools (e.g., for models that don't support them).
|
|
88
|
+
* Default implementation passes tools through unchanged.
|
|
89
|
+
* @param tools - The tool definitions to filter
|
|
90
|
+
* @param modelId - The model ID being called (useful for per-model decisions)
|
|
91
|
+
*/
|
|
92
|
+
protected filterTools(tools: ToolDefinition[], modelId: string): ToolDefinition[] {
|
|
93
|
+
return tools;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// --- Shared implementations ---
|
|
97
|
+
|
|
98
|
+
async complete(messages: Message[], options: ModelRequestOptions): Promise<ModelResponse> {
|
|
99
|
+
try {
|
|
100
|
+
const openaiMessages = this.convertMessages(messages, options.systemPrompt);
|
|
101
|
+
const tools = this.convertTools(this.filterTools(options.tools, options.model));
|
|
102
|
+
|
|
103
|
+
const params: OpenAI.ChatCompletionCreateParams = {
|
|
104
|
+
model: options.model,
|
|
105
|
+
max_tokens: options.maxTokens,
|
|
106
|
+
messages: openaiMessages,
|
|
107
|
+
temperature: options.temperature,
|
|
108
|
+
...(tools.length > 0 && { tools }),
|
|
109
|
+
...(options.stopSequences && options.stopSequences.length > 0 && { stop: options.stopSequences }),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const response = await this.client.chat.completions.create(params);
|
|
113
|
+
const choice = response.choices[0]!;
|
|
114
|
+
const content = this.convertResponseContent(choice);
|
|
115
|
+
const usage = this.convertUsage(response.usage);
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
content,
|
|
119
|
+
model: response.model,
|
|
120
|
+
stopReason: this.convertStopReason(choice.finish_reason),
|
|
121
|
+
usage,
|
|
122
|
+
sessionId: options.sessionId,
|
|
123
|
+
};
|
|
124
|
+
} catch (err) {
|
|
125
|
+
this.handleError(err, 'complete');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async *stream(messages: Message[], options: ModelRequestOptions): AsyncGenerator<StreamEvent> {
|
|
130
|
+
try {
|
|
131
|
+
const openaiMessages = this.convertMessages(messages, options.systemPrompt);
|
|
132
|
+
const tools = this.convertTools(this.filterTools(options.tools, options.model));
|
|
133
|
+
|
|
134
|
+
const params: OpenAI.ChatCompletionCreateParams = {
|
|
135
|
+
model: options.model,
|
|
136
|
+
max_tokens: options.maxTokens,
|
|
137
|
+
messages: openaiMessages,
|
|
138
|
+
temperature: options.temperature,
|
|
139
|
+
...(tools.length > 0 && { tools }),
|
|
140
|
+
stream: true,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const stream = await this.client.chat.completions.create(params);
|
|
144
|
+
let currentToolCallId = '';
|
|
145
|
+
let currentToolName = '';
|
|
146
|
+
|
|
147
|
+
for await (const chunk of stream as AsyncIterable<OpenAI.ChatCompletionChunk>) {
|
|
148
|
+
const delta = chunk.choices[0]?.delta;
|
|
149
|
+
if (!delta) continue;
|
|
150
|
+
|
|
151
|
+
if (delta.content) {
|
|
152
|
+
yield { type: 'text_delta', delta: delta.content };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (delta.tool_calls) {
|
|
156
|
+
for (const tc of delta.tool_calls) {
|
|
157
|
+
if (tc.id) {
|
|
158
|
+
currentToolCallId = tc.id;
|
|
159
|
+
currentToolName = tc.function?.name || '';
|
|
160
|
+
yield { type: 'tool_call_start', toolCallId: tc.id, toolName: currentToolName };
|
|
161
|
+
}
|
|
162
|
+
if (tc.function?.arguments) {
|
|
163
|
+
yield {
|
|
164
|
+
type: 'tool_call_delta',
|
|
165
|
+
toolCallId: tc.id || currentToolCallId,
|
|
166
|
+
delta: tc.function.arguments,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (chunk.choices[0]?.finish_reason) {
|
|
173
|
+
const usage: TokenUsage = {
|
|
174
|
+
inputTokens: chunk.usage?.prompt_tokens ?? 0,
|
|
175
|
+
outputTokens: chunk.usage?.completion_tokens ?? 0,
|
|
176
|
+
};
|
|
177
|
+
yield {
|
|
178
|
+
type: 'message_complete',
|
|
179
|
+
stopReason: this.convertStopReason(chunk.choices[0].finish_reason),
|
|
180
|
+
usage,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} catch (err) {
|
|
185
|
+
yield this.handleStreamError(err);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async countTokens(messages: Message[]): Promise<number> {
|
|
190
|
+
const text = messages
|
|
191
|
+
.map((m) => m.content
|
|
192
|
+
.filter((c): c is Extract<ContentBlock, { type: 'text' }> => c.type === 'text')
|
|
193
|
+
.map((c) => c.text)
|
|
194
|
+
.join(' '))
|
|
195
|
+
.join(' ');
|
|
196
|
+
return Math.ceil(text.length / 4);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// --- Conversion helpers (shared by all OpenAI-compatible providers) ---
|
|
200
|
+
|
|
201
|
+
protected convertMessages(messages: Message[], systemPrompt?: string): OpenAI.ChatCompletionMessageParam[] {
|
|
202
|
+
const result: OpenAI.ChatCompletionMessageParam[] = [];
|
|
203
|
+
|
|
204
|
+
if (systemPrompt) {
|
|
205
|
+
result.push({ role: 'system', content: systemPrompt });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const msg of messages) {
|
|
209
|
+
if (msg.role === 'system') {
|
|
210
|
+
result.push({ role: 'system', content: msg.content.map((c) => c.type === 'text' ? c.text : '').join('') });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (msg.role === 'tool') {
|
|
215
|
+
const toolResults = msg.content
|
|
216
|
+
.filter((c): c is ToolResultContent => c.type === 'tool_result')
|
|
217
|
+
.map((c) => ({
|
|
218
|
+
role: 'tool' as const,
|
|
219
|
+
tool_call_id: c.tool_use_id,
|
|
220
|
+
content: typeof c.content === 'string' ? c.content : c.content.map((cc) => 'text' in cc ? cc.text : '').join(''),
|
|
221
|
+
}));
|
|
222
|
+
result.push(...toolResults);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// user or assistant
|
|
227
|
+
const textContent = msg.content
|
|
228
|
+
.filter((c): c is Extract<ContentBlock, { type: 'text' }> => c.type === 'text')
|
|
229
|
+
.map((c) => c.text)
|
|
230
|
+
.join('');
|
|
231
|
+
|
|
232
|
+
const toolCalls = msg.content
|
|
233
|
+
.filter((c): c is ToolUseContent => c.type === 'tool_use')
|
|
234
|
+
.map((c) => ({
|
|
235
|
+
id: c.id,
|
|
236
|
+
type: 'function' as const,
|
|
237
|
+
function: { name: c.name, arguments: JSON.stringify(c.input) },
|
|
238
|
+
}));
|
|
239
|
+
|
|
240
|
+
if (msg.role === 'assistant') {
|
|
241
|
+
const param: OpenAI.ChatCompletionAssistantMessageParam = {
|
|
242
|
+
role: 'assistant',
|
|
243
|
+
content: textContent || null,
|
|
244
|
+
...(toolCalls.length > 0 && { tool_calls: toolCalls }),
|
|
245
|
+
};
|
|
246
|
+
result.push(param);
|
|
247
|
+
} else {
|
|
248
|
+
result.push({ role: 'user', content: textContent });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
protected convertTools(tools: ToolDefinition[]): OpenAI.ChatCompletionTool[] {
|
|
256
|
+
return tools.map((t) => ({
|
|
257
|
+
type: 'function' as const,
|
|
258
|
+
function: {
|
|
259
|
+
name: t.name,
|
|
260
|
+
description: t.description,
|
|
261
|
+
parameters: t.inputSchema,
|
|
262
|
+
},
|
|
263
|
+
}));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected convertResponseContent(choice: OpenAI.ChatCompletion.Choice): ContentBlock[] {
|
|
267
|
+
const content: ContentBlock[] = [];
|
|
268
|
+
|
|
269
|
+
if (choice.message.content) {
|
|
270
|
+
content.push({ type: 'text', text: choice.message.content });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (choice.message.tool_calls) {
|
|
274
|
+
for (const tc of choice.message.tool_calls) {
|
|
275
|
+
let input: Record<string, unknown>;
|
|
276
|
+
try {
|
|
277
|
+
input = JSON.parse(tc.function.arguments);
|
|
278
|
+
} catch {
|
|
279
|
+
input = { raw: tc.function.arguments };
|
|
280
|
+
}
|
|
281
|
+
content.push({
|
|
282
|
+
type: 'tool_use',
|
|
283
|
+
id: createToolCallId(tc.id),
|
|
284
|
+
name: tc.function.name,
|
|
285
|
+
input,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return content;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
protected convertUsage(usage: OpenAI.CompletionUsage | undefined): TokenUsage {
|
|
294
|
+
return {
|
|
295
|
+
inputTokens: usage?.prompt_tokens ?? 0,
|
|
296
|
+
outputTokens: usage?.completion_tokens ?? 0,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
protected convertStopReason(reason: string | null | undefined): ModelResponse['stopReason'] {
|
|
301
|
+
switch (reason) {
|
|
302
|
+
case 'stop': return 'end_turn';
|
|
303
|
+
case 'tool_calls': return 'tool_use';
|
|
304
|
+
case 'length': return 'max_tokens';
|
|
305
|
+
case 'content_filter': return 'end_turn';
|
|
306
|
+
default: return 'end_turn';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* List available models from the API.
|
|
312
|
+
* Returns model IDs that can be used with this provider.
|
|
313
|
+
*/
|
|
314
|
+
async listModels(): Promise<string[]> {
|
|
315
|
+
try {
|
|
316
|
+
const response = await this.client.models.list();
|
|
317
|
+
const models: string[] = [];
|
|
318
|
+
for await (const model of response) {
|
|
319
|
+
models.push(model.id);
|
|
320
|
+
}
|
|
321
|
+
return models.sort();
|
|
322
|
+
} catch {
|
|
323
|
+
// If the API doesn't support /models endpoint, return empty array
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAIProvider.d.ts","sourceRoot":"","sources":["OpenAIProvider.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,cAAe,SAAQ,wBAAwB;IAC1D,QAAQ,CAAC,IAAI,YAAY;gBAEb,MAAM,EAAE,oBAAoB;CAQzC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// OpenAI Provider - GPT API integration
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Refactored: now extends OpenAICompatibleProvider base class.
|
|
5
|
+
// Only provider-specific logic remains (constructor, error hints).
|
|
6
|
+
// ============================================================================
|
|
7
|
+
|
|
8
|
+
import type { OpenAICompatibleConfig } from './OpenAICompatibleProvider.js';
|
|
9
|
+
import { OpenAICompatibleProvider } from './OpenAICompatibleProvider.js';
|
|
10
|
+
|
|
11
|
+
export interface OpenAIProviderConfig {
|
|
12
|
+
apiKey: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
organizationId?: string;
|
|
15
|
+
model: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class OpenAIProvider extends OpenAICompatibleProvider {
|
|
19
|
+
readonly name = 'OpenAI';
|
|
20
|
+
|
|
21
|
+
constructor(config: OpenAIProviderConfig) {
|
|
22
|
+
super({
|
|
23
|
+
apiKey: config.apiKey,
|
|
24
|
+
baseUrl: config.baseUrl,
|
|
25
|
+
model: config.model,
|
|
26
|
+
organizationId: config.organizationId,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { AnthropicProvider } from './AnthropicProvider.js';
|
|
2
|
+
export type { AnthropicProviderConfig } from './AnthropicProvider.js';
|
|
3
|
+
export { OpenAICompatibleProvider } from './OpenAICompatibleProvider.js';
|
|
4
|
+
export type { OpenAICompatibleConfig } from './OpenAICompatibleProvider.js';
|
|
5
|
+
export { OpenAIProvider } from './OpenAIProvider.js';
|
|
6
|
+
export type { OpenAIProviderConfig } from './OpenAIProvider.js';
|
|
7
|
+
export { OllamaProvider } from './OllamaProvider.js';
|
|
8
|
+
export type { OllamaProviderConfig } from './OllamaProvider.js';
|
|
9
|
+
export { OllamaCloudProvider } from './OllamaCloudProvider.js';
|
|
10
|
+
export type { OllamaCloudConfig } from './OllamaCloudProvider.js';
|
|
11
|
+
export { OllamaManager } from './OllamaManager.js';
|
|
12
|
+
export type { OllamaModel, OllamaPullProgress, OllamaModelInfo } from './OllamaManager.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"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"}
|